From f3d0fc7a66fa40e86036e7c626231e7de265cd64 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 15 Apr 2025 18:54:56 -0400 Subject: [PATCH] backends: port to new `std.io.BufferedWriter` API --- lib/compiler/aro/aro/Compilation.zig | 2 +- lib/compiler/build_runner.zig | 7 +- lib/std/Build/Cache/Path.zig | 4 +- lib/std/Build/Step.zig | 8 +- lib/std/Build/Step/CheckObject.zig | 8 +- lib/std/Target.zig | 19 +- lib/std/Uri.zig | 26 +- lib/std/fmt.zig | 6 +- lib/std/io/BufferedReader.zig | 130 +- lib/std/io/BufferedWriter.zig | 239 +-- lib/std/leb128.zig | 4 +- lib/std/math/big/int.zig | 36 +- lib/std/net.zig | 4 +- lib/std/zig.zig | 8 +- lib/std/zig/Ast.zig | 2 +- lib/std/zig/AstGen.zig | 13 +- lib/std/zig/LibCInstallation.zig | 2 +- lib/std/zig/ZonGen.zig | 5 +- lib/std/zig/llvm/BitcodeReader.zig | 24 +- lib/std/zig/llvm/Builder.zig | 851 +++++------ lib/std/zig/render.zig | 36 +- lib/std/zig/string_literal.zig | 38 +- lib/std/zon/stringify.zig | 10 +- src/Air.zig | 13 +- src/Air/Liveness.zig | 50 +- src/Air/Liveness/Verify.zig | 16 +- src/Air/print.zig | 28 +- src/Builtin.zig | 34 +- src/Compilation.zig | 43 +- src/InternPool.zig | 17 +- src/Package.zig | 2 +- src/Package/Fetch.zig | 30 +- src/Package/Fetch/git.zig | 10 +- src/Package/Manifest.zig | 4 +- src/Sema.zig | 835 +++++------ src/Sema/LowerZon.zig | 32 +- src/Type.zig | 158 +- src/Zcu.zig | 123 +- src/Zcu/PerThread.zig | 42 +- src/arch/aarch64/CodeGen.zig | 6 +- src/arch/aarch64/Emit.zig | 33 +- src/arch/arm/CodeGen.zig | 6 +- src/arch/arm/Emit.zig | 22 +- src/arch/riscv64/CodeGen.zig | 125 +- src/arch/riscv64/Emit.zig | 31 +- src/arch/riscv64/Lower.zig | 2 +- src/arch/riscv64/Mir.zig | 9 +- src/arch/riscv64/bits.zig | 21 +- src/arch/sparc64/CodeGen.zig | 10 +- src/arch/wasm/CodeGen.zig | 32 +- src/arch/wasm/Emit.zig | 238 ++- src/arch/x86_64/CodeGen.zig | 426 +++--- src/arch/x86_64/Disassembler.zig | 165 +- src/arch/x86_64/Emit.zig | 37 +- src/arch/x86_64/Encoding.zig | 54 +- src/arch/x86_64/bits.zig | 35 +- src/arch/x86_64/encoder.zig | 223 ++- src/codegen.zig | 276 ++-- src/codegen/llvm.zig | 26 +- src/codegen/spirv.zig | 18 +- src/codegen/spirv/spec.zig | 11 +- src/crash_report.zig | 25 +- src/fmt.zig | 6 +- src/libs/glibc.zig | 57 +- src/libs/mingw.zig | 14 +- src/libs/musl.zig | 24 +- src/link.zig | 50 +- src/link/Coff.zig | 57 +- src/link/Dwarf.zig | 1492 ++++++++++--------- src/link/Elf.zig | 275 ++-- src/link/Elf/Archive.zig | 75 +- src/link/Elf/Atom.zig | 392 +++-- src/link/Elf/AtomList.zig | 32 +- src/link/Elf/LinkerDefined.zig | 14 +- src/link/Elf/Merge.zig | 44 +- src/link/Elf/Object.zig | 137 +- src/link/Elf/SharedObject.zig | 24 +- src/link/Elf/Symbol.zig | 48 +- src/link/Elf/Thunk.zig | 22 +- src/link/Elf/ZigObject.zig | 61 +- src/link/Elf/eh_frame.zig | 87 +- src/link/Elf/file.zig | 16 +- src/link/Elf/gc.zig | 16 +- src/link/Elf/relocatable.zig | 44 +- src/link/Elf/relocation.zig | 14 +- src/link/Elf/synthetic_sections.zig | 242 ++- src/link/LdScript.zig | 2 +- src/link/MachO.zig | 326 ++-- src/link/MachO/Archive.zig | 83 +- src/link/MachO/Atom.zig | 126 +- src/link/MachO/CodeSignature.zig | 22 +- src/link/MachO/DebugSymbols.zig | 28 +- src/link/MachO/Dwarf.zig | 50 +- src/link/MachO/Dylib.zig | 98 +- src/link/MachO/InternalObject.zig | 28 +- src/link/MachO/Object.zig | 131 +- src/link/MachO/Relocation.zig | 13 +- src/link/MachO/Symbol.zig | 40 +- src/link/MachO/Thunk.zig | 30 +- src/link/MachO/UnwindInfo.zig | 100 +- src/link/MachO/ZigObject.zig | 46 +- src/link/MachO/dead_strip.zig | 12 +- src/link/MachO/dyld_info/Rebase.zig | 90 +- src/link/MachO/dyld_info/Trie.zig | 67 +- src/link/MachO/dyld_info/bind.zig | 335 ++--- src/link/MachO/eh_frame.zig | 90 +- src/link/MachO/file.zig | 22 +- src/link/MachO/load_commands.zig | 51 +- src/link/MachO/relocatable.zig | 91 +- src/link/MachO/synthetic.zig | 132 +- src/link/Plan9.zig | 116 +- src/link/SpirV.zig | 17 +- src/link/SpirV/deduplicate.zig | 2 +- src/link/SpirV/lower_invocation_globals.zig | 18 +- src/link/SpirV/prune_unused.zig | 8 +- src/link/Wasm.zig | 61 +- src/link/Wasm/Archive.zig | 5 +- src/link/Wasm/Flush.zig | 1025 ++++++------- src/link/Wasm/Object.zig | 594 ++++---- src/link/aarch64.zig | 6 +- src/link/riscv.zig | 46 +- src/link/table_section.zig | 12 +- src/main.zig | 107 +- src/print_targets.zig | 8 +- src/print_value.zig | 237 ++- src/print_zir.zig | 36 +- src/print_zoir.zig | 6 +- src/register_manager.zig | 6 +- src/translate_c.zig | 16 +- 129 files changed, 5612 insertions(+), 6720 deletions(-) diff --git a/lib/compiler/aro/aro/Compilation.zig b/lib/compiler/aro/aro/Compilation.zig index 798c192516..4dcbf95590 100644 --- a/lib/compiler/aro/aro/Compilation.zig +++ b/lib/compiler/aro/aro/Compilation.zig @@ -546,7 +546,7 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi } try buf.appendSlice("#define __STDC__ 1\n"); - try buf.writer().print("#define __STDC_HOSTED__ {d}\n", .{@intFromBool(comp.target.os.tag != .freestanding)}); + try buf.print("#define __STDC_HOSTED__ {d}\n", .{@intFromBool(comp.target.os.tag != .freestanding)}); // standard macros try buf.appendSlice( diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig index fcd27145f2..44aa3ea5ad 100644 --- a/lib/compiler/build_runner.zig +++ b/lib/compiler/build_runner.zig @@ -695,7 +695,10 @@ fn runStepNames( if (run.summary != .none) { var bw = std.debug.lockStdErr2(&stdio_buffer); - defer std.debug.unlockStdErr(); + defer { + bw.flush() catch {}; + std.debug.unlockStdErr(); + } const total_count = success_count + failure_count + pending_count + skipped_count; ttyconf.setColor(&bw, .cyan) catch {}; @@ -710,7 +713,7 @@ fn runStepNames( if (test_fail_count > 0) bw.print("; {d} failed", .{test_fail_count}) catch {}; if (test_leak_count > 0) bw.print("; {d} leaked", .{test_leak_count}) catch {}; - bw.writeAll("\n") catch {}; + bw.writeByte('\n') catch {}; // Print a fancy tree with build results. var step_stack_copy = try step_stack.clone(gpa); diff --git a/lib/std/Build/Cache/Path.zig b/lib/std/Build/Cache/Path.zig index 52cffe18dc..98d5884e9d 100644 --- a/lib/std/Build/Cache/Path.zig +++ b/lib/std/Build/Cache/Path.zig @@ -133,11 +133,11 @@ pub fn makePath(p: Path, sub_path: []const u8) !void { } pub fn toString(p: Path, allocator: Allocator) Allocator.Error![]u8 { - return std.fmt.allocPrint(allocator, "{}", .{p}); + return std.fmt.allocPrint(allocator, "{f}", .{p}); } pub fn toStringZ(p: Path, allocator: Allocator) Allocator.Error![:0]u8 { - return std.fmt.allocPrintZ(allocator, "{}", .{p}); + return std.fmt.allocPrintZ(allocator, "{f}", .{p}); } pub fn format( diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index a0f8da9ea3..fa86a35ecd 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -469,7 +469,7 @@ pub fn evalZigProcess( // This is intentionally printed for failure on the first build but not for // subsequent rebuilds. if (s.result_error_bundle.errorMessageCount() > 0) { - return s.fail("the following command failed with {d} compilation errors:\n{s}", .{ + return s.fail("the following command failed with {d} compilation errors:\n{s}\n", .{ s.result_error_bundle.errorMessageCount(), try allocPrintCmd(arena, null, argv), }); @@ -689,7 +689,7 @@ pub inline fn handleChildProcUnsupported( ) error{ OutOfMemory, MakeFailed }!void { if (!std.process.can_spawn) { return s.fail( - "unable to execute the following command: host cannot spawn child processes\n{s}", + "unable to execute the following command: host cannot spawn child processes\n{s}\n", .{try allocPrintCmd(s.owner.allocator, opt_cwd, argv)}, ); } @@ -706,14 +706,14 @@ pub fn handleChildProcessTerm( .Exited => |code| { if (code != 0) { return s.fail( - "the following command exited with error code {d}:\n{s}", + "the following command exited with error code {d}:\n{s}\n", .{ code, try allocPrintCmd(arena, opt_cwd, argv) }, ); } }, .Signal, .Stopped, .Unknown => { return s.fail( - "the following command terminated unexpectedly:\n{s}", + "the following command terminated unexpectedly:\n{s}\n", .{try allocPrintCmd(arena, opt_cwd, argv)}, ); }, diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index 5aa61a9d3b..fad5769015 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -1523,11 +1523,11 @@ const MachODumper = struct { ) !void { const size = try br.takeLeb128(u64); if (size > 0) { - const flags = try br.takeLeb128(u64); + const flags = try br.takeLeb128(u8); switch (flags) { macho.EXPORT_SYMBOL_FLAGS_REEXPORT => { const ord = try br.takeLeb128(u64); - const name = try br.takeDelimiterConclusive(0); + const name = try br.takeSentinel(0); try exports.append(.{ .name = if (name.len > 0) name else prefix, .tag = .reexport, @@ -1568,8 +1568,8 @@ const MachODumper = struct { const nedges = try br.takeByte(); for (0..nedges) |_| { - const label = try br.takeDelimiterConclusive(0); - const off = try br.takeLeb128(u64); + const label = try br.takeSentinel(0); + const off = try br.takeLeb128(usize); const prefix_label = try std.fmt.allocPrint(arena, "{s}{s}", .{ prefix, label }); const seek = br.seek; br.seek = off; diff --git a/lib/std/Target.zig b/lib/std/Target.zig index 26e5cab182..8fe70ec5ac 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -301,28 +301,23 @@ pub const Os = struct { /// This function is defined to serialize a Zig source code representation of this /// type, that, when parsed, will deserialize into the same data. - pub fn format( - ver: WindowsVersion, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: *std.io.BufferedWriter, - ) anyerror!void { + pub fn format(ver: WindowsVersion, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) anyerror!void { const maybe_name = std.enums.tagName(WindowsVersion, ver); if (comptime std.mem.eql(u8, fmt_str, "s")) { if (maybe_name) |name| - try writer.print(".{s}", .{name}) + try bw.print(".{s}", .{name}) else - try writer.print(".{d}", .{@intFromEnum(ver)}); + try bw.print(".{d}", .{@intFromEnum(ver)}); } else if (comptime std.mem.eql(u8, fmt_str, "c")) { if (maybe_name) |name| - try writer.print(".{s}", .{name}) + try bw.print(".{s}", .{name}) else - try writer.print("@enumFromInt(0x{X:0>8})", .{@intFromEnum(ver)}); + try bw.print("@enumFromInt(0x{X:0>8})", .{@intFromEnum(ver)}); } else if (fmt_str.len == 0) { if (maybe_name) |name| - try writer.print("WindowsVersion.{s}", .{name}) + try bw.print("WindowsVersion.{s}", .{name}) else - try writer.print("WindowsVersion(0x{X:0>8})", .{@intFromEnum(ver)}); + try bw.print("WindowsVersion(0x{X:0>8})", .{@intFromEnum(ver)}); } else std.fmt.invalidFmtError(fmt_str, ver); } }; diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig index fcb552fc4a..dd5bfa5ad1 100644 --- a/lib/std/Uri.zig +++ b/lib/std/Uri.zig @@ -236,44 +236,44 @@ pub const WriteToStreamOptions = struct { port: bool = true, }; -pub fn writeToStream(uri: Uri, options: WriteToStreamOptions, writer: *std.io.BufferedWriter) anyerror!void { +pub fn writeToStream(uri: Uri, options: WriteToStreamOptions, bw: *std.io.BufferedWriter) anyerror!void { if (options.scheme) { - try writer.print("{s}:", .{uri.scheme}); + try bw.print("{s}:", .{uri.scheme}); if (options.authority and uri.host != null) { - try writer.writeAll("//"); + try bw.writeAll("//"); } } if (options.authority) { if (options.authentication and uri.host != null) { if (uri.user) |user| { - try writer.print("{fuser}", .{user}); + try bw.print("{fuser}", .{user}); if (uri.password) |password| { - try writer.print(":{fpassword}", .{password}); + try bw.print(":{fpassword}", .{password}); } - try writer.writeByte('@'); + try bw.writeByte('@'); } } if (uri.host) |host| { - try writer.print("{fhost}", .{host}); + try bw.print("{fhost}", .{host}); if (options.port) { - if (uri.port) |port| try writer.print(":{d}", .{port}); + if (uri.port) |port| try bw.print(":{d}", .{port}); } } } if (options.path) { - try writer.print("{fpath}", .{ + try bw.print("{fpath}", .{ if (uri.path.isEmpty()) Uri.Component{ .percent_encoded = "/" } else uri.path, }); if (options.query) { - if (uri.query) |query| try writer.print("?{fquery}", .{query}); + if (uri.query) |query| try bw.print("?{fquery}", .{query}); } if (options.fragment) { - if (uri.fragment) |fragment| try writer.print("#{ffragment}", .{fragment}); + if (uri.fragment) |fragment| try bw.print("#{ffragment}", .{fragment}); } } } -pub fn format(uri: Uri, comptime fmt: []const u8, _: std.fmt.Options, writer: *std.io.BufferedWriter) anyerror!void { +pub fn format(uri: Uri, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { const scheme = comptime std.mem.indexOfScalar(u8, fmt, ';') != null or fmt.len == 0; const authentication = comptime std.mem.indexOfScalar(u8, fmt, '@') != null or fmt.len == 0; const authority = comptime std.mem.indexOfScalar(u8, fmt, '+') != null or fmt.len == 0; @@ -288,7 +288,7 @@ pub fn format(uri: Uri, comptime fmt: []const u8, _: std.fmt.Options, writer: *s .path = path, .query = query, .fragment = fragment, - }, writer); + }, bw); } /// Parses the URI or returns an error. diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 54fec30cfb..726af3f649 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -531,11 +531,7 @@ pub fn Formatter(comptime formatFn: anytype) type { const Data = @typeInfo(@TypeOf(formatFn)).@"fn".params[0].type.?; return struct { data: Data, - pub fn format( - self: @This(), - writer: *std.io.BufferedWriter, - comptime fmt: []const u8, - ) anyerror!void { + pub fn format(self: @This(), writer: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { try formatFn(self.data, writer, fmt); } }; diff --git a/lib/std/io/BufferedReader.zig b/lib/std/io/BufferedReader.zig index ef1634659e..b119002392 100644 --- a/lib/std/io/BufferedReader.zig +++ b/lib/std/io/BufferedReader.zig @@ -201,8 +201,8 @@ pub fn toss(br: *BufferedReader, n: usize) void { /// Equivalent to `peek` + `toss`. pub fn take(br: *BufferedReader, n: usize) anyerror![]u8 { - const result = try peek(br, n); - toss(br, n); + const result = try br.peek(n); + br.toss(n); return result; } @@ -218,7 +218,7 @@ pub fn take(br: *BufferedReader, n: usize) anyerror![]u8 { /// See also: /// * `take` pub fn takeArray(br: *BufferedReader, comptime n: usize) anyerror!*[n]u8 { - return (try take(br, n))[0..n]; + return (try br.take(n))[0..n]; } /// Skips the next `n` bytes from the stream, advancing the seek position. @@ -232,7 +232,7 @@ pub fn takeArray(br: *BufferedReader, comptime n: usize) anyerror!*[n]u8 { /// * `discardUntilEnd` /// * `discardUpTo` pub fn discard(br: *BufferedReader, n: usize) anyerror!void { - if ((try discardUpTo(br, n)) != n) return error.EndOfStream; + if ((try br.discardUpTo(n)) != n) return error.EndOfStream; } /// Skips the next `n` bytes from the stream, advancing the seek position. @@ -325,6 +325,34 @@ pub fn partialRead(br: *BufferedReader, buffer: []u8) anyerror!usize { @panic("TODO"); } +/// Returns a slice of the next bytes of buffered data from the stream until +/// `sentinel` is found, advancing the seek position. +/// +/// Returned slice has a sentinel. +/// +/// If the stream ends before the sentinel is found, `error.EndOfStream` is +/// returned. +/// +/// If the sentinel is not found within a number of bytes matching the +/// capacity of the `BufferedReader`, `error.StreamTooLong` is returned. +/// +/// Invalidates previously returned values from `peek`. +/// +/// See also: +/// * `peekSentinel` +/// * `takeDelimiterExclusive` +/// * `takeDelimiterInclusive` +pub fn takeSentinel(br: *BufferedReader, comptime sentinel: u8) anyerror![:sentinel]u8 { + const result = try br.peekSentinel(sentinel); + br.toss(result.len + 1); + return result; +} + +pub fn peekSentinel(br: *BufferedReader, comptime sentinel: u8) anyerror![:sentinel]u8 { + const result = try br.takeDelimiterInclusive(sentinel); + return result[0 .. result.len - 1 :sentinel]; +} + /// Returns a slice of the next bytes of buffered data from the stream until /// `delimiter` is found, advancing the seek position. /// @@ -339,36 +367,17 @@ pub fn partialRead(br: *BufferedReader, buffer: []u8) anyerror!usize { /// Invalidates previously returned values from `peek`. /// /// See also: -/// * `takeDelimiterConclusive` +/// * `takeSentinel` +/// * `takeDelimiterExclusive` /// * `peekDelimiterInclusive` pub fn takeDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { - const result = try peekDelimiterInclusive(br, delimiter); - toss(result.len); + const result = try br.peekDelimiterInclusive(delimiter); + br.toss(result.len); return result; } pub fn peekDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { - const storage = &br.storage; - const buffer = storage.buffer[0..storage.end]; - const seek = br.seek; - if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| { - @branchHint(.likely); - return buffer[seek .. end + 1]; - } - const remainder = buffer[seek..]; - std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); - var i = remainder.len; - storage.end = i; - br.seek = 0; - while (i < storage.buffer.len) { - const status = try br.unbuffered_reader.read(storage, .none); - if (std.mem.indexOfScalarPos(u8, storage.buffer[0..storage.end], i, delimiter)) |end| { - return storage.buffer[0 .. end + 1]; - } - if (status.end) return error.EndOfStream; - i = storage.end; - } - return error.StreamTooLong; + return (try br.peekDelimiterInclusiveUnlessEnd(delimiter)) orelse error.EndOfStream; } /// Returns a slice of the next bytes of buffered data from the stream until @@ -384,21 +393,32 @@ pub fn peekDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 /// Invalidates previously returned values from `peek`. /// /// See also: +/// * `takeSentinel` /// * `takeDelimiterInclusive` -/// * `peekDelimiterConclusive` -pub fn takeDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { - const result = try peekDelimiterConclusive(br, delimiter); +/// * `peekDelimiterExclusive` +pub fn takeDelimiterExclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { + const result_unless_end = try br.peekDelimiterInclusiveUnlessEnd(delimiter); + const result = result_unless_end orelse { + br.toss(br.storage.end); + return br.storage.buffer[0..br.storage.end]; + }; br.toss(result.len); - return result; + return result[0 .. result.len - 1]; } -pub fn peekDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { +pub fn peekDelimiterExclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { + const result_unless_end = try br.peekDelimiterInclusiveUnlessEnd(delimiter); + const result = result_unless_end orelse return br.storage.buffer[0..br.storage.end]; + return result[0 .. result.len - 1]; +} + +fn peekDelimiterInclusiveUnlessEnd(br: *BufferedReader, delimiter: u8) anyerror!?[]u8 { const storage = &br.storage; const buffer = storage.buffer[0..storage.end]; const seek = br.seek; if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| { @branchHint(.likely); - return buffer[seek..end]; + return buffer[seek .. end + 1]; } const remainder = buffer[seek..]; std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); @@ -407,10 +427,8 @@ pub fn peekDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 br.seek = 0; while (i < storage.buffer.len) { const status = try br.unbuffered_reader.read(storage, .unlimited); - if (std.mem.indexOfScalarPos(u8, storage.buffer[0..storage.end], i, delimiter)) |end| { - return storage.buffer[0 .. end + 1]; - } - if (status.end) return storage.buffer[0..storage.end]; + if (std.mem.indexOfScalarPos(u8, storage.buffer[0..storage.end], i, delimiter)) |end| return storage.buffer[0 .. end + 1]; + if (status.end) return null; i = storage.end; } return error.StreamTooLong; @@ -436,7 +454,7 @@ pub fn streamReadDelimiter(br: *BufferedReader, bw: *std.io.BufferedWriter, deli /// /// Returns number of bytes streamed as well as whether the input reached the end. /// The end is not signaled to the writer. -pub fn streamReadDelimiterConclusive( +pub fn streamReadDelimiterExclusive( br: *BufferedReader, bw: *std.io.BufferedWriter, delimiter: u8, @@ -468,7 +486,7 @@ pub fn streamReadDelimiterLimited( /// including the delimiter. /// /// If end of stream is found, this function succeeds. -pub fn discardDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror!void { +pub fn discardDelimiterExclusive(br: *BufferedReader, delimiter: u8) anyerror!void { _ = br; _ = delimiter; @panic("TODO"); @@ -517,7 +535,7 @@ pub fn takeByte(br: *BufferedReader) anyerror!u8 { const seek = br.seek; if (seek >= buffer.len) { @branchHint(.unlikely); - try fill(br, 1); + try br.fill(1); } br.seek = seek + 1; return buffer[seek]; @@ -531,20 +549,20 @@ pub fn takeByteSigned(br: *BufferedReader) anyerror!i8 { /// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`. pub inline fn takeInt(br: *BufferedReader, comptime T: type, endian: std.builtin.Endian) anyerror!T { const n = @divExact(@typeInfo(T).int.bits, 8); - return std.mem.readInt(T, try takeArray(br, n), endian); + return std.mem.readInt(T, try br.takeArray(n), endian); } /// Asserts the buffer was initialized with a capacity at least `n`. pub fn takeVarInt(br: *BufferedReader, comptime Int: type, endian: std.builtin.Endian, n: usize) anyerror!Int { assert(n <= @sizeOf(Int)); - return std.mem.readVarInt(Int, try take(br, n), endian); + return std.mem.readVarInt(Int, try br.take(n), endian); } /// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`. pub fn takeStruct(br: *BufferedReader, comptime T: type) anyerror!*align(1) T { // Only extern and packed structs have defined in-memory layout. comptime assert(@typeInfo(T).@"struct".layout != .auto); - return @ptrCast(try takeArray(br, @sizeOf(T))); + return @ptrCast(try br.takeArray(@sizeOf(T))); } /// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`. @@ -561,7 +579,7 @@ pub fn takeStructEndian(br: *BufferedReader, comptime T: type, endian: std.built /// Asserts the buffer was initialized with a capacity at least `@sizeOf(Enum)`. pub fn takeEnum(br: *BufferedReader, comptime Enum: type, endian: std.builtin.Endian) anyerror!Enum { const Tag = @typeInfo(Enum).@"enum".tag_type; - const int = try takeInt(br, Tag, endian); + const int = try br.takeInt(Tag, endian); return std.meta.intToEnum(Enum, int); } @@ -588,10 +606,12 @@ fn takeMultipleOf7Leb128(br: *BufferedReader, comptime Result: type) anyerror!Re const buffer: []const packed struct(u8) { bits: u7, more: bool } = @ptrCast(try br.peekAll(1)); for (buffer, 1..) |byte, len| { if (remaining_bits > 0) { - result = @shlExact(@as(UnsignedResult, byte.bits), result_info.bits - 7) | if (result_info.bits > 7) @shrExact(result, 7) else 0; + result = @shlExact(@as(UnsignedResult, byte.bits), result_info.bits - 7) | + if (result_info.bits > 7) @shrExact(result, 7) else 0; remaining_bits -= 7; } else if (fits) fits = switch (result_info.signedness) { - .signed => @as(i7, @bitCast(byte.bits)) == @as(i7, @truncate(@as(Result, @bitCast(result)) >> (result_info.bits - 1))), + .signed => @as(i7, @bitCast(byte.bits)) == + @as(i7, @truncate(@as(Result, @bitCast(result)) >> (result_info.bits - 1))), .unsigned => byte.bits == 0, }; if (byte.more) continue; @@ -652,6 +672,14 @@ test read { return error.Unimplemented; } +test takeSentinel { + return error.Unimplemented; +} + +test peekSentinel { + return error.Unimplemented; +} + test takeDelimiterInclusive { return error.Unimplemented; } @@ -660,11 +688,11 @@ test peekDelimiterInclusive { return error.Unimplemented; } -test takeDelimiterConclusive { +test takeDelimiterExclusive { return error.Unimplemented; } -test peekDelimiterConclusive { +test peekDelimiterExclusive { return error.Unimplemented; } @@ -672,7 +700,7 @@ test streamReadDelimiter { return error.Unimplemented; } -test streamReadDelimiterConclusive { +test streamReadDelimiterExclusive { return error.Unimplemented; } @@ -680,7 +708,7 @@ test streamReadDelimiterLimited { return error.Unimplemented; } -test discardDelimiterConclusive { +test discardDelimiterExclusive { return error.Unimplemented; } diff --git a/lib/std/io/BufferedWriter.zig b/lib/std/io/BufferedWriter.zig index 114b6491a6..fcafca757c 100644 --- a/lib/std/io/BufferedWriter.zig +++ b/lib/std/io/BufferedWriter.zig @@ -92,7 +92,7 @@ pub fn writableSlice(bw: *BufferedWriter, minimum_length: usize) anyerror![]u8 { return cap_slice; } const buffer = bw.buffer[0..bw.end]; - const n = try bw.unbuffered_writer.write(buffer); + const n = try bw.unbuffered_writer.writev(&.{buffer}); if (n == buffer.len) { @branchHint(.likely); bw.end = 0; @@ -306,7 +306,7 @@ pub fn write(bw: *BufferedWriter, bytes: []const u8) anyerror!usize { /// transferred. pub fn writeAll(bw: *BufferedWriter, bytes: []const u8) anyerror!void { var index: usize = 0; - while (index < bytes.len) index += try write(bw, bytes[index..]); + while (index < bytes.len) index += try bw.write(bytes[index..]); } pub fn print(bw: *BufferedWriter, comptime format: []const u8, args: anytype) anyerror!void { @@ -354,7 +354,7 @@ pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void { /// many times as necessary. pub fn splatByteAll(bw: *BufferedWriter, byte: u8, n: usize) anyerror!void { var remaining: usize = n; - while (remaining > 0) remaining -= try splatByte(bw, byte, remaining); + while (remaining > 0) remaining -= try bw.splatByte(byte, remaining); } /// Writes the same byte many times, allowing short writes. @@ -368,11 +368,11 @@ pub fn splatByte(bw: *BufferedWriter, byte: u8, n: usize) anyerror!usize { /// many times as necessary. pub fn splatBytesAll(bw: *BufferedWriter, bytes: []const u8, splat: usize) anyerror!void { var remaining_bytes: usize = bytes.len * splat; - remaining_bytes -= try splatBytes(bw, bytes, splat); + remaining_bytes -= try bw.splatBytes(bytes, splat); while (remaining_bytes > 0) { const leftover = remaining_bytes % bytes.len; const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes }; - remaining_bytes -= try splatBytes(bw, &buffers, splat); + remaining_bytes -= try bw.splatBytes(&buffers, splat); } } @@ -519,7 +519,7 @@ pub fn writeFileAll(bw: *BufferedWriter, file: std.fs.File, options: WriteFileOp const headers_and_trailers = options.headers_and_trailers; const headers = headers_and_trailers[0..options.headers_len]; switch (options.limit) { - .nothing => return writevAll(bw, headers_and_trailers), + .nothing => return bw.writevAll(headers_and_trailers), .unlimited => { // When reading the whole file, we cannot include the trailers in the // call that reads from the file handle, because we have no way to @@ -528,7 +528,7 @@ pub fn writeFileAll(bw: *BufferedWriter, file: std.fs.File, options: WriteFileOp var i: usize = 0; var offset = options.offset; while (true) { - var n = try writeFile(bw, file, offset, .unlimited, headers[i..], headers.len - i); + var n = try bw.writeFile(file, offset, .unlimited, headers[i..], headers.len - i); while (i < headers.len and n >= headers[i].len) { n -= headers[i].len; i += 1; @@ -546,7 +546,7 @@ pub fn writeFileAll(bw: *BufferedWriter, file: std.fs.File, options: WriteFileOp var i: usize = 0; var offset = options.offset; while (true) { - var n = try writeFile(bw, file, offset, .limited(len), headers_and_trailers[i..], headers.len - i); + var n = try bw.writeFile(file, offset, .limited(len), headers_and_trailers[i..], headers.len - i); while (i < headers.len and n >= headers[i].len) { n -= headers[i].len; i += 1; @@ -564,7 +564,7 @@ pub fn writeFileAll(bw: *BufferedWriter, file: std.fs.File, options: WriteFileOp if (i >= headers_and_trailers.len) return; } headers_and_trailers[i] = headers_and_trailers[i][n..]; - return writevAll(bw, headers_and_trailers[i..]); + return bw.writevAll(headers_and_trailers[i..]); } offset = offset.advance(n); len -= n; @@ -605,7 +605,7 @@ pub fn alignBuffer( } pub fn alignBufferOptions(bw: *BufferedWriter, buffer: []const u8, options: std.fmt.Options) anyerror!void { - return alignBuffer(bw, buffer, options.width orelse buffer.len, options.alignment, options.fill); + return bw.alignBuffer(buffer, options.width orelse buffer.len, options.alignment, options.fill); } pub fn printAddress(bw: *BufferedWriter, value: anytype) anyerror!void { @@ -614,15 +614,15 @@ pub fn printAddress(bw: *BufferedWriter, value: anytype) anyerror!void { .pointer => |info| { try bw.writeAll(@typeName(info.child) ++ "@"); if (info.size == .slice) - try printIntOptions(bw, @intFromPtr(value.ptr), 16, .lower, .{}) + try bw.printIntOptions(@intFromPtr(value.ptr), 16, .lower, .{}) else - try printIntOptions(bw, @intFromPtr(value), 16, .lower, .{}); + try bw.printIntOptions(@intFromPtr(value), 16, .lower, .{}); return; }, .optional => |info| { if (@typeInfo(info.child) == .pointer) { try bw.writeAll(@typeName(info.child) ++ "@"); - try printIntOptions(bw, @intFromPtr(value), 16, .lower, .{}); + try bw.printIntOptions(@intFromPtr(value), 16, .lower, .{}); return; } }, @@ -648,7 +648,7 @@ pub fn printValue( } else fmt; if (comptime std.mem.eql(u8, actual_fmt, "*")) { - return printAddress(bw, value); + return bw.printAddress(value); } if (std.meta.hasMethod(T, "format")) { @@ -661,24 +661,24 @@ pub fn printValue( } switch (@typeInfo(T)) { - .float, .comptime_float => return printFloat(bw, actual_fmt, options, value), - .int, .comptime_int => return printInt(bw, actual_fmt, options, value), + .float, .comptime_float => return bw.printFloat(actual_fmt, options, value), + .int, .comptime_int => return bw.printInt(actual_fmt, options, value), .bool => { if (actual_fmt.len != 0) invalidFmtError(fmt, value); - return alignBufferOptions(bw, if (value) "true" else "false", options); + return bw.alignBufferOptions(if (value) "true" else "false", options); }, .void => { if (actual_fmt.len != 0) invalidFmtError(fmt, value); - return alignBufferOptions(bw, "void", options); + return bw.alignBufferOptions("void", options); }, .optional => { if (actual_fmt.len == 0 or actual_fmt[0] != '?') @compileError("cannot print optional without a specifier (i.e. {?} or {any})"); const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt); if (value) |payload| { - return printValue(bw, remaining_fmt, options, payload, max_depth); + return bw.printValue(remaining_fmt, options, payload, max_depth); } else { - return alignBufferOptions(bw, "null", options); + return bw.alignBufferOptions("null", options); } }, .error_union => { @@ -686,9 +686,9 @@ pub fn printValue( @compileError("cannot format error union without a specifier (i.e. {!} or {any})"); const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt); if (value) |payload| { - return printValue(bw, remaining_fmt, options, payload, max_depth); + return bw.printValue(remaining_fmt, options, payload, max_depth); } else |err| { - return printValue(bw, "", options, err, max_depth); + return bw.printValue("", options, err, max_depth); } }, .error_set => { @@ -721,14 +721,14 @@ pub fn printValue( } try bw.writeByte('('); - try printValue(bw, actual_fmt, options, @intFromEnum(value), max_depth); + try bw.printValue(actual_fmt, options, @intFromEnum(value), max_depth); try bw.writeByte(')'); }, .@"union" => |info| { if (actual_fmt.len != 0) invalidFmtError(fmt, value); try bw.writeAll(@typeName(T)); if (max_depth == 0) { - bw.writeAll("{ ... }"); + try bw.writeAll("{ ... }"); return; } if (info.tag_type) |UnionTagType| { @@ -737,13 +737,13 @@ pub fn printValue( try bw.writeAll(" = "); inline for (info.fields) |u_field| { if (value == @field(UnionTagType, u_field.name)) { - try printValue(bw, ANY, options, @field(value, u_field.name), max_depth - 1); + try bw.printValue(ANY, options, @field(value, u_field.name), max_depth - 1); } } try bw.writeAll(" }"); } else { try bw.writeByte('@'); - try bw.printIntOptions(@intFromPtr(&value), 16, .lower); + try bw.printIntOptions(@intFromPtr(&value), 16, .lower, options); } }, .@"struct" => |info| { @@ -761,7 +761,7 @@ pub fn printValue( } else { try bw.writeAll(", "); } - try printValue(bw, ANY, options, @field(value, f.name), max_depth - 1); + try bw.printValue(ANY, options, @field(value, f.name), max_depth - 1); } try bw.writeAll(" }"); return; @@ -780,19 +780,19 @@ pub fn printValue( } try bw.writeAll(f.name); try bw.writeAll(" = "); - try printValue(bw, ANY, options, @field(value, f.name), max_depth - 1); + try bw.printValue(ANY, options, @field(value, f.name), max_depth - 1); } try bw.writeAll(" }"); }, .pointer => |ptr_info| switch (ptr_info.size) { .one => switch (@typeInfo(ptr_info.child)) { .array, .@"enum", .@"union", .@"struct" => { - return printValue(bw, actual_fmt, options, value.*, max_depth); + return bw.printValue(actual_fmt, options, value.*, max_depth); }, else => { var buffers: [2][]const u8 = .{ @typeName(ptr_info.child), "@" }; - try writevAll(bw, &buffers); - try printIntOptions(bw, @intFromPtr(value), 16, .lower, options); + try bw.writevAll(&buffers); + try bw.printIntOptions(@intFromPtr(value), 16, .lower, options); return; }, }, @@ -800,10 +800,10 @@ pub fn printValue( if (actual_fmt.len == 0) @compileError("cannot format pointer without a specifier (i.e. {s} or {*})"); if (ptr_info.sentinel() != null) { - return printValue(bw, actual_fmt, options, std.mem.span(value), max_depth); + return bw.printValue(actual_fmt, options, std.mem.span(value), max_depth); } if (actual_fmt[0] == 's' and ptr_info.child == u8) { - return alignBufferOptions(bw, std.mem.span(value), options); + return bw.alignBufferOptions(std.mem.span(value), options); } invalidFmtError(fmt, value); }, @@ -815,19 +815,19 @@ pub fn printValue( } if (ptr_info.child == u8) switch (actual_fmt.len) { 1 => switch (actual_fmt[0]) { - 's' => return alignBufferOptions(bw, value, options), - 'x' => return printHex(bw, value, .lower), - 'X' => return printHex(bw, value, .upper), + 's' => return bw.alignBufferOptions(value, options), + 'x' => return bw.printHex(value, .lower), + 'X' => return bw.printHex(value, .upper), else => {}, }, 3 => if (actual_fmt[0] == 'b' and actual_fmt[1] == '6' and actual_fmt[2] == '4') { - return printBase64(bw, value); + return bw.printBase64(value); }, else => {}, }; try bw.writeAll("{ "); for (value, 0..) |elem, i| { - try printValue(bw, actual_fmt, options, elem, max_depth - 1); + try bw.printValue(actual_fmt, options, elem, max_depth - 1); if (i != value.len - 1) { try bw.writeAll(", "); } @@ -843,16 +843,16 @@ pub fn printValue( } if (info.child == u8) { if (actual_fmt[0] == 's') { - return alignBufferOptions(bw, &value, options); + return bw.alignBufferOptions(&value, options); } else if (actual_fmt[0] == 'x') { - return printHex(bw, &value, .lower); + return bw.printHex(&value, .lower); } else if (actual_fmt[0] == 'X') { - return printHex(bw, &value, .upper); + return bw.printHex(&value, .upper); } } try bw.writeAll("{ "); for (value, 0..) |elem, i| { - try printValue(bw, actual_fmt, options, elem, max_depth - 1); + try bw.printValue(actual_fmt, options, elem, max_depth - 1); if (i < value.len - 1) { try bw.writeAll(", "); } @@ -866,7 +866,7 @@ pub fn printValue( try bw.writeAll("{ "); var i: usize = 0; while (i < info.len) : (i += 1) { - try printValue(bw, actual_fmt, options, value[i], max_depth - 1); + try bw.printValue(actual_fmt, options, value[i], max_depth - 1); if (i < info.len - 1) { try bw.writeAll(", "); } @@ -876,16 +876,16 @@ pub fn printValue( .@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"), .type => { if (actual_fmt.len != 0) invalidFmtError(fmt, value); - return alignBufferOptions(bw, @typeName(value), options); + return bw.alignBufferOptions(@typeName(value), options); }, .enum_literal => { if (actual_fmt.len != 0) invalidFmtError(fmt, value); const buffer = [_]u8{'.'} ++ @tagName(value); - return alignBufferOptions(bw, buffer, options); + return bw.alignBufferOptions(buffer, options); }, .null => { if (actual_fmt.len != 0) invalidFmtError(fmt, value); - return alignBufferOptions(bw, "null", options); + return bw.alignBufferOptions("null", options); }, else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"), } @@ -903,34 +903,34 @@ pub fn printInt( } else value; switch (fmt.len) { - 0 => return printIntOptions(bw, int_value, 10, .lower, options), + 0 => return bw.printIntOptions(int_value, 10, .lower, options), 1 => switch (fmt[0]) { - 'd' => return printIntOptions(bw, int_value, 10, .lower, options), + 'd' => return bw.printIntOptions(int_value, 10, .lower, options), 'c' => { if (@typeInfo(@TypeOf(int_value)).int.bits <= 8) { - return printAsciiChar(bw, @as(u8, int_value), options); + return bw.printAsciiChar(@as(u8, int_value), options); } else { @compileError("cannot print integer that is larger than 8 bits as an ASCII character"); } }, 'u' => { if (@typeInfo(@TypeOf(int_value)).int.bits <= 21) { - return printUnicodeCodepoint(bw, @as(u21, int_value), options); + return bw.printUnicodeCodepoint(@as(u21, int_value), options); } else { @compileError("cannot print integer that is larger than 21 bits as an UTF-8 sequence"); } }, - 'b' => return printIntOptions(bw, int_value, 2, .lower, options), - 'x' => return printIntOptions(bw, int_value, 16, .lower, options), - 'X' => return printIntOptions(bw, int_value, 16, .upper, options), - 'o' => return printIntOptions(bw, int_value, 8, .lower, options), - 'B' => return printByteSize(bw, int_value, .decimal, options), - 'D' => return printDuration(bw, int_value, options), + 'b' => return bw.printIntOptions(int_value, 2, .lower, options), + 'x' => return bw.printIntOptions(int_value, 16, .lower, options), + 'X' => return bw.printIntOptions(int_value, 16, .upper, options), + 'o' => return bw.printIntOptions(int_value, 8, .lower, options), + 'B' => return bw.printByteSize(int_value, .decimal, options), + 'D' => return bw.printDuration(int_value, options), else => invalidFmtError(fmt, value), }, 2 => { if (fmt[0] == 'B' and fmt[1] == 'i') { - return printByteSize(bw, int_value, .binary, options); + return bw.printByteSize(int_value, .binary, options); } else { invalidFmtError(fmt, value); } @@ -941,17 +941,17 @@ pub fn printInt( } pub fn printAsciiChar(bw: *BufferedWriter, c: u8, options: std.fmt.Options) anyerror!void { - return alignBufferOptions(bw, @as(*const [1]u8, &c), options); + return bw.alignBufferOptions(@as(*const [1]u8, &c), options); } pub fn printAscii(bw: *BufferedWriter, bytes: []const u8, options: std.fmt.Options) anyerror!void { - return alignBufferOptions(bw, bytes, options); + return bw.alignBufferOptions(bytes, options); } pub fn printUnicodeCodepoint(bw: *BufferedWriter, c: u21, options: std.fmt.Options) anyerror!void { var buf: [4]u8 = undefined; const len = try std.unicode.utf8Encode(c, &buf); - return alignBufferOptions(bw, buf[0..len], options); + return bw.alignBufferOptions(buf[0..len], options); } pub fn printIntOptions( @@ -1019,7 +1019,7 @@ pub fn printIntOptions( } } - return alignBufferOptions(bw, buf[index..], options); + return bw.alignBufferOptions(buf[index..], options); } pub fn printFloat( @@ -1036,19 +1036,19 @@ pub fn printFloat( const s = std.fmt.float.render(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) { error.BufferTooSmall => "(float)", }; - return alignBufferOptions(bw, s, options); + return bw.alignBufferOptions(s, options); }, 'd' => { const s = std.fmt.float.render(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { error.BufferTooSmall => "(float)", }; - return alignBufferOptions(bw, s, options); + return bw.alignBufferOptions(s, options); }, 'x' => { var sub_bw: BufferedWriter = undefined; sub_bw.initFixed(&buf); sub_bw.printFloatHexadecimal(value, options.precision) catch unreachable; - return alignBufferOptions(bw, sub_bw.getWritten(), options); + return bw.alignBufferOptions(sub_bw.getWritten(), options); }, else => invalidFmtError(fmt, value), } @@ -1150,7 +1150,7 @@ pub fn printFloatHexadecimal(bw: *BufferedWriter, value: anytype, opt_precision: try bw.splatByteAll('0', precision - trimmed.len); }; try bw.writeAll("p"); - try printIntOptions(bw, exponent - exponent_bias, 10, .lower, .{}); + try bw.printIntOptions(exponent - exponent_bias, 10, .lower, .{}); } pub const ByteSizeUnits = enum { @@ -1169,7 +1169,7 @@ pub fn printByteSize( comptime units: ByteSizeUnits, options: std.fmt.Options, ) anyerror!void { - if (value == 0) return alignBufferOptions(bw, "0B", options); + if (value == 0) return bw.alignBufferOptions("0B", options); // The worst case in terms of space needed is 32 bytes + 3 for the suffix. var buf: [std.fmt.float.min_buffer_size + 3]u8 = undefined; @@ -1213,7 +1213,7 @@ pub fn printByteSize( }, } - return alignBufferOptions(bw, buf[0..i], options); + return bw.alignBufferOptions(buf[0..i], options); } // This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948 @@ -1250,7 +1250,7 @@ pub fn invalidFmtError(comptime fmt: []const u8, value: anytype) noreturn { pub fn printDurationSigned(bw: *BufferedWriter, ns: i64) anyerror!void { if (ns < 0) try bw.writeByte('-'); - return printDurationUnsigned(bw, @abs(ns)); + return bw.printDurationUnsigned(@abs(ns)); } pub fn printDurationUnsigned(bw: *BufferedWriter, ns: u64) anyerror!void { @@ -1296,7 +1296,7 @@ pub fn printDurationUnsigned(bw: *BufferedWriter, ns: u64) anyerror!void { } } - try printIntOptions(bw, ns_remaining, 10, .lower, .{}); + try bw.printIntOptions(ns_remaining, 10, .lower, .{}); try bw.writeAll("ns"); } @@ -1312,7 +1312,7 @@ pub fn printDuration(bw: *BufferedWriter, nanoseconds: anytype, options: std.fmt .signed => sub_bw.printDurationSigned(nanoseconds) catch unreachable, .unsigned => sub_bw.printDurationUnsigned(nanoseconds) catch unreachable, } - return alignBufferOptions(bw, sub_bw.getWritten(), options); + return bw.alignBufferOptions(sub_bw.getWritten(), options); } pub fn printHex(bw: *BufferedWriter, bytes: []const u8, case: std.fmt.Case) anyerror!void { @@ -1321,8 +1321,8 @@ pub fn printHex(bw: *BufferedWriter, bytes: []const u8, case: std.fmt.Case) anye .lower => "0123456789abcdef", }; for (bytes) |c| { - try writeByte(bw, charset[c >> 4]); - try writeByte(bw, charset[c & 15]); + try bw.writeByte(charset[c >> 4]); + try bw.writeByte(charset[c & 15]); } } @@ -1334,50 +1334,67 @@ pub fn printBase64(bw: *BufferedWriter, bytes: []const u8) anyerror!void { } } -/// Write a single unsigned integer as unsigned LEB128 to the given writer. -pub fn writeUleb128(bw: *std.io.BufferedWriter, arg: anytype) anyerror!void { - const Arg = @TypeOf(arg); - const Int = switch (Arg) { - comptime_int => std.math.IntFittingRange(arg, arg), - else => Arg, - }; - const Value = if (@typeInfo(Int).int.bits < 8) u8 else Int; - var value: Value = arg; - - while (true) { - const byte: u8 = @truncate(value & 0x7f); - value >>= 7; - if (value == 0) { - try bw.writeByte(byte); - return; - } else { - try bw.writeByte(byte | 0x80); - } - } +/// Write a single unsigned integer as LEB128 to the given writer. +pub fn writeUleb128(bw: *BufferedWriter, value: anytype) anyerror!void { + try bw.writeLeb128(switch (@typeInfo(@TypeOf(value))) { + .comptime_int => @as(std.math.IntFittingRange(0, @abs(value)), value), + .int => |value_info| switch (value_info.signedness) { + .signed => @as(@Type(.{ .int = .{ .signedness = .unsigned, .bits = value_info.bits -| 1 } }), @intCast(value)), + .unsigned => value, + }, + else => comptime unreachable, + }); } -/// Write a single signed integer as signed LEB128 to the given writer. -pub fn writeIleb128(bw: *std.io.BufferedWriter, arg: anytype) anyerror!void { - const Arg = @TypeOf(arg); - const Int = switch (Arg) { - comptime_int => std.math.IntFittingRange(-@abs(arg), @abs(arg)), - else => Arg, - }; - const Signed = if (@typeInfo(Int).int.bits < 8) i8 else Int; - const Unsigned = std.meta.Int(.unsigned, @typeInfo(Signed).int.bits); - var value: Signed = arg; +/// Write a single signed integer as LEB128 to the given writer. +pub fn writeSleb128(bw: *BufferedWriter, value: anytype) anyerror!void { + try bw.writeLeb128(switch (@typeInfo(@TypeOf(value))) { + .comptime_int => @as(std.math.IntFittingRange(@min(value, -1), @max(0, value)), value), + .int => |value_info| switch (value_info.signedness) { + .signed => value, + .unsigned => @as(@Type(.{ .int = .{ .signedness = .signed, .bits = value_info.bits + 1 } }), value), + }, + else => comptime unreachable, + }); +} +/// Write a single integer as LEB128 to the given writer. +pub fn writeLeb128(bw: *BufferedWriter, value: anytype) anyerror!void { + const value_info = @typeInfo(@TypeOf(value)).int; + try bw.writeMultipleOf7Leb128(@as(@Type(.{ .int = .{ + .signedness = value_info.signedness, + .bits = std.mem.alignForwardAnyAlign(u16, value_info.bits, 7), + } }), value)); +} + +fn writeMultipleOf7Leb128(bw: *BufferedWriter, value: anytype) anyerror!void { + const value_info = @typeInfo(@TypeOf(value)).int; + comptime assert(value_info.bits % 7 == 0); + var remaining = value; while (true) { - const unsigned: Unsigned = @bitCast(value); - const byte: u8 = @truncate(unsigned); - value >>= 6; - if (value == -1 or value == 0) { - try bw.writeByte(byte & 0x7F); - return; - } else { - value >>= 1; - try bw.writeByte(byte | 0x80); + const buffer: []packed struct(u8) { bits: u7, more: bool } = @ptrCast(try bw.writableSlice(1)); + for (buffer, 1..) |*byte, len| { + const more = switch (value_info.signedness) { + .signed => remaining >> 6 != remaining >> (value_info.bits - 1), + .unsigned => remaining > std.math.maxInt(u7), + }; + byte.* = if (@inComptime()) @typeInfo(@TypeOf(buffer)).pointer.child{ + .bits = @bitCast(@as(@Type(.{ .int = .{ + .signedness = value_info.signedness, + .bits = 7, + } }), @truncate(remaining))), + .more = more, + } else .{ + .bits = @bitCast(@as(@Type(.{ .int = .{ + .signedness = value_info.signedness, + .bits = 7, + } }), @truncate(remaining))), + .more = more, + }; + if (value_info.bits > 7) remaining >>= 7; + if (!more) return bw.advance(len); } + bw.advance(buffer.len); } } diff --git a/lib/std/leb128.zig b/lib/std/leb128.zig index 5e48fa107f..be53fba57a 100644 --- a/lib/std/leb128.zig +++ b/lib/std/leb128.zig @@ -55,10 +55,10 @@ test writeUnsignedFixed { } /// This is an "advanced" function. It allows one to use a fixed amount of memory to store an -/// ILEB128. This defeats the entire purpose of using this data encoding; it will no longer use +/// SLEB128. This defeats the entire purpose of using this data encoding; it will no longer use /// fewer bytes to store smaller numbers. The advantage of using a fixed width is that it makes /// fields have a predictable size and so depending on the use case this tradeoff can be worthwhile. -/// An example use case of this is in emitting DWARF info where one wants to make a ILEB128 field +/// An example use case of this is in emitting DWARF info where one wants to make a SLEB128 field /// "relocatable", meaning that it becomes possible to later go back and patch the number to be a /// different value without shifting all the following code. pub fn writeSignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(.signed, l * 7)) void { diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 552ded4d51..fed3613baf 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -2322,13 +2322,7 @@ pub const Const = struct { /// this function will fail to print the string, printing "(BigInt)" instead of a number. /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory. /// See `toString` and `toStringAlloc` for a way to print big integers without failure. - pub fn format( - self: Const, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - out_stream: anytype, - ) !void { - _ = options; + pub fn format(self: Const, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { comptime var base = 10; comptime var case: std.fmt.Case = .lower; @@ -2348,19 +2342,21 @@ pub const Const = struct { std.fmt.invalidFmtError(fmt, self); } - const available_len = 64; - if (self.limbs.len > available_len) - return out_stream.writeAll("(BigInt)"); - - var limbs: [calcToStringLimbsBufferLen(available_len, base)]Limb = undefined; - - const biggest: Const = .{ - .limbs = &([1]Limb{comptime math.maxInt(Limb)} ** available_len), - .positive = false, - }; - var buf: [biggest.sizeInBaseUpperBound(base)]u8 = undefined; - const len = self.toString(&buf, base, case, &limbs); - return out_stream.writeAll(buf[0..len]); + const max_str_len = self.sizeInBaseUpperBound(base); + const limbs_len = calcToStringLimbsBufferLen(self.limbs.len, base); + if (bw.writableSlice(max_str_len + @alignOf(Limb) - 1 + @sizeOf(Limb) * limbs_len)) |buf| { + const limbs: [*]Limb = @alignCast(@ptrCast(std.mem.alignPointer(buf[max_str_len..].ptr, @alignOf(Limb)))); + bw.advance(self.toString(buf[0..max_str_len], base, case, limbs[0..limbs_len])); + return; + } else |_| if (bw.writableSlice(max_str_len)) |buf| { + const available_len = 64; + var limbs: [calcToStringLimbsBufferLen(available_len, base)]Limb = undefined; + if (limbs.len >= limbs_len) { + bw.advance(self.toString(buf, base, case, &limbs)); + return; + } + } else |_| {} + try bw.writeAll("(BigInt)"); } /// Converts self to a string in the requested base. diff --git a/lib/std/net.zig b/lib/std/net.zig index e01df2b417..0e0e9327bc 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -1358,7 +1358,7 @@ fn linuxLookupNameFromHosts( var line_buf: [512]u8 = undefined; var br = file.reader().buffered(&line_buf); - while (br.takeDelimiterConclusive('\n')) |line| { + while (br.takeSentinel('\n')) |line| { var split_it = mem.splitScalar(u8, line, '#'); const no_comment_line = split_it.first(); @@ -1550,7 +1550,7 @@ fn getResolvConf(allocator: mem.Allocator, rc: *ResolvConf) !void { var line_buf: [512]u8 = undefined; var br = file.reader().buffered(&line_buf); - while (br.takeDelimiterConclusive('\n')) |line_with_comment| { + while (br.takeSentinel('\n')) |line_with_comment| { const line = line: { var split = mem.splitScalar(u8, line_with_comment, '#'); break :line split.first(); diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 04fb6e4d19..25e498d53b 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -544,9 +544,9 @@ pub fn readSourceFileToEndAlloc(gpa: Allocator, input: std.fs.File, size_hint: u var buffer: std.ArrayListAlignedUnmanaged(u8, .@"2") = .empty; defer buffer.deinit(gpa); - try buffer.ensureUnusedCapacity(size_hint); + try buffer.ensureUnusedCapacity(gpa, size_hint); - input.readIntoArrayList(gpa, .init(max_src_size), .@"2", &buffer) catch |err| switch (err) { + input.readIntoArrayList(gpa, .limited(max_src_size), .@"2", &buffer) catch |err| switch (err) { error.ConnectionResetByPeer => unreachable, error.ConnectionTimedOut => unreachable, error.NotOpenForReading => unreachable, @@ -568,7 +568,7 @@ pub fn readSourceFileToEndAlloc(gpa: Allocator, input: std.fs.File, size_hint: u // If the file starts with a UTF-16 little endian BOM, translate it to UTF-8 if (std.mem.startsWith(u8, buffer.items, "\xff\xfe")) { if (buffer.items.len % 2 != 0) return error.InvalidEncoding; - return std.unicode.utf16LeToUtf8AllocZ(gpa, buffer.items) catch |err| switch (err) { + return std.unicode.utf16LeToUtf8AllocZ(gpa, @ptrCast(buffer.items)) catch |err| switch (err) { error.DanglingSurrogateHalf => error.UnsupportedEncoding, error.ExpectedSecondSurrogateHalf => error.UnsupportedEncoding, error.UnexpectedSecondSurrogateHalf => error.UnsupportedEncoding, @@ -576,7 +576,7 @@ pub fn readSourceFileToEndAlloc(gpa: Allocator, input: std.fs.File, size_hint: u }; } - return buffer.toOwnedSliceSentinel(0); + return buffer.toOwnedSliceSentinel(gpa, 0); } pub fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void { diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index fbfe4f8d33..ab2d51d3e6 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -562,7 +562,7 @@ pub fn renderError(tree: Ast, parse_error: Error, bw: *std.io.BufferedWriter) an .invalid_byte => { const tok_slice = tree.source[tree.tokens.items(.start)[parse_error.token]..]; - return bw.print("{s} contains invalid byte: '{'}'", .{ + return bw.print("{s} contains invalid byte: '{f'}'", .{ switch (tok_slice[0]) { '\'' => "character literal", '"', '\\' => "string literal", diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index fd6b02901f..8c38761ed7 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -11465,7 +11465,7 @@ fn failWithStrLitError( astgen, token, @intCast(offset + err.offset()), - "{}", + "{f}", .{err.fmt(raw_string)}, ); } @@ -13898,8 +13898,9 @@ fn lowerAstErrors(astgen: *AstGen) error{OutOfMemory}!void { assert(tree.errors.len > 0); var msg: std.io.AllocatingWriter = undefined; - const msg_writer = msg.init(gpa); + msg.init(gpa); defer msg.deinit(); + const msg_bw = &msg.buffered_writer; var notes: std.ArrayListUnmanaged(u32) = .empty; defer notes.deinit(gpa); @@ -13933,19 +13934,19 @@ fn lowerAstErrors(astgen: *AstGen) error{OutOfMemory}!void { .extra = .{ .offset = bad_off }, }; msg.clearRetainingCapacity(); - tree.renderError(err, msg_writer) catch |e| return @errorCast(e); // TODO try @errorCast(...) + tree.renderError(err, msg_bw) catch |e| return @errorCast(e); // TODO try @errorCast(...) return try astgen.appendErrorTokNotesOff(tok, bad_off, "{s}", .{msg.getWritten()}, notes.items); } var cur_err = tree.errors[0]; for (tree.errors[1..]) |err| { if (err.is_note) { - tree.renderError(err, msg_writer) catch |e| return @errorCast(e); // TODO try @errorCast(...) + tree.renderError(err, msg_bw) catch |e| return @errorCast(e); // TODO try @errorCast(...) try notes.append(gpa, try astgen.errNoteTok(err.token, "{s}", .{msg.getWritten()})); } else { // Flush error const extra_offset = tree.errorOffset(cur_err); - tree.renderError(cur_err, msg_writer) catch |e| return @errorCast(e); // TODO try @errorCast(...) + tree.renderError(cur_err, msg_bw) catch |e| return @errorCast(e); // TODO try @errorCast(...) try astgen.appendErrorTokNotesOff(cur_err.token, extra_offset, "{s}", .{msg.getWritten()}, notes.items); notes.clearRetainingCapacity(); cur_err = err; @@ -13959,7 +13960,7 @@ fn lowerAstErrors(astgen: *AstGen) error{OutOfMemory}!void { // Flush error const extra_offset = tree.errorOffset(cur_err); - tree.renderError(cur_err, msg_writer) catch |e| return @errorCast(e); // TODO try @errorCast(...) + tree.renderError(cur_err, msg_bw) catch |e| return @errorCast(e); // TODO try @errorCast(...) try astgen.appendErrorTokNotesOff(cur_err.token, extra_offset, "{s}", .{msg.getWritten()}, notes.items); } diff --git a/lib/std/zig/LibCInstallation.zig b/lib/std/zig/LibCInstallation.zig index cc58b7f49b..233336d898 100644 --- a/lib/std/zig/LibCInstallation.zig +++ b/lib/std/zig/LibCInstallation.zig @@ -43,7 +43,7 @@ pub fn parse( } } - const contents = try std.fs.cwd().readFileAlloc(allocator, libc_file, std.math.maxInt(usize)); + const contents = try std.fs.cwd().readFileAlloc(libc_file, allocator, .unlimited); defer allocator.free(contents); var it = std.mem.tokenizeScalar(u8, contents, '\n'); diff --git a/lib/std/zig/ZonGen.zig b/lib/std/zig/ZonGen.zig index 0acd996d8f..938259b757 100644 --- a/lib/std/zig/ZonGen.zig +++ b/lib/std/zig/ZonGen.zig @@ -778,7 +778,7 @@ fn lowerStrLitError( zg, token, @intCast(offset + err.offset()), - "{}", + "{f}", .{err.fmt(raw_string)}, ); } @@ -885,8 +885,9 @@ fn lowerAstErrors(zg: *ZonGen) Allocator.Error!void { assert(tree.errors.len > 0); var msg: std.io.AllocatingWriter = undefined; - const msg_bw = msg.init(gpa); + msg.init(gpa); defer msg.deinit(); + const msg_bw = &msg.buffered_writer; var notes: std.ArrayListUnmanaged(Zoir.CompileError.Note) = .empty; defer notes.deinit(gpa); diff --git a/lib/std/zig/llvm/BitcodeReader.zig b/lib/std/zig/llvm/BitcodeReader.zig index ea18b7978e..1215bcb4d1 100644 --- a/lib/std/zig/llvm/BitcodeReader.zig +++ b/lib/std/zig/llvm/BitcodeReader.zig @@ -1,6 +1,6 @@ allocator: std.mem.Allocator, record_arena: std.heap.ArenaAllocator.State, -reader: std.io.AnyReader, +br: *std.io.BufferedReader, keep_names: bool, bit_buffer: u32, bit_offset: u5, @@ -93,14 +93,14 @@ pub const Record = struct { }; pub const InitOptions = struct { - reader: std.io.AnyReader, + br: *std.io.BufferedReader, keep_names: bool = false, }; pub fn init(allocator: std.mem.Allocator, options: InitOptions) BitcodeReader { return .{ .allocator = allocator, .record_arena = .{}, - .reader = options.reader, + .br = options.br, .keep_names = options.keep_names, .bit_buffer = 0, .bit_offset = 0, @@ -170,9 +170,9 @@ pub fn next(bc: *BitcodeReader) !?Item { } } -pub fn skipBlock(bc: *BitcodeReader, block: Block) !void { +pub fn skipBlock(bc: *BitcodeReader, block: Block) anyerror!void { assert(bc.bit_offset == 0); - try bc.reader.skipBytes(@as(u34, block.len) * 4, .{}); + try bc.br.discard(4 * @as(u34, block.len)); try bc.endBlock(); } @@ -369,21 +369,21 @@ fn align32Bits(bc: *BitcodeReader) void { bc.bit_offset = 0; } -fn read32Bits(bc: *BitcodeReader) !u32 { +fn read32Bits(bc: *BitcodeReader) anyerror!u32 { assert(bc.bit_offset == 0); - return bc.reader.readInt(u32, .little); + return bc.br.takeInt(u32, .little); } -fn readBytes(bc: *BitcodeReader, bytes: []u8) !void { +fn readBytes(bc: *BitcodeReader, bytes: []u8) anyerror!void { assert(bc.bit_offset == 0); - try bc.reader.readNoEof(bytes); + try bc.br.read(bytes); const trailing_bytes = bytes.len % 4; if (trailing_bytes > 0) { - var bit_buffer = [1]u8{0} ** 4; - try bc.reader.readNoEof(bit_buffer[trailing_bytes..]); + var bit_buffer: [4]u8 = @splat(0); + try bc.br.read(bit_buffer[trailing_bytes..]); bc.bit_buffer = std.mem.readInt(u32, &bit_buffer, .little); - bc.bit_offset = @intCast(trailing_bytes * 8); + bc.bit_offset = @intCast(8 * trailing_bytes); } } diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index 20c4df53b5..e734d5dd9f 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -91,26 +91,21 @@ pub const String = enum(u32) { string: String, builder: *const Builder, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) anyerror!void { if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_| @compileError("invalid format string: '" ++ fmt_str ++ "'"); assert(data.string != .none); const string_slice = data.string.slice(data.builder) orelse - return writer.print("{d}", .{@intFromEnum(data.string)}); + return bw.print("{d}", .{@intFromEnum(data.string)}); if (comptime std.mem.indexOfScalar(u8, fmt_str, 'r')) |_| - return writer.writeAll(string_slice); + return bw.writeAll(string_slice); try printEscapedString( string_slice, if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_| .always_quote else .quote_unless_valid_identifier, - writer, + bw, ); } pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) { @@ -228,7 +223,7 @@ pub const Type = enum(u32) { _, pub const ptr_amdgpu_constant = - @field(Type, std.fmt.comptimePrint("ptr{ }", .{AddrSpace.amdgpu.constant})); + @field(Type, std.fmt.comptimePrint("ptr{f }", .{AddrSpace.amdgpu.constant})); pub const Tag = enum(u4) { simple, @@ -654,17 +649,12 @@ pub const Type = enum(u32) { type: Type, builder: *const Builder, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - fmt_opts: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) anyerror!void { assert(data.type != .none); if (comptime std.mem.eql(u8, fmt_str, "m")) { const item = data.builder.type_items.items[@intFromEnum(data.type)]; switch (item.tag) { - .simple => try writer.writeAll(switch (@as(Simple, @enumFromInt(item.data))) { + .simple => try bw.writeAll(switch (@as(Simple, @enumFromInt(item.data))) { .void => "isVoid", .half => "f16", .bfloat => "bf16", @@ -681,29 +671,29 @@ pub const Type = enum(u32) { .function, .vararg_function => |kind| { var extra = data.builder.typeExtraDataTrail(Type.Function, item.data); const params = extra.trail.next(extra.data.params_len, Type, data.builder); - try writer.print("f_{m}", .{extra.data.ret.fmt(data.builder)}); - for (params) |param| try writer.print("{m}", .{param.fmt(data.builder)}); + try bw.print("f_{fm}", .{extra.data.ret.fmt(data.builder)}); + for (params) |param| try bw.print("{fm}", .{param.fmt(data.builder)}); switch (kind) { .function => {}, - .vararg_function => try writer.writeAll("vararg"), + .vararg_function => try bw.writeAll("vararg"), else => unreachable, } - try writer.writeByte('f'); + try bw.writeByte('f'); }, - .integer => try writer.print("i{d}", .{item.data}), - .pointer => try writer.print("p{d}", .{item.data}), + .integer => try bw.print("i{d}", .{item.data}), + .pointer => try bw.print("p{d}", .{item.data}), .target => { var extra = data.builder.typeExtraDataTrail(Type.Target, item.data); const types = extra.trail.next(extra.data.types_len, Type, data.builder); const ints = extra.trail.next(extra.data.ints_len, u32, data.builder); - try writer.print("t{s}", .{extra.data.name.slice(data.builder).?}); - for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)}); - for (ints) |int| try writer.print("_{d}", .{int}); - try writer.writeByte('t'); + try bw.print("t{s}", .{extra.data.name.slice(data.builder).?}); + for (types) |ty| try bw.print("_{fm}", .{ty.fmt(data.builder)}); + for (ints) |int| try bw.print("_{d}", .{int}); + try bw.writeByte('t'); }, .vector, .scalable_vector => |kind| { const extra = data.builder.typeExtraData(Type.Vector, item.data); - try writer.print("{s}v{d}{m}", .{ + try bw.print("{s}v{d}{fm}", .{ switch (kind) { .vector => "", .scalable_vector => "nx", @@ -719,24 +709,24 @@ pub const Type = enum(u32) { .array => Type.Array, else => unreachable, }, item.data); - try writer.print("a{d}{m}", .{ extra.length(), extra.child.fmt(data.builder) }); + try bw.print("a{d}{fm}", .{ extra.length(), extra.child.fmt(data.builder) }); }, .structure, .packed_structure => { var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data); const fields = extra.trail.next(extra.data.fields_len, Type, data.builder); - try writer.writeAll("sl_"); - for (fields) |field| try writer.print("{m}", .{field.fmt(data.builder)}); - try writer.writeByte('s'); + try bw.writeAll("sl_"); + for (fields) |field| try bw.print("{fm}", .{field.fmt(data.builder)}); + try bw.writeByte('s'); }, .named_structure => { const extra = data.builder.typeExtraData(Type.NamedStructure, item.data); - try writer.writeAll("s_"); - if (extra.id.slice(data.builder)) |id| try writer.writeAll(id); + try bw.writeAll("s_"); + if (extra.id.slice(data.builder)) |id| try bw.writeAll(id); }, } return; } - if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name); + if (std.enums.tagName(Type, data.type)) |name| return bw.writeAll(name); const item = data.builder.type_items.items[@intFromEnum(data.type)]; switch (item.tag) { .simple => unreachable, @@ -744,40 +734,40 @@ pub const Type = enum(u32) { var extra = data.builder.typeExtraDataTrail(Type.Function, item.data); const params = extra.trail.next(extra.data.params_len, Type, data.builder); if (!comptime std.mem.eql(u8, fmt_str, ">")) - try writer.print("{%} ", .{extra.data.ret.fmt(data.builder)}); + try bw.print("{f%} ", .{extra.data.ret.fmt(data.builder)}); if (!comptime std.mem.eql(u8, fmt_str, "<")) { - try writer.writeByte('('); + try bw.writeByte('('); for (params, 0..) |param, index| { - if (index > 0) try writer.writeAll(", "); - try writer.print("{%}", .{param.fmt(data.builder)}); + if (index > 0) try bw.writeAll(", "); + try bw.print("{f%}", .{param.fmt(data.builder)}); } switch (kind) { .function => {}, .vararg_function => { - if (params.len > 0) try writer.writeAll(", "); - try writer.writeAll("..."); + if (params.len > 0) try bw.writeAll(", "); + try bw.writeAll("..."); }, else => unreachable, } - try writer.writeByte(')'); + try bw.writeByte(')'); } }, - .integer => try writer.print("i{d}", .{item.data}), - .pointer => try writer.print("ptr{ }", .{@as(AddrSpace, @enumFromInt(item.data))}), + .integer => try bw.print("i{d}", .{item.data}), + .pointer => try bw.print("ptr{f }", .{@as(AddrSpace, @enumFromInt(item.data))}), .target => { var extra = data.builder.typeExtraDataTrail(Type.Target, item.data); const types = extra.trail.next(extra.data.types_len, Type, data.builder); const ints = extra.trail.next(extra.data.ints_len, u32, data.builder); - try writer.print( - \\target({"} + try bw.print( + \\target({f"} , .{extra.data.name.fmt(data.builder)}); - for (types) |ty| try writer.print(", {%}", .{ty.fmt(data.builder)}); - for (ints) |int| try writer.print(", {d}", .{int}); - try writer.writeByte(')'); + for (types) |ty| try bw.print(", {f%}", .{ty.fmt(data.builder)}); + for (ints) |int| try bw.print(", {d}", .{int}); + try bw.writeByte(')'); }, .vector, .scalable_vector => |kind| { const extra = data.builder.typeExtraData(Type.Vector, item.data); - try writer.print("<{s}{d} x {%}>", .{ + try bw.print("<{s}{d} x {f%}>", .{ switch (kind) { .vector => "", .scalable_vector => "vscale x ", @@ -793,38 +783,38 @@ pub const Type = enum(u32) { .array => Type.Array, else => unreachable, }, item.data); - try writer.print("[{d} x {%}]", .{ extra.length(), extra.child.fmt(data.builder) }); + try bw.print("[{d} x {f%}]", .{ extra.length(), extra.child.fmt(data.builder) }); }, .structure, .packed_structure => |kind| { var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data); const fields = extra.trail.next(extra.data.fields_len, Type, data.builder); switch (kind) { .structure => {}, - .packed_structure => try writer.writeByte('<'), + .packed_structure => try bw.writeByte('<'), else => unreachable, } - try writer.writeAll("{ "); + try bw.writeAll("{ "); for (fields, 0..) |field, index| { - if (index > 0) try writer.writeAll(", "); - try writer.print("{%}", .{field.fmt(data.builder)}); + if (index > 0) try bw.writeAll(", "); + try bw.print("{f%}", .{field.fmt(data.builder)}); } - try writer.writeAll(" }"); + try bw.writeAll(" }"); switch (kind) { .structure => {}, - .packed_structure => try writer.writeByte('>'), + .packed_structure => try bw.writeByte('>'), else => unreachable, } }, .named_structure => { const extra = data.builder.typeExtraData(Type.NamedStructure, item.data); - if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{ + if (comptime std.mem.eql(u8, fmt_str, "%")) try bw.print("%{f}", .{ extra.id.fmt(data.builder), }) else switch (extra.body) { - .none => try writer.writeAll("opaque"), + .none => try bw.writeAll("opaque"), else => try format(.{ .type = extra.body, .builder = data.builder, - }, fmt_str, fmt_opts, writer), + }, bw, fmt_str), } }, } @@ -1139,12 +1129,7 @@ pub const Attribute = union(Kind) { attribute_index: Index, builder: *const Builder, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) anyerror!void { if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_| @compileError("invalid format string: '" ++ fmt_str ++ "'"); const attribute = data.attribute_index.toAttribute(data.builder); @@ -1219,37 +1204,37 @@ pub const Attribute = union(Kind) { .no_sanitize_address, .no_sanitize_hwaddress, .sanitize_address_dyninit, - => try writer.print(" {s}", .{@tagName(attribute)}), + => try bw.print(" {s}", .{@tagName(attribute)}), .byval, .byref, .preallocated, .inalloca, .sret, .elementtype, - => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }), - .@"align" => |alignment| try writer.print("{ }", .{alignment}), + => |ty| try bw.print(" {s}({f%})", .{ @tagName(attribute), ty.fmt(data.builder) }), + .@"align" => |alignment| try bw.print("{f }", .{alignment}), .dereferenceable, .dereferenceable_or_null, - => |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }), + => |size| try bw.print(" {s}({d})", .{ @tagName(attribute), size }), .nofpclass => |fpclass| { const Int = @typeInfo(FpClass).@"struct".backing_integer.?; - try writer.print(" {s}(", .{@tagName(attribute)}); + try bw.print(" {s}(", .{@tagName(attribute)}); var any = false; var remaining: Int = @bitCast(fpclass); inline for (@typeInfo(FpClass).@"struct".decls) |decl| { const pattern: Int = @bitCast(@field(FpClass, decl.name)); if (remaining & pattern == pattern) { if (!any) { - try writer.writeByte(' '); + try bw.writeByte(' '); any = true; } - try writer.writeAll(decl.name); + try bw.writeAll(decl.name); remaining &= ~pattern; } } - try writer.writeByte(')'); + try bw.writeByte(')'); }, - .alignstack => |alignment| try writer.print( + .alignstack => |alignment| try bw.print( if (comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null) " {s}={d}" else @@ -1257,53 +1242,53 @@ pub const Attribute = union(Kind) { .{ @tagName(attribute), alignment.toByteUnits() orelse return }, ), .allockind => |allockind| { - try writer.print(" {s}(\"", .{@tagName(attribute)}); + try bw.print(" {s}(\"", .{@tagName(attribute)}); var any = false; inline for (@typeInfo(AllocKind).@"struct".fields) |field| { if (comptime std.mem.eql(u8, field.name, "_")) continue; if (@field(allockind, field.name)) { if (!any) { - try writer.writeByte(','); + try bw.writeByte(','); any = true; } - try writer.writeAll(field.name); + try bw.writeAll(field.name); } } - try writer.writeAll("\")"); + try bw.writeAll("\")"); }, .allocsize => |allocsize| { - try writer.print(" {s}({d}", .{ @tagName(attribute), allocsize.elem_size }); + try bw.print(" {s}({d}", .{ @tagName(attribute), allocsize.elem_size }); if (allocsize.num_elems != AllocSize.none) - try writer.print(",{d}", .{allocsize.num_elems}); - try writer.writeByte(')'); + try bw.print(",{d}", .{allocsize.num_elems}); + try bw.writeByte(')'); }, .memory => |memory| { - try writer.print(" {s}(", .{@tagName(attribute)}); + try bw.print(" {s}(", .{@tagName(attribute)}); var any = memory.other != .none or (memory.argmem == .none and memory.inaccessiblemem == .none); - if (any) try writer.writeAll(@tagName(memory.other)); + if (any) try bw.writeAll(@tagName(memory.other)); inline for (.{ "argmem", "inaccessiblemem" }) |kind| { if (@field(memory, kind) != memory.other) { - if (any) try writer.writeAll(", "); - try writer.print("{s}: {s}", .{ kind, @tagName(@field(memory, kind)) }); + if (any) try bw.writeAll(", "); + try bw.print("{s}: {s}", .{ kind, @tagName(@field(memory, kind)) }); any = true; } } - try writer.writeByte(')'); + try bw.writeByte(')'); }, .uwtable => |uwtable| if (uwtable != .none) { - try writer.print(" {s}", .{@tagName(attribute)}); - if (uwtable != UwTable.default) try writer.print("({s})", .{@tagName(uwtable)}); + try bw.print(" {s}", .{@tagName(attribute)}); + if (uwtable != UwTable.default) try bw.print("({s})", .{@tagName(uwtable)}); }, - .vscale_range => |vscale_range| try writer.print(" {s}({d},{d})", .{ + .vscale_range => |vscale_range| try bw.print(" {s}({d},{d})", .{ @tagName(attribute), vscale_range.min.toByteUnits().?, vscale_range.max.toByteUnits() orelse 0, }), .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) { - try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)}); + try bw.print(" {f\"}", .{string_attr.kind.fmt(data.builder)}); if (string_attr.value != .empty) - try writer.print("={\"}", .{string_attr.value.fmt(data.builder)}); + try bw.print("={f\"}", .{string_attr.value.fmt(data.builder)}); }, .none => unreachable, } @@ -1583,16 +1568,11 @@ pub const Attributes = enum(u32) { attributes: Attributes, builder: *const Builder, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - fmt_opts: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) anyerror!void { for (data.attributes.slice(data.builder)) |attribute_index| try Attribute.Index.format(.{ .attribute_index = attribute_index, .builder = data.builder, - }, fmt_str, fmt_opts, writer); + }, bw, fmt_str); } pub fn fmt(self: Attributes, builder: *const Builder) std.fmt.Formatter(format) { return .{ .data = .{ .attributes = self, .builder = builder } }; @@ -1781,22 +1761,12 @@ pub const Linkage = enum(u4) { extern_weak = 7, external = 0, - pub fn format( - self: Linkage, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .external) try writer.print(" {s}", .{@tagName(self)}); + pub fn format(self: Linkage, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + if (self != .external) try bw.print(" {s}", .{@tagName(self)}); } - fn formatOptional( - data: ?Linkage, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (data) |linkage| try writer.print(" {s}", .{@tagName(linkage)}); + fn formatOptional(data: ?Linkage, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + if (data) |linkage| try bw.print(" {s}", .{@tagName(linkage)}); } pub fn fmtOptional(self: ?Linkage) std.fmt.Formatter(formatOptional) { return .{ .data = self }; @@ -1808,13 +1778,8 @@ pub const Preemption = enum { dso_local, implicit_dso_local, - pub fn format( - self: Preemption, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self == .dso_local) try writer.print(" {s}", .{@tagName(self)}); + pub fn format(self: Preemption, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + if (self == .dso_local) try bw.print(" {s}", .{@tagName(self)}); } }; @@ -1833,10 +1798,10 @@ pub const Visibility = enum(u2) { pub fn format( self: Visibility, - comptime _: []const u8, - _: std.fmt.FormatOptions, + comptime format_string: []const u8, writer: anytype, ) @TypeOf(writer).Error!void { + comptime assert(format_string.len == 0); if (self != .default) try writer.print(" {s}", .{@tagName(self)}); } }; @@ -1846,13 +1811,8 @@ pub const DllStorageClass = enum(u2) { dllimport = 1, dllexport = 2, - pub fn format( - self: DllStorageClass, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .default) try writer.print(" {s}", .{@tagName(self)}); + pub fn format(self: DllStorageClass, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + if (self != .default) try bw.print(" {s}", .{@tagName(self)}); } }; @@ -1863,15 +1823,10 @@ pub const ThreadLocal = enum(u3) { initialexec = 3, localexec = 4, - pub fn format( - self: ThreadLocal, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(self: ThreadLocal, bw: *std.io.BufferedWriter, comptime prefix: []const u8) anyerror!void { if (self == .default) return; - try writer.print("{s}thread_local", .{prefix}); - if (self != .generaldynamic) try writer.print("({s})", .{@tagName(self)}); + try bw.print("{s}thread_local", .{prefix}); + if (self != .generaldynamic) try bw.print("({s})", .{@tagName(self)}); } }; @@ -1882,13 +1837,8 @@ pub const UnnamedAddr = enum(u2) { unnamed_addr = 1, local_unnamed_addr = 2, - pub fn format( - self: UnnamedAddr, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .default) try writer.print(" {s}", .{@tagName(self)}); + pub fn format(self: UnnamedAddr, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + if (self != .default) try bw.print(" {s}", .{@tagName(self)}); } }; @@ -1981,13 +1931,8 @@ pub const AddrSpace = enum(u24) { pub const funcref: AddrSpace = @enumFromInt(20); }; - pub fn format( - self: AddrSpace, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .default) try writer.print("{s}addrspace({d})", .{ prefix, @intFromEnum(self) }); + pub fn format(self: AddrSpace, bw: *std.io.BufferedWriter, comptime prefix: []const u8) anyerror!void { + if (self != .default) try bw.print("{s}addrspace({d})", .{ prefix, @intFromEnum(self) }); } }; @@ -1995,15 +1940,8 @@ pub const ExternallyInitialized = enum { default, externally_initialized, - pub fn format( - self: ExternallyInitialized, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self == .default) return; - try writer.writeByte(' '); - try writer.writeAll(@tagName(self)); + pub fn format(self: ExternallyInitialized, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + if (self != .default) try bw.print(" {s}", .{@tagName(self)}); } }; @@ -2026,13 +1964,8 @@ pub const Alignment = enum(u6) { return if (self == .default) 0 else (@intFromEnum(self) + 1); } - pub fn format( - self: Alignment, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - try writer.print("{s}align {d}", .{ prefix, self.toByteUnits() orelse return }); + pub fn format(self: Alignment, bw: *std.io.BufferedWriter, comptime prefix: []const u8) anyerror!void { + try bw.print("{s}align {d}", .{ prefix, self.toByteUnits() orelse return }); } }; @@ -2105,12 +2038,7 @@ pub const CallConv = enum(u10) { pub const default = CallConv.ccc; - pub fn format( - self: CallConv, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(self: CallConv, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { switch (self) { default => {}, .fastcc, @@ -2164,8 +2092,8 @@ pub const CallConv = enum(u10) { .aarch64_sme_preservemost_from_x2, .m68k_rtdcc, .riscv_vectorcallcc, - => try writer.print(" {s}", .{@tagName(self)}), - _ => try writer.print(" cc{d}", .{@intFromEnum(self)}), + => try bw.print(" {s}", .{@tagName(self)}), + _ => try bw.print(" cc{d}", .{@intFromEnum(self)}), } } }; @@ -2191,26 +2119,21 @@ pub const StrtabString = enum(u32) { string: StrtabString, builder: *const Builder, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) anyerror!void { if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_| @compileError("invalid format string: '" ++ fmt_str ++ "'"); assert(data.string != .none); const string_slice = data.string.slice(data.builder) orelse - return writer.print("{d}", .{@intFromEnum(data.string)}); + return bw.print("{d}", .{@intFromEnum(data.string)}); if (comptime std.mem.indexOfScalar(u8, fmt_str, 'r')) |_| - return writer.writeAll(string_slice); + return bw.writeAll(string_slice); try printEscapedString( string_slice, if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_| .always_quote else .quote_unless_valid_identifier, - writer, + bw, ); } pub fn fmt(self: StrtabString, builder: *const Builder) std.fmt.Formatter(format) { @@ -2264,7 +2187,7 @@ pub fn strtabStringFmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: a } pub fn strtabStringFmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) StrtabString { - self.strtab_string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable; + self.strtab_string_bytes.printAssumeCapacity(fmt_str, fmt_args); return self.trailingStrtabStringAssumeCapacity(); } @@ -2383,13 +2306,8 @@ pub const Global = struct { global: Index, builder: *const Builder, }; - fn format( - data: FormatData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - try writer.print("@{}", .{ + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + try bw.print("@{f}", .{ data.global.unwrap(data.builder).name(data.builder).fmt(data.builder), }); } @@ -4834,28 +4752,23 @@ pub const Function = struct { function: Function.Index, builder: *Builder, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) anyerror!void { if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_| @compileError("invalid format string: '" ++ fmt_str ++ "'"); if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) { if (data.instruction == .none) return; - try writer.writeByte(','); + try bw.writeByte(','); } if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) { if (data.instruction == .none) return; - try writer.writeByte(' '); + try bw.writeByte(' '); } - if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null) try writer.print( - "{%} ", + if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null) try bw.print( + "{f%} ", .{data.instruction.typeOf(data.function, data.builder).fmt(data.builder)}, ); assert(data.instruction != .none); - try writer.print("%{}", .{ + try bw.print("%{f}", .{ data.instruction.name(data.function.ptrConst(data.builder)).fmt(data.builder), }); } @@ -6361,7 +6274,7 @@ pub const WipFunction = struct { while (true) { gop.value_ptr.* = @enumFromInt(@intFromEnum(gop.value_ptr.*) + 1); - const unique_name = try wip_name.builder.fmt("{r}{s}{r}", .{ + const unique_name = try wip_name.builder.fmt("{fr}{s}{fr}", .{ name.fmt(wip_name.builder), sep, gop.value_ptr.fmt(wip_name.builder), @@ -7031,13 +6944,8 @@ pub const MemoryAccessKind = enum(u1) { normal, @"volatile", - pub fn format( - self: MemoryAccessKind, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .normal) try writer.print("{s}{s}", .{ prefix, @tagName(self) }); + pub fn format(self: MemoryAccessKind, bw: *std.io.BufferedWriter, comptime prefix: []const u8) anyerror!void { + if (self != .normal) try bw.print("{s}{s}", .{ prefix, @tagName(self) }); } }; @@ -7045,13 +6953,8 @@ pub const SyncScope = enum(u1) { singlethread, system, - pub fn format( - self: SyncScope, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .system) try writer.print( + pub fn format(self: SyncScope, bw: *std.io.BufferedWriter, comptime prefix: []const u8) anyerror!void { + if (self != .system) try bw.print( \\{s}syncscope("{s}") , .{ prefix, @tagName(self) }); } @@ -7066,13 +6969,8 @@ pub const AtomicOrdering = enum(u3) { acq_rel = 5, seq_cst = 6, - pub fn format( - self: AtomicOrdering, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .none) try writer.print("{s}{s}", .{ prefix, @tagName(self) }); + pub fn format(self: AtomicOrdering, bw: *std.io.BufferedWriter, comptime prefix: []const u8) anyerror!void { + if (self != .none) try bw.print("{s}{s}", .{ prefix, @tagName(self) }); } }; @@ -7487,26 +7385,21 @@ pub const Constant = enum(u32) { constant: Constant, builder: *Builder, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) anyerror!void { if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_| @compileError("invalid format string: '" ++ fmt_str ++ "'"); if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) { if (data.constant == .no_init) return; - try writer.writeByte(','); + try bw.writeByte(','); } if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) { if (data.constant == .no_init) return; - try writer.writeByte(' '); + try bw.writeByte(' '); } if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null) - try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)}); + try bw.print("{f%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)}); assert(data.constant != .no_init); - if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name); + if (std.enums.tagName(Constant, data.constant)) |name| return bw.writeAll(name); switch (data.constant.unwrap()) { .constant => |constant| { const item = data.builder.constant_items.get(constant); @@ -7545,11 +7438,11 @@ pub const Constant = enum(u32) { const allocator = stack.get(); const str = try bigint.toStringAlloc(allocator, 10, undefined); defer allocator.free(str); - try writer.writeAll(str); + try bw.writeAll(str); }, .half, .bfloat, - => |tag| try writer.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) { + => |tag| try bw.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) { .half => 'H', .bfloat => 'R', else => unreachable, @@ -7580,7 +7473,7 @@ pub const Constant = enum(u32) { ) + 1, else => 0, }; - try writer.print("0x{X:0>16}", .{@as(u64, @bitCast(Float.Repr(f64){ + try bw.print("0x{X:0>16}", .{@as(u64, @bitCast(Float.Repr(f64){ .mantissa = std.math.shl( Mantissa64, repr.mantissa, @@ -7602,13 +7495,13 @@ pub const Constant = enum(u32) { }, .double => { const extra = data.builder.constantExtraData(Double, item.data); - try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo }); + try bw.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo }); }, .fp128, .ppc_fp128, => |tag| { const extra = data.builder.constantExtraData(Fp128, item.data); - try writer.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{ + try bw.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{ @as(u8, switch (tag) { .fp128 => 'L', .ppc_fp128 => 'M', @@ -7622,7 +7515,7 @@ pub const Constant = enum(u32) { }, .x86_fp80 => { const extra = data.builder.constantExtraData(Fp80, item.data); - try writer.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{ + try bw.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{ extra.hi, extra.lo_hi, extra.lo_lo, }); }, @@ -7631,7 +7524,7 @@ pub const Constant = enum(u32) { .zeroinitializer, .undef, .poison, - => |tag| try writer.writeAll(@tagName(tag)), + => |tag| try bw.writeAll(@tagName(tag)), .structure, .packed_structure, .array, @@ -7640,7 +7533,7 @@ pub const Constant = enum(u32) { var extra = data.builder.constantExtraDataTrail(Aggregate, item.data); const len: u32 = @intCast(extra.data.type.aggregateLen(data.builder)); const vals = extra.trail.next(len, Constant, data.builder); - try writer.writeAll(switch (tag) { + try bw.writeAll(switch (tag) { .structure => "{ ", .packed_structure => "<{ ", .array => "[", @@ -7648,10 +7541,10 @@ pub const Constant = enum(u32) { else => unreachable, }); for (vals, 0..) |val, index| { - if (index > 0) try writer.writeAll(", "); - try writer.print("{%}", .{val.fmt(data.builder)}); + if (index > 0) try bw.writeAll(", "); + try bw.print("{f%}", .{val.fmt(data.builder)}); } - try writer.writeAll(switch (tag) { + try bw.writeAll(switch (tag) { .structure => " }", .packed_structure => " }>", .array => "]", @@ -7662,20 +7555,20 @@ pub const Constant = enum(u32) { .splat => { const extra = data.builder.constantExtraData(Splat, item.data); const len = extra.type.vectorLen(data.builder); - try writer.writeByte('<'); + try bw.writeByte('<'); for (0..len) |index| { - if (index > 0) try writer.writeAll(", "); - try writer.print("{%}", .{extra.value.fmt(data.builder)}); + if (index > 0) try bw.writeAll(", "); + try bw.print("{f%}", .{extra.value.fmt(data.builder)}); } - try writer.writeByte('>'); + try bw.writeByte('>'); }, - .string => try writer.print("c{\"}", .{ + .string => try bw.print("c{f\"}", .{ @as(String, @enumFromInt(item.data)).fmt(data.builder), }), .blockaddress => |tag| { const extra = data.builder.constantExtraData(BlockAddress, item.data); const function = extra.function.ptrConst(data.builder); - try writer.print("{s}({}, {})", .{ + try bw.print("{s}({f}, {f})", .{ @tagName(tag), function.global.fmt(data.builder), extra.block.toInst(function).fmt(extra.function, data.builder), @@ -7685,7 +7578,7 @@ pub const Constant = enum(u32) { .no_cfi, => |tag| { const function: Function.Index = @enumFromInt(item.data); - try writer.print("{s} {}", .{ + try bw.print("{s} {f}", .{ @tagName(tag), function.ptrConst(data.builder).global.fmt(data.builder), }); @@ -7697,7 +7590,7 @@ pub const Constant = enum(u32) { .addrspacecast, => |tag| { const extra = data.builder.constantExtraData(Cast, item.data); - try writer.print("{s} ({%} to {%})", .{ + try bw.print("{s} ({f%} to {f%})", .{ @tagName(tag), extra.val.fmt(data.builder), extra.type.fmt(data.builder), @@ -7709,13 +7602,13 @@ pub const Constant = enum(u32) { var extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data); const indices = extra.trail.next(extra.data.info.indices_len, Constant, data.builder); - try writer.print("{s} ({%}, {%}", .{ + try bw.print("{s} ({f%}, {f%}", .{ @tagName(tag), extra.data.type.fmt(data.builder), extra.data.base.fmt(data.builder), }); - for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)}); - try writer.writeByte(')'); + for (indices) |index| try bw.print(", {f%}", .{index.fmt(data.builder)}); + try bw.writeByte(')'); }, .add, .@"add nsw", @@ -7727,7 +7620,7 @@ pub const Constant = enum(u32) { .xor, => |tag| { const extra = data.builder.constantExtraData(Binary, item.data); - try writer.print("{s} ({%}, {%})", .{ + try bw.print("{s} ({f%}, {f%})", .{ @tagName(tag), extra.lhs.fmt(data.builder), extra.rhs.fmt(data.builder), @@ -7751,7 +7644,7 @@ pub const Constant = enum(u32) { .@"asm sideeffect alignstack inteldialect unwind", => |tag| { const extra = data.builder.constantExtraData(Assembly, item.data); - try writer.print("{s} {\"}, {\"}", .{ + try bw.print("{s} {f\"}, {f\"}", .{ @tagName(tag), extra.assembly.fmt(data.builder), extra.constraints.fmt(data.builder), @@ -7759,7 +7652,7 @@ pub const Constant = enum(u32) { }, } }, - .global => |global| try writer.print("{}", .{global.fmt(data.builder)}), + .global => |global| try bw.print("{f}", .{global.fmt(data.builder)}), } } pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) { @@ -7819,22 +7712,17 @@ pub const Value = enum(u32) { function: Function.Index, builder: *Builder, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - fmt_opts: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) anyerror!void { switch (data.value.unwrap()) { .instruction => |instruction| try Function.Instruction.Index.format(.{ .instruction = instruction, .function = data.function, .builder = data.builder, - }, fmt_str, fmt_opts, writer), + }, bw, fmt_str), .constant => |constant| try Constant.format(.{ .constant = constant, .builder = data.builder, - }, fmt_str, fmt_opts, writer), + }, bw, fmt_str), .metadata => unreachable, } } @@ -7869,13 +7757,8 @@ pub const MetadataString = enum(u32) { metadata_string: MetadataString, builder: *const Builder, }; - fn format( - data: FormatData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - try printEscapedString(data.metadata_string.slice(data.builder), .always_quote, writer); + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + try printEscapedString(data.metadata_string.slice(data.builder), .always_quote, bw); } fn fmt(self: MetadataString, builder: *const Builder) std.fmt.Formatter(format) { return .{ .data = .{ .metadata_string = self, .builder = builder } }; @@ -8039,29 +7922,24 @@ pub const Metadata = enum(u32) { AllCallsDescribed: bool = false, Unused: u2 = 0, - pub fn format( - self: DIFlags, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(self: DIFlags, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { var need_pipe = false; inline for (@typeInfo(DIFlags).@"struct".fields) |field| { switch (@typeInfo(field.type)) { .bool => if (@field(self, field.name)) { - if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; - try writer.print("DIFlag{s}", .{field.name}); + if (need_pipe) try bw.writeAll(" | ") else need_pipe = true; + try bw.print("DIFlag{s}", .{field.name}); }, .@"enum" => if (@field(self, field.name) != .Zero) { - if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; - try writer.print("DIFlag{s}", .{@tagName(@field(self, field.name))}); + if (need_pipe) try bw.writeAll(" | ") else need_pipe = true; + try bw.print("DIFlag{s}", .{@tagName(@field(self, field.name))}); }, .int => assert(@field(self, field.name) == 0), else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)), } } - if (!need_pipe) try writer.writeByte('0'); + if (!need_pipe) try bw.writeByte('0'); } }; @@ -8101,29 +7979,24 @@ pub const Metadata = enum(u32) { ObjCDirect: bool = false, Unused: u20 = 0, - pub fn format( - self: DISPFlags, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(self: DISPFlags, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { var need_pipe = false; inline for (@typeInfo(DISPFlags).@"struct".fields) |field| { switch (@typeInfo(field.type)) { .bool => if (@field(self, field.name)) { - if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; - try writer.print("DISPFlag{s}", .{field.name}); + if (need_pipe) try bw.writeAll(" | ") else need_pipe = true; + try bw.print("DISPFlag{s}", .{field.name}); }, .@"enum" => if (@field(self, field.name) != .Zero) { - if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; - try writer.print("DISPFlag{s}", .{@tagName(@field(self, field.name))}); + if (need_pipe) try bw.writeAll(" | ") else need_pipe = true; + try bw.print("DISPFlag{s}", .{@tagName(@field(self, field.name))}); }, .int => assert(@field(self, field.name) == 0), else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)), } } - if (!need_pipe) try writer.writeByte('0'); + if (!need_pipe) try bw.writeByte('0'); } }; @@ -8323,20 +8196,15 @@ pub const Metadata = enum(u32) { }; }; }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - fmt_opts: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime fmt_str: []const u8) anyerror!void { if (data.node == .none) return; const is_specialized = fmt_str.len > 0 and fmt_str[0] == 'S'; const recurse_fmt_str = if (is_specialized) fmt_str[1..] else fmt_str; - if (data.formatter.need_comma) try writer.writeAll(", "); + if (data.formatter.need_comma) try bw.writeAll(", "); defer data.formatter.need_comma = true; - try writer.writeAll(data.prefix); + try bw.writeAll(data.prefix); const builder = data.formatter.builder; switch (data.node) { @@ -8351,48 +8219,44 @@ pub const Metadata = enum(u32) { .expression => { var extra = builder.metadataExtraDataTrail(Expression, item.data); const elements = extra.trail.next(extra.data.elements_len, u32, builder); - try writer.writeAll("!DIExpression("); + try bw.writeAll("!DIExpression("); for (elements) |element| try format(.{ .formatter = data.formatter, .node = .{ .u64 = element }, - }, "%", fmt_opts, writer); - try writer.writeByte(')'); + }, bw, "%"); + try bw.writeByte(')'); }, .constant => try Constant.format(.{ .constant = @enumFromInt(item.data), .builder = builder, - }, recurse_fmt_str, fmt_opts, writer), + }, bw, recurse_fmt_str), else => unreachable, } }, - .index => |node| try writer.print("!{d}", .{node}), + .index => |node| try bw.print("!{d}", .{node}), inline .local_value, .local_metadata => |node, tag| try Value.format(.{ .value = node.value, .function = node.function, .builder = builder, - }, switch (tag) { + }, bw, switch (tag) { .local_value => recurse_fmt_str, .local_metadata => "%", else => unreachable, - }, fmt_opts, writer), + }), inline .local_inline, .local_index => |node, tag| { if (comptime std.mem.eql(u8, recurse_fmt_str, "%")) - try writer.print("{%} ", .{Type.metadata.fmt(builder)}); + try bw.print("{f%} ", .{Type.metadata.fmt(builder)}); try format(.{ .formatter = data.formatter, .node = @unionInit(FormatData.Node, @tagName(tag)["local_".len..], node), - }, "%", fmt_opts, writer); + }, bw, "%"); }, - .string => |node| try writer.print((if (is_specialized) "" else "!") ++ "{}", .{ + .string => |node| try bw.print((if (is_specialized) "" else "!") ++ "{f}", .{ node.fmt(builder), }), - inline .bool, - .u32, - .u64, - .di_flags, - .sp_flags, - => |node| try writer.print("{}", .{node}), - .raw => |node| try writer.writeAll(node), + inline .bool, .u32, .u64 => |node| try bw.print("{}", .{node}), + inline .di_flags, .sp_flags => |node| try bw.print("{f}", .{node}), + .raw => |node| try bw.writeAll(node), } } inline fn fmt(formatter: *Formatter, prefix: []const u8, node: anytype) switch (@TypeOf(node)) { @@ -8506,8 +8370,8 @@ pub const Metadata = enum(u32) { DIGlobalVariableExpression, }, nodes: anytype, - writer: anytype, - ) !void { + bw: *std.io.BufferedWriter, + ) anyerror!void { comptime var fmt_str: []const u8 = ""; const names = comptime std.meta.fieldNames(@TypeOf(nodes)); comptime var fields: [2 + names.len]std.builtin.Type.StructField = undefined; @@ -8523,7 +8387,7 @@ pub const Metadata = enum(u32) { } fmt_str = fmt_str ++ "("; inline for (fields[2..], names) |*field, name| { - fmt_str = fmt_str ++ "{[" ++ name ++ "]S}"; + fmt_str = fmt_str ++ "{[" ++ name ++ "]fS}"; field.* = .{ .name = name, .type = std.fmt.Formatter(format), @@ -8546,7 +8410,7 @@ pub const Metadata = enum(u32) { name ++ ": ", @field(nodes, name), ); - try writer.print(fmt_str, fmt_args); + try bw.print(fmt_str, fmt_args); } }; }; @@ -8636,7 +8500,7 @@ pub fn init(options: Options) Allocator.Error!Builder { inline for (.{ 0, 4 }) |addr_space_index| { const addr_space: AddrSpace = @enumFromInt(addr_space_index); assert(self.ptrTypeAssumeCapacity(addr_space) == - @field(Type, std.fmt.comptimePrint("ptr{ }", .{addr_space}))); + @field(Type, std.fmt.comptimePrint("ptr{f }", .{addr_space}))); } } @@ -8759,16 +8623,17 @@ pub fn deinit(self: *Builder) void { self.* = undefined; } -pub fn setModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer { +pub fn setModuleAsm(self: *Builder, aw: *std.io.AllocatingWriter) *std.io.BufferedWriter { self.module_asm.clearRetainingCapacity(); - return self.appendModuleAsm(); + return self.appendModuleAsm(aw); } -pub fn appendModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer { - return self.module_asm.writer(self.gpa); +pub fn appendModuleAsm(self: *Builder, aw: *std.io.AllocatingWriter) *std.io.BufferedWriter { + return aw.fromArrayList(self.gpa, &self.module_asm); } -pub fn finishModuleAsm(self: *Builder) Allocator.Error!void { +pub fn finishModuleAsm(self: *Builder, aw: *std.io.AllocatingWriter) Allocator.Error!void { + self.module_asm = aw.toArrayList(); if (self.module_asm.getLastOrNull()) |last| if (last != '\n') try self.module_asm.append(self.gpa, '\n'); } @@ -8804,7 +8669,7 @@ pub fn fmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) Allo } pub fn fmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) String { - self.string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable; + self.string_bytes.printAssumeCapacity(fmt_str, fmt_args); return self.trailingStringAssumeCapacity(); } @@ -9076,9 +8941,13 @@ pub fn getIntrinsic( const allocator = stack.get(); const name = name: { - const writer = self.strtab_string_bytes.writer(self.gpa); - try writer.print("llvm.{s}", .{@tagName(id)}); - for (overload) |ty| try writer.print(".{m}", .{ty.fmt(self)}); + { + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.fromArrayList(self.gpa, &self.strtab_string_bytes); + defer self.strtab_string_bytes = aw.toArrayList(); + bw.print("llvm.{s}", .{@tagName(id)}) catch |err| return @errorCast(err); + for (overload) |ty| bw.print(".{fm}", .{ty.fmt(self)}) catch |err| return @errorCast(err); + } break :name try self.trailingStrtabString(); }; if (self.getGlobal(name)) |global| return global.ptrConst(self).kind.function; @@ -9494,108 +9363,78 @@ pub fn asmValue( pub fn dump(self: *Builder) void { const stderr: std.fs.File = .stderr(); - self.print(stderr.writer().unbuffered()) catch {}; + self.printBuffered(stderr.writer()) catch {}; } -pub fn printToFile(self: *Builder, path: []const u8) Allocator.Error!bool { +pub fn printToFile(self: *Builder, path: []const u8) bool { var file = std.fs.cwd().createFile(path, .{}) catch |err| { log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) }); return false; }; defer file.close(); - self.print(file.writer()) catch |err| { + self.printBuffered(file.writer()) catch |err| { log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) }); return false; }; return true; } -pub fn print(self: *Builder, writer: *std.io.BufferedWriter) (@TypeOf(writer).Error || Allocator.Error)!void { - var bw = std.io.bufferedWriter(writer); - try self.printUnbuffered(bw.writer()); +pub fn printBuffered(self: *Builder, writer: std.io.Writer) anyerror!void { + var buffer: [4096]u8 = undefined; + var bw = writer.buffered(&buffer); + try self.print(&bw); try bw.flush(); } -fn WriterWithErrors(comptime BackingWriter: type, comptime ExtraErrors: type) type { - return struct { - backing_writer: BackingWriter, - - pub const Error = BackingWriter.Error || ExtraErrors; - pub const Writer = std.io.Writer(*const Self, Error, write); - - const Self = @This(); - - pub fn writer(self: *const Self) Writer { - return .{ .context = self }; - } - - pub fn write(self: *const Self, bytes: []const u8) Error!usize { - return self.backing_writer.write(bytes); - } - }; -} -fn writerWithErrors( - backing_writer: anytype, - comptime ExtraErrors: type, -) WriterWithErrors(@TypeOf(backing_writer), ExtraErrors) { - return .{ .backing_writer = backing_writer }; -} - -pub fn printUnbuffered( - self: *Builder, - backing_writer: anytype, -) (@TypeOf(backing_writer).Error || Allocator.Error)!void { - const writer_with_errors = writerWithErrors(backing_writer, Allocator.Error); - const writer = writer_with_errors.writer(); - +pub fn print(self: *Builder, bw: *std.io.BufferedWriter) anyerror!void { var need_newline = false; var metadata_formatter: Metadata.Formatter = .{ .builder = self, .need_comma = undefined }; defer metadata_formatter.map.deinit(self.gpa); if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; - if (self.source_filename != .none) try writer.print( + if (need_newline) try bw.writeByte('\n') else need_newline = true; + if (self.source_filename != .none) try bw.print( \\; ModuleID = '{s}' - \\source_filename = {"} + \\source_filename = {f"} \\ , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) }); - if (self.data_layout != .none) try writer.print( - \\target datalayout = {"} + if (self.data_layout != .none) try bw.print( + \\target datalayout = {f"} \\ , .{self.data_layout.fmt(self)}); - if (self.target_triple != .none) try writer.print( - \\target triple = {"} + if (self.target_triple != .none) try bw.print( + \\target triple = {f"} \\ , .{self.target_triple.fmt(self)}); } if (self.module_asm.items.len > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try bw.writeByte('\n') else need_newline = true; var line_it = std.mem.tokenizeScalar(u8, self.module_asm.items, '\n'); while (line_it.next()) |line| { - try writer.writeAll("module asm "); - try printEscapedString(line, .always_quote, writer); - try writer.writeByte('\n'); + try bw.writeAll("module asm "); + try printEscapedString(line, .always_quote, bw); + try bw.writeByte('\n'); } } if (self.types.count() > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; - for (self.types.keys(), self.types.values()) |id, ty| try writer.print( - \\%{} = type {} + if (need_newline) try bw.writeByte('\n') else need_newline = true; + for (self.types.keys(), self.types.values()) |id, ty| try bw.print( + \\%{f} = type {f} \\ , .{ id.fmt(self), ty.fmt(self) }); } if (self.variables.items.len > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try bw.writeByte('\n') else need_newline = true; for (self.variables.items) |variable| { if (variable.global.getReplacement(self) != .none) continue; const global = variable.global.ptrConst(self); metadata_formatter.need_comma = true; defer metadata_formatter.need_comma = undefined; - try writer.print( - \\{} ={}{}{}{}{ }{}{ }{} {s} {%}{ }{, }{} + try bw.print( + \\{f} ={f}{f}{f}{f}{f }{f}{f }{f} {s} {f%}{f }{f, }{f} \\ , .{ variable.global.fmt(self), @@ -9618,14 +9457,14 @@ pub fn printUnbuffered( } if (self.aliases.items.len > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try bw.writeByte('\n') else need_newline = true; for (self.aliases.items) |alias| { if (alias.global.getReplacement(self) != .none) continue; const global = alias.global.ptrConst(self); metadata_formatter.need_comma = true; defer metadata_formatter.need_comma = undefined; - try writer.print( - \\{} ={}{}{}{}{ }{} alias {%}, {%}{} + try bw.print( + \\{f} ={f}{f}{f}{f}{f }{f} alias {f%}, {f%}{f} \\ , .{ alias.global.fmt(self), @@ -9647,17 +9486,17 @@ pub fn printUnbuffered( for (0.., self.functions.items) |function_i, function| { if (function.global.getReplacement(self) != .none) continue; - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try bw.writeByte('\n') else need_newline = true; const function_index: Function.Index = @enumFromInt(function_i); const global = function.global.ptrConst(self); const params_len = global.type.functionParameters(self).len; const function_attributes = function.attributes.func(self); - if (function_attributes != .none) try writer.print( - \\; Function Attrs:{} + if (function_attributes != .none) try bw.print( + \\; Function Attrs:{f} \\ , .{function_attributes.fmt(self)}); - try writer.print( - \\{s}{}{}{}{}{}{"} {%} {}( + try bw.print( + \\{s}{f}{f}{f}{f}{f}{f"} {f%} {f}( , .{ if (function.instructions.len > 0) "define" else "declare", global.linkage, @@ -9670,40 +9509,40 @@ pub fn printUnbuffered( function.global.fmt(self), }); for (0..params_len) |arg| { - if (arg > 0) try writer.writeAll(", "); - try writer.print( - \\{%}{"} + if (arg > 0) try bw.writeAll(", "); + try bw.print( + \\{f%}{f"} , .{ global.type.functionParameters(self)[arg].fmt(self), function.attributes.param(arg, self).fmt(self), }); if (function.instructions.len > 0) - try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)}) + try bw.print(" {f}", .{function.arg(@intCast(arg)).fmt(function_index, self)}) else - try writer.print(" %{d}", .{arg}); + try bw.print(" %{d}", .{arg}); } switch (global.type.functionKind(self)) { .normal => {}, .vararg => { - if (params_len > 0) try writer.writeAll(", "); - try writer.writeAll("..."); + if (params_len > 0) try bw.writeAll(", "); + try bw.writeAll("..."); }, } - try writer.print("){}{ }", .{ global.unnamed_addr, global.addr_space }); - if (function_attributes != .none) try writer.print(" #{d}", .{ + try bw.print("){f}{f }", .{ global.unnamed_addr, global.addr_space }); + if (function_attributes != .none) try bw.print(" #{d}", .{ (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index, }); { metadata_formatter.need_comma = false; defer metadata_formatter.need_comma = undefined; - try writer.print("{ }{}", .{ + try bw.print("{f }{f}", .{ function.alignment, try metadata_formatter.fmt(" !dbg ", global.dbg), }); } if (function.instructions.len > 0) { var block_incoming_len: u32 = undefined; - try writer.writeAll(" {\n"); + try bw.writeAll(" {\n"); var maybe_dbg_index: ?u32 = null; for (params_len..function.instructions.len) |instruction_i| { const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i); @@ -9801,7 +9640,7 @@ pub fn printUnbuffered( .xor, => |tag| { const extra = function.extraData(Function.Instruction.Binary, instruction.data); - try writer.print(" %{} = {s} {%}, {}", .{ + try bw.print(" %{f} = {s} {f%}, {f}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.lhs.fmt(function_index, self), @@ -9823,7 +9662,7 @@ pub fn printUnbuffered( .zext, => |tag| { const extra = function.extraData(Function.Instruction.Cast, instruction.data); - try writer.print(" %{} = {s} {%} to {%}", .{ + try bw.print(" %{f} = {s} {f%} to {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.val.fmt(function_index, self), @@ -9834,7 +9673,7 @@ pub fn printUnbuffered( .@"alloca inalloca", => |tag| { const extra = function.extraData(Function.Instruction.Alloca, instruction.data); - try writer.print(" %{} = {s} {%}{,%}{, }{, }", .{ + try bw.print(" %{f} = {s} {f%}{f,%}{f, }{f, }", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.type.fmt(self), @@ -9850,7 +9689,7 @@ pub fn printUnbuffered( .atomicrmw => |tag| { const extra = function.extraData(Function.Instruction.AtomicRmw, instruction.data); - try writer.print(" %{} = {s}{ } {s} {%}, {%}{ }{ }{, }", .{ + try bw.print(" %{f} = {s}{f } {s} {f%}, {f%}{f }{f }{f, }", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.info.access_kind, @@ -9866,19 +9705,19 @@ pub fn printUnbuffered( block_incoming_len = instruction.data; const name = instruction_index.name(&function); if (@intFromEnum(instruction_index) > params_len) - try writer.writeByte('\n'); - try writer.print("{}:\n", .{name.fmt(self)}); + try bw.writeByte('\n'); + try bw.print("{f}:\n", .{name.fmt(self)}); continue; }, .br => |tag| { const target: Function.Block.Index = @enumFromInt(instruction.data); - try writer.print(" {s} {%}", .{ + try bw.print(" {s} {f%}", .{ @tagName(tag), target.toInst(&function).fmt(function_index, self), }); }, .br_cond => { const extra = function.extraData(Function.Instruction.BrCond, instruction.data); - try writer.print(" br {%}, {%}, {%}", .{ + try bw.print(" br {f%}, {f%}, {f%}", .{ extra.cond.fmt(function_index, self), extra.then.toInst(&function).fmt(function_index, self), extra.@"else".toInst(&function).fmt(function_index, self), @@ -9887,8 +9726,8 @@ pub fn printUnbuffered( defer metadata_formatter.need_comma = undefined; switch (extra.weights) { .none => {}, - .unpredictable => try writer.writeAll("!unpredictable !{}"), - _ => try writer.print("{}", .{ + .unpredictable => try bw.writeAll("!unpredictable !{}"), + _ => try bw.print("{f}", .{ try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.weights)))), }), } @@ -9905,16 +9744,16 @@ pub fn printUnbuffered( var extra = function.extraDataTrail(Function.Instruction.Call, instruction.data); const args = extra.trail.next(extra.data.args_len, Value, &function); - try writer.writeAll(" "); + try bw.writeAll(" "); const ret_ty = extra.data.ty.functionReturn(self); switch (ret_ty) { .void => {}, - else => try writer.print("%{} = ", .{ + else => try bw.print("%{f} = ", .{ instruction_index.name(&function).fmt(self), }), .none => unreachable, } - try writer.print("{s}{}{}{} {%} {}(", .{ + try bw.print("{s}{f}{f}{f} {f%} {f}(", .{ @tagName(tag), extra.data.info.call_conv, extra.data.attributes.ret(self).fmt(self), @@ -9926,21 +9765,21 @@ pub fn printUnbuffered( extra.data.callee.fmt(function_index, self), }); for (0.., args) |arg_index, arg| { - if (arg_index > 0) try writer.writeAll(", "); + if (arg_index > 0) try bw.writeAll(", "); metadata_formatter.need_comma = false; defer metadata_formatter.need_comma = undefined; - try writer.print("{%}{}{}", .{ + try bw.print("{f%}{f}{f}", .{ arg.typeOf(function_index, self).fmt(self), extra.data.attributes.param(arg_index, self).fmt(self), try metadata_formatter.fmtLocal(" ", arg, function_index), }); } - try writer.writeByte(')'); + try bw.writeByte(')'); if (extra.data.info.has_op_bundle_cold) { - try writer.writeAll(" [ \"cold\"() ]"); + try bw.writeAll(" [ \"cold\"() ]"); } const call_function_attributes = extra.data.attributes.func(self); - if (call_function_attributes != .none) try writer.print(" #{d}", .{ + if (call_function_attributes != .none) try bw.print(" #{d}", .{ (try attribute_groups.getOrPutValue( self.gpa, call_function_attributes, @@ -9953,7 +9792,7 @@ pub fn printUnbuffered( => |tag| { const extra = function.extraData(Function.Instruction.CmpXchg, instruction.data); - try writer.print(" %{} = {s}{ } {%}, {%}, {%}{ }{ }{ }{, }", .{ + try bw.print(" %{f} = {s}{f } {f%}, {f%}, {f%}{f }{f }{f }{f, }", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.info.access_kind, @@ -9969,7 +9808,7 @@ pub fn printUnbuffered( .extractelement => |tag| { const extra = function.extraData(Function.Instruction.ExtractElement, instruction.data); - try writer.print(" %{} = {s} {%}, {%}", .{ + try bw.print(" %{f} = {s} {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.val.fmt(function_index, self), @@ -9982,16 +9821,16 @@ pub fn printUnbuffered( instruction.data, ); const indices = extra.trail.next(extra.data.indices_len, u32, &function); - try writer.print(" %{} = {s} {%}", .{ + try bw.print(" %{f} = {s} {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.data.val.fmt(function_index, self), }); - for (indices) |index| try writer.print(", {d}", .{index}); + for (indices) |index| try bw.print(", {d}", .{index}); }, .fence => |tag| { const info: MemoryAccessInfo = @bitCast(instruction.data); - try writer.print(" {s}{ }{ }", .{ + try bw.print(" {s}{f }{f }", .{ @tagName(tag), info.sync_scope, info.success_ordering, @@ -10001,7 +9840,7 @@ pub fn printUnbuffered( .@"fneg fast", => |tag| { const val: Value = @enumFromInt(instruction.data); - try writer.print(" %{} = {s} {%}", .{ + try bw.print(" %{f} = {s} {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), val.fmt(function_index, self), @@ -10015,13 +9854,13 @@ pub fn printUnbuffered( instruction.data, ); const indices = extra.trail.next(extra.data.indices_len, Value, &function); - try writer.print(" %{} = {s} {%}, {%}", .{ + try bw.print(" %{f} = {s} {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.data.type.fmt(self), extra.data.base.fmt(function_index, self), }); - for (indices) |index| try writer.print(", {%}", .{ + for (indices) |index| try bw.print(", {f%}", .{ index.fmt(function_index, self), }); }, @@ -10030,22 +9869,22 @@ pub fn printUnbuffered( function.extraDataTrail(Function.Instruction.IndirectBr, instruction.data); const targets = extra.trail.next(extra.data.targets_len, Function.Block.Index, &function); - try writer.print(" {s} {%}, [", .{ + try bw.print(" {s} {f%}, [", .{ @tagName(tag), extra.data.addr.fmt(function_index, self), }); for (0.., targets) |target_index, target| { - if (target_index > 0) try writer.writeAll(", "); - try writer.print("{%}", .{ + if (target_index > 0) try bw.writeAll(", "); + try bw.print("{f%}", .{ target.toInst(&function).fmt(function_index, self), }); } - try writer.writeByte(']'); + try bw.writeByte(']'); }, .insertelement => |tag| { const extra = function.extraData(Function.Instruction.InsertElement, instruction.data); - try writer.print(" %{} = {s} {%}, {%}, {%}", .{ + try bw.print(" %{f} = {s} {f%}, {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.val.fmt(function_index, self), @@ -10057,19 +9896,19 @@ pub fn printUnbuffered( var extra = function.extraDataTrail(Function.Instruction.InsertValue, instruction.data); const indices = extra.trail.next(extra.data.indices_len, u32, &function); - try writer.print(" %{} = {s} {%}, {%}", .{ + try bw.print(" %{f} = {s} {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.data.val.fmt(function_index, self), extra.data.elem.fmt(function_index, self), }); - for (indices) |index| try writer.print(", {d}", .{index}); + for (indices) |index| try bw.print(", {d}", .{index}); }, .load, .@"load atomic", => |tag| { const extra = function.extraData(Function.Instruction.Load, instruction.data); - try writer.print(" %{} = {s}{ } {%}, {%}{ }{ }{, }", .{ + try bw.print(" %{f} = {s}{f } {f%}, {f%}{f }{f }{f, }", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.info.access_kind, @@ -10087,14 +9926,14 @@ pub fn printUnbuffered( const vals = extra.trail.next(block_incoming_len, Value, &function); const blocks = extra.trail.next(block_incoming_len, Function.Block.Index, &function); - try writer.print(" %{} = {s} {%} ", .{ + try bw.print(" %{f} = {s} {f%} ", .{ instruction_index.name(&function).fmt(self), @tagName(tag), vals[0].typeOf(function_index, self).fmt(self), }); for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| { - if (incoming_index > 0) try writer.writeAll(", "); - try writer.print("[ {}, {} ]", .{ + if (incoming_index > 0) try bw.writeAll(", "); + try bw.print("[ {f}, {f} ]", .{ incoming_val.fmt(function_index, self), incoming_block.toInst(&function).fmt(function_index, self), }); @@ -10102,19 +9941,19 @@ pub fn printUnbuffered( }, .ret => |tag| { const val: Value = @enumFromInt(instruction.data); - try writer.print(" {s} {%}", .{ + try bw.print(" {s} {f%}", .{ @tagName(tag), val.fmt(function_index, self), }); }, .@"ret void", .@"unreachable", - => |tag| try writer.print(" {s}", .{@tagName(tag)}), + => |tag| try bw.print(" {s}", .{@tagName(tag)}), .select, .@"select fast", => |tag| { const extra = function.extraData(Function.Instruction.Select, instruction.data); - try writer.print(" %{} = {s} {%}, {%}, {%}", .{ + try bw.print(" %{f} = {s} {f%}, {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.cond.fmt(function_index, self), @@ -10125,7 +9964,7 @@ pub fn printUnbuffered( .shufflevector => |tag| { const extra = function.extraData(Function.Instruction.ShuffleVector, instruction.data); - try writer.print(" %{} = {s} {%}, {%}, {%}", .{ + try bw.print(" %{f} = {s} {f%}, {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.lhs.fmt(function_index, self), @@ -10137,7 +9976,7 @@ pub fn printUnbuffered( .@"store atomic", => |tag| { const extra = function.extraData(Function.Instruction.Store, instruction.data); - try writer.print(" {s}{ } {%}, {%}{ }{ }{, }", .{ + try bw.print(" {s}{f } {f%}, {f%}{f }{f }{f, }", .{ @tagName(tag), extra.info.access_kind, extra.val.fmt(function_index, self), @@ -10153,32 +9992,32 @@ pub fn printUnbuffered( const vals = extra.trail.next(extra.data.cases_len, Constant, &function); const blocks = extra.trail.next(extra.data.cases_len, Function.Block.Index, &function); - try writer.print(" {s} {%}, {%} [\n", .{ + try bw.print(" {s} {f%}, {f%} [\n", .{ @tagName(tag), extra.data.val.fmt(function_index, self), extra.data.default.toInst(&function).fmt(function_index, self), }); - for (vals, blocks) |case_val, case_block| try writer.print( - " {%}, {%}\n", + for (vals, blocks) |case_val, case_block| try bw.print( + " {f%}, {f%}\n", .{ case_val.fmt(self), case_block.toInst(&function).fmt(function_index, self), }, ); - try writer.writeAll(" ]"); + try bw.writeAll(" ]"); metadata_formatter.need_comma = true; defer metadata_formatter.need_comma = undefined; switch (extra.data.weights) { .none => {}, - .unpredictable => try writer.writeAll("!unpredictable !{}"), - _ => try writer.print("{}", .{ + .unpredictable => try bw.writeAll("!unpredictable !{}"), + _ => try bw.print("{f}", .{ try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.data.weights)))), }), } }, .va_arg => |tag| { const extra = function.extraData(Function.Instruction.VaArg, instruction.data); - try writer.print(" %{} = {s} {%}, {%}", .{ + try bw.print(" %{f} = {s} {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.list.fmt(function_index, self), @@ -10188,45 +10027,45 @@ pub fn printUnbuffered( } if (maybe_dbg_index) |dbg_index| { - try writer.print(", !dbg !{}", .{dbg_index}); + try bw.print(", !dbg !{d}", .{dbg_index}); } - try writer.writeByte('\n'); + try bw.writeByte('\n'); } - try writer.writeByte('}'); + try bw.writeByte('}'); } - try writer.writeByte('\n'); + try bw.writeByte('\n'); } if (attribute_groups.count() > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try bw.writeByte('\n') else need_newline = true; for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group| - try writer.print( - \\attributes #{d} = {{{#"} }} + try bw.print( + \\attributes #{d} = {{{f#"} }} \\ , .{ attribute_group_index, attribute_group.fmt(self) }); } if (self.metadata_named.count() > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try bw.writeByte('\n') else need_newline = true; for (self.metadata_named.keys(), self.metadata_named.values()) |name, data| { const elements: []const Metadata = @ptrCast(self.metadata_extra.items[data.index..][0..data.len]); - try writer.writeByte('!'); - try printEscapedString(name.slice(self), .quote_unless_valid_identifier, writer); - try writer.writeAll(" = !{"); + try bw.writeByte('!'); + try printEscapedString(name.slice(self), .quote_unless_valid_identifier, bw); + try bw.writeAll(" = !{"); metadata_formatter.need_comma = false; defer metadata_formatter.need_comma = undefined; - for (elements) |element| try writer.print("{}", .{try metadata_formatter.fmt("", element)}); - try writer.writeAll("}\n"); + for (elements) |element| try bw.print("{f}", .{try metadata_formatter.fmt("", element)}); + try bw.writeAll("}\n"); } } if (metadata_formatter.map.count() > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try bw.writeByte('\n') else need_newline = true; var metadata_index: usize = 0; while (metadata_index < metadata_formatter.map.count()) : (metadata_index += 1) { @setEvalBranchQuota(10_000); - try writer.print("!{} = ", .{metadata_index}); + try bw.print("!{d} = ", .{metadata_index}); metadata_formatter.need_comma = false; defer metadata_formatter.need_comma = undefined; @@ -10239,7 +10078,7 @@ pub fn printUnbuffered( .scope = location.scope, .inlinedAt = location.inlined_at, .isImplicitCode = false, - }, writer); + }, bw); continue; }, .metadata => |metadata| self.metadata_items.get(@intFromEnum(metadata)), @@ -10255,7 +10094,7 @@ pub fn printUnbuffered( .checksumkind = null, .checksum = null, .source = null, - }, writer); + }, bw); }, .compile_unit, .@"compile_unit optimized", @@ -10286,7 +10125,7 @@ pub fn printUnbuffered( .rangesBaseAddress = null, .sysroot = null, .sdk = null, - }, writer); + }, bw); }, .subprogram, .@"subprogram local", @@ -10320,7 +10159,7 @@ pub fn printUnbuffered( .thrownTypes = null, .annotations = null, .targetFuncName = null, - }, writer); + }, bw); }, .lexical_block => { const extra = self.metadataExtraData(Metadata.LexicalBlock, metadata_item.data); @@ -10329,7 +10168,7 @@ pub fn printUnbuffered( .file = extra.file, .line = extra.line, .column = extra.column, - }, writer); + }, bw); }, .location => { const extra = self.metadataExtraData(Metadata.Location, metadata_item.data); @@ -10339,7 +10178,7 @@ pub fn printUnbuffered( .scope = extra.scope, .inlinedAt = extra.inlined_at, .isImplicitCode = false, - }, writer); + }, bw); }, .basic_bool_type, .basic_unsigned_type, @@ -10368,7 +10207,7 @@ pub fn printUnbuffered( else => unreachable, }), .flags = null, - }, writer); + }, bw); }, .composite_struct_type, .composite_union_type, @@ -10413,7 +10252,7 @@ pub fn printUnbuffered( .allocated = null, .rank = null, .annotations = null, - }, writer); + }, bw); }, .derived_pointer_type, .derived_member_type, @@ -10446,7 +10285,7 @@ pub fn printUnbuffered( .extraData = null, .dwarfAddressSpace = null, .annotations = null, - }, writer); + }, bw); }, .subroutine_type => { const extra = self.metadataExtraData(Metadata.SubroutineType, metadata_item.data); @@ -10454,7 +10293,7 @@ pub fn printUnbuffered( .flags = null, .cc = null, .types = extra.types_tuple, - }, writer); + }, bw); }, .enumerator_unsigned, .enumerator_signed_positive, @@ -10504,7 +10343,7 @@ pub fn printUnbuffered( => false, else => unreachable, }, - }, writer); + }, bw); }, .subrange => { const extra = self.metadataExtraData(Metadata.Subrange, metadata_item.data); @@ -10513,31 +10352,31 @@ pub fn printUnbuffered( .lowerBound = extra.lower_bound, .upperBound = null, .stride = null, - }, writer); + }, bw); }, .tuple => { var extra = self.metadataExtraDataTrail(Metadata.Tuple, metadata_item.data); const elements = extra.trail.next(extra.data.elements_len, Metadata, self); - try writer.writeAll("!{"); - for (elements) |element| try writer.print("{[element]%}", .{ + try bw.writeAll("!{"); + for (elements) |element| try bw.print("{[element]f%}", .{ .element = try metadata_formatter.fmt("", element), }); - try writer.writeAll("}\n"); + try bw.writeAll("}\n"); }, .str_tuple => { var extra = self.metadataExtraDataTrail(Metadata.StrTuple, metadata_item.data); const elements = extra.trail.next(extra.data.elements_len, Metadata, self); - try writer.print("!{{{[str]%}", .{ + try bw.print("!{{{[str]f%}", .{ .str = try metadata_formatter.fmt("", extra.data.str), }); - for (elements) |element| try writer.print("{[element]%}", .{ + for (elements) |element| try bw.print("{[element]f%}", .{ .element = try metadata_formatter.fmt("", element), }); - try writer.writeAll("}\n"); + try bw.writeAll("}\n"); }, .module_flag => { const extra = self.metadataExtraData(Metadata.ModuleFlag, metadata_item.data); - try writer.print("!{{{[behavior]%}{[name]%}{[constant]%}}}\n", .{ + try bw.print("!{{{[behavior]f%}{[name]f%}{[constant]f%}}}\n", .{ .behavior = try metadata_formatter.fmt("", extra.behavior), .name = try metadata_formatter.fmt("", extra.name), .constant = try metadata_formatter.fmt("", extra.constant), @@ -10555,7 +10394,7 @@ pub fn printUnbuffered( .flags = null, .@"align" = null, .annotations = null, - }, writer); + }, bw); }, .parameter => { const extra = self.metadataExtraData(Metadata.Parameter, metadata_item.data); @@ -10569,7 +10408,7 @@ pub fn printUnbuffered( .flags = null, .@"align" = null, .annotations = null, - }, writer); + }, bw); }, .global_var, .@"global_var local", @@ -10592,7 +10431,7 @@ pub fn printUnbuffered( .templateParams = null, .@"align" = null, .annotations = null, - }, writer); + }, bw); }, .global_var_expression => { const extra = @@ -10600,7 +10439,7 @@ pub fn printUnbuffered( try metadata_formatter.specialized(.@"!", .DIGlobalVariableExpression, .{ .@"var" = extra.variable, .expr = extra.expression, - }, writer); + }, bw); }, } } @@ -10619,22 +10458,18 @@ fn isValidIdentifier(id: []const u8) bool { } const QuoteBehavior = enum { always_quote, quote_unless_valid_identifier }; -fn printEscapedString( - slice: []const u8, - quotes: QuoteBehavior, - writer: anytype, -) @TypeOf(writer).Error!void { +fn printEscapedString(slice: []const u8, quotes: QuoteBehavior, bw: *std.io.BufferedWriter) anyerror!void { const need_quotes = switch (quotes) { .always_quote => true, .quote_unless_valid_identifier => !isValidIdentifier(slice), }; - if (need_quotes) try writer.writeByte('"'); + if (need_quotes) try bw.writeByte('"'); for (slice) |byte| switch (byte) { - '\\' => try writer.writeAll("\\\\"), - ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(byte), - else => try writer.print("\\{X:0>2}", .{byte}), + '\\' => try bw.writeAll("\\\\"), + ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try bw.writeByte(byte), + else => try bw.print("\\{X:0>2}", .{byte}), }; - if (need_quotes) try writer.writeByte('"'); + if (need_quotes) try bw.writeByte('"'); } fn ensureUnusedGlobalCapacity(self: *Builder, name: StrtabString) Allocator.Error!void { @@ -12019,7 +11854,7 @@ pub fn metadataStringFmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: } pub fn metadataStringFmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) MetadataString { - self.metadata_string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable; + self.metadata_string_bytes.printAssumeCapacity(fmt_str, fmt_args); return self.trailingMetadataStringAssumeCapacity(); } diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 7bd6c928d7..27528d095c 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -77,7 +77,7 @@ const Render = struct { pub fn renderTree(gpa: Allocator, bw: *std.io.BufferedWriter, tree: Ast, fixups: Fixups) anyerror!void { assert(tree.errors.len == 0); // Cannot render an invalid tree. - var auto_indenting_stream: AutoIndentingStream = .init(bw, indent_delta); + var auto_indenting_stream: AutoIndentingStream = .init(gpa, bw, indent_delta); defer auto_indenting_stream.deinit(); var r: Render = .{ .gpa = gpa, @@ -2135,13 +2135,13 @@ fn renderArrayInit( const section_exprs = row_exprs[0..section_end]; var sub_expr_buffer: std.io.AllocatingWriter = undefined; - const sub_expr_buffer_writer = sub_expr_buffer.init(gpa); + sub_expr_buffer.init(gpa); defer sub_expr_buffer.deinit(); const sub_expr_buffer_starts = try gpa.alloc(usize, section_exprs.len + 1); defer gpa.free(sub_expr_buffer_starts); - var auto_indenting_stream: AutoIndentingStream = .init(sub_expr_buffer_writer, indent_delta); + var auto_indenting_stream: AutoIndentingStream = .init(gpa, &sub_expr_buffer.buffered_writer, indent_delta); defer auto_indenting_stream.deinit(); var sub_render: Render = .{ .gpa = r.gpa, @@ -2160,8 +2160,9 @@ fn renderArrayInit( if (i + 1 < section_exprs.len) { try renderExpression(&sub_render, expr, .none); - const width = sub_expr_buffer.getWritten().len - start; - const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.getWritten()[start..], '\n') != null; + const written = sub_expr_buffer.getWritten(); + const width = written.len - start; + const this_contains_newline = mem.indexOfScalar(u8, written[start..], '\n') != null; contains_newline = contains_newline or this_contains_newline; expr_widths[i] = width; expr_newlines[i] = this_contains_newline; @@ -2183,8 +2184,9 @@ fn renderArrayInit( try renderExpression(&sub_render, expr, .comma); ais.popSpace(); - const width = sub_expr_buffer.items.len - start - 2; - const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.getWritten()[start .. sub_expr_buffer.items.len - 1], '\n') != null; + const written = sub_expr_buffer.getWritten(); + const width = written.len - start - 2; + const this_contains_newline = mem.indexOfScalar(u8, written[start .. written.len - 1], '\n') != null; contains_newline = contains_newline or this_contains_newline; expr_widths[i] = width; expr_newlines[i] = contains_newline; @@ -2682,7 +2684,7 @@ fn renderTokenOverrideSpaceMode(r: *Render, token_index: Ast.TokenIndex, space: const tree = r.tree; const ais = r.ais; const lexeme = tokenSliceForRender(tree, token_index); - try ais.writer().writeAll(lexeme); + try ais.writeAll(lexeme); ais.enableSpaceMode(override_space); defer ais.disableSpaceMode(); try renderSpace(r, token_index, lexeme.len, space); @@ -3259,6 +3261,14 @@ fn rowSize(tree: Ast, exprs: []const Ast.Node.Index, rtoken: Ast.TokenIndex) usi const AutoIndentingStream = struct { underlying_writer: *std.io.BufferedWriter, + /// Offset into the source at which formatting has been disabled with + /// a `zig fmt: off` comment. + /// + /// If non-null, the AutoIndentingStream will not write any bytes + /// to the underlying writer. It will however continue to track the + /// indentation level. + disabled_offset: ?usize = null, + indent_count: usize = 0, indent_delta: usize, indent_stack: std.ArrayList(StackElem), @@ -3284,12 +3294,12 @@ const AutoIndentingStream = struct { indent_count: usize, }; - pub fn init(buffer: *std.ArrayList(u8), indent_delta_: usize) AutoIndentingStream { + pub fn init(gpa: Allocator, bw: *std.io.BufferedWriter, indent_delta_: usize) AutoIndentingStream { return .{ - .underlying_writer = buffer.writer(), + .underlying_writer = bw, .indent_delta = indent_delta_, - .indent_stack = std.ArrayList(StackElem).init(buffer.allocator), - .space_stack = std.ArrayList(SpaceElem).init(buffer.allocator), + .indent_stack = .init(gpa), + .space_stack = .init(gpa), }; } @@ -3477,7 +3487,7 @@ const AutoIndentingStream = struct { const current_indent = ais.currentIndent(); if (ais.current_line_empty and current_indent > 0) { if (ais.disabled_offset == null) { - try ais.underlying_writer.writeByteNTimes(' ', current_indent); + try ais.underlying_writer.splatByteAll(' ', current_indent); } ais.applied_indent = current_indent; } diff --git a/lib/std/zig/string_literal.zig b/lib/std/zig/string_literal.zig index 5df4777f7d..89653de312 100644 --- a/lib/std/zig/string_literal.zig +++ b/lib/std/zig/string_literal.zig @@ -44,50 +44,44 @@ pub const Error = union(enum) { raw_string: []const u8, }; - fn formatMessage( - self: FormatMessage, - comptime f: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + fn formatMessage(self: FormatMessage, bw: *std.io.BufferedWriter, comptime f: []const u8) anyerror!void { _ = f; - _ = options; switch (self.err) { - .invalid_escape_character => |bad_index| try writer.print( + .invalid_escape_character => |bad_index| try bw.print( "invalid escape character: '{c}'", .{self.raw_string[bad_index]}, ), - .expected_hex_digit => |bad_index| try writer.print( + .expected_hex_digit => |bad_index| try bw.print( "expected hex digit, found '{c}'", .{self.raw_string[bad_index]}, ), - .empty_unicode_escape_sequence => try writer.writeAll( + .empty_unicode_escape_sequence => try bw.writeAll( "empty unicode escape sequence", ), - .expected_hex_digit_or_rbrace => |bad_index| try writer.print( + .expected_hex_digit_or_rbrace => |bad_index| try bw.print( "expected hex digit or '}}', found '{c}'", .{self.raw_string[bad_index]}, ), - .invalid_unicode_codepoint => try writer.writeAll( + .invalid_unicode_codepoint => try bw.writeAll( "unicode escape does not correspond to a valid unicode scalar value", ), - .expected_lbrace => |bad_index| try writer.print( + .expected_lbrace => |bad_index| try bw.print( "expected '{{', found '{c}'", .{self.raw_string[bad_index]}, ), - .expected_rbrace => |bad_index| try writer.print( + .expected_rbrace => |bad_index| try bw.print( "expected '}}', found '{c}'", .{self.raw_string[bad_index]}, ), - .expected_single_quote => |bad_index| try writer.print( + .expected_single_quote => |bad_index| try bw.print( "expected single quote ('), found '{c}'", .{self.raw_string[bad_index]}, ), - .invalid_character => |bad_index| try writer.print( + .invalid_character => |bad_index| try bw.print( "invalid byte in string or character literal: '{c}'", .{self.raw_string[bad_index]}, ), - .empty_char_literal => try writer.writeAll( + .empty_char_literal => try bw.writeAll( "empty character literal", ), } @@ -363,13 +357,13 @@ pub fn parseWrite(writer: *std.io.BufferedWriter, bytes: []const u8) anyerror!Re /// Higher level API. Does not return extra info about parse errors. /// Caller owns returned memory. pub fn parseAlloc(allocator: std.mem.Allocator, bytes: []const u8) ParseError![]u8 { - var buf: std.io.AllocatingWriter = undefined; - const bw = buf.init(allocator); - defer buf.deinit(); + var aw: std.io.AllocatingWriter = undefined; + aw.init(allocator); + defer aw.deinit(); // TODO try @errorCast(...) - const result = parseWrite(bw, bytes) catch |err| return @errorCast(err); + const result = parseWrite(&aw.buffered_writer, bytes) catch |err| return @errorCast(err); switch (result) { - .success => return buf.toOwnedSlice(), + .success => return aw.toOwnedSlice(), .failure => return error.InvalidLiteral, } } diff --git a/lib/std/zon/stringify.zig b/lib/std/zon/stringify.zig index f7233f009a..07bfe93ae1 100644 --- a/lib/std/zon/stringify.zig +++ b/lib/std/zon/stringify.zig @@ -583,7 +583,7 @@ pub const Serializer = struct { /// Serialize an integer. pub fn int(self: *Serializer, val: anytype) anyerror!void { - try std.fmt.formatInt(val, 10, .lower, .{}, self.writer); + try self.writer.printIntOptions(val, 10, .lower, .{}); } /// Serialize a float. @@ -613,7 +613,7 @@ pub const Serializer = struct { /// /// Escapes the identifier if necessary. pub fn ident(self: *Serializer, name: []const u8) anyerror!void { - try self.writer.print(".{p_}", .{std.zig.fmtId(name)}); + try self.writer.print(".{fp_}", .{std.zig.fmtId(name)}); } /// Serialize `val` as a Unicode codepoint. @@ -626,7 +626,7 @@ pub const Serializer = struct { var buf: [8]u8 = undefined; const len = std.unicode.utf8Encode(val, &buf) catch return error.InvalidCodepoint; const str = buf[0..len]; - try std.fmt.format(self.writer, "'{'}'", .{std.zig.fmtEscapes(str)}); + try std.fmt.format(self.writer, "'{f'}'", .{std.zig.fmtEscapes(str)}); } /// Like `value`, but always serializes `val` as a tuple. @@ -684,7 +684,7 @@ pub const Serializer = struct { /// Like `value`, but always serializes `val` as a string. pub fn string(self: *Serializer, val: []const u8) anyerror!void { - try std.fmt.format(self.writer, "\"{}\"", .{std.zig.fmtEscapes(val)}); + try std.fmt.format(self.writer, "\"{f}\"", .{std.zig.fmtEscapes(val)}); } /// Options for formatting multiline strings. @@ -758,7 +758,7 @@ pub const Serializer = struct { fn indent(self: *Serializer) anyerror!void { if (self.options.whitespace) { - try self.writer.writeByteNTimes(' ', 4 * self.indent_level); + try self.writer.splatByteAll(' ', 4 * self.indent_level); } } diff --git a/src/Air.zig b/src/Air.zig index acc0643f25..6cd8a4a2cb 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -957,18 +957,13 @@ pub const Inst = struct { return index.unwrap().target; } - pub fn format( - index: Index, - comptime _: []const u8, - _: std.fmt.Options, - writer: *std.io.BufferedWriter, - ) anyerror!void { - try writer.writeByte('%'); + pub fn format(index: Index, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + try bw.writeByte('%'); switch (index.unwrap()) { .ref => {}, - .target => try writer.writeByte('t'), + .target => try bw.writeByte('t'), } - try writer.print("{d}", .{@as(u31, @truncate(@intFromEnum(index)))}); + try bw.print("{d}", .{@as(u31, @truncate(@intFromEnum(index)))}); } }; diff --git a/src/Air/Liveness.zig b/src/Air/Liveness.zig index 94ed60fbf2..5364853a6a 100644 --- a/src/Air/Liveness.zig +++ b/src/Air/Liveness.zig @@ -1323,7 +1323,7 @@ fn analyzeOperands( const mask = @as(Bpi, 1) << @as(OperandInt, @intCast(i)); if ((try data.live_set.fetchPut(gpa, operand, {})) == null) { - log.debug("[{}] %{}: added %{} to live set (operand dies here)", .{ pass, @intFromEnum(inst), operand }); + log.debug("[{}] %{}: added %{f} to live set (operand dies here)", .{ pass, @intFromEnum(inst), operand }); tomb_bits |= mask; } } @@ -1462,19 +1462,19 @@ fn analyzeInstBlock( }, .main_analysis => { - log.debug("[{}] %{}: block live set is {}", .{ pass, inst, fmtInstSet(&data.live_set) }); + log.debug("[{}] %{f}: block live set is {f}", .{ pass, inst, fmtInstSet(&data.live_set) }); // We can move the live set because the body should have a noreturn // instruction which overrides the set. try data.block_scopes.put(gpa, inst, .{ .live_set = data.live_set.move(), }); defer { - log.debug("[{}] %{}: popped block scope", .{ pass, inst }); + log.debug("[{}] %{f}: popped block scope", .{ pass, inst }); var scope = data.block_scopes.fetchRemove(inst).?.value; scope.live_set.deinit(gpa); } - log.debug("[{}] %{}: pushed new block scope", .{ pass, inst }); + log.debug("[{}] %{f}: pushed new block scope", .{ pass, inst }); try analyzeBody(a, pass, data, body); // If the block is noreturn, block deaths not only aren't useful, they're impossible to @@ -1501,7 +1501,7 @@ fn analyzeInstBlock( } assert(measured_num == num_deaths); // post-live-set should be a subset of pre-live-set try a.special.put(gpa, inst, extra_index); - log.debug("[{}] %{}: block deaths are {}", .{ + log.debug("[{}] %{f}: block deaths are {f}", .{ pass, inst, fmtInstList(@ptrCast(a.extra.items[extra_index + 1 ..][0..num_deaths])), @@ -1538,7 +1538,7 @@ fn writeLoopInfo( const block_inst = key.*; a.extra.appendAssumeCapacity(@intFromEnum(block_inst)); } - log.debug("[{}] %{}: includes breaks to {}", .{ LivenessPass.loop_analysis, inst, fmtInstSet(&data.breaks) }); + log.debug("[{}] %{f}: includes breaks to {f}", .{ LivenessPass.loop_analysis, inst, fmtInstSet(&data.breaks) }); // Now we put the live operands from the loop body in too const num_live = data.live_set.count(); @@ -1550,7 +1550,7 @@ fn writeLoopInfo( const alive = key.*; a.extra.appendAssumeCapacity(@intFromEnum(alive)); } - log.debug("[{}] %{}: maintain liveness of {}", .{ LivenessPass.loop_analysis, inst, fmtInstSet(&data.live_set) }); + log.debug("[{}] %{f}: maintain liveness of {f}", .{ LivenessPass.loop_analysis, inst, fmtInstSet(&data.live_set) }); try a.special.put(gpa, inst, extra_index); @@ -1591,7 +1591,7 @@ fn resolveLoopLiveSet( try data.live_set.ensureUnusedCapacity(gpa, @intCast(loop_live.len)); for (loop_live) |alive| data.live_set.putAssumeCapacity(alive, {}); - log.debug("[{}] %{}: block live set is {}", .{ LivenessPass.main_analysis, inst, fmtInstSet(&data.live_set) }); + log.debug("[{}] %{f}: block live set is {f}", .{ LivenessPass.main_analysis, inst, fmtInstSet(&data.live_set) }); for (breaks) |block_inst| { // We might break to this block, so include every operand that the block needs alive @@ -1604,7 +1604,7 @@ fn resolveLoopLiveSet( } } - log.debug("[{}] %{}: loop live set is {}", .{ LivenessPass.main_analysis, inst, fmtInstSet(&data.live_set) }); + log.debug("[{}] %{f}: loop live set is {f}", .{ LivenessPass.main_analysis, inst, fmtInstSet(&data.live_set) }); } fn analyzeInstLoop( @@ -1642,7 +1642,7 @@ fn analyzeInstLoop( .live_set = data.live_set.move(), }); defer { - log.debug("[{}] %{}: popped loop block scop", .{ pass, inst }); + log.debug("[{}] %{f}: popped loop block scop", .{ pass, inst }); var scope = data.block_scopes.fetchRemove(inst).?.value; scope.live_set.deinit(gpa); } @@ -1743,13 +1743,13 @@ fn analyzeInstCondBr( } } - log.debug("[{}] %{}: 'then' branch mirrored deaths are {}", .{ pass, inst, fmtInstList(then_mirrored_deaths.items) }); - log.debug("[{}] %{}: 'else' branch mirrored deaths are {}", .{ pass, inst, fmtInstList(else_mirrored_deaths.items) }); + log.debug("[{}] %{f}: 'then' branch mirrored deaths are {f}", .{ pass, inst, fmtInstList(then_mirrored_deaths.items) }); + log.debug("[{}] %{f}: 'else' branch mirrored deaths are {f}", .{ pass, inst, fmtInstList(else_mirrored_deaths.items) }); data.live_set.deinit(gpa); data.live_set = then_live.move(); // Really the union of both live sets - log.debug("[{}] %{}: new live set is {}", .{ pass, inst, fmtInstSet(&data.live_set) }); + log.debug("[{}] %{f}: new live set is {f}", .{ pass, inst, fmtInstSet(&data.live_set) }); // Write the mirrored deaths to `extra` const then_death_count = @as(u32, @intCast(then_mirrored_deaths.items.len)); @@ -1817,7 +1817,7 @@ fn analyzeInstSwitchBr( }); } defer if (is_dispatch_loop) { - log.debug("[{}] %{}: popped loop block scop", .{ pass, inst }); + log.debug("[{}] %{f}: popped loop block scop", .{ pass, inst }); var scope = data.block_scopes.fetchRemove(inst).?.value; scope.live_set.deinit(gpa); }; @@ -1875,13 +1875,13 @@ fn analyzeInstSwitchBr( } for (mirrored_deaths, 0..) |mirrored, i| { - log.debug("[{}] %{}: case {} mirrored deaths are {}", .{ pass, inst, i, fmtInstList(mirrored.items) }); + log.debug("[{}] %{f}: case {} mirrored deaths are {f}", .{ pass, inst, i, fmtInstList(mirrored.items) }); } data.live_set.deinit(gpa); data.live_set = all_alive.move(); - log.debug("[{}] %{}: new live set is {}", .{ pass, inst, fmtInstSet(&data.live_set) }); + log.debug("[{}] %{f}: new live set is {f}", .{ pass, inst, fmtInstSet(&data.live_set) }); } const else_death_count = @as(u32, @intCast(mirrored_deaths[ncases].items.len)); @@ -1980,7 +1980,7 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type { .main_analysis => { if ((try big.data.live_set.fetchPut(gpa, operand, {})) == null) { - log.debug("[{}] %{}: added %{} to live set (operand dies here)", .{ pass, big.inst, operand }); + log.debug("[{}] %{f}: added %{f} to live set (operand dies here)", .{ pass, big.inst, operand }); big.extra_tombs[extra_byte] |= @as(u32, 1) << extra_bit; } }, @@ -2036,15 +2036,15 @@ fn fmtInstSet(set: *const std.AutoHashMapUnmanaged(Air.Inst.Index, void)) FmtIns const FmtInstSet = struct { set: *const std.AutoHashMapUnmanaged(Air.Inst.Index, void), - pub fn format(val: FmtInstSet, comptime _: []const u8, _: std.fmt.FormatOptions, w: anytype) !void { + pub fn format(val: FmtInstSet, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { if (val.set.count() == 0) { - try w.writeAll("[no instructions]"); + try bw.writeAll("[no instructions]"); return; } var it = val.set.keyIterator(); - try w.print("%{}", .{it.next().?.*}); + try bw.print("%{f}", .{it.next().?.*}); while (it.next()) |key| { - try w.print(" %{}", .{key.*}); + try bw.print(" %{f}", .{key.*}); } } }; @@ -2056,14 +2056,14 @@ fn fmtInstList(list: []const Air.Inst.Index) FmtInstList { const FmtInstList = struct { list: []const Air.Inst.Index, - pub fn format(val: FmtInstList, comptime _: []const u8, _: std.fmt.FormatOptions, w: anytype) !void { + pub fn format(val: FmtInstList, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { if (val.list.len == 0) { - try w.writeAll("[no instructions]"); + try bw.writeAll("[no instructions]"); return; } - try w.print("%{}", .{val.list[0]}); + try bw.print("%{f}", .{val.list[0]}); for (val.list[1..]) |inst| { - try w.print(" %{}", .{inst}); + try bw.print(" %{f}", .{inst}); } } }; diff --git a/src/Air/Liveness/Verify.zig b/src/Air/Liveness/Verify.zig index 85345ceb66..78c42bded5 100644 --- a/src/Air/Liveness/Verify.zig +++ b/src/Air/Liveness/Verify.zig @@ -73,7 +73,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { .trap, .unreach => { try self.verifyInstOperands(inst, .{ .none, .none, .none }); // This instruction terminates the function, so everything should be dead - if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst}); + if (self.live.count() > 0) return invalid("%{f}: instructions still alive", .{inst}); }, // unary @@ -166,7 +166,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { const un_op = data[@intFromEnum(inst)].un_op; try self.verifyInstOperands(inst, .{ un_op, .none, .none }); // This instruction terminates the function, so everything should be dead - if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst}); + if (self.live.count() > 0) return invalid("%{f}: instructions still alive", .{inst}); }, .dbg_var_ptr, .dbg_var_val, @@ -450,7 +450,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { .repeat => { const repeat = data[@intFromEnum(inst)].repeat; const expected_live = self.loops.get(repeat.loop_inst) orelse - return invalid("%{}: loop %{} not in scope", .{ @intFromEnum(inst), @intFromEnum(repeat.loop_inst) }); + return invalid("%{d}: loop %{d} not in scope", .{ @intFromEnum(inst), @intFromEnum(repeat.loop_inst) }); try self.verifyMatchingLiveness(repeat.loop_inst, expected_live); }, @@ -460,7 +460,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { try self.verifyOperand(inst, br.operand, self.liveness.operandDies(inst, 0)); const expected_live = self.loops.get(br.block_inst) orelse - return invalid("%{}: loop %{} not in scope", .{ @intFromEnum(inst), @intFromEnum(br.block_inst) }); + return invalid("%{d}: loop %{d} not in scope", .{ @intFromEnum(inst), @intFromEnum(br.block_inst) }); try self.verifyMatchingLiveness(br.block_inst, expected_live); }, @@ -601,9 +601,9 @@ fn verifyOperand(self: *Verify, inst: Air.Inst.Index, op_ref: Air.Inst.Ref, dies return; }; if (dies) { - if (!self.live.remove(operand)) return invalid("%{}: dead operand %{} reused and killed again", .{ inst, operand }); + if (!self.live.remove(operand)) return invalid("%{f}: dead operand %{f} reused and killed again", .{ inst, operand }); } else { - if (!self.live.contains(operand)) return invalid("%{}: dead operand %{} reused", .{ inst, operand }); + if (!self.live.contains(operand)) return invalid("%{f}: dead operand %{f} reused", .{ inst, operand }); } } @@ -628,9 +628,9 @@ fn verifyInst(self: *Verify, inst: Air.Inst.Index) Error!void { } fn verifyMatchingLiveness(self: *Verify, block: Air.Inst.Index, live: LiveMap) Error!void { - if (self.live.count() != live.count()) return invalid("%{}: different deaths across branches", .{block}); + if (self.live.count() != live.count()) return invalid("%{f}: different deaths across branches", .{block}); var live_it = self.live.keyIterator(); - while (live_it.next()) |live_inst| if (!live.contains(live_inst.*)) return invalid("%{}: different deaths across branches", .{block}); + while (live_it.next()) |live_inst| if (!live.contains(live_inst.*)) return invalid("%{f}: different deaths across branches", .{block}); } fn invalid(comptime fmt: []const u8, args: anytype) error{LivenessInvalid} { diff --git a/src/Air/print.zig b/src/Air/print.zig index 1dc3648bc8..5867494af6 100644 --- a/src/Air/print.zig +++ b/src/Air/print.zig @@ -101,7 +101,7 @@ const Writer = struct { fn writeInst(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) anyerror!void { const tag = w.air.instructions.items(.tag)[@intFromEnum(inst)]; try s.splatByteAll(' ', w.indent); - try s.print("{}{c}= {s}(", .{ + try s.print("{f}{c}= {s}(", .{ inst, @as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '), @tagName(tag), @@ -416,7 +416,7 @@ const Writer = struct { try s.writeAll("}"); for (liveness_block.deaths) |operand| { - try s.print(" {}!", .{operand}); + try s.print(" {f}!", .{operand}); } } @@ -708,7 +708,7 @@ const Writer = struct { } } const asm_source = std.mem.sliceAsBytes(w.air.extra.items[extra_i..])[0..extra.data.source_len]; - try s.print(", \"{}\"", .{std.zig.fmtEscapes(asm_source)}); + try s.print(", \"{f}\"", .{std.zig.fmtEscapes(asm_source)}); } fn writeDbgStmt(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) anyerror!void { @@ -720,7 +720,7 @@ const Writer = struct { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; try w.writeOperand(s, inst, 0, pl_op.operand); const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); - try s.print(", \"{}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))}); + try s.print(", \"{f}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))}); } fn writeCall(w: *Writer, s: *std.io.BufferedWriter, inst: Air.Inst.Index) anyerror!void { @@ -767,7 +767,7 @@ const Writer = struct { try s.splatByteAll(' ', w.indent); for (liveness_condbr.else_deaths, 0..) |operand, i| { if (i != 0) try s.writeAll(" "); - try s.print("{}!", .{operand}); + try s.print("{f}!", .{operand}); } try s.writeAll("\n"); } @@ -778,7 +778,7 @@ const Writer = struct { try s.writeAll("}"); for (liveness_condbr.then_deaths) |operand| { - try s.print(" {}!", .{operand}); + try s.print(" {f}!", .{operand}); } } @@ -804,7 +804,7 @@ const Writer = struct { try s.splatByteAll(' ', w.indent); for (liveness_condbr.else_deaths, 0..) |operand, i| { if (i != 0) try s.writeAll(" "); - try s.print("{}!", .{operand}); + try s.print("{f}!", .{operand}); } try s.writeAll("\n"); } @@ -815,7 +815,7 @@ const Writer = struct { try s.writeAll("}"); for (liveness_condbr.then_deaths) |operand| { - try s.print(" {}!", .{operand}); + try s.print(" {f}!", .{operand}); } } @@ -846,7 +846,7 @@ const Writer = struct { try s.splatByteAll(' ', w.indent); for (liveness_condbr.then_deaths, 0..) |operand, i| { if (i != 0) try s.writeAll(" "); - try s.print("{}!", .{operand}); + try s.print("{f}!", .{operand}); } try s.writeAll("\n"); } @@ -866,7 +866,7 @@ const Writer = struct { try s.splatByteAll(' ', w.indent); for (liveness_condbr.else_deaths, 0..) |operand, i| { if (i != 0) try s.writeAll(" "); - try s.print("{}!", .{operand}); + try s.print("{f}!", .{operand}); } try s.writeAll("\n"); } @@ -923,7 +923,7 @@ const Writer = struct { try s.splatByteAll(' ', w.indent); for (deaths, 0..) |operand, i| { if (i != 0) try s.writeAll(" "); - try s.print("{}!", .{operand}); + try s.print("{f}!", .{operand}); } try s.writeAll("\n"); } @@ -949,7 +949,7 @@ const Writer = struct { try s.splatByteAll(' ', w.indent); for (deaths, 0..) |operand, i| { if (i != 0) try s.writeAll(" "); - try s.print("{}!", .{operand}); + try s.print("{f}!", .{operand}); } try s.writeAll("\n"); } @@ -1017,7 +1017,7 @@ const Writer = struct { } else if (operand.toInterned()) |ip_index| { const pt = w.pt; const ty = Type.fromInterned(pt.zcu.intern_pool.indexToKey(ip_index).typeOf()); - try s.print("<{}, {}>", .{ + try s.print("<{f}, {f}>", .{ ty.fmt(pt), Value.fromInterned(ip_index).fmtValue(pt), }); @@ -1033,7 +1033,7 @@ const Writer = struct { dies: bool, ) anyerror!void { _ = w; - try s.print("{}", .{inst}); + try s.print("{f}", .{inst}); if (dies) try s.writeByte('!'); } diff --git a/src/Builtin.zig b/src/Builtin.zig index 33518723fb..92b2dfd841 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -57,18 +57,18 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks. \\pub const zig_version = std.SemanticVersion.parse(zig_version_string) catch unreachable; \\pub const zig_version_string = "{s}"; - \\pub const zig_backend = std.builtin.CompilerBackend.{p_}; + \\pub const zig_backend = std.builtin.CompilerBackend.{fp_}; \\ - \\pub const output_mode: std.builtin.OutputMode = .{p_}; - \\pub const link_mode: std.builtin.LinkMode = .{p_}; - \\pub const unwind_tables: std.builtin.UnwindTables = .{p_}; + \\pub const output_mode: std.builtin.OutputMode = .{fp_}; + \\pub const link_mode: std.builtin.LinkMode = .{fp_}; + \\pub const unwind_tables: std.builtin.UnwindTables = .{fp_}; \\pub const is_test = {}; \\pub const single_threaded = {}; - \\pub const abi: std.Target.Abi = .{p_}; + \\pub const abi: std.Target.Abi = .{fp_}; \\pub const cpu: std.Target.Cpu = .{{ - \\ .arch = .{p_}, - \\ .model = &std.Target.{p_}.cpu.{p_}, - \\ .features = std.Target.{p_}.featureSet(&.{{ + \\ .arch = .{fp_}, + \\ .model = &std.Target.{fp_}.cpu.{fp_}, + \\ .features = std.Target.{fp_}.featureSet(&.{{ \\ , .{ build_options.version, @@ -89,14 +89,14 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize)); const is_enabled = target.cpu.features.isEnabled(index); if (is_enabled) { - try buffer.print(" .{p_},\n", .{std.zig.fmtId(feature.name)}); + try buffer.print(" .{fp_},\n", .{std.zig.fmtId(feature.name)}); } } try buffer.print( \\ }}), \\}}; \\pub const os: std.Target.Os = .{{ - \\ .tag = .{p_}, + \\ .tag = .{fp_}, \\ .version_range = .{{ , .{std.zig.fmtId(@tagName(target.os.tag))}, @@ -200,8 +200,8 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { }), .windows => |windows| try buffer.print( \\ .windows = .{{ - \\ .min = {c}, - \\ .max = {c}, + \\ .min = {fc}, + \\ .max = {fc}, \\ }}}}, \\ , .{ windows.min, windows.max }), @@ -238,8 +238,8 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { const link_libc = opts.link_libc; try buffer.print( - \\pub const object_format: std.Target.ObjectFormat = .{p_}; - \\pub const mode: std.builtin.OptimizeMode = .{p_}; + \\pub const object_format: std.Target.ObjectFormat = .{fp_}; + \\pub const mode: std.builtin.OptimizeMode = .{fp_}; \\pub const link_libc = {}; \\pub const link_libcpp = {}; \\pub const have_error_return_tracing = {}; @@ -249,7 +249,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { \\pub const position_independent_code = {}; \\pub const position_independent_executable = {}; \\pub const strip_debug_info = {}; - \\pub const code_model: std.builtin.CodeModel = .{p_}; + \\pub const code_model: std.builtin.CodeModel = .{fp_}; \\pub const omit_frame_pointer = {}; \\ , .{ @@ -270,7 +270,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { if (target.os.tag == .wasi) { try buffer.print( - \\pub const wasi_exec_model: std.builtin.WasiExecModel = .{p_}; + \\pub const wasi_exec_model: std.builtin.WasiExecModel = .{fp_}; \\ , .{std.zig.fmtId(@tagName(opts.wasi_exec_model))}); } @@ -317,7 +317,7 @@ pub fn updateFileOnDisk(file: *File, comp: *Compilation) !void { if (root_dir.statFile(sub_path)) |stat| { if (stat.size != file.source.?.len) { std.log.warn( - "the cached file '{}' had the wrong size. Expected {d}, found {d}. " ++ + "the cached file '{f}{s}' had the wrong size. Expected {d}, found {d}. " ++ "Overwriting with correct file contents now", .{ file.path.fmt(comp), file.source.?.len, stat.size }, ); diff --git a/src/Compilation.zig b/src/Compilation.zig index 698b3f2c2d..881173feb0 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1068,11 +1068,12 @@ pub const CObject = struct { } }; + var buffer: [1024]u8 = undefined; const file = try std.fs.cwd().openFile(path, .{}); defer file.close(); - var br = std.io.bufferedReader(file.reader()); - const reader = br.reader(); - var bc = std.zig.llvm.BitcodeReader.init(gpa, .{ .reader = reader.any() }); + var br: std.io.BufferedReader = undefined; + br.init(file.reader(), &buffer); + var bc = std.zig.llvm.BitcodeReader.init(gpa, .{ .br = &br }); defer bc.deinit(); var file_names: std.AutoArrayHashMapUnmanaged(u32, []const u8) = .empty; @@ -2709,7 +2710,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { const prefix = man.cache.prefixes()[pp.prefix]; return comp.setMiscFailure( .check_whole_cache, - "failed to check cache: '{}{s}' {s} {s}", + "failed to check cache: '{f}{s}' {s} {s}", .{ prefix, pp.sub_path, @tagName(man.diagnostic), @errorName(op.err) }, ); }, @@ -2926,7 +2927,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { renameTmpIntoCache(comp.dirs.local_cache, tmp_dir_sub_path, o_sub_path) catch |err| { return comp.setMiscFailure( .rename_results, - "failed to rename compilation results ('{}{s}') into local cache ('{}{s}'): {s}", + "failed to rename compilation results ('{f}{s}') into local cache ('{f}{s}'): {s}", .{ comp.dirs.local_cache, tmp_dir_sub_path, comp.dirs.local_cache, o_sub_path, @@ -4847,7 +4848,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { var out_dir = docs_path.root_dir.handle.makeOpenPath(docs_path.sub_path, .{}) catch |err| { return comp.lockAndSetMiscFailure( .docs_copy, - "unable to create output directory '{}': {s}", + "unable to create output directory '{f}': {s}", .{ docs_path, @errorName(err) }, ); }; @@ -4867,7 +4868,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { var tar_file = out_dir.createFile("sources.tar", .{}) catch |err| { return comp.lockAndSetMiscFailure( .docs_copy, - "unable to create '{}/sources.tar': {s}", + "unable to create '{f}/sources.tar': {s}", .{ docs_path, @errorName(err) }, ); }; @@ -4896,7 +4897,7 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, const root_dir, const sub_path = root.openInfo(comp.dirs); break :d root_dir.openDir(sub_path, .{ .iterate = true }); } catch |err| { - return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{}': {s}", .{ + return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {s}", .{ root.fmt(comp), @errorName(err), }); }; @@ -5142,7 +5143,7 @@ fn workerUpdateBuiltinFile(comp: *Compilation, file: *Zcu.File) void { defer comp.mutex.unlock(); comp.setMiscFailure( .write_builtin_zig, - "unable to write '{}': {s}", + "unable to write '{f}': {s}", .{ file.path.fmt(comp), @errorName(err) }, ); }; @@ -5863,7 +5864,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr try child.spawn(); - const stderr = try child.stderr.?.reader().readAllAlloc(arena, std.math.maxInt(usize)); + const stderr = try child.stderr.?.readToEndAlloc(arena, .unlimited); const term = child.wait() catch |err| { return comp.failCObj(c_object, "failed to spawn zig clang {s}: {s}", .{ argv.items[0], @errorName(err) }); @@ -6023,13 +6024,12 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 // In .rc files, a " within a quoted string is escaped as "" const fmtRcEscape = struct { - fn formatRcEscape(bytes: []const u8, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { + fn formatRcEscape(bytes: []const u8, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { _ = fmt; - _ = options; for (bytes) |byte| switch (byte) { - '"' => try writer.writeAll("\"\""), - '\\' => try writer.writeAll("\\\\"), - else => try writer.writeByte(byte), + '"' => try bw.writeAll("\"\""), + '\\' => try bw.writeAll("\\\\"), + else => try bw.writeByte(byte), }; } @@ -6047,7 +6047,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 // 24 is RT_MANIFEST const resource_type = 24; - const input = try std.fmt.allocPrint(arena, "{} {} \"{s}\"", .{ resource_id, resource_type, fmtRcEscape(src_path) }); + const input = try std.fmt.allocPrint(arena, "{} {} \"{f}\"", .{ resource_id, resource_type, fmtRcEscape(src_path) }); try o_dir.writeFile(.{ .sub_path = rc_basename, .data = input }); @@ -6227,13 +6227,10 @@ fn spawnZigRc( const stdout = poller.fifo(.stdout); poll: while (true) { - while (stdout.readableLength() < @sizeOf(std.zig.Server.Message.Header)) { - if (!(try poller.poll())) break :poll; - } - const header = stdout.reader().readStruct(std.zig.Server.Message.Header) catch unreachable; - while (stdout.readableLength() < header.bytes_len) { - if (!(try poller.poll())) break :poll; - } + while (stdout.readableLength() < @sizeOf(std.zig.Server.Message.Header)) if (!try poller.poll()) break :poll; + var header: std.zig.Server.Message.Header = undefined; + assert(stdout.read(std.mem.asBytes(&header)) == @sizeOf(std.zig.Server.Message.Header)); + while (stdout.readableLength() < header.bytes_len) if (!try poller.poll()) break :poll; const body = stdout.readableSliceOfLen(header.bytes_len); switch (header.tag) { diff --git a/src/InternPool.zig b/src/InternPool.zig index fb926f2532..42b5fd44a6 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1888,17 +1888,12 @@ pub const NullTerminatedString = enum(u32) { string: NullTerminatedString, ip: *const InternPool, }; - fn format( - data: FormatData, - comptime specifier: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, bw: *std.io.BufferedWriter, comptime specifier: []const u8) anyerror!void { const slice = data.string.toSlice(data.ip); if (comptime std.mem.eql(u8, specifier, "")) { - try writer.writeAll(slice); + try bw.writeAll(slice); } else if (comptime std.mem.eql(u8, specifier, "i")) { - try writer.print("{p}", .{std.zig.fmtId(slice)}); + try bw.print("{fp}", .{std.zig.fmtId(slice)}); } else @compileError("invalid format string '" ++ specifier ++ "' for '" ++ @typeName(NullTerminatedString) ++ "'"); } @@ -9758,7 +9753,7 @@ fn finishFuncInstance( const fn_namespace = fn_owner_nav.analysis.?.namespace; // TODO: improve this name - const nav_name = try ip.getOrPutStringFmt(gpa, tid, "{}__anon_{d}", .{ + const nav_name = try ip.getOrPutStringFmt(gpa, tid, "{f}__anon_{d}", .{ fn_owner_nav.name.fmt(ip), @intFromEnum(func_index), }, .no_embedded_nulls); const nav_index = try ip.createNav(gpa, tid, .{ @@ -11415,12 +11410,12 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator) var it = instances.iterator(); while (it.next()) |entry| { const generic_fn_owner_nav = ip.getNav(ip.funcDeclInfo(entry.key_ptr.*).owner_nav); - try bw.print("{} ({}): \n", .{ generic_fn_owner_nav.name.fmt(ip), entry.value_ptr.items.len }); + try bw.print("{f} ({}): \n", .{ generic_fn_owner_nav.name.fmt(ip), entry.value_ptr.items.len }); for (entry.value_ptr.items) |index| { const unwrapped_index = index.unwrap(ip); const func = ip.extraFuncInstance(unwrapped_index.tid, unwrapped_index.getExtra(ip), unwrapped_index.getData(ip)); const owner_nav = ip.getNav(func.owner_nav); - try bw.print(" {}: (", .{owner_nav.name.fmt(ip)}); + try bw.print(" {f}: (", .{owner_nav.name.fmt(ip)}); for (func.comptime_args.get(ip)) |arg| { if (arg != .none) { const key = ip.indexToKey(arg); diff --git a/src/Package.zig b/src/Package.zig index 2eb7321cee..f625dd4908 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -134,7 +134,7 @@ pub const Hash = struct { } var bin_digest: [Algo.digest_length]u8 = undefined; Algo.hash(sub_path, &bin_digest, .{}); - _ = std.fmt.bufPrint(result.bytes[i..], "{}", .{std.fmt.fmtSliceHexLower(&bin_digest)}) catch unreachable; + _ = std.fmt.bufPrint(result.bytes[i..], "{x}", .{&bin_digest}) catch unreachable; return result; } }; diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index 81bb8ca4a7..c0d83d37a6 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -185,7 +185,7 @@ pub const JobQueue = struct { const hash_slice = hash.toSlice(); try buf.print( - \\ pub const {} = struct {{ + \\ pub const {f} = struct {{ \\ , .{std.zig.fmtId(hash_slice)}); @@ -211,13 +211,13 @@ pub const JobQueue = struct { } try buf.print( - \\ pub const build_root = "{q}"; + \\ pub const build_root = "{fq}"; \\ , .{fetch.package_root}); if (fetch.has_build_zig) { try buf.print( - \\ pub const build_zig = @import("{}"); + \\ pub const build_zig = @import("{f}"); \\ , .{std.zig.fmtEscapes(hash_slice)}); } @@ -230,7 +230,7 @@ pub const JobQueue = struct { for (manifest.dependencies.keys(), manifest.dependencies.values()) |name, dep| { const h = depDigest(fetch.package_root, jq.global_cache, dep) orelse continue; try buf.print( - " .{{ \"{}\", \"{}\" }},\n", + " .{{ \"{f}\", \"{f}\" }},\n", .{ std.zig.fmtEscapes(name), std.zig.fmtEscapes(h.toSlice()) }, ); } @@ -262,7 +262,7 @@ pub const JobQueue = struct { for (root_manifest.dependencies.keys(), root_manifest.dependencies.values()) |name, dep| { const h = depDigest(root_fetch.package_root, jq.global_cache, dep) orelse continue; try buf.print( - " .{{ \"{}\", \"{}\" }},\n", + " .{{ \"{f}\", \"{f}\" }},\n", .{ std.zig.fmtEscapes(name), std.zig.fmtEscapes(h.toSlice()) }, ); } @@ -353,7 +353,7 @@ pub fn run(f: *Fetch) RunError!void { if (!std.mem.startsWith(u8, pkg_root.sub_path, expected_prefix)) { return f.fail( f.location_tok, - try eb.printString("dependency path outside project: '{}'", .{pkg_root}), + try eb.printString("dependency path outside project: '{f}'", .{pkg_root}), ); } } @@ -604,7 +604,7 @@ pub fn computedPackageHash(f: *const Fetch) Package.Hash { const saturated_size = std.math.cast(u32, f.computed_hash.total_size) orelse std.math.maxInt(u32); if (f.manifest) |man| { var version_buffer: [32]u8 = undefined; - const version: []const u8 = std.fmt.bufPrint(&version_buffer, "{}", .{man.version}) catch &version_buffer; + const version: []const u8 = std.fmt.bufPrint(&version_buffer, "{f}", .{man.version}) catch &version_buffer; return .init(f.computed_hash.digest, man.name, version, man.id, saturated_size); } // In the future build.zig.zon fields will be added to allow overriding these values @@ -622,7 +622,7 @@ fn checkBuildFileExistence(f: *Fetch) RunError!void { error.FileNotFound => {}, else => |e| { try eb.addRootErrorMessage(.{ - .msg = try eb.printString("unable to access '{}{s}': {s}", .{ + .msg = try eb.printString("unable to access '{f}{s}': {s}", .{ f.package_root, Package.build_zig_basename, @errorName(e), }), }); @@ -636,9 +636,9 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void { const eb = &f.error_bundle; const arena = f.arena.allocator(); const manifest_bytes = pkg_root.root_dir.handle.readFileAllocOptions( - arena, try fs.path.join(arena, &.{ pkg_root.sub_path, Manifest.basename }), - Manifest.max_bytes, + arena, + .limited(Manifest.max_bytes), null, .@"1", 0, @@ -647,7 +647,7 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void { else => |e| { const file_path = try pkg_root.join(arena, Manifest.basename); try eb.addRootErrorMessage(.{ - .msg = try eb.printString("unable to load package manifest '{}': {s}", .{ + .msg = try eb.printString("unable to load package manifest '{f}': {s}", .{ file_path, @errorName(e), }), }); @@ -659,7 +659,7 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void { ast.* = try std.zig.Ast.parse(arena, manifest_bytes, .zon); if (ast.errors.len > 0) { - const file_path = try std.fmt.allocPrint(arena, "{}" ++ fs.path.sep_str ++ Manifest.basename, .{pkg_root}); + const file_path = try std.fmt.allocPrint(arena, "{f}" ++ fs.path.sep_str ++ Manifest.basename, .{pkg_root}); try std.zig.putAstErrorsIntoBundle(arena, ast.*, file_path, eb); return error.FetchFailed; } @@ -672,7 +672,7 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void { const manifest = &f.manifest.?; if (manifest.errors.len > 0) { - const src_path = try eb.printString("{}" ++ fs.path.sep_str ++ "{s}", .{ pkg_root, Manifest.basename }); + const src_path = try eb.printString("{f}" ++ fs.path.sep_str ++ "{s}", .{ pkg_root, Manifest.basename }); try manifest.copyErrorsIntoBundle(ast.*, src_path, eb); return error.FetchFailed; } @@ -827,7 +827,7 @@ fn srcLoc( const ast = f.parent_manifest_ast orelse return .none; const eb = &f.error_bundle; const start_loc = ast.tokenLocation(0, tok); - const src_path = try eb.printString("{}" ++ fs.path.sep_str ++ Manifest.basename, .{f.parent_package_root}); + const src_path = try eb.printString("{f}" ++ fs.path.sep_str ++ Manifest.basename, .{f.parent_package_root}); const msg_off = 0; return eb.addSourceLocation(.{ .src_path = src_path, @@ -1512,7 +1512,7 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute while (walker.next() catch |err| { try eb.addRootErrorMessage(.{ .msg = try eb.printString( - "unable to walk temporary directory '{}': {s}", + "unable to walk temporary directory '{f}': {s}", .{ pkg_path, @errorName(err) }, ) }); return error.FetchFailed; diff --git a/src/Package/Fetch/git.zig b/src/Package/Fetch/git.zig index 78ee29d940..ff28658226 100644 --- a/src/Package/Fetch/git.zig +++ b/src/Package/Fetch/git.zig @@ -119,15 +119,9 @@ pub const Oid = union(Format) { } else error.InvalidOid; } - pub fn format( - oid: Oid, - comptime fmt: []const u8, - options: std.fmt.Options, - writer: *std.io.BufferedWriter, - ) anyerror!void { + pub fn format(oid: Oid, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { _ = fmt; - _ = options; - try writer.print("{x}", .{oid.slice()}); + try bw.print("{x}", .{oid.slice()}); } pub fn slice(oid: *const Oid) []const u8 { diff --git a/src/Package/Manifest.zig b/src/Package/Manifest.zig index 32d614248f..ca3eba5bc1 100644 --- a/src/Package/Manifest.zig +++ b/src/Package/Manifest.zig @@ -401,7 +401,7 @@ const Parse = struct { return fail(p, main_token, "name must be a valid bare zig identifier (hint: switch from string to enum literal)", .{}); if (name.len > max_name_len) - return fail(p, main_token, "name '{}' exceeds max length of {d}", .{ + return fail(p, main_token, "name '{f}' exceeds max length of {d}", .{ std.zig.fmtId(name), max_name_len, }); @@ -416,7 +416,7 @@ const Parse = struct { return fail(p, main_token, "name must be a valid bare zig identifier", .{}); if (ident_name.len > max_name_len) - return fail(p, main_token, "name '{}' exceeds max length of {d}", .{ + return fail(p, main_token, "name '{f}' exceeds max length of {d}", .{ std.zig.fmtId(ident_name), max_name_len, }); diff --git a/src/Sema.zig b/src/Sema.zig index 5b2e846ff0..4518d7122f 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -888,7 +888,7 @@ const ComptimeReason = union(enum) { /// Evaluating at comptime because of a comptime-only type. This field is separate so that /// the type in question can be included in the error message. AstGen could never emit this /// reason, because it knows nothing of types. - /// The format string looks like "foo '{}' bar", where "{}" is the comptime-only type. + /// The format string looks like "foo '{f}' bar", where "{f}" is the comptime-only type. /// We will then explain why this type is comptime-only. comptime_only: struct { ty: Type, @@ -930,17 +930,17 @@ const ComptimeReason = union(enum) { .struct_init => .{ "initializer of comptime-only struct", "must be comptime-known" }, .tuple_init => .{ "initializer of comptime-only tuple", "must be comptime-known" }, }; - try sema.errNote(src, err_msg, "{s} '{}' {s}", .{ pre, co.ty.fmt(sema.pt), post }); + try sema.errNote(src, err_msg, "{s} '{f}' {s}", .{ pre, co.ty.fmt(sema.pt), post }); try sema.explainWhyTypeIsComptime(err_msg, src, co.ty); }, .comptime_only_param_ty => |co| { - try sema.errNote(src, err_msg, "argument to parameter with comptime-only type '{}' must be comptime-known", .{co.ty.fmt(sema.pt)}); + try sema.errNote(src, err_msg, "argument to parameter with comptime-only type '{f}' must be comptime-known", .{co.ty.fmt(sema.pt)}); try sema.errNote(co.param_ty_src, err_msg, "parameter type declared here", .{}); try sema.explainWhyTypeIsComptime(err_msg, src, co.ty); }, .comptime_only_ret_ty => |co| { const function_with: []const u8 = if (co.is_generic_inst) "generic function instantiated with" else "function with"; - try sema.errNote(src, err_msg, "call to {s} comptime-only return type '{}' is evaluated at comptime", .{ function_with, co.ty.fmt(sema.pt) }); + try sema.errNote(src, err_msg, "call to {s} comptime-only return type '{f}' is evaluated at comptime", .{ function_with, co.ty.fmt(sema.pt) }); try sema.errNote(co.ret_ty_src, err_msg, "return type declared here", .{}); try sema.explainWhyTypeIsComptime(err_msg, src, co.ty); }, @@ -1909,7 +1909,7 @@ fn analyzeBodyInner( const err_union = try sema.resolveInst(extra.data.operand); const err_union_ty = sema.typeOf(err_union); if (err_union_ty.zigTypeTag(zcu) != .error_union) { - return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ + return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{ err_union_ty.fmt(pt), }); } @@ -2343,7 +2343,7 @@ pub fn failWithDivideByZero(sema: *Sema, block: *Block, src: LazySrcLoc) Compile fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: Type, rhs_ty: Type) CompileError { const pt = sema.pt; - return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ + return sema.fail(block, src, "remainder division with '{f}' and '{f}': signed integers and floats must use @rem or @mod", .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt), }); } @@ -2351,7 +2351,7 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non_optional_ty: Type) CompileError { const pt = sema.pt; const msg = msg: { - const msg = try sema.errMsg(src, "expected optional type, found '{}'", .{ + const msg = try sema.errMsg(src, "expected optional type, found '{f}'", .{ non_optional_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -2367,12 +2367,12 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { const pt = sema.pt; const msg = msg: { - const msg = try sema.errMsg(src, "type '{}' does not support array initialization syntax", .{ + const msg = try sema.errMsg(src, "type '{f}' does not support array initialization syntax", .{ ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); if (ty.isSlice(pt.zcu)) { - try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2(pt.zcu).fmt(pt)}); + try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{f}'", .{ty.elemType2(pt.zcu).fmt(pt)}); } break :msg msg; }; @@ -2381,7 +2381,7 @@ fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { const pt = sema.pt; - return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ + return sema.fail(block, src, "type '{f}' does not support struct initialization syntax", .{ ty.fmt(pt), }); } @@ -2394,7 +2394,7 @@ fn failWithErrorSetCodeMissing( src_err_set_ty: Type, ) CompileError { const pt = sema.pt; - return sema.fail(block, src, "expected type '{}', found type '{}'", .{ + return sema.fail(block, src, "expected type '{f}', found type '{f}'", .{ dest_err_set_ty.fmt(pt), src_err_set_ty.fmt(pt), }); } @@ -2402,7 +2402,7 @@ fn failWithErrorSetCodeMissing( pub fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: ?usize) CompileError { const pt = sema.pt; return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "overflow of integer type '{}' with value '{}'", .{ + const msg = try sema.errMsg(src, "overflow of integer type '{f}' with value '{f}'", .{ int_ty.fmt(pt), val.fmtValueSema(pt, sema), }); errdefer msg.destroy(sema.gpa); @@ -2452,7 +2452,7 @@ fn failWithInvalidFieldAccess( const child_ty = inner_ty.optionalChild(zcu); if (!typeSupportsFieldAccess(zcu, child_ty, field_name)) break :opt; const msg = msg: { - const msg = try sema.errMsg(src, "optional type '{}' does not support field access", .{object_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "optional type '{f}' does not support field access", .{object_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "consider using '.?', 'orelse', or 'if'", .{}); break :msg msg; @@ -2462,14 +2462,14 @@ fn failWithInvalidFieldAccess( const child_ty = inner_ty.errorUnionPayload(zcu); if (!typeSupportsFieldAccess(zcu, child_ty, field_name)) break :err; const msg = msg: { - const msg = try sema.errMsg(src, "error union type '{}' does not support field access", .{object_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "error union type '{f}' does not support field access", .{object_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "consider using 'try', 'catch', or 'if'", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(block, msg); } - return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(pt)}); + return sema.fail(block, src, "type '{f}' does not support field access", .{object_ty.fmt(pt)}); } fn typeSupportsFieldAccess(zcu: *const Zcu, ty: Type, field_name: InternPool.NullTerminatedString) bool { @@ -2498,7 +2498,7 @@ fn failWithComptimeErrorRetTrace( const pt = sema.pt; const zcu = pt.zcu; const msg = msg: { - const msg = try sema.errMsg(src, "caught unexpected error '{}'", .{name.fmt(&zcu.intern_pool)}); + const msg = try sema.errMsg(src, "caught unexpected error '{f}'", .{name.fmt(&zcu.intern_pool)}); errdefer msg.destroy(sema.gpa); for (sema.comptime_err_ret_trace.items) |src_loc| { @@ -3009,7 +3009,7 @@ pub fn createTypeName( inst: ?Zir.Inst.Index, /// This is used purely to give the type a unique name in the `anon` case. type_index: InternPool.Index, -) !struct { +) CompileError!struct { name: InternPool.NullTerminatedString, nav: InternPool.Nav.Index.Optional, } { @@ -3028,11 +3028,11 @@ pub fn createTypeName( const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail); const zir_tags = sema.code.instructions.items(.tag); - var buf: std.ArrayListUnmanaged(u8) = .empty; - defer buf.deinit(gpa); - - const writer = buf.writer(gpa); - try writer.print("{}(", .{block.type_name_ctx.fmt(ip)}); + var aw: std.io.AllocatingWriter = undefined; + aw.init(gpa); + defer aw.deinit(); + const bw = &aw.buffered_writer; + bw.print("{f}(", .{block.type_name_ctx.fmt(ip)}) catch |err| return @errorCast(err); var arg_i: usize = 0; for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) { @@ -3045,18 +3045,18 @@ pub fn createTypeName( // result in a compile error. const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat - if (arg_i != 0) try writer.writeByte(','); + if (arg_i != 0) bw.writeByte(',') catch |err| return @errorCast(err); // Limiting the depth here helps avoid type names getting too long, which // in turn helps to avoid unreasonably long symbol names for namespaced // symbols. Such names should ideally be human-readable, and additionally, // some tooling may not support very long symbol names. - try writer.print("{}", .{Value.fmtValueSemaFull(.{ + bw.print("{f}", .{Value.fmtValueSemaFull(.{ .val = arg_val, .pt = pt, .opt_sema = sema, .depth = 1, - })}); + })}) catch |err| return @errorCast(err); arg_i += 1; continue; @@ -3064,9 +3064,9 @@ pub fn createTypeName( else => continue, }; - try writer.writeByte(')'); + try bw.writeByte(')'); return .{ - .name = try ip.getOrPutString(gpa, pt.tid, buf.items, .no_embedded_nulls), + .name = try ip.getOrPutString(gpa, pt.tid, aw.getWritten(), .no_embedded_nulls), .nav = .none, }; }, @@ -3078,7 +3078,7 @@ pub fn createTypeName( for (@intFromEnum(inst.?)..zir_tags.len) |i| switch (zir_tags[i]) { .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) { return .{ - .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{}.{s}", .{ + .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}.{s}", .{ block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code), }, .no_embedded_nulls), .nav = .none, @@ -3101,7 +3101,7 @@ pub fn createTypeName( // that builtin from the language, we can consider this. return .{ - .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{}__{s}_{d}", .{ + .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}__{s}_{d}", .{ block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(type_index), }, .no_embedded_nulls), .nav = .none, @@ -3585,7 +3585,7 @@ fn ensureResultUsed( }, else => { const msg = msg: { - const msg = try sema.errMsg(src, "value of type '{}' ignored", .{ty.fmt(pt)}); + const msg = try sema.errMsg(src, "value of type '{f}' ignored", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "all non-void values must be used", .{}); try sema.errNote(src, msg, "to discard the value, assign it to '_'", .{}); @@ -3855,7 +3855,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro // The value was initialized through RLS, so we didn't detect the runtime condition earlier. // TODO: source location of runtime control flow const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node }); - return sema.fail(block, init_src, "value with comptime-only type '{}' depends on runtime control flow", .{elem_ty.fmt(pt)}); + return sema.fail(block, init_src, "value with comptime-only type '{f}' depends on runtime control flow", .{elem_ty.fmt(pt)}); } // This is a runtime value. @@ -4352,7 +4352,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com // The alloc wasn't comptime-known per the above logic, so the // type cannot be comptime-only. // TODO: source location of runtime control flow - return sema.fail(block, src, "value with comptime-only type '{}' depends on runtime control flow", .{final_elem_ty.fmt(pt)}); + return sema.fail(block, src, "value with comptime-only type '{f}' depends on runtime control flow", .{final_elem_ty.fmt(pt)}); } if (sema.func_is_naked and try final_elem_ty.hasRuntimeBitsSema(pt)) { const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); @@ -4449,7 +4449,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. if (!object_ty.isIndexable(zcu)) { // Instead of using checkIndexable we customize this error. const msg = msg: { - const msg = try sema.errMsg(arg_src, "type '{}' is not indexable and not a range", .{object_ty.fmt(pt)}); + const msg = try sema.errMsg(arg_src, "type '{f}' is not indexable and not a range", .{object_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(arg_src, msg, "for loop operand must be a range, array, slice, tuple, or vector", .{}); @@ -4484,10 +4484,10 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .for_node_offset = inst_data.src_node, .input_index = len_idx, } }); - try sema.errNote(a_src, msg, "length {} here", .{ + try sema.errNote(a_src, msg, "length {f} here", .{ v.fmtValueSema(pt, sema), }); - try sema.errNote(arg_src, msg, "length {} here", .{ + try sema.errNote(arg_src, msg, "length {f} here", .{ arg_val.fmtValueSema(pt, sema), }); break :msg msg; @@ -4519,7 +4519,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .for_node_offset = inst_data.src_node, .input_index = i, } }); - try sema.errNote(arg_src, msg, "type '{}' has no upper bound", .{ + try sema.errNote(arg_src, msg, "type '{f}' has no upper bound", .{ object_ty.fmt(pt), }); } @@ -4595,7 +4595,7 @@ fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE switch (val_ty.zigTypeTag(zcu)) { .array, .vector => {}, else => if (!val_ty.isTuple(zcu)) { - return sema.fail(block, src, "expected array of '{}', found '{}'", .{ elem_ty.fmt(pt), val_ty.fmt(pt) }); + return sema.fail(block, src, "expected array of '{f}', found '{f}'", .{ elem_ty.fmt(pt), val_ty.fmt(pt) }); }, } const want_ty = try pt.arrayType(.{ @@ -4669,7 +4669,7 @@ fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const ty_operand = try sema.resolveTypeOrPoison(block, src, un_tok.operand) orelse return; if (ty_operand.optEuBaseType(zcu).zigTypeTag(zcu) != .pointer) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "expected type '{}', found pointer", .{ty_operand.fmt(pt)}); + const msg = try sema.errMsg(src, "expected type '{f}', found pointer", .{ty_operand.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "address-of operator always returns a pointer", .{}); break :msg msg; @@ -5078,7 +5078,7 @@ fn validateStructInit( } continue; }; - const template = "missing struct field: {}"; + const template = "missing struct field: {f}"; const args = .{field_name.fmt(ip)}; if (root_msg) |msg| { try sema.errNote(init_src, msg, template, args); @@ -5208,7 +5208,7 @@ fn validateStructInit( } continue; }; - const template = "missing struct field: {}"; + const template = "missing struct field: {f}"; const args = .{field_name.fmt(ip)}; if (root_msg) |msg| { try sema.errNote(init_src, msg, template, args); @@ -5512,11 +5512,11 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const operand_ty = sema.typeOf(operand); if (operand_ty.zigTypeTag(zcu) != .pointer) { - return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(pt)}); + return sema.fail(block, src, "cannot dereference non-pointer type '{f}'", .{operand_ty.fmt(pt)}); } else switch (operand_ty.ptrSize(zcu)) { .one, .c => {}, - .many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(pt)}), - .slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(pt)}), + .many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{f}'", .{operand_ty.fmt(pt)}), + .slice => return sema.fail(block, src, "index syntax required for slice type '{f}'", .{operand_ty.fmt(pt)}), } if ((try sema.typeHasOnePossibleValue(operand_ty.childType(zcu))) != null) { @@ -5533,7 +5533,7 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const msg = msg: { const msg = try sema.errMsg( src, - "values of type '{}' must be comptime-known, but operand value is runtime-known", + "values of type '{f}' must be comptime-known, but operand value is runtime-known", .{elem_ty.fmt(pt)}, ); errdefer msg.destroy(sema.gpa); @@ -5565,7 +5565,7 @@ fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp if (!typeIsDestructurable(operand_ty, zcu)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "type '{}' cannot be destructured", .{operand_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "type '{f}' cannot be destructured", .{operand_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(destructure_src, msg, "result destructured here", .{}); if (operand_ty.zigTypeTag(pt.zcu) == .error_union) { @@ -5608,12 +5608,12 @@ fn failWithBadMemberAccess( else => unreachable, }; if (agg_ty.typeDeclInst(zcu)) |inst| if ((inst.resolve(ip) orelse return error.AnalysisFail) == .main_struct_inst) { - return sema.fail(block, field_src, "root source file struct '{}' has no member named '{}'", .{ + return sema.fail(block, field_src, "root source file struct '{f}' has no member named '{f}'", .{ agg_ty.fmt(pt), field_name.fmt(ip), }); }; - return sema.fail(block, field_src, "{s} '{}' has no member named '{}'", .{ + return sema.fail(block, field_src, "{s} '{f}' has no member named '{f}'", .{ kw_name, agg_ty.fmt(pt), field_name.fmt(ip), }); } @@ -5633,7 +5633,7 @@ fn failWithBadStructFieldAccess( const msg = msg: { const msg = try sema.errMsg( field_src, - "no field named '{}' in struct '{}'", + "no field named '{f}' in struct '{f}'", .{ field_name.fmt(ip), struct_type.name.fmt(ip) }, ); errdefer msg.destroy(sema.gpa); @@ -5659,7 +5659,7 @@ fn failWithBadUnionFieldAccess( const msg = msg: { const msg = try sema.errMsg( field_src, - "no field named '{}' in union '{}'", + "no field named '{f}' in union '{f}'", .{ field_name.fmt(ip), union_obj.name.fmt(ip) }, ); errdefer msg.destroy(gpa); @@ -5911,30 +5911,30 @@ fn zirCompileLog( const zcu = pt.zcu; const gpa = zcu.gpa; - var buf: std.ArrayListUnmanaged(u8) = .empty; - defer buf.deinit(gpa); - - const writer = buf.writer(gpa); + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.init(sema.gpa); + defer aw.deinit(); const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); const src_node = extra.data.src_node; const args = sema.code.refSlice(extra.end, extended.small); for (args, 0..) |arg_ref, i| { - if (i != 0) try writer.print(", ", .{}); + if (i != 0) bw.writeAll(", ") catch |err| return @errorCast(err); const arg = try sema.resolveInst(arg_ref); const arg_ty = sema.typeOf(arg); if (try sema.resolveValueResolveLazy(arg)) |val| { - try writer.print("@as({}, {})", .{ + bw.print("@as({f}, {f})", .{ arg_ty.fmt(pt), val.fmtValueSema(pt, sema), - }); + }) catch |err| return @errorCast(err); } else { - try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(pt)}); + bw.print("@as({f}, [runtime value])", .{arg_ty.fmt(pt)}) catch |err| return @errorCast(err); } } + try bw.print("\n", .{}); - const line_data = try zcu.intern_pool.getOrPutString(gpa, pt.tid, buf.items, .no_embedded_nulls); + const line_data = try zcu.intern_pool.getOrPutString(gpa, pt.tid, aw.getWritten(), .no_embedded_nulls); const line_idx: Zcu.CompileLogLine.Index = if (zcu.free_compile_log_lines.pop()) |idx| idx: { zcu.compile_log_lines.items[@intFromEnum(idx)] = .{ @@ -6476,7 +6476,7 @@ fn resolveAnalyzedBlock( const type_src = src; // TODO: better source location if (try resolved_ty.comptimeOnlySema(pt)) { const msg = msg: { - const msg = try sema.errMsg(type_src, "value with comptime-only type '{}' depends on runtime control flow", .{resolved_ty.fmt(pt)}); + const msg = try sema.errMsg(type_src, "value with comptime-only type '{f}' depends on runtime control flow", .{resolved_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); const runtime_src = child_block.runtime_cond orelse child_block.runtime_loop.?; @@ -6592,7 +6592,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { if (ptr_ty.zigTypeTag(zcu) != .pointer) { - return sema.fail(block, ptr_src, "expected pointer type, found '{}'", .{ptr_ty.fmt(pt)}); + return sema.fail(block, ptr_src, "expected pointer type, found '{f}'", .{ptr_ty.fmt(pt)}); } const ptr_ty_info = ptr_ty.ptrInfo(zcu); if (ptr_ty_info.flags.size == .slice) { @@ -6615,7 +6615,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void const export_ty = Value.fromInterned(uav.val).typeOf(zcu); if (!try sema.validateExternType(export_ty, .other)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "unable to export type '{}'", .{export_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other); try sema.addDeclaredHereNote(msg, export_ty); @@ -6667,7 +6667,7 @@ pub fn analyzeExport( if (!try sema.validateExternType(export_ty, .other)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "unable to export type '{}'", .{export_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other); @@ -7363,7 +7363,7 @@ fn checkCallArgumentCount( opt_child.childType(zcu).zigTypeTag(zcu) == .@"fn")) { const msg = msg: { - const msg = try sema.errMsg(func_src, "cannot call optional type '{}'", .{ + const msg = try sema.errMsg(func_src, "cannot call optional type '{f}'", .{ callee_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -7375,7 +7375,7 @@ fn checkCallArgumentCount( }, else => {}, } - return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(pt)}); + return sema.fail(block, func_src, "type '{f}' not a function", .{callee_ty.fmt(pt)}); }; const func_ty_info = zcu.typeToFunc(func_ty).?; @@ -7438,7 +7438,7 @@ fn callBuiltin( }, else => {}, } - std.debug.panic("type '{}' is not a function calling builtin fn", .{callee_ty.fmt(pt)}); + std.debug.panic("type '{f}' is not a function calling builtin fn", .{callee_ty.fmt(pt)}); }; const func_ty_info = zcu.typeToFunc(func_ty).?; @@ -7826,7 +7826,7 @@ fn analyzeCall( if (!param_ty.isValidParamType(zcu)) { const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; - return sema.fail(block, param_src, "parameter of {s}type '{}' not allowed", .{ + return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{ opaque_str, param_ty.fmt(pt), }); } @@ -7923,7 +7923,7 @@ fn analyzeCall( if (!full_ty.isValidReturnType(zcu)) { const opaque_str = if (full_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; - return sema.fail(block, func_ret_ty_src, "{s}return type '{}' not allowed", .{ + return sema.fail(block, func_ret_ty_src, "{s}return type '{f}' not allowed", .{ opaque_str, full_ty.fmt(pt), }); } @@ -8382,7 +8382,7 @@ fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Typ } const owner_func_ty: Type = .fromInterned(zcu.funcInfo(sema.owner.unwrap().func).ty); if (owner_func_ty.toIntern() != func_ty.toIntern()) { - return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{ + return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{f}' does not match type of calling function '{f}'", .{ func_ty.fmt(pt), owner_func_ty.fmt(pt), }); } @@ -8406,9 +8406,9 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro const operand_src = block.src(.{ .node_offset_un_op = inst_data.src_node }); const child_type = try sema.resolveType(block, operand_src, inst_data.operand); if (child_type.zigTypeTag(zcu) == .@"opaque") { - return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(pt)}); + return sema.fail(block, operand_src, "opaque type '{f}' cannot be optional", .{child_type.fmt(pt)}); } else if (child_type.zigTypeTag(zcu) == .null) { - return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(pt)}); + return sema.fail(block, operand_src, "type '{f}' cannot be optional", .{child_type.fmt(pt)}); } const opt_type = try pt.optionalType(child_type.toIntern()); @@ -8469,7 +8469,7 @@ fn zirVecArrElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const vec_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, un_node.operand) orelse return .generic_poison_type; switch (vec_ty.zigTypeTag(zcu)) { .array, .vector => {}, - else => return sema.fail(block, block.nodeOffset(un_node.src_node), "expected array or vector type, found '{}'", .{vec_ty.fmt(pt)}), + else => return sema.fail(block, block.nodeOffset(un_node.src_node), "expected array or vector type, found '{f}'", .{vec_ty.fmt(pt)}), } return Air.internedToRef(vec_ty.childType(zcu).toIntern()); } @@ -8537,7 +8537,7 @@ fn validateArrayElemType(sema: *Sema, block: *Block, elem_type: Type, elem_src: const pt = sema.pt; const zcu = pt.zcu; if (elem_type.zigTypeTag(zcu) == .@"opaque") { - return sema.fail(block, elem_src, "array of opaque type '{}' not allowed", .{elem_type.fmt(pt)}); + return sema.fail(block, elem_src, "array of opaque type '{f}' not allowed", .{elem_type.fmt(pt)}); } else if (elem_type.zigTypeTag(zcu) == .noreturn) { return sema.fail(block, elem_src, "array of 'noreturn' not allowed", .{}); } @@ -8573,7 +8573,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const payload = try sema.resolveType(block, rhs_src, extra.rhs); if (error_set.zigTypeTag(zcu) != .error_set) { - return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{ + return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{ error_set.fmt(pt), }); } @@ -8586,11 +8586,11 @@ fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, p const pt = sema.pt; const zcu = pt.zcu; if (payload_ty.zigTypeTag(zcu) == .@"opaque") { - return sema.fail(block, payload_src, "error union with payload of opaque type '{}' not allowed", .{ + return sema.fail(block, payload_src, "error union with payload of opaque type '{f}' not allowed", .{ payload_ty.fmt(pt), }); } else if (payload_ty.zigTypeTag(zcu) == .error_set) { - return sema.fail(block, payload_src, "error union with payload of error set type '{}' not allowed", .{ + return sema.fail(block, payload_src, "error union with payload of error set type '{f}' not allowed", .{ payload_ty.fmt(pt), }); } @@ -8728,9 +8728,9 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs); const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs); if (lhs_ty.zigTypeTag(zcu) != .error_set) - return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(pt)}); + return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{lhs_ty.fmt(pt)}); if (rhs_ty.zigTypeTag(zcu) != .error_set) - return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(pt)}); + return sema.fail(block, rhs_src, "expected error set type, found '{f}'", .{rhs_ty.fmt(pt)}); // Anything merged with anyerror is anyerror. if (lhs_ty.toIntern() == .anyerror_type or rhs_ty.toIntern() == .anyerror_type) { @@ -8840,7 +8840,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return sema.fail( block, operand_src, - "untagged union '{}' cannot be converted to integer", + "untagged union '{f}' cannot be converted to integer", .{operand_ty.fmt(pt)}, ); }; @@ -8848,7 +8848,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError break :blk try sema.unionToTag(block, tag_ty, operand, operand_src); }, else => { - return sema.fail(block, operand_src, "expected enum or tagged union, found '{}'", .{ + return sema.fail(block, operand_src, "expected enum or tagged union, found '{f}'", .{ operand_ty.fmt(pt), }); }, @@ -8859,7 +8859,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError // TODO: use correct solution // https://github.com/ziglang/zig/issues/15909 if (enum_tag_ty.enumFieldCount(zcu) == 0 and !enum_tag_ty.isNonexhaustiveEnum(zcu)) { - return sema.fail(block, operand_src, "cannot use @intFromEnum on empty enum '{}'", .{ + return sema.fail(block, operand_src, "cannot use @intFromEnum on empty enum '{f}'", .{ enum_tag_ty.fmt(pt), }); } @@ -8893,7 +8893,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const operand_ty = sema.typeOf(operand); if (dest_ty.zigTypeTag(zcu) != .@"enum") { - return sema.fail(block, src, "expected enum, found '{}'", .{dest_ty.fmt(pt)}); + return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)}); } _ = try sema.checkIntType(block, operand_src, operand_ty); @@ -8903,7 +8903,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError if (try sema.intFitsInType(int_val, int_tag_ty, null)) { return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern()); } - return sema.fail(block, src, "int value '{}' out of range of non-exhaustive enum '{}'", .{ + return sema.fail(block, src, "int value '{f}' out of range of non-exhaustive enum '{f}'", .{ int_val.fmtValueSema(pt, sema), dest_ty.fmt(pt), }); } @@ -8911,7 +8911,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return sema.failWithUseOfUndef(block, operand_src); } if (!(try sema.enumHasInt(dest_ty, int_val))) { - return sema.fail(block, src, "enum '{}' has no tag with value '{}'", .{ + return sema.fail(block, src, "enum '{f}' has no tag with value '{f}'", .{ dest_ty.fmt(pt), int_val.fmtValueSema(pt, sema), }); } @@ -9105,7 +9105,7 @@ fn zirErrUnionPayload( const operand_src = src; const err_union_ty = sema.typeOf(operand); if (err_union_ty.zigTypeTag(zcu) != .error_union) { - return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ + return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{ err_union_ty.fmt(pt), }); } @@ -9173,7 +9173,7 @@ fn analyzeErrUnionPayloadPtr( assert(operand_ty.zigTypeTag(zcu) == .pointer); if (operand_ty.childType(zcu).zigTypeTag(zcu) != .error_union) { - return sema.fail(block, src, "expected error union type, found '{}'", .{ + return sema.fail(block, src, "expected error union type, found '{f}'", .{ operand_ty.childType(zcu).fmt(pt), }); } @@ -9250,7 +9250,7 @@ fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air const zcu = pt.zcu; const operand_ty = sema.typeOf(operand); if (operand_ty.zigTypeTag(zcu) != .error_union) { - return sema.fail(block, src, "expected error union type, found '{}'", .{ + return sema.fail(block, src, "expected error union type, found '{f}'", .{ operand_ty.fmt(pt), }); } @@ -9286,7 +9286,7 @@ fn analyzeErrUnionCodePtr(sema: *Sema, block: *Block, src: LazySrcLoc, operand: assert(operand_ty.zigTypeTag(zcu) == .pointer); if (operand_ty.childType(zcu).zigTypeTag(zcu) != .error_union) { - return sema.fail(block, src, "expected error union type, found '{}'", .{ + return sema.fail(block, src, "expected error union type, found '{f}'", .{ operand_ty.childType(zcu).fmt(pt), }); } @@ -9544,19 +9544,18 @@ fn callConvSupportsVarArgs(cc: std.builtin.CallingConvention.Tag) bool { fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc: std.builtin.CallingConvention.Tag) CompileError!void { const CallingConventionsSupportingVarArgsList = struct { arch: std.Target.Cpu.Arch, - pub fn format(ctx: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { + pub fn format(ctx: @This(), bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { _ = fmt; - _ = options; var first = true; for (calling_conventions_supporting_var_args) |cc_inner| { for (std.Target.Cpu.Arch.fromCallingConvention(cc_inner)) |supported_arch| { if (supported_arch == ctx.arch) break; } else continue; // callconv not supported by this arch if (!first) { - try writer.writeAll(", "); + try bw.writeAll(", "); } first = false; - try writer.print("'{s}'", .{@tagName(cc_inner)}); + try bw.print("'{s}'", .{@tagName(cc_inner)}); } } }; @@ -9566,7 +9565,7 @@ fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc: const msg = try sema.errMsg(src, "variadic function does not support '{s}' calling convention", .{@tagName(cc)}); errdefer msg.destroy(sema.gpa); const target = sema.pt.zcu.getTarget(); - try sema.errNote(src, msg, "supported calling conventions: {}", .{CallingConventionsSupportingVarArgsList{ .arch = target.cpu.arch }}); + try sema.errNote(src, msg, "supported calling conventions: {f}", .{CallingConventionsSupportingVarArgsList{ .arch = target.cpu.arch }}); break :msg msg; }); } @@ -9614,7 +9613,7 @@ fn checkMergeAllowed(sema: *Sema, block: *Block, src: LazySrcLoc, peer_ty: Type) } return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "value with non-mergable pointer type '{}' depends on runtime control flow", .{peer_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "value with non-mergable pointer type '{f}' depends on runtime control flow", .{peer_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); const runtime_src = block.runtime_cond orelse block.runtime_loop.?; @@ -9692,13 +9691,13 @@ fn funcCommon( } if (!param_ty.isValidParamType(zcu)) { const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; - return sema.fail(block, param_src, "parameter of {s}type '{}' not allowed", .{ + return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{ opaque_str, param_ty.fmt(pt), }); } if (!param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc) and !try sema.validateExternType(param_ty, .param_ty)) { const msg = msg: { - const msg = try sema.errMsg(param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ + const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{ param_ty.fmt(pt), @tagName(cc), }); errdefer msg.destroy(sema.gpa); @@ -9712,7 +9711,7 @@ fn funcCommon( } if (param_ty_comptime and !param_is_comptime and has_body and !block.isComptime()) { const msg = msg: { - const msg = try sema.errMsg(param_src, "parameter of type '{}' must be declared comptime", .{ + const msg = try sema.errMsg(param_src, "parameter of type '{f}' must be declared comptime", .{ param_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -9892,7 +9891,7 @@ fn finishFunc( if (!return_type.isValidReturnType(zcu)) { const opaque_str = if (return_type.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; - return sema.fail(block, ret_ty_src, "{s}return type '{}' not allowed", .{ + return sema.fail(block, ret_ty_src, "{s}return type '{f}' not allowed", .{ opaque_str, return_type.fmt(pt), }); } @@ -9900,7 +9899,7 @@ fn finishFunc( !try sema.validateExternType(return_type, .ret_ty)) { const msg = msg: { - const msg = try sema.errMsg(ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ + const msg = try sema.errMsg(ret_ty_src, "return type '{f}' not allowed in function with calling convention '{s}'", .{ return_type.fmt(pt), @tagName(cc_resolved), }); errdefer msg.destroy(gpa); @@ -9922,7 +9921,7 @@ fn finishFunc( const msg = try sema.errMsg( ret_ty_src, - "function with comptime-only return type '{}' requires all parameters to be comptime", + "function with comptime-only return type '{f}' requires all parameters to be comptime", .{return_type.fmt(pt)}, ); errdefer msg.destroy(sema.gpa); @@ -9991,17 +9990,16 @@ fn finishFunc( .bad_arch => |allowed_archs| { const ArchListFormatter = struct { archs: []const std.Target.Cpu.Arch, - pub fn format(formatter: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { + pub fn format(formatter: @This(), bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { _ = fmt; - _ = options; for (formatter.archs, 0..) |arch, i| { if (i != 0) - try writer.writeAll(", "); - try writer.print("'{s}'", .{@tagName(arch)}); + try bw.writeAll(", "); + try bw.print("'{s}'", .{@tagName(arch)}); } } }; - return sema.fail(block, cc_src, "calling convention '{s}' only available on architectures {}", .{ + return sema.fail(block, cc_src, "calling convention '{s}' only available on architectures {f}", .{ @tagName(cc_resolved), ArchListFormatter{ .archs = allowed_archs }, }); @@ -10102,7 +10100,7 @@ fn analyzeAs( const operand = try sema.resolveInst(zir_operand); const dest_ty = try sema.resolveTypeOrPoison(block, src, zir_dest_type) orelse return operand; switch (dest_ty.zigTypeTag(zcu)) { - .@"opaque" => return sema.fail(block, src, "cannot cast to opaque type '{}'", .{dest_ty.fmt(pt)}), + .@"opaque" => return sema.fail(block, src, "cannot cast to opaque type '{f}'", .{dest_ty.fmt(pt)}), .noreturn => return sema.fail(block, src, "cannot cast to noreturn", .{}), else => {}, } @@ -10130,12 +10128,12 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const ptr_ty = operand_ty.scalarType(zcu); const is_vector = operand_ty.zigTypeTag(zcu) == .vector; if (!ptr_ty.isPtrAtRuntime(zcu)) { - return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(pt)}); + return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)}); } const pointee_ty = ptr_ty.childType(zcu); if (try ptr_ty.comptimeOnlySema(pt)) { const msg = msg: { - const msg = try sema.errMsg(ptr_src, "comptime-only type '{}' has no pointer address", .{pointee_ty.fmt(pt)}); + const msg = try sema.errMsg(ptr_src, "comptime-only type '{f}' has no pointer address", .{pointee_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsComptime(msg, ptr_src, pointee_ty); break :msg msg; @@ -10383,14 +10381,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .type, .undefined, .void, - => return sema.fail(block, src, "cannot @bitCast to '{}'", .{dest_ty.fmt(pt)}), + => return sema.fail(block, src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}), .@"enum" => { const msg = msg: { - const msg = try sema.errMsg(src, "cannot @bitCast to '{}'", .{dest_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); switch (operand_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(src, msg, "use @enumFromInt to cast from '{}'", .{operand_ty.fmt(pt)}), + .int, .comptime_int => try sema.errNote(src, msg, "use @enumFromInt to cast from '{f}'", .{operand_ty.fmt(pt)}), else => {}, } @@ -10401,11 +10399,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .pointer => { const msg = msg: { - const msg = try sema.errMsg(src, "cannot @bitCast to '{}'", .{dest_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); switch (operand_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(src, msg, "use @ptrFromInt to cast from '{}'", .{operand_ty.fmt(pt)}), - .pointer => try sema.errNote(src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(pt)}), + .int, .comptime_int => try sema.errNote(src, msg, "use @ptrFromInt to cast from '{f}'", .{operand_ty.fmt(pt)}), + .pointer => try sema.errNote(src, msg, "use @ptrCast to cast from '{f}'", .{operand_ty.fmt(pt)}), else => {}, } @@ -10419,7 +10417,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .@"union" => "union", else => unreachable, }; - return sema.fail(block, src, "cannot @bitCast to '{}'; {s} does not have a guaranteed in-memory layout", .{ + return sema.fail(block, src, "cannot @bitCast to '{f}'; {s} does not have a guaranteed in-memory layout", .{ dest_ty.fmt(pt), container, }); }, @@ -10447,14 +10445,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .type, .undefined, .void, - => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(pt)}), + => return sema.fail(block, operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}), .@"enum" => { const msg = msg: { - const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(pt)}); + const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); switch (dest_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromEnum to cast to '{}'", .{dest_ty.fmt(pt)}), + .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromEnum to cast to '{f}'", .{dest_ty.fmt(pt)}), else => {}, } @@ -10464,11 +10462,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air }, .pointer => { const msg = msg: { - const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(pt)}); + const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); switch (dest_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromPtr to cast to '{}'", .{dest_ty.fmt(pt)}), - .pointer => try sema.errNote(operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(pt)}), + .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromPtr to cast to '{f}'", .{dest_ty.fmt(pt)}), + .pointer => try sema.errNote(operand_src, msg, "use @ptrCast to cast to '{f}'", .{dest_ty.fmt(pt)}), else => {}, } @@ -10482,7 +10480,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .@"union" => "union", else => unreachable, }; - return sema.fail(block, operand_src, "cannot @bitCast from '{}'; {s} does not have a guaranteed in-memory layout", .{ + return sema.fail(block, operand_src, "cannot @bitCast from '{f}'; {s} does not have a guaranteed in-memory layout", .{ operand_ty.fmt(pt), container, }); }, @@ -10525,7 +10523,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A else => return sema.fail( block, src, - "expected float or vector type, found '{}'", + "expected float or vector type, found '{f}'", .{dest_ty.fmt(pt)}, ), }; @@ -10535,7 +10533,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A else => return sema.fail( block, operand_src, - "expected float or vector type, found '{}'", + "expected float or vector type, found '{f}'", .{operand_ty.fmt(pt)}, ), } @@ -10619,7 +10617,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air if (indexable_ty.zigTypeTag(zcu) != .pointer) { const capture_src = block.src(.{ .for_capture_from_input = inst_data.src_node }); const msg = msg: { - const msg = try sema.errMsg(capture_src, "pointer capture of non pointer type '{}'", .{ + const msg = try sema.errMsg(capture_src, "pointer capture of non pointer type '{f}'", .{ indexable_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -10761,7 +10759,7 @@ fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE const lhs_ptr_ty = sema.typeOf(try sema.resolveInst(inst_data.operand)); const lhs_ty = switch (lhs_ptr_ty.zigTypeTag(zcu)) { .pointer => lhs_ptr_ty.childType(zcu), - else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{lhs_ptr_ty.fmt(pt)}), + else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{lhs_ptr_ty.fmt(pt)}), }; const sentinel_ty: Type = switch (lhs_ty.zigTypeTag(zcu)) { @@ -10776,7 +10774,7 @@ fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE }; }, }, - else => return sema.fail(block, src, "slice of non-array type '{}'", .{lhs_ty.fmt(pt)}), + else => return sema.fail(block, src, "slice of non-array type '{f}'", .{lhs_ty.fmt(pt)}), }; return Air.internedToRef(sentinel_ty.toIntern()); @@ -10971,7 +10969,7 @@ const SwitchProngAnalysis = struct { .base_node_inst = capture_src.base_node_inst, .offset = .{ .switch_tag_capture = capture_src.offset.switch_capture }, }; - return sema.fail(block, tag_capture_src, "cannot capture tag of non-union type '{}'", .{ + return sema.fail(block, tag_capture_src, "cannot capture tag of non-union type '{f}'", .{ operand_ty.fmt(pt), }); } @@ -11403,7 +11401,7 @@ fn switchCond( .@"enum", => { if (operand_ty.isSlice(zcu)) { - return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(pt)}); + return sema.fail(block, src, "switch on type '{f}'", .{operand_ty.fmt(pt)}); } if ((try sema.typeHasOnePossibleValue(operand_ty))) |opv| { return Air.internedToRef(opv.toIntern()); @@ -11438,7 +11436,7 @@ fn switchCond( .vector, .frame, .@"anyframe", - => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(pt)}), + => return sema.fail(block, src, "switch on type '{f}'", .{operand_ty.fmt(pt)}), } } @@ -11539,7 +11537,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp operand_ty; if (operand_err_set.zigTypeTag(zcu) != .error_union) { - return sema.fail(block, switch_src, "expected error union type, found '{}'", .{ + return sema.fail(block, switch_src, "expected error union type, found '{f}'", .{ operand_ty.fmt(pt), }); } @@ -11793,7 +11791,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r // Even if the operand is comptime-known, this `switch` is runtime. if (try operand_ty.comptimeOnlySema(pt)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{}'", .{operand_ty.fmt(pt)}); + const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{f}'", .{operand_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.errNote(operand_src, msg, "switch loops are evaluated at runtime outside of comptime scopes", .{}); break :msg msg; @@ -12017,14 +12015,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r cond_ty, i, msg, - "unhandled enumeration value: '{}'", + "unhandled enumeration value: '{f}'", .{field_name.fmt(&zcu.intern_pool)}, ); } try sema.errNote( cond_ty.srcLoc(zcu), msg, - "enum '{}' declared here", + "enum '{f}' declared here", .{cond_ty.fmt(pt)}, ); break :msg msg; @@ -12236,7 +12234,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r return sema.fail( block, src, - "else prong required when switching on type '{}'", + "else prong required when switching on type '{f}'", .{cond_ty.fmt(pt)}, ); } @@ -12312,7 +12310,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r .@"anyframe", .comptime_float, .float, - => return sema.fail(block, operand_src, "invalid switch operand type '{}'", .{ + => return sema.fail(block, operand_src, "invalid switch operand type '{f}'", .{ raw_operand_ty.fmt(pt), }), } @@ -12841,7 +12839,7 @@ fn analyzeSwitchRuntimeBlock( if (special.is_inline) switch (operand_ty.zigTypeTag(zcu)) { .@"enum" => { if (operand_ty.isNonexhaustiveEnum(zcu) and !union_originally) { - return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ + return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ operand_ty.fmt(pt), }); } @@ -12897,7 +12895,7 @@ fn analyzeSwitchRuntimeBlock( }, .error_set => { if (operand_ty.isAnyError(zcu)) { - return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ + return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ operand_ty.fmt(pt), }); } @@ -13058,7 +13056,7 @@ fn analyzeSwitchRuntimeBlock( cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items)); } }, - else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ + else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ operand_ty.fmt(pt), }), }; @@ -13572,7 +13570,7 @@ fn validateErrSetSwitch( try sema.errNote( src, msg, - "unhandled error value: 'error.{}'", + "unhandled error value: 'error.{f}'", .{error_name.fmt(ip)}, ); } @@ -13798,7 +13796,7 @@ fn validateSwitchNoRange( const msg = msg: { const msg = try sema.errMsg( operand_src, - "ranges not allowed when switching on type '{}'", + "ranges not allowed when switching on type '{f}'", .{operand_ty.fmt(sema.pt)}, ); errdefer msg.destroy(sema.gpa); @@ -13956,7 +13954,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .array_type => break :hf field_name.eqlSlice("len", ip), else => {}, } - return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ + return sema.fail(block, ty_src, "type '{f}' does not support '@hasField'", .{ ty.fmt(pt), }); }; @@ -14145,7 +14143,7 @@ fn zirShl( while (i < rhs_ty.vectorLen(zcu)) : (i += 1) { const rhs_elem = try rhs_val.elemValue(pt, i); if (rhs_elem.compareHetero(.gte, bit_value, zcu)) { - return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ + return sema.fail(block, rhs_src, "shift amount '{f}' at index '{d}' is too large for operand type '{f}'", .{ rhs_elem.fmtValueSema(pt, sema), i, scalar_ty.fmt(pt), @@ -14153,7 +14151,7 @@ fn zirShl( } } } else if (rhs_val.compareHetero(.gte, bit_value, zcu)) { - return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ + return sema.fail(block, rhs_src, "shift amount '{f}' is too large for operand type '{f}'", .{ rhs_val.fmtValueSema(pt, sema), scalar_ty.fmt(pt), }); @@ -14164,14 +14162,14 @@ fn zirShl( while (i < rhs_ty.vectorLen(zcu)) : (i += 1) { const rhs_elem = try rhs_val.elemValue(pt, i); if (rhs_elem.compareHetero(.lt, try pt.intValue(scalar_rhs_ty, 0), zcu)) { - return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ + return sema.fail(block, rhs_src, "shift by negative amount '{f}' at index '{d}'", .{ rhs_elem.fmtValueSema(pt, sema), i, }); } } } else if (rhs_val.compareHetero(.lt, try pt.intValue(rhs_ty, 0), zcu)) { - return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ + return sema.fail(block, rhs_src, "shift by negative amount '{f}'", .{ rhs_val.fmtValueSema(pt, sema), }); } @@ -14326,7 +14324,7 @@ fn zirShr( while (i < rhs_ty.vectorLen(zcu)) : (i += 1) { const rhs_elem = try rhs_val.elemValue(pt, i); if (rhs_elem.compareHetero(.gte, bit_value, zcu)) { - return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ + return sema.fail(block, rhs_src, "shift amount '{f}' at index '{d}' is too large for operand type '{f}'", .{ rhs_elem.fmtValueSema(pt, sema), i, scalar_ty.fmt(pt), @@ -14334,7 +14332,7 @@ fn zirShr( } } } else if (rhs_val.compareHetero(.gte, bit_value, zcu)) { - return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ + return sema.fail(block, rhs_src, "shift amount '{f}' is too large for operand type '{f}'", .{ rhs_val.fmtValueSema(pt, sema), scalar_ty.fmt(pt), }); @@ -14345,14 +14343,14 @@ fn zirShr( while (i < rhs_ty.vectorLen(zcu)) : (i += 1) { const rhs_elem = try rhs_val.elemValue(pt, i); if (rhs_elem.compareHetero(.lt, try pt.intValue(rhs_ty.childType(zcu), 0), zcu)) { - return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ + return sema.fail(block, rhs_src, "shift by negative amount '{f}' at index '{d}'", .{ rhs_elem.fmtValueSema(pt, sema), i, }); } } } else if (rhs_val.compareHetero(.lt, try pt.intValue(rhs_ty, 0), zcu)) { - return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ + return sema.fail(block, rhs_src, "shift by negative amount '{f}'", .{ rhs_val.fmtValueSema(pt, sema), }); } @@ -14638,11 +14636,11 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, rhs_ty) orelse lhs_info: { if (lhs_is_tuple) break :lhs_info undefined; - return sema.fail(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(pt)}); + return sema.fail(block, lhs_src, "expected indexable; found '{f}'", .{lhs_ty.fmt(pt)}); }; const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs, lhs_ty) orelse { assert(!rhs_is_tuple); - return sema.fail(block, rhs_src, "expected indexable; found '{}'", .{rhs_ty.fmt(pt)}); + return sema.fail(block, rhs_src, "expected indexable; found '{f}'", .{rhs_ty.fmt(pt)}); }; const resolved_elem_ty = t: { @@ -15095,7 +15093,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // Analyze the lhs first, to catch the case that someone tried to do exponentiation const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse { const msg = msg: { - const msg = try sema.errMsg(lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(pt)}); + const msg = try sema.errMsg(lhs_src, "expected indexable; found '{f}'", .{lhs_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); switch (lhs_ty.zigTypeTag(zcu)) { .int, .float, .comptime_float, .comptime_int, .vector => { @@ -15227,7 +15225,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .int, .comptime_int, .float, .comptime_float => false, else => true, }) { - return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(pt)}); + return sema.fail(block, src, "negation of type '{f}'", .{rhs_ty.fmt(pt)}); } if (rhs_scalar_ty.isAnyFloat()) { @@ -15258,7 +15256,7 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! switch (rhs_scalar_ty.zigTypeTag(zcu)) { .int, .comptime_int, .float, .comptime_float => {}, - else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(pt)}), + else => return sema.fail(block, src, "negation of type '{f}'", .{rhs_ty.fmt(pt)}), } const lhs = Air.internedToRef((try sema.splat(rhs_ty, try pt.intValue(rhs_scalar_ty, 0))).toIntern()); @@ -15332,7 +15330,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins return sema.fail( block, src, - "ambiguous coercion of division operands '{}' and '{}'; non-zero remainder '{}'", + "ambiguous coercion of division operands '{f}' and '{f}'; non-zero remainder '{f}'", .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt), rem.fmtValueSema(pt, sema) }, ); } @@ -15384,7 +15382,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins return sema.fail( block, src, - "division with '{}' and '{}': signed integers must use @divTrunc, @divFloor, or @divExact", + "division with '{f}' and '{f}': signed integers must use @divTrunc, @divFloor, or @divExact", .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt) }, ); } @@ -16046,7 +16044,7 @@ fn zirOverflowArithmetic( const rhs = try sema.coerce(block, rhs_dest_ty, uncasted_rhs, rhs_src); if (dest_ty.scalarType(zcu).zigTypeTag(zcu) != .int) { - return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(pt)}); + return sema.fail(block, src, "expected vector of integers or integer tag type, found '{f}'", .{dest_ty.fmt(pt)}); } const maybe_lhs_val = try sema.resolveValue(lhs); @@ -16252,14 +16250,14 @@ fn analyzeArithmetic( return sema.failWithInvalidPtrArithmetic(block, src, "pointer-pointer", "subtraction"); } if (!lhs_ty.elemType2(zcu).eql(rhs_ty.elemType2(zcu), zcu)) { - return sema.fail(block, src, "incompatible pointer arithmetic operands '{}' and '{}'", .{ + return sema.fail(block, src, "incompatible pointer arithmetic operands '{f}' and '{f}'", .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt), }); } const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu); if (elem_size == 0) { - return sema.fail(block, src, "pointer arithmetic requires element type '{}' to have runtime bits", .{ + return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{ lhs_ty.elemType2(zcu).fmt(pt), }); } @@ -16310,7 +16308,7 @@ fn analyzeArithmetic( }; if (!try lhs_ty.elemType2(zcu).hasRuntimeBitsSema(pt)) { - return sema.fail(block, src, "pointer arithmetic requires element type '{}' to have runtime bits", .{ + return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{ lhs_ty.elemType2(zcu).fmt(pt), }); } @@ -16714,7 +16712,7 @@ fn zirCmpEq( if (lhs_ty_tag == .null or rhs_ty_tag == .null) { const non_null_type = if (lhs_ty_tag == .null) rhs_ty else lhs_ty; - return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(pt)}); + return sema.fail(block, src, "comparison of '{f}' with null", .{non_null_type.fmt(pt)}); } if (lhs_ty_tag == .@"union" and (rhs_ty_tag == .enum_literal or rhs_ty_tag == .@"enum")) { @@ -16771,7 +16769,7 @@ fn analyzeCmpUnionTag( const msg = msg: { const msg = try sema.errMsg(un_src, "comparison of union and enum literal is only valid for tagged union types", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(union_ty.srcLoc(zcu), msg, "union '{}' is not a tagged union", .{union_ty.fmt(pt)}); + try sema.errNote(union_ty.srcLoc(zcu), msg, "union '{f}' is not a tagged union", .{union_ty.fmt(pt)}); break :msg msg; }; return sema.failWithOwnedErrorMsg(block, msg); @@ -16857,7 +16855,7 @@ fn analyzeCmp( const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } }); if (!resolved_type.isSelfComparable(zcu, is_equality_cmp)) { - return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{ + return sema.fail(block, src, "operator {s} not allowed for type '{f}'", .{ compareOperatorName(op), resolved_type.fmt(pt), }); } @@ -16966,7 +16964,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .undefined, .null, .@"opaque", - => return sema.fail(block, operand_src, "no size available for type '{}'", .{ty.fmt(pt)}), + => return sema.fail(block, operand_src, "no size available for type '{f}'", .{ty.fmt(pt)}), .type, .enum_literal, @@ -17007,7 +17005,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A .undefined, .null, .@"opaque", - => return sema.fail(block, operand_src, "no size available for type '{}'", .{operand_ty.fmt(pt)}), + => return sema.fail(block, operand_src, "no size available for type '{f}'", .{operand_ty.fmt(pt)}), .type, .enum_literal, @@ -18319,7 +18317,7 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi return sema.fail( block, src, - "bit shifting operation expected integer type, found '{}'", + "bit shifting operation expected integer type, found '{f}'", .{operand.fmt(pt)}, ); } @@ -18558,7 +18556,7 @@ fn checkSentinelType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !voi const pt = sema.pt; const zcu = pt.zcu; if (!ty.isSelfComparable(zcu, true)) { - return sema.fail(block, src, "non-scalar sentinel type '{}'", .{ty.fmt(pt)}); + return sema.fail(block, src, "non-scalar sentinel type '{f}'", .{ty.fmt(pt)}); } } @@ -18608,7 +18606,7 @@ fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { const zcu = pt.zcu; switch (ty.zigTypeTag(zcu)) { .error_set, .error_union, .undefined => return, - else => return sema.fail(block, src, "expected error union type, found '{}'", .{ + else => return sema.fail(block, src, "expected error union type, found '{f}'", .{ ty.fmt(pt), }), } @@ -18752,7 +18750,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError! const pt = sema.pt; const zcu = pt.zcu; if (err_union_ty.zigTypeTag(zcu) != .error_union) { - return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ + return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{ err_union_ty.fmt(pt), }); } @@ -18812,7 +18810,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr const pt = sema.pt; const zcu = pt.zcu; if (err_union_ty.zigTypeTag(zcu) != .error_union) { - return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ + return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{ err_union_ty.fmt(pt), }); } @@ -19010,7 +19008,7 @@ fn zirRetImplicit( const base_tag = sema.fn_ret_ty.baseZigTypeTag(zcu); if (base_tag == .noreturn) { const msg = msg: { - const msg = try sema.errMsg(ret_ty_src, "function declared '{}' implicitly returns", .{ + const msg = try sema.errMsg(ret_ty_src, "function declared '{f}' implicitly returns", .{ sema.fn_ret_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -19020,7 +19018,7 @@ fn zirRetImplicit( return sema.failWithOwnedErrorMsg(block, msg); } else if (base_tag != .void) { const msg = msg: { - const msg = try sema.errMsg(ret_ty_src, "function with non-void return type '{}' implicitly returns", .{ + const msg = try sema.errMsg(ret_ty_src, "function with non-void return type '{f}' implicitly returns", .{ sema.fn_ret_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -19409,13 +19407,13 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air if (host_size != 0) { if (bit_offset >= host_size * 8) { - return sema.fail(block, bitoffset_src, "packed type '{}' at bit offset {} starts {} bits after the end of a {} byte host integer", .{ + return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {} starts {} bits after the end of a {} byte host integer", .{ elem_ty.fmt(pt), bit_offset, bit_offset - host_size * 8, host_size, }); } const elem_bit_size = try elem_ty.bitSizeSema(pt); if (elem_bit_size > host_size * 8 - bit_offset) { - return sema.fail(block, bitoffset_src, "packed type '{}' at bit offset {} ends {} bits after the end of a {} byte host integer", .{ + return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {} ends {} bits after the end of a {} byte host integer", .{ elem_ty.fmt(pt), bit_offset, elem_bit_size - (host_size * 8 - bit_offset), host_size, }); } @@ -19430,7 +19428,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air } else if (inst_data.size == .c) { if (!try sema.validateExternType(elem_ty, .other)) { const msg = msg: { - const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(pt)}); + const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other); @@ -19447,7 +19445,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air if (host_size != 0 and !try sema.validatePackedType(elem_ty)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{}'", .{elem_ty.fmt(pt)}); + const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotPacked(msg, elem_ty_src, elem_ty); break :msg msg; @@ -19616,7 +19614,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; const union_ty = try sema.resolveType(block, ty_src, extra.union_type); if (union_ty.zigTypeTag(pt.zcu) != .@"union") { - return sema.fail(block, ty_src, "expected union type, found '{}'", .{union_ty.fmt(pt)}); + return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)}); } const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_name }); const init = try sema.resolveInst(extra.init); @@ -19779,7 +19777,7 @@ fn zirStructInit( const msg = try sema.errMsg(src, "cannot initialize 'noreturn' field of union", .{}); errdefer msg.destroy(sema.gpa); - try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{}' declared here", .{ + try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{f}' declared here", .{ field_name.fmt(ip), }); try sema.addDeclaredHereNote(msg, resolved_ty); @@ -19898,7 +19896,7 @@ fn finishStructInit( const field_init = struct_type.fieldInit(ip, i); if (field_init == .none) { const field_name = struct_type.field_names.get(ip)[i]; - const template = "missing struct field: {}"; + const template = "missing struct field: {f}"; const args = .{field_name.fmt(ip)}; if (root_msg) |msg| { try sema.errNote(init_src, msg, template, args); @@ -20513,7 +20511,7 @@ fn fieldType( }, else => {}, } - return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{ + return sema.fail(block, ty_src, "expected struct or union; found '{f}'", .{ cur_ty.fmt(pt), }); } @@ -20560,7 +20558,7 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); const ty = try sema.resolveType(block, operand_src, inst_data.operand); if (ty.isNoReturn(zcu)) { - return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.pt)}); + return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)}); } const val = try ty.lazyAbiAlignment(sema.pt); return Air.internedToRef(val.toIntern()); @@ -20638,7 +20636,7 @@ fn zirAbs( else => return sema.fail( block, operand_src, - "expected integer, float, or vector of either integers or floats, found '{}'", + "expected integer, float, or vector of either integers or floats, found '{f}'", .{operand_ty.fmt(pt)}, ), }; @@ -20707,7 +20705,7 @@ fn zirUnaryMath( else => return sema.fail( block, operand_src, - "expected vector of floats or float type, found '{}'", + "expected vector of floats or float type, found '{f}'", .{operand_ty.fmt(pt)}, ), } @@ -20736,8 +20734,8 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air }, .@"enum" => operand_ty, .@"union" => operand_ty.unionTagType(zcu) orelse - return sema.fail(block, src, "union '{}' is untagged", .{operand_ty.fmt(pt)}), - else => return sema.fail(block, operand_src, "expected enum or union; found '{}'", .{ + return sema.fail(block, src, "union '{f}' is untagged", .{operand_ty.fmt(pt)}), + else => return sema.fail(block, operand_src, "expected enum or union; found '{f}'", .{ operand_ty.fmt(pt), }), }; @@ -20745,7 +20743,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air // TODO I don't think this is the correct way to handle this but // it prevents a crash. // https://github.com/ziglang/zig/issues/15909 - return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{ + return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{f}'", .{ enum_ty.fmt(pt), }); } @@ -20753,7 +20751,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| { const field_index = enum_ty.enumTagFieldIndex(val, zcu) orelse { const msg = msg: { - const msg = try sema.errMsg(src, "no field with value '{}' in enum '{}'", .{ + const msg = try sema.errMsg(src, "no field with value '{f}' in enum '{f}'", .{ val.fmtValueSema(pt, sema), enum_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -20940,7 +20938,7 @@ fn zirReify( } else if (ptr_size == .c) { if (!try sema.validateExternType(elem_ty, .other)) { const msg = msg: { - const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotExtern(msg, src, elem_ty, .other); @@ -21053,7 +21051,7 @@ fn zirReify( _ = try pt.getErrorValue(name); const gop = names.getOrPutAssumeCapacity(name); if (gop.found_existing) { - return sema.fail(block, src, "duplicate error '{}'", .{ + return sema.fail(block, src, "duplicate error '{f}'", .{ name.fmt(ip), }); } @@ -21401,7 +21399,7 @@ fn reifyEnum( if (!try sema.intFitsInType(field_value_val, tag_ty, null)) { // TODO: better source location - return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{ + return sema.fail(block, src, "field '{f}' with enumeration value '{f}' is too large for backing int type '{f}'", .{ field_name.fmt(ip), field_value_val.fmtValueSema(pt, sema), tag_ty.fmt(pt), @@ -21412,14 +21410,14 @@ fn reifyEnum( if (wip_ty.nextField(ip, field_name, coerced_field_val.toIntern())) |conflict| { return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) { .name => msg: { - const msg = try sema.errMsg(src, "duplicate enum field '{}'", .{field_name.fmt(ip)}); + const msg = try sema.errMsg(src, "duplicate enum field '{f}'", .{field_name.fmt(ip)}); errdefer msg.destroy(gpa); _ = conflict.prev_field_idx; // TODO: this note is incorrect try sema.errNote(src, msg, "other field here", .{}); break :msg msg; }, .value => msg: { - const msg = try sema.errMsg(src, "enum tag value {} already taken", .{field_value_val.fmtValueSema(pt, sema)}); + const msg = try sema.errMsg(src, "enum tag value {f} already taken", .{field_value_val.fmtValueSema(pt, sema)}); errdefer msg.destroy(gpa); _ = conflict.prev_field_idx; // TODO: this note is incorrect try sema.errNote(src, msg, "other enum tag value here", .{}); @@ -21567,13 +21565,13 @@ fn reifyUnion( const enum_index = enum_tag_ty.enumFieldIndex(field_name, zcu) orelse { // TODO: better source location - return sema.fail(block, src, "no field named '{}' in enum '{}'", .{ + return sema.fail(block, src, "no field named '{f}' in enum '{f}'", .{ field_name.fmt(ip), enum_tag_ty.fmt(pt), }); }; if (seen_tags.isSet(enum_index)) { // TODO: better source location - return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)}); + return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)}); } seen_tags.set(enum_index); @@ -21594,7 +21592,7 @@ fn reifyUnion( var it = seen_tags.iterator(.{ .kind = .unset }); while (it.next()) |enum_index| { const field_name = enum_tag_ty.enumFieldName(enum_index, zcu); - try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{}' missing, declared here", .{ + try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{f}' missing, declared here", .{ field_name.fmt(ip), }); } @@ -21619,7 +21617,7 @@ fn reifyUnion( const gop = field_names.getOrPutAssumeCapacity(field_name); if (gop.found_existing) { // TODO: better source location - return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)}); + return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)}); } field_ty.* = field_type_val.toIntern(); @@ -21651,7 +21649,7 @@ fn reifyUnion( } if (layout == .@"extern" and !try sema.validateExternType(field_ty, .union_field)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .union_field); @@ -21661,7 +21659,7 @@ fn reifyUnion( }); } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotPacked(msg, src, field_ty); @@ -21743,7 +21741,7 @@ fn reifyTuple( const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail( block, src, - "tuple cannot have non-numeric field '{}'", + "tuple cannot have non-numeric field '{f}'", .{field_name.fmt(ip)}, ); if (field_name_index != field_idx) { @@ -21921,7 +21919,7 @@ fn reifyStruct( const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined); if (struct_type.addFieldName(ip, field_name)) |prev_index| { _ = prev_index; // TODO: better source location - return sema.fail(block, src, "duplicate struct field name {}", .{field_name.fmt(ip)}); + return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)}); } if (any_aligned_fields) { @@ -21990,7 +21988,7 @@ fn reifyStruct( } if (layout == .@"extern" and !try sema.validateExternType(field_ty, .struct_field)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .struct_field); @@ -22000,7 +21998,7 @@ fn reifyStruct( }); } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotPacked(msg, src, field_ty); @@ -22077,7 +22075,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C if (!try sema.validateExternType(arg_ty, .param_ty)) { const msg = msg: { - const msg = try sema.errMsg(ty_src, "cannot get '{}' from variadic argument", .{arg_ty.fmt(sema.pt)}); + const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, ty_src, arg_ty, .param_ty); @@ -22136,7 +22134,7 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0); const ty = try sema.resolveType(block, ty_src, inst_data.operand); - const type_name = try ip.getOrPutStringFmt(sema.gpa, pt.tid, "{}", .{ty.fmt(pt)}, .no_embedded_nulls); + const type_name = try ip.getOrPutStringFmt(sema.gpa, pt.tid, "{f}", .{ty.fmt(pt)}, .no_embedded_nulls); return sema.addNullTerminatedStrLit(type_name); } @@ -22270,7 +22268,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! if (ptr_ty.isSlice(zcu)) { const msg = msg: { - const msg = try sema.errMsg(src, "integer cannot be converted to slice type '{}'", .{ptr_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "integer cannot be converted to slice type '{f}'", .{ptr_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "slice length cannot be inferred from address", .{}); break :msg msg; @@ -22297,7 +22295,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! } if (try ptr_ty.comptimeOnlySema(pt)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "pointer to comptime-only type '{}' must be comptime-known, but operand is runtime-known", .{ptr_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "pointer to comptime-only type '{f}' must be comptime-known, but operand is runtime-known", .{ptr_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsComptime(msg, src, ptr_ty); @@ -22354,7 +22352,7 @@ fn ptrFromIntVal( } const addr = try operand_val.toUnsignedIntSema(pt); if (!ptr_ty.isAllowzeroPtr(zcu) and addr == 0) - return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(pt)}); + return sema.fail(block, operand_src, "pointer type '{f}' does not allow address zero", .{ptr_ty.fmt(pt)}); if (addr != 0 and ptr_align != .none) { const masked_addr = if (ptr_ty.childType(zcu).fnPtrMaskOrNull(zcu)) |mask| addr & mask @@ -22407,8 +22405,8 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData errdefer msg.destroy(sema.gpa); const dest_payload_ty = dest_ty.errorUnionPayload(zcu); const operand_payload_ty = operand_ty.errorUnionPayload(zcu); - try sema.errNote(src, msg, "destination payload is '{}'", .{dest_payload_ty.fmt(pt)}); - try sema.errNote(src, msg, "operand payload is '{}'", .{operand_payload_ty.fmt(pt)}); + try sema.errNote(src, msg, "destination payload is '{f}'", .{dest_payload_ty.fmt(pt)}); + try sema.errNote(src, msg, "operand payload is '{f}'", .{operand_payload_ty.fmt(pt)}); try addDeclaredHereNote(sema, msg, dest_ty); try addDeclaredHereNote(sema, msg, operand_ty); break :msg msg; @@ -22453,7 +22451,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData break :disjoint true; }; if (disjoint and !(operand_tag == .error_union and dest_tag == .error_union)) { - return sema.fail(block, src, "error sets '{}' and '{}' have no common errors", .{ + return sema.fail(block, src, "error sets '{f}' and '{f}' have no common errors", .{ operand_err_ty.fmt(pt), dest_err_ty.fmt(pt), }); } @@ -22473,7 +22471,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData }; if (!dest_err_ty.isAnyError(zcu) and !Type.errorSetHasFieldIp(ip, dest_err_ty.toIntern(), err_name)) { - return sema.fail(block, src, "'error.{}' not a member of error set '{}'", .{ + return sema.fail(block, src, "'error.{f}' not a member of error set '{f}'", .{ err_name.fmt(ip), dest_err_ty.fmt(pt), }); } @@ -22633,13 +22631,15 @@ fn ptrCastFull( const src_elem_size = src_elem_ty.abiSize(zcu); const dest_elem_size = dest_elem_ty.abiSize(zcu); if (dest_elem_size == 0) { - return sema.fail(block, src, "cannot infer length of slice of zero-bit '{}' from '{}'", .{ dest_elem_ty.fmt(pt), operand_ty.fmt(pt) }); + return sema.fail(block, src, "cannot infer length of slice of zero-bit '{f}' from '{f}'", .{ + dest_elem_ty.fmt(pt), operand_ty.fmt(pt), + }); } if (opt_src_len) |src_len| { const bytes = src_len * src_elem_size; const dest_len = std.math.divExact(u64, bytes, dest_elem_size) catch switch (src_info.flags.size) { .slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}), - .one => return sema.fail(block, src, "type '{}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}), + .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}), else => unreachable, }; break :len .{ .constant = dest_len }; @@ -22657,7 +22657,9 @@ fn ptrCastFull( // The source value has `src_len * src_base_per_elem` values of type `src_base_ty`. // The result value will have `dest_len * dest_base_per_elem` values of type `dest_base_ty`. if (dest_base_ty.toIntern() != src_base_ty.toIntern()) { - return sema.fail(block, src, "cannot infer length of comptime-only '{}' from incompatible '{}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) }); + return sema.fail(block, src, "cannot infer length of comptime-only '{f}' from incompatible '{f}'", .{ + dest_ty.fmt(pt), operand_ty.fmt(pt), + }); } // `src_base_ty` is comptime-only, so `src_elem_ty` is comptime-only, so `operand_ty` is // comptime-only, so `operand` is comptime-known, so `opt_src_len` is non-`null`. @@ -22665,7 +22667,7 @@ fn ptrCastFull( const base_len = src_len * src_base_per_elem; const dest_len = std.math.divExact(u64, base_len, dest_base_per_elem) catch switch (src_info.flags.size) { .slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}), - .one => return sema.fail(block, src, "type '{}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}), + .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}), else => unreachable, }; break :len .{ .constant = dest_len }; @@ -22726,7 +22728,7 @@ fn ptrCastFull( ); if (imc_res == .ok) break :check_child; return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "pointer element type '{}' cannot coerce into element type '{}'", .{ + const msg = try sema.errMsg(src, "pointer element type '{f}' cannot coerce into element type '{f}'", .{ src_child.fmt(pt), dest_child.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -22753,11 +22755,11 @@ fn ptrCastFull( } return sema.failWithOwnedErrorMsg(block, msg: { const msg = if (src_info.sentinel == .none) blk: { - break :blk try sema.errMsg(src, "destination pointer requires '{}' sentinel", .{ + break :blk try sema.errMsg(src, "destination pointer requires '{f}' sentinel", .{ Value.fromInterned(dest_info.sentinel).fmtValueSema(pt, sema), }); } else blk: { - break :blk try sema.errMsg(src, "pointer sentinel '{}' cannot coerce into pointer sentinel '{}'", .{ + break :blk try sema.errMsg(src, "pointer sentinel '{f}' cannot coerce into pointer sentinel '{f}'", .{ Value.fromInterned(src_info.sentinel).fmtValueSema(pt, sema), Value.fromInterned(dest_info.sentinel).fmtValueSema(pt, sema), }); @@ -22799,7 +22801,7 @@ fn ptrCastFull( if (dest_allows_zero) break :check_allowzero; return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "'{}' could have null values which are illegal in type '{}'", .{ + const msg = try sema.errMsg(src, "'{f}' could have null values which are illegal in type '{f}'", .{ operand_ty.fmt(pt), dest_ty.fmt(pt), }); @@ -22827,10 +22829,10 @@ fn ptrCastFull( return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(src, "{s} increases pointer alignment", .{operation}); errdefer msg.destroy(sema.gpa); - try sema.errNote(operand_src, msg, "'{}' has alignment '{d}'", .{ + try sema.errNote(operand_src, msg, "'{f}' has alignment '{d}'", .{ operand_ty.fmt(pt), src_align.toByteUnits() orelse 0, }); - try sema.errNote(src, msg, "'{}' has alignment '{d}'", .{ + try sema.errNote(src, msg, "'{f}' has alignment '{d}'", .{ dest_ty.fmt(pt), dest_align.toByteUnits() orelse 0, }); try sema.errNote(src, msg, "use @alignCast to assert pointer alignment", .{}); @@ -22844,10 +22846,10 @@ fn ptrCastFull( return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(src, "{s} changes pointer address space", .{operation}); errdefer msg.destroy(sema.gpa); - try sema.errNote(operand_src, msg, "'{}' has address space '{s}'", .{ + try sema.errNote(operand_src, msg, "'{f}' has address space '{s}'", .{ operand_ty.fmt(pt), @tagName(src_info.flags.address_space), }); - try sema.errNote(src, msg, "'{}' has address space '{s}'", .{ + try sema.errNote(src, msg, "'{f}' has address space '{s}'", .{ dest_ty.fmt(pt), @tagName(dest_info.flags.address_space), }); try sema.errNote(src, msg, "use @addrSpaceCast to cast pointer address space", .{}); @@ -22914,7 +22916,7 @@ fn ptrCastFull( if (operand_val.isNull(zcu)) { if (!dest_ty.ptrAllowsZero(zcu)) { - return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(pt)}); + return sema.fail(block, operand_src, "null pointer casted to type '{f}'", .{dest_ty.fmt(pt)}); } if (dest_ty.zigTypeTag(zcu) == .optional) { return Air.internedToRef((try pt.nullValue(dest_ty)).toIntern()); @@ -23205,7 +23207,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const operand_is_vector = operand_ty.zigTypeTag(zcu) == .vector; const dest_is_vector = dest_ty.zigTypeTag(zcu) == .vector; if (operand_is_vector != dest_is_vector) { - return sema.fail(block, operand_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) }); + return sema.fail(block, operand_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) }); } if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_int) { @@ -23225,7 +23227,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } if (operand_info.signedness != dest_info.signedness) { - return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{ + return sema.fail(block, operand_src, "expected {s} integer type, found '{f}'", .{ @tagName(dest_info.signedness), operand_ty.fmt(pt), }); } @@ -23234,7 +23236,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const msg = msg: { const msg = try sema.errMsg( src, - "destination type '{}' has more bits than source type '{}'", + "destination type '{f}' has more bits than source type '{f}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) }, ); errdefer msg.destroy(sema.gpa); @@ -23352,7 +23354,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai return sema.fail( block, operand_src, - "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits", + "@byteSwap requires the number of bits to be evenly divisible by 8, but {f} has {} bits", .{ scalar_ty.fmt(pt), bits }, ); } @@ -23472,7 +23474,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 try ty.resolveLayout(pt); switch (ty.zigTypeTag(zcu)) { .@"struct" => {}, - else => return sema.fail(block, ty_src, "expected struct type, found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, ty_src, "expected struct type, found '{f}'", .{ty.fmt(pt)}), } const field_index = if (ty.isTuple(zcu)) blk: { @@ -23507,7 +23509,7 @@ fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Com const zcu = pt.zcu; switch (ty.zigTypeTag(zcu)) { .@"struct", .@"enum", .@"union", .@"opaque" => return, - else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{f}'", .{ty.fmt(pt)}), } } @@ -23518,7 +23520,7 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr switch (ty.zigTypeTag(zcu)) { .comptime_int => return true, .int => return false, - else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, src, "expected integer type, found '{f}'", .{ty.fmt(pt)}), } } @@ -23572,7 +23574,7 @@ fn checkPtrOperand( const msg = msg: { const msg = try sema.errMsg( ty_src, - "expected pointer, found '{}'", + "expected pointer, found '{f}'", .{ty.fmt(pt)}, ); errdefer msg.destroy(sema.gpa); @@ -23586,7 +23588,7 @@ fn checkPtrOperand( .optional => if (ty.childType(zcu).zigTypeTag(zcu) == .pointer) return, else => {}, } - return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(pt)}); + return sema.fail(block, ty_src, "expected pointer type, found '{f}'", .{ty.fmt(pt)}); } fn checkPtrType( @@ -23604,7 +23606,7 @@ fn checkPtrType( const msg = msg: { const msg = try sema.errMsg( ty_src, - "expected pointer type, found '{}'", + "expected pointer type, found '{f}'", .{ty.fmt(pt)}, ); errdefer msg.destroy(sema.gpa); @@ -23618,7 +23620,7 @@ fn checkPtrType( .optional => if (ty.childType(zcu).zigTypeTag(zcu) == .pointer) return, else => {}, } - return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(pt)}); + return sema.fail(block, ty_src, "expected pointer type, found '{f}'", .{ty.fmt(pt)}); } fn checkLogicalPtrOperation(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { @@ -23629,7 +23631,7 @@ fn checkLogicalPtrOperation(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ const as = ty.ptrAddressSpace(zcu); if (target_util.arePointersLogical(target, as)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "illegal operation on logical pointer of type '{}'", .{ty.fmt(pt)}); + const msg = try sema.errMsg(src, "illegal operation on logical pointer of type '{f}'", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote( src, @@ -23660,7 +23662,7 @@ fn checkVectorElemType( .optional, .pointer => if (ty.isPtrAtRuntime(zcu)) return, else => {}, } - return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(pt)}); + return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{f}'", .{ty.fmt(pt)}); } fn checkFloatType( @@ -23673,7 +23675,7 @@ fn checkFloatType( const zcu = pt.zcu; switch (ty.zigTypeTag(zcu)) { .comptime_int, .comptime_float, .float => {}, - else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, ty_src, "expected float type, found '{f}'", .{ty.fmt(pt)}), } } @@ -23691,7 +23693,7 @@ fn checkNumericType( .comptime_float, .float, .comptime_int, .int => {}, else => |t| return sema.fail(block, ty_src, "expected number, found '{}'", .{t}), }, - else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, ty_src, "expected number, found '{f}'", .{ty.fmt(pt)}), } } @@ -23725,7 +23727,7 @@ fn checkAtomicPtrOperand( error.BadType => return sema.fail( block, elem_ty_src, - "expected bool, integer, float, enum, packed struct, or pointer type; found '{}'", + "expected bool, integer, float, enum, packed struct, or pointer type; found '{f}'", .{elem_ty.fmt(pt)}, ), }; @@ -23786,12 +23788,12 @@ fn checkIntOrVector( const elem_ty = operand_ty.childType(zcu); switch (elem_ty.zigTypeTag(zcu)) { .int => return elem_ty, - else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ + else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{f}'", .{ elem_ty.fmt(pt), }), } }, - else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ + else => return sema.fail(block, operand_src, "expected integer or vector, found '{f}'", .{ operand_ty.fmt(pt), }), } @@ -23811,12 +23813,12 @@ fn checkIntOrVectorAllowComptime( const elem_ty = operand_ty.childType(zcu); switch (elem_ty.zigTypeTag(zcu)) { .int, .comptime_int => return elem_ty, - else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ + else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{f}'", .{ elem_ty.fmt(pt), }), } }, - else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ + else => return sema.fail(block, operand_src, "expected integer or vector, found '{f}'", .{ operand_ty.fmt(pt), }), } @@ -23907,7 +23909,7 @@ fn checkVectorizableBinaryOperands( } } else { const msg = msg: { - const msg = try sema.errMsg(src, "mixed scalar and vector operands: '{}' and '{}'", .{ + const msg = try sema.errMsg(src, "mixed scalar and vector operands: '{f}' and '{f}'", .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -24041,7 +24043,7 @@ fn zirCmpxchg( return sema.fail( block, elem_ty_src, - "expected bool, integer, enum, packed struct, or pointer type; found '{}'", + "expected bool, integer, enum, packed struct, or pointer type; found '{f}'", .{elem_ty.fmt(pt)}, ); } @@ -24125,7 +24127,7 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I switch (dest_ty.zigTypeTag(zcu)) { .array, .vector => {}, - else => return sema.fail(block, src, "expected array or vector type, found '{}'", .{dest_ty.fmt(pt)}), + else => return sema.fail(block, src, "expected array or vector type, found '{f}'", .{dest_ty.fmt(pt)}), } const operand = try sema.resolveInst(extra.rhs); @@ -24201,7 +24203,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. const zcu = pt.zcu; if (operand_ty.zigTypeTag(zcu) != .vector) { - return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(pt)}); + return sema.fail(block, operand_src, "expected vector, found '{f}'", .{operand_ty.fmt(pt)}); } const scalar_ty = operand_ty.childType(zcu); @@ -24210,13 +24212,13 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. switch (operation) { .And, .Or, .Xor => switch (scalar_ty.zigTypeTag(zcu)) { .int, .bool => {}, - else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{}'", .{ + else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{f}'", .{ @tagName(operation), operand_ty.fmt(pt), }), }, .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag(zcu)) { .int, .float => {}, - else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{}'", .{ + else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{f}'", .{ @tagName(operation), operand_ty.fmt(pt), }), }, @@ -24270,7 +24272,7 @@ fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const mask_len = switch (sema.typeOf(mask).zigTypeTag(zcu)) { .array, .vector => sema.typeOf(mask).arrayLen(zcu), - else => return sema.fail(block, mask_src, "expected vector or array, found '{}'", .{sema.typeOf(mask).fmt(pt)}), + else => return sema.fail(block, mask_src, "expected vector or array, found '{f}'", .{sema.typeOf(mask).fmt(pt)}), }; mask_ty = try pt.vectorType(.{ .len = @intCast(mask_len), @@ -24297,11 +24299,14 @@ fn analyzeShuffle( const b_src = block.builtinCallArgSrc(src_node, 2); const mask_src = block.builtinCallArgSrc(src_node, 3); - // If the type of `a` is `@Type(.undefined)`, i.e. the argument is untyped, this is 0, because it is an error to index into this vector. + // If the type of `a` is `@Type(.undefined)`, i.e. the argument is untyped, + // this is 0, because it is an error to index into this vector. const a_len: u32 = switch (sema.typeOf(a_uncoerced).zigTypeTag(zcu)) { .array, .vector => @intCast(sema.typeOf(a_uncoerced).arrayLen(zcu)), .undefined => 0, - else => return sema.fail(block, a_src, "expected vector of '{}', found '{}'", .{ elem_ty.fmt(pt), sema.typeOf(a_uncoerced).fmt(pt) }), + else => return sema.fail(block, a_src, "expected vector of '{f}', found '{f}'", .{ + elem_ty.fmt(pt), sema.typeOf(a_uncoerced).fmt(pt), + }), }; const a_ty = try pt.vectorType(.{ .len = a_len, .child = elem_ty.toIntern() }); const a_coerced = try sema.coerce(block, a_ty, a_uncoerced, a_src); @@ -24310,7 +24315,9 @@ fn analyzeShuffle( const b_len: u32 = switch (sema.typeOf(b_uncoerced).zigTypeTag(zcu)) { .array, .vector => @intCast(sema.typeOf(b_uncoerced).arrayLen(zcu)), .undefined => 0, - else => return sema.fail(block, b_src, "expected vector of '{}', found '{}'", .{ elem_ty.fmt(pt), sema.typeOf(b_uncoerced).fmt(pt) }), + else => return sema.fail(block, b_src, "expected vector of '{f}', found '{f}'", .{ + elem_ty.fmt(pt), sema.typeOf(b_uncoerced).fmt(pt), + }), }; const b_ty = try pt.vectorType(.{ .len = b_len, .child = elem_ty.toIntern() }); const b_coerced = try sema.coerce(block, b_ty, b_uncoerced, b_src); @@ -24348,7 +24355,7 @@ fn analyzeShuffle( if (idx >= a_len) return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(mask_src, "mask element at index '{d}' selects out-of-bounds index", .{mask_idx}); errdefer msg.destroy(sema.gpa); - try sema.errNote(a_src, msg, "index '{d}' exceeds bounds of '{}' given here", .{ idx, a_ty.fmt(pt) }); + try sema.errNote(a_src, msg, "index '{d}' exceeds bounds of '{f}' given here", .{ idx, a_ty.fmt(pt) }); if (idx < b_len) { try sema.errNote(b_src, msg, "use '~@as(u32, {d})' to index into second vector given here", .{idx}); } @@ -24464,7 +24471,7 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C const vec_len_u64 = switch (pred_ty.zigTypeTag(zcu)) { .vector, .array => pred_ty.arrayLen(zcu), - else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(pt)}), + else => return sema.fail(block, pred_src, "expected vector or array, found '{f}'", .{pred_ty.fmt(pt)}), }; const vec_len: u32 = @intCast(try sema.usizeCast(block, pred_src, vec_len_u64)); @@ -24724,7 +24731,7 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. switch (ty.scalarType(zcu).zigTypeTag(zcu)) { .comptime_float, .float => {}, - else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, src, "expected vector of floats or float type, found '{f}'", .{ty.fmt(pt)}), } const runtime_src = if (maybe_mulend1) |mulend1_val| rs: { @@ -24833,7 +24840,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const args_ty = sema.typeOf(args); if (!args_ty.isTuple(zcu)) { - return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(pt)}); + return sema.fail(block, args_src, "expected a tuple, found '{f}'", .{args_ty.fmt(pt)}); } const resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount(zcu)); @@ -24878,12 +24885,12 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins try sema.checkPtrType(block, inst_src, parent_ptr_ty, true); const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu); if (parent_ptr_info.flags.size != .one) { - return sema.fail(block, inst_src, "expected single pointer type, found '{}'", .{parent_ptr_ty.fmt(pt)}); + return sema.fail(block, inst_src, "expected single pointer type, found '{f}'", .{parent_ptr_ty.fmt(pt)}); } const parent_ty: Type = .fromInterned(parent_ptr_info.child); switch (parent_ty.zigTypeTag(zcu)) { .@"struct", .@"union" => {}, - else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{}'", .{parent_ptr_ty.fmt(pt)}), + else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{f}'", .{parent_ptr_ty.fmt(pt)}), } try parent_ty.resolveLayout(pt); @@ -25033,7 +25040,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins } if (field.index != field_index) { - return sema.fail(block, inst_src, "field '{}' has index '{d}' but pointer value is index '{d}' of struct '{}'", .{ + return sema.fail(block, inst_src, "field '{f}' has index '{d}' but pointer value is index '{d}' of struct '{f}'", .{ field_name.fmt(ip), field_index, field.index, parent_ty.fmt(pt), }); } @@ -25492,10 +25499,10 @@ fn zirMemcpy( const msg = msg: { const msg = try sema.errMsg(src, "unknown copy length", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(dest_src, msg, "destination type '{}' provides no length", .{ + try sema.errNote(dest_src, msg, "destination type '{f}' provides no length", .{ dest_ty.fmt(pt), }); - try sema.errNote(src_src, msg, "source type '{}' provides no length", .{ + try sema.errNote(src_src, msg, "source type '{f}' provides no length", .{ src_ty.fmt(pt), }); break :msg msg; @@ -25519,7 +25526,7 @@ fn zirMemcpy( if (imc != .ok) return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg( src, - "pointer element type '{}' cannot coerce into element type '{}'", + "pointer element type '{f}' cannot coerce into element type '{f}'", .{ src_elem_ty.fmt(pt), dest_elem_ty.fmt(pt) }, ); errdefer msg.destroy(sema.gpa); @@ -25538,10 +25545,10 @@ fn zirMemcpy( const msg = msg: { const msg = try sema.errMsg(src, "non-matching copy lengths", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(dest_src, msg, "length {} here", .{ + try sema.errNote(dest_src, msg, "length {f} here", .{ dest_len_val.fmtValueSema(pt, sema), }); - try sema.errNote(src_src, msg, "length {} here", .{ + try sema.errNote(src_src, msg, "length {f} here", .{ src_len_val.fmtValueSema(pt, sema), }); break :msg msg; @@ -25756,7 +25763,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(src, "unknown @memset length", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(dest_src, msg, "destination type '{}' provides no length", .{ + try sema.errNote(dest_src, msg, "destination type '{f}' provides no length", .{ dest_ptr_ty.fmt(pt), }); break :msg msg; @@ -25964,7 +25971,7 @@ fn zirCUndef( const src = block.builtinCallArgSrc(extra.node, 0); const name = try sema.resolveConstString(block, src, extra.operand, .{ .simple = .operand_cUndef_macro_name }); - try block.c_import_buf.?.writer().print("#undef {s}\n", .{name}); + try block.c_import_buf.?.print("#undef {s}\n", .{name}); return .void_value; } @@ -25977,7 +25984,7 @@ fn zirCInclude( const src = block.builtinCallArgSrc(extra.node, 0); const name = try sema.resolveConstString(block, src, extra.operand, .{ .simple = .operand_cInclude_file_name }); - try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name}); + try block.c_import_buf.?.print("#include <{s}>\n", .{name}); return .void_value; } @@ -25996,9 +26003,9 @@ fn zirCDefine( const rhs = try sema.resolveInst(extra.rhs); if (sema.typeOf(rhs).zigTypeTag(zcu) != .void) { const value = try sema.resolveConstString(block, val_src, extra.rhs, .{ .simple = .operand_cDefine_macro_value }); - try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); + try block.c_import_buf.?.print("#define {s} {s}\n", .{ name, value }); } else { - try block.c_import_buf.?.writer().print("#define {s}\n", .{name}); + try block.c_import_buf.?.print("#define {s}\n", .{name}); } return .void_value; } @@ -26216,7 +26223,7 @@ fn zirBuiltinExtern( } if (!try sema.validateExternType(ty, .other)) { const msg = msg: { - const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(pt)}); + const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, ty_src, ty, .other); break :msg msg; @@ -26456,7 +26463,7 @@ pub fn validateVarType( if (is_extern) { if (!try sema.validateExternType(var_ty, .other)) { const msg = msg: { - const msg = try sema.errMsg(src, "extern variable cannot have type '{}'", .{var_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "extern variable cannot have type '{f}'", .{var_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, src, var_ty, .other); break :msg msg; @@ -26468,7 +26475,7 @@ pub fn validateVarType( return sema.fail( block, src, - "non-extern variable with opaque type '{}'", + "non-extern variable with opaque type '{f}'", .{var_ty.fmt(pt)}, ); } @@ -26477,7 +26484,7 @@ pub fn validateVarType( if (!try var_ty.comptimeOnlySema(pt)) return; const msg = msg: { - const msg = try sema.errMsg(src, "variable of type '{}' must be const or comptime", .{var_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "variable of type '{f}' must be const or comptime", .{var_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsComptime(msg, src, var_ty); @@ -26527,7 +26534,7 @@ fn explainWhyTypeIsComptimeInner( => return, .@"fn" => { - try sema.errNote(src_loc, msg, "use '*const {}' for a function pointer type", .{ty.fmt(pt)}); + try sema.errNote(src_loc, msg, "use '*const {f}' for a function pointer type", .{ty.fmt(pt)}); }, .type => { @@ -26543,7 +26550,7 @@ fn explainWhyTypeIsComptimeInner( => return, .@"opaque" => { - try sema.errNote(src_loc, msg, "opaque type '{}' has undefined size", .{ty.fmt(pt)}); + try sema.errNote(src_loc, msg, "opaque type '{f}' has undefined size", .{ty.fmt(pt)}); }, .array, .vector => { @@ -26730,7 +26737,7 @@ fn explainWhyTypeIsNotExtern( if (!ty.isConstPtr(zcu) and pointee_ty.zigTypeTag(zcu) == .@"fn") { try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{}); } else if (try ty.comptimeOnlySema(pt)) { - try sema.errNote(src_loc, msg, "pointer to comptime-only type '{}'", .{pointee_ty.fmt(pt)}); + try sema.errNote(src_loc, msg, "pointer to comptime-only type '{f}'", .{pointee_ty.fmt(pt)}); try sema.explainWhyTypeIsComptime(msg, src_loc, ty); } try sema.explainWhyTypeIsNotExtern(msg, src_loc, pointee_ty, .other); @@ -26758,7 +26765,7 @@ fn explainWhyTypeIsNotExtern( }, .@"enum" => { const tag_ty = ty.intTagType(zcu); - try sema.errNote(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(pt)}); + try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)}); try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); }, .@"struct" => try sema.errNote(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}), @@ -27194,7 +27201,7 @@ fn fieldVal( return sema.fail( block, field_name_src, - "no member named '{}' in '{}'", + "no member named '{f}' in '{f}'", .{ field_name.fmt(ip), object_ty.fmt(pt) }, ); } @@ -27218,7 +27225,7 @@ fn fieldVal( return sema.fail( block, field_name_src, - "no member named '{}' in '{}'", + "no member named '{f}' in '{f}'", .{ field_name.fmt(ip), object_ty.fmt(pt) }, ); } @@ -27238,7 +27245,7 @@ fn fieldVal( switch (ip.indexToKey(child_type.toIntern())) { .error_set_type => |error_set_type| blk: { if (error_set_type.nameIndex(ip, field_name) != null) break :blk; - return sema.fail(block, src, "no error named '{}' in '{}'", .{ + return sema.fail(block, src, "no error named '{f}' in '{f}'", .{ field_name.fmt(ip), child_type.fmt(pt), }); }, @@ -27293,7 +27300,7 @@ fn fieldVal( return sema.failWithBadMemberAccess(block, child_type, src, field_name); }, else => return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "type '{}' has no members", .{child_type.fmt(pt)}); + const msg = try sema.errMsg(src, "type '{f}' has no members", .{child_type.fmt(pt)}); errdefer msg.destroy(sema.gpa); if (child_type.isSlice(zcu)) try sema.errNote(src, msg, "slice values have 'len' and 'ptr' members", .{}); if (child_type.zigTypeTag(zcu) == .array) try sema.errNote(src, msg, "array values have 'len' member", .{}); @@ -27339,7 +27346,7 @@ fn fieldPtr( const object_ptr_ty = sema.typeOf(object_ptr); const object_ty = switch (object_ptr_ty.zigTypeTag(zcu)) { .pointer => object_ptr_ty.childType(zcu), - else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(pt)}), + else => return sema.fail(block, object_ptr_src, "expected pointer, found '{f}'", .{object_ptr_ty.fmt(pt)}), }; // Zig allows dereferencing a single pointer during field lookup. Note that @@ -27392,7 +27399,7 @@ fn fieldPtr( return sema.fail( block, field_name_src, - "no member named '{}' in '{}'", + "no member named '{f}' in '{f}'", .{ field_name.fmt(ip), object_ty.fmt(pt) }, ); } @@ -27447,7 +27454,7 @@ fn fieldPtr( return sema.fail( block, field_name_src, - "no member named '{}' in '{}'", + "no member named '{f}' in '{f}'", .{ field_name.fmt(ip), object_ty.fmt(pt) }, ); } @@ -27470,7 +27477,7 @@ fn fieldPtr( if (error_set_type.nameIndex(ip, field_name) != null) { break :blk; } - return sema.fail(block, src, "no error named '{}' in '{}'", .{ + return sema.fail(block, src, "no error named '{f}' in '{f}'", .{ field_name.fmt(ip), child_type.fmt(pt), }); }, @@ -27524,7 +27531,7 @@ fn fieldPtr( } return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); }, - else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(pt)}), + else => return sema.fail(block, src, "type '{f}' has no members", .{child_type.fmt(pt)}), } }, .@"struct" => { @@ -27579,7 +27586,7 @@ fn fieldCallBind( const inner_ty = if (raw_ptr_ty.zigTypeTag(zcu) == .pointer and (raw_ptr_ty.ptrSize(zcu) == .one or raw_ptr_ty.ptrSize(zcu) == .c)) raw_ptr_ty.childType(zcu) else - return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(pt)}); + return sema.fail(block, raw_ptr_src, "expected single pointer, found '{f}'", .{raw_ptr_ty.fmt(pt)}); // Optionally dereference a second pointer to get the concrete type. const is_double_ptr = inner_ty.zigTypeTag(zcu) == .pointer and inner_ty.ptrSize(zcu) == .one; @@ -27698,7 +27705,7 @@ fn fieldCallBind( }; const msg = msg: { - const msg = try sema.errMsg(src, "no field or member function named '{}' in '{}'", .{ + const msg = try sema.errMsg(src, "no field or member function named '{f}' in '{f}'", .{ field_name.fmt(ip), concrete_ty.fmt(pt), }); @@ -27708,7 +27715,7 @@ fn fieldCallBind( try sema.errNote( zcu.navSrcLoc(nav_index), msg, - "'{}' is not a member function", + "'{f}' is not a member function", .{field_name.fmt(ip)}, ); } @@ -27776,7 +27783,7 @@ fn namespaceLookup( if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |lookup| { if (!lookup.accessible) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "'{}' is not marked 'pub'", .{ + const msg = try sema.errMsg(src, "'{f}' is not marked 'pub'", .{ decl_name.fmt(&zcu.intern_pool), }); errdefer msg.destroy(gpa); @@ -28014,12 +28021,12 @@ fn tupleFieldIndex( assert(!field_name.eqlSlice("len", ip)); if (field_name.toUnsigned(ip)) |field_index| { if (field_index < tuple_ty.structFieldCount(pt.zcu)) return field_index; - return sema.fail(block, field_name_src, "index '{}' out of bounds of tuple '{}'", .{ + return sema.fail(block, field_name_src, "index '{f}' out of bounds of tuple '{f}'", .{ field_name.fmt(ip), tuple_ty.fmt(pt), }); } - return sema.fail(block, field_name_src, "no field named '{}' in tuple '{}'", .{ + return sema.fail(block, field_name_src, "no field named '{f}' in tuple '{f}'", .{ field_name.fmt(ip), tuple_ty.fmt(pt), }); } @@ -28106,7 +28113,7 @@ fn unionFieldPtr( const msg = try sema.errMsg(src, "cannot initialize 'noreturn' field of union", .{}); errdefer msg.destroy(sema.gpa); - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{ + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{ field_name.fmt(ip), }); try sema.addDeclaredHereNote(msg, union_ty); @@ -28140,7 +28147,7 @@ fn unionFieldPtr( const msg = msg: { const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?; const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu); - const msg = try sema.errMsg(src, "access of union field '{}' while field '{}' is active", .{ + const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{ field_name.fmt(ip), active_field_name.fmt(ip), }); @@ -28208,7 +28215,7 @@ fn unionFieldVal( const msg = msg: { const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?; const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu); - const msg = try sema.errMsg(src, "access of union field '{}' while field '{}' is active", .{ + const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{ field_name.fmt(ip), active_field_name.fmt(ip), }); errdefer msg.destroy(sema.gpa); @@ -28266,7 +28273,7 @@ fn elemPtr( const indexable_ty = switch (indexable_ptr_ty.zigTypeTag(zcu)) { .pointer => indexable_ptr_ty.childType(zcu), - else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(pt)}), + else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{f}'", .{indexable_ptr_ty.fmt(pt)}), }; try sema.checkIndexable(block, src, indexable_ty); @@ -28437,7 +28444,7 @@ fn validateRuntimeElemAccess( const msg = msg: { const msg = try sema.errMsg( elem_index_src, - "values of type '{}' must be comptime-known, but index value is runtime-known", + "values of type '{f}' must be comptime-known, but index value is runtime-known", .{parent_ty.fmt(sema.pt)}, ); errdefer msg.destroy(sema.gpa); @@ -28453,7 +28460,7 @@ fn validateRuntimeElemAccess( const target = zcu.getTarget(); const as = parent_ty.ptrAddressSpace(zcu); if (target_util.arePointersLogical(target, as)) { - return sema.fail(block, elem_index_src, "cannot access element of logical pointer '{}'", .{parent_ty.fmt(pt)}); + return sema.fail(block, elem_index_src, "cannot access element of logical pointer '{f}'", .{parent_ty.fmt(pt)}); } } } @@ -29149,7 +29156,7 @@ fn coerceExtra( return sema.fail( block, inst_src, - "array literal requires address-of operator (&) to coerce to slice type '{}'", + "array literal requires address-of operator (&) to coerce to slice type '{f}'", .{dest_ty.fmt(pt)}, ); } @@ -29176,7 +29183,7 @@ fn coerceExtra( // pointer to tuple to slice if (!dest_info.flags.is_const) { const err_msg = err_msg: { - const err_msg = try sema.errMsg(inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(pt)}); + const err_msg = try sema.errMsg(inst_src, "cannot cast pointer to tuple to '{f}'", .{dest_ty.fmt(pt)}); errdefer err_msg.destroy(sema.gpa); try sema.errNote(dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{}); break :err_msg err_msg; @@ -29231,7 +29238,7 @@ fn coerceExtra( // comptime-known integer to other number if (!(try sema.intFitsInType(val, dest_ty, null))) { if (!opts.report_err) return error.NotCoercible; - return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) }); + return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) }); } return switch (zcu.intern_pool.indexToKey(val.toIntern())) { .undef => try pt.undefRef(dest_ty), @@ -29273,7 +29280,7 @@ fn coerceExtra( return sema.fail( block, inst_src, - "type '{}' cannot represent float value '{}'", + "type '{f}' cannot represent float value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) }, ); } @@ -29306,7 +29313,7 @@ fn coerceExtra( // return sema.fail( // block, // inst_src, - // "type '{}' cannot represent integer value '{}'", + // "type '{f}' cannot represent integer value '{}'", // .{ dest_ty.fmt(pt), val }, // ); //} @@ -29320,7 +29327,7 @@ fn coerceExtra( const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined); const string = zcu.intern_pool.indexToKey(val.toIntern()).enum_literal; const field_index = dest_ty.enumFieldIndex(string, zcu) orelse { - return sema.fail(block, inst_src, "no field named '{}' in enum '{}'", .{ + return sema.fail(block, inst_src, "no field named '{f}' in enum '{f}'", .{ string.fmt(&zcu.intern_pool), dest_ty.fmt(pt), }); }; @@ -29469,11 +29476,11 @@ fn coerceExtra( } const msg = msg: { - const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt) }); + const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt) }); errdefer msg.destroy(sema.gpa); if (!can_coerce_to) { - try sema.errNote(inst_src, msg, "cannot coerce to '{}'", .{dest_ty.fmt(pt)}); + try sema.errNote(inst_src, msg, "cannot coerce to '{f}'", .{dest_ty.fmt(pt)}); } // E!T to T @@ -29662,13 +29669,13 @@ const InMemoryCoercionResult = union(enum) { break; }, .comptime_int_not_coercible => |int| { - try sema.errNote(src, msg, "type '{}' cannot represent value '{}'", .{ + try sema.errNote(src, msg, "type '{f}' cannot represent value '{f}'", .{ int.wanted.fmt(pt), int.actual.fmtValueSema(pt, sema), }); break; }, .error_union_payload => |pair| { - try sema.errNote(src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{ + try sema.errNote(src, msg, "error union payload '{f}' cannot cast into error union payload '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; @@ -29681,18 +29688,18 @@ const InMemoryCoercionResult = union(enum) { }, .array_sentinel => |sentinel| { if (sentinel.actual.toIntern() != .unreachable_value) { - try sema.errNote(src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{ + try sema.errNote(src, msg, "array sentinel '{f}' cannot cast into array sentinel '{f}'", .{ sentinel.actual.fmtValueSema(pt, sema), sentinel.wanted.fmtValueSema(pt, sema), }); } else { - try sema.errNote(src, msg, "destination array requires '{}' sentinel", .{ + try sema.errNote(src, msg, "destination array requires '{f}' sentinel", .{ sentinel.wanted.fmtValueSema(pt, sema), }); } break; }, .array_elem => |pair| { - try sema.errNote(src, msg, "array element type '{}' cannot cast into array element type '{}'", .{ + try sema.errNote(src, msg, "array element type '{f}' cannot cast into array element type '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; @@ -29704,19 +29711,19 @@ const InMemoryCoercionResult = union(enum) { break; }, .vector_elem => |pair| { - try sema.errNote(src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{ + try sema.errNote(src, msg, "vector element type '{f}' cannot cast into vector element type '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; }, .optional_shape => |pair| { - try sema.errNote(src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ + try sema.errNote(src, msg, "optional type child '{f}' cannot cast into optional type child '{f}'", .{ pair.actual.optionalChild(pt.zcu).fmt(pt), pair.wanted.optionalChild(pt.zcu).fmt(pt), }); break; }, .optional_child => |pair| { - try sema.errNote(src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ + try sema.errNote(src, msg, "optional type child '{f}' cannot cast into optional type child '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; @@ -29727,7 +29734,7 @@ const InMemoryCoercionResult = union(enum) { }, .missing_error => |missing_errors| { for (missing_errors) |err| { - try sema.errNote(src, msg, "'error.{}' not a member of destination error set", .{err.fmt(&pt.zcu.intern_pool)}); + try sema.errNote(src, msg, "'error.{f}' not a member of destination error set", .{err.fmt(&pt.zcu.intern_pool)}); } break; }, @@ -29780,7 +29787,7 @@ const InMemoryCoercionResult = union(enum) { break; }, .fn_param => |param| { - try sema.errNote(src, msg, "parameter {d} '{}' cannot cast into '{}'", .{ + try sema.errNote(src, msg, "parameter {d} '{f}' cannot cast into '{f}'", .{ param.index, param.actual.fmt(pt), param.wanted.fmt(pt), }); cur = param.child; @@ -29790,13 +29797,13 @@ const InMemoryCoercionResult = union(enum) { break; }, .fn_return_type => |pair| { - try sema.errNote(src, msg, "return type '{}' cannot cast into return type '{}'", .{ + try sema.errNote(src, msg, "return type '{f}' cannot cast into return type '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; }, .ptr_child => |pair| { - try sema.errNote(src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{ + try sema.errNote(src, msg, "pointer type child '{f}' cannot cast into pointer type child '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; @@ -29807,11 +29814,11 @@ const InMemoryCoercionResult = union(enum) { }, .ptr_sentinel => |sentinel| { if (sentinel.actual.toIntern() != .unreachable_value) { - try sema.errNote(src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{ + try sema.errNote(src, msg, "pointer sentinel '{f}' cannot cast into pointer sentinel '{f}'", .{ sentinel.actual.fmtValueSema(pt, sema), sentinel.wanted.fmtValueSema(pt, sema), }); } else { - try sema.errNote(src, msg, "destination pointer requires '{}' sentinel", .{ + try sema.errNote(src, msg, "destination pointer requires '{f}' sentinel", .{ sentinel.wanted.fmtValueSema(pt, sema), }); } @@ -29825,11 +29832,11 @@ const InMemoryCoercionResult = union(enum) { const wanted_allow_zero = pair.wanted.ptrAllowsZero(pt.zcu); const actual_allow_zero = pair.actual.ptrAllowsZero(pt.zcu); if (actual_allow_zero and !wanted_allow_zero) { - try sema.errNote(src, msg, "'{}' could have null values which are illegal in type '{}'", .{ + try sema.errNote(src, msg, "'{f}' could have null values which are illegal in type '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); } else { - try sema.errNote(src, msg, "mutable '{}' would allow illegal null values stored to type '{}'", .{ + try sema.errNote(src, msg, "mutable '{f}' would allow illegal null values stored to type '{f}'", .{ pair.wanted.fmt(pt), pair.actual.fmt(pt), }); } @@ -29841,7 +29848,7 @@ const InMemoryCoercionResult = union(enum) { if (actual_const and !wanted_const) { try sema.errNote(src, msg, "cast discards const qualifier", .{}); } else { - try sema.errNote(src, msg, "mutable '{}' would allow illegal const pointers stored to type '{}'", .{ + try sema.errNote(src, msg, "mutable '{f}' would allow illegal const pointers stored to type '{f}'", .{ pair.wanted.fmt(pt), pair.actual.fmt(pt), }); } @@ -29853,7 +29860,7 @@ const InMemoryCoercionResult = union(enum) { if (actual_volatile and !wanted_volatile) { try sema.errNote(src, msg, "cast discards volatile qualifier", .{}); } else { - try sema.errNote(src, msg, "mutable '{}' would allow illegal volatile pointers stored to type '{}'", .{ + try sema.errNote(src, msg, "mutable '{f}' would allow illegal volatile pointers stored to type '{f}'", .{ pair.wanted.fmt(pt), pair.actual.fmt(pt), }); } @@ -29879,13 +29886,13 @@ const InMemoryCoercionResult = union(enum) { break; }, .double_ptr_to_anyopaque => |pair| { - try sema.errNote(src, msg, "cannot implicitly cast double pointer '{}' to anyopaque pointer '{}'", .{ + try sema.errNote(src, msg, "cannot implicitly cast double pointer '{f}' to anyopaque pointer '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); break; }, .slice_to_anyopaque => |pair| { - try sema.errNote(src, msg, "cannot implicitly cast slice '{}' to anyopaque pointer '{}'", .{ + try sema.errNote(src, msg, "cannot implicitly cast slice '{f}' to anyopaque pointer '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); try sema.errNote(src, msg, "consider using '.ptr'", .{}); @@ -30659,7 +30666,7 @@ fn coerceVarArgParam( const coerced_ty = sema.typeOf(coerced); if (!try sema.validateExternType(coerced_ty, .param_ty)) { const msg = msg: { - const msg = try sema.errMsg(inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(pt)}); + const msg = try sema.errMsg(inst_src, "cannot pass '{f}' to variadic function", .{coerced_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, inst_src, coerced_ty, .param_ty); @@ -30762,7 +30769,7 @@ fn storePtr2( // is not comptime-only. We can hit this case with a `@ptrFromInt` pointer. if (try elem_ty.comptimeOnlySema(pt)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "cannot store comptime-only type '{}' at runtime", .{elem_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(ptr_src, msg, "operation is runtime due to this pointer", .{}); break :msg msg; @@ -30795,7 +30802,7 @@ fn storePtr2( }); return; } - return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{ + return sema.fail(block, ptr_src, "unable to determine vector element index of type '{f}'", .{ ptr_ty.fmt(pt), }); } @@ -30964,19 +30971,19 @@ fn storePtrVal( .{}, ), .undef => return sema.failWithUseOfUndef(block, src), - .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {}", .{err_name.fmt(ip)}), + .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {f}", .{err_name.fmt(ip)}), .null_payload => return sema.fail(block, src, "attempt to use null value", .{}), .inactive_union_field => return sema.fail(block, src, "access of inactive union field", .{}), .needed_well_defined => |ty| return sema.fail( block, src, - "comptime dereference requires '{}' to have a well-defined layout", + "comptime dereference requires '{f}' to have a well-defined layout", .{ty.fmt(pt)}, ), .out_of_bounds => |ty| return sema.fail( block, src, - "dereference of '{}' exceeds bounds of containing decl of type '{}'", + "dereference of '{f}' exceeds bounds of containing decl of type '{f}'", .{ ptr_ty.fmt(pt), ty.fmt(pt) }, ), .exceeds_host_size => return sema.fail(block, src, "bit-pointer target exceeds host size", .{}), @@ -31002,7 +31009,7 @@ fn bitCast( const old_bits = old_ty.bitSize(zcu); if (old_bits != dest_bits) { - return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{ + return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{f}' has {d} bits but source type '{f}' has {d} bits", .{ dest_ty.fmt(pt), dest_bits, old_ty.fmt(pt), @@ -31120,7 +31127,7 @@ fn coerceCompatiblePtrs( const inst_ty = sema.typeOf(inst); if (try sema.resolveValue(inst)) |val| { if (!val.isUndef(zcu) and val.isNull(zcu) and !dest_ty.isAllowzeroPtr(zcu)) { - return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(pt)}); + return sema.fail(block, inst_src, "null pointer casted to type '{f}'", .{dest_ty.fmt(pt)}); } // The comptime Value representation is compatible with both types. return Air.internedToRef( @@ -31166,7 +31173,7 @@ fn coerceEnumToUnion( const tag_ty = union_ty.unionTagType(zcu) orelse { const msg = msg: { - const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{ + const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ union_ty.fmt(pt), inst_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -31180,7 +31187,7 @@ fn coerceEnumToUnion( const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src); if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| { const field_index = union_ty.unionTagFieldIndex(val, pt.zcu) orelse { - return sema.fail(block, inst_src, "union '{}' has no tag with value '{}'", .{ + return sema.fail(block, inst_src, "union '{f}' has no tag with value '{f}'", .{ union_ty.fmt(pt), val.fmtValueSema(pt, sema), }); }; @@ -31194,7 +31201,7 @@ fn coerceEnumToUnion( errdefer msg.destroy(sema.gpa); const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index]; - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{ + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{ field_name.fmt(ip), }); try sema.addDeclaredHereNote(msg, union_ty); @@ -31205,13 +31212,13 @@ fn coerceEnumToUnion( const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse { const msg = msg: { const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index]; - const msg = try sema.errMsg(inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{ + const msg = try sema.errMsg(inst_src, "coercion from enum '{f}' to union '{f}' must initialize '{f}' field '{f}'", .{ inst_ty.fmt(pt), union_ty.fmt(pt), field_ty.fmt(pt), field_name.fmt(ip), }); errdefer msg.destroy(sema.gpa); - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{ + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{ field_name.fmt(ip), }); try sema.addDeclaredHereNote(msg, union_ty); @@ -31227,7 +31234,7 @@ fn coerceEnumToUnion( if (tag_ty.isNonexhaustiveEnum(zcu)) { const msg = msg: { - const msg = try sema.errMsg(inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{ + const msg = try sema.errMsg(inst_src, "runtime coercion to union '{f}' from non-exhaustive enum", .{ union_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -31246,7 +31253,7 @@ fn coerceEnumToUnion( if (Type.fromInterned(field_ty).zigTypeTag(zcu) == .noreturn) { const err_msg = msg orelse try sema.errMsg( inst_src, - "runtime coercion from enum '{}' to union '{}' which has a 'noreturn' field", + "runtime coercion from enum '{f}' to union '{f}' which has a 'noreturn' field", .{ tag_ty.fmt(pt), union_ty.fmt(pt) }, ); msg = err_msg; @@ -31269,7 +31276,7 @@ fn coerceEnumToUnion( const msg = msg: { const msg = try sema.errMsg( inst_src, - "runtime coercion from enum '{}' to union '{}' which has non-void fields", + "runtime coercion from enum '{f}' to union '{f}' which has non-void fields", .{ tag_ty.fmt(pt), union_ty.fmt(pt) }, ); errdefer msg.destroy(sema.gpa); @@ -31278,7 +31285,7 @@ fn coerceEnumToUnion( const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index]; const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); if (!(try field_ty.hasRuntimeBitsSema(pt))) continue; - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' has type '{}'", .{ + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' has type '{f}'", .{ field_name.fmt(ip), field_ty.fmt(pt), }); @@ -31319,7 +31326,7 @@ fn coerceArrayLike( const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(zcu)); if (dest_len != inst_len) { const msg = msg: { - const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{ + const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -31407,7 +31414,7 @@ fn coerceTupleToArray( if (dest_len != inst_len) { const msg = msg: { - const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{ + const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -31883,10 +31890,10 @@ fn analyzeLoad( const ptr_ty = sema.typeOf(ptr); const elem_ty = switch (ptr_ty.zigTypeTag(zcu)) { .pointer => ptr_ty.childType(zcu), - else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(pt)}), + else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)}), }; if (elem_ty.zigTypeTag(zcu) == .@"opaque") { - return sema.fail(block, ptr_src, "cannot load opaque type '{}'", .{elem_ty.fmt(pt)}); + return sema.fail(block, ptr_src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}); } if (try sema.typeHasOnePossibleValue(elem_ty)) |opv| { @@ -31907,7 +31914,7 @@ fn analyzeLoad( const bin_op = sema.getTmpAir().extraData(Air.Bin, ty_pl.payload).data; return block.addBinOp(.ptr_elem_val, bin_op.lhs, bin_op.rhs); } - return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{ + return sema.fail(block, ptr_src, "unable to determine vector element index of type '{f}'", .{ ptr_ty.fmt(pt), }); } @@ -32195,7 +32202,7 @@ fn analyzeSlice( const ptr_ptr_ty = sema.typeOf(ptr_ptr); const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag(zcu)) { .pointer => ptr_ptr_ty.childType(zcu), - else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(pt)}), + else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ptr_ty.fmt(pt)}), }; var array_ty = ptr_ptr_child_ty; @@ -32244,7 +32251,7 @@ fn analyzeSlice( try sema.errNote( start_src, msg, - "expected '{}', found '{}'", + "expected '{f}', found '{f}'", .{ Value.zero_comptime_int.fmtValueSema(pt, sema), start_value.fmtValueSema(pt, sema), @@ -32260,7 +32267,7 @@ fn analyzeSlice( try sema.errNote( end_src, msg, - "expected '{}', found '{}'", + "expected '{f}', found '{f}'", .{ Value.one_comptime_int.fmtValueSema(pt, sema), end_value.fmtValueSema(pt, sema), @@ -32275,7 +32282,7 @@ fn analyzeSlice( return sema.fail( block, end_src, - "end index {} out of bounds for slice of single-item pointer", + "end index {f} out of bounds for slice of single-item pointer", .{end_value.fmtValueSema(pt, sema)}, ); } @@ -32322,7 +32329,7 @@ fn analyzeSlice( elem_ty = ptr_ptr_child_ty.childType(zcu); }, }, - else => return sema.fail(block, src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(pt)}), + else => return sema.fail(block, src, "slice of non-array type '{f}'", .{ptr_ptr_child_ty.fmt(pt)}), } const ptr = if (slice_ty.isSlice(zcu)) @@ -32369,7 +32376,7 @@ fn analyzeSlice( return sema.fail( block, end_src, - "end index {} out of bounds for array of length {}{s}", + "end index {f} out of bounds for array of length {f}{s}", .{ end_val.fmtValueSema(pt, sema), len_val.fmtValueSema(pt, sema), @@ -32414,7 +32421,7 @@ fn analyzeSlice( return sema.fail( block, end_src, - "end index {} out of bounds for slice of length {d}{s}", + "end index {f} out of bounds for slice of length {d}{s}", .{ end_val.fmtValueSema(pt, sema), try slice_val.sliceLen(pt), @@ -32473,7 +32480,7 @@ fn analyzeSlice( return sema.fail( block, start_src, - "start index {} is larger than end index {}", + "start index {f} is larger than end index {f}", .{ start_val.fmtValueSema(pt, sema), end_val.fmtValueSema(pt, sema), @@ -32497,13 +32504,13 @@ fn analyzeSlice( .needed_well_defined => |ty| return sema.fail( block, src, - "comptime dereference requires '{}' to have a well-defined layout", + "comptime dereference requires '{f}' to have a well-defined layout", .{ty.fmt(pt)}, ), .out_of_bounds => |ty| return sema.fail( block, end_src, - "slice end index {d} exceeds bounds of containing decl of type '{}'", + "slice end index {d} exceeds bounds of containing decl of type '{f}'", .{ end_int, ty.fmt(pt) }, ), }; @@ -32512,7 +32519,7 @@ fn analyzeSlice( const msg = msg: { const msg = try sema.errMsg(src, "value in memory does not match slice sentinel", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(src, msg, "expected '{}', found '{}'", .{ + try sema.errNote(src, msg, "expected '{f}', found '{f}'", .{ expected_sentinel.fmtValueSema(pt, sema), actual_sentinel.fmtValueSema(pt, sema), }); @@ -33400,7 +33407,7 @@ const PeerResolveResult = union(enum) { }; }, .field_error => |field_error| { - const fmt = "struct field '{}' has conflicting types"; + const fmt = "struct field '{f}' has conflicting types"; const args = .{field_error.field_name.fmt(&pt.zcu.intern_pool)}; if (opt_msg) |msg| { try sema.errNote(src, msg, fmt, args); @@ -33431,7 +33438,7 @@ const PeerResolveResult = union(enum) { candidate_srcs.resolve(block, conflict_idx[1]), }; - const fmt = "incompatible types: '{}' and '{}'"; + const fmt = "incompatible types: '{f}' and '{f}'"; const args = .{ conflict_tys[0].fmt(pt), conflict_tys[1].fmt(pt), @@ -33445,8 +33452,8 @@ const PeerResolveResult = union(enum) { break :msg msg; }; - if (conflict_srcs[0]) |src_loc| try sema.errNote(src_loc, msg, "type '{}' here", .{conflict_tys[0].fmt(pt)}); - if (conflict_srcs[1]) |src_loc| try sema.errNote(src_loc, msg, "type '{}' here", .{conflict_tys[1].fmt(pt)}); + if (conflict_srcs[0]) |src_loc| try sema.errNote(src_loc, msg, "type '{f}' here", .{conflict_tys[0].fmt(pt)}); + if (conflict_srcs[1]) |src_loc| try sema.errNote(src_loc, msg, "type '{f}' here", .{conflict_tys[1].fmt(pt)}); // No child error break; @@ -34758,7 +34765,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { if (struct_type.setLayoutWip(ip)) { const msg = try sema.errMsg( ty.srcLoc(zcu), - "struct '{}' depends on itself", + "struct '{f}' depends on itself", .{ty.fmt(pt)}, ); return sema.failWithOwnedErrorMsg(null, msg); @@ -34977,13 +34984,13 @@ fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ const zcu = pt.zcu; if (!backing_int_ty.isInt(zcu)) { - return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(pt)}); + return sema.fail(block, src, "expected backing integer type, found '{f}'", .{backing_int_ty.fmt(pt)}); } if (backing_int_ty.bitSize(zcu) != fields_bit_sum) { return sema.fail( block, src, - "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}", + "backing integer type '{f}' has bit size {} but the struct fields have a total bit size of {}", .{ backing_int_ty.fmt(pt), backing_int_ty.bitSize(zcu), fields_bit_sum }, ); } @@ -34993,7 +35000,7 @@ fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { const pt = sema.pt; if (!ty.isIndexable(pt.zcu)) { const msg = msg: { - const msg = try sema.errMsg(src, "type '{}' does not support indexing", .{ty.fmt(pt)}); + const msg = try sema.errMsg(src, "type '{f}' does not support indexing", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "operand must be an array, slice, tuple, or vector", .{}); break :msg msg; @@ -35017,7 +35024,7 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void } } const msg = msg: { - const msg = try sema.errMsg(src, "type '{}' is not an indexable pointer", .{ty.fmt(pt)}); + const msg = try sema.errMsg(src, "type '{f}' is not an indexable pointer", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "operand must be a slice, a many pointer or a pointer to an array", .{}); break :msg msg; @@ -35085,7 +35092,7 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void { .field_types_wip, .layout_wip => { const msg = try sema.errMsg( ty.srcLoc(pt.zcu), - "union '{}' depends on itself", + "union '{f}' depends on itself", .{ty.fmt(pt)}, ); return sema.failWithOwnedErrorMsg(null, msg); @@ -35273,7 +35280,7 @@ pub fn resolveStructFieldTypes( if (struct_type.setFieldTypesWip(ip)) { const msg = try sema.errMsg( Type.fromInterned(ty).srcLoc(zcu), - "struct '{}' depends on itself", + "struct '{f}' depends on itself", .{Type.fromInterned(ty).fmt(pt)}, ); return sema.failWithOwnedErrorMsg(null, msg); @@ -35302,7 +35309,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void { if (struct_type.setInitsWip(ip)) { const msg = try sema.errMsg( ty.srcLoc(zcu), - "struct '{}' depends on itself", + "struct '{f}' depends on itself", .{ty.fmt(pt)}, ); return sema.failWithOwnedErrorMsg(null, msg); @@ -35328,7 +35335,7 @@ pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.Load .field_types_wip => { const msg = try sema.errMsg( ty.srcLoc(zcu), - "union '{}' depends on itself", + "union '{f}' depends on itself", .{ty.fmt(pt)}, ); return sema.failWithOwnedErrorMsg(null, msg); @@ -35698,7 +35705,7 @@ fn structFields( switch (struct_type.layout) { .@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) { const msg = msg: { - const msg = try sema.errMsg(ty_src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .struct_field); @@ -35710,7 +35717,7 @@ fn structFields( }, .@"packed" => if (!try sema.validatePackedType(field_ty)) { const msg = msg: { - const msg = try sema.errMsg(ty_src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty); @@ -35957,7 +35964,7 @@ fn unionFields( // The provided type is an integer type and we must construct the enum tag type here. int_tag_ty = provided_ty; if (int_tag_ty.zigTypeTag(zcu) != .int and int_tag_ty.zigTypeTag(zcu) != .comptime_int) { - return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(pt)}); + return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{f}'", .{int_tag_ty.fmt(pt)}); } if (fields_len > 0) { @@ -35966,7 +35973,7 @@ fn unionFields( const msg = msg: { const msg = try sema.errMsg(tag_ty_src, "specified integer tag type cannot represent every field", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(tag_ty_src, msg, "type '{}' cannot fit values in range 0...{d}", .{ + try sema.errNote(tag_ty_src, msg, "type '{f}' cannot fit values in range 0...{d}", .{ int_tag_ty.fmt(pt), fields_len - 1, }); @@ -35981,7 +35988,7 @@ fn unionFields( // The provided type is the enum tag type. const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) { .enum_type => ip.loadEnumType(provided_ty.toIntern()), - else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{provided_ty.fmt(pt)}), + else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{f}'", .{provided_ty.fmt(pt)}), }; union_type.setTagType(ip, provided_ty.toIntern()); // The fields of the union must match the enum exactly. @@ -36078,7 +36085,7 @@ fn unionFields( if (result.overflow) return sema.fail( &block_scope, value_src, - "enumeration value '{}' too large for type '{}'", + "enumeration value '{f}' too large for type '{f}'", .{ result.val.fmtValueSema(pt, sema), int_tag_ty.fmt(pt) }, ); last_tag_val = result.val; @@ -36096,7 +36103,7 @@ fn unionFields( const msg = msg: { const msg = try sema.errMsg( value_src, - "enum tag value {} already taken", + "enum tag value {f} already taken", .{enum_tag_val.fmtValueSema(pt, sema)}, ); errdefer msg.destroy(gpa); @@ -36124,7 +36131,7 @@ fn unionFields( const tag_ty = union_type.tagTypeUnordered(ip); const tag_info = ip.loadEnumType(tag_ty); const enum_index = tag_info.nameIndex(ip, field_name) orelse { - return sema.fail(&block_scope, name_src, "no field named '{}' in enum '{}'", .{ + return sema.fail(&block_scope, name_src, "no field named '{f}' in enum '{f}'", .{ field_name.fmt(ip), Type.fromInterned(tag_ty).fmt(pt), }); }; @@ -36141,7 +36148,7 @@ fn unionFields( .base_node_inst = Type.fromInterned(tag_ty).typeDeclInstAllowGeneratedTag(zcu).?, .offset = .{ .container_field_name = enum_index }, }; - const msg = try sema.errMsg(name_src, "union field '{}' ordered differently than corresponding enum field", .{ + const msg = try sema.errMsg(name_src, "union field '{f}' ordered differently than corresponding enum field", .{ field_name.fmt(ip), }); errdefer msg.destroy(sema.gpa); @@ -36167,7 +36174,7 @@ fn unionFields( !try sema.validateExternType(field_ty, .union_field)) { const msg = msg: { - const msg = try sema.errMsg(type_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(type_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, type_src, field_ty, .union_field); @@ -36178,7 +36185,7 @@ fn unionFields( return sema.failWithOwnedErrorMsg(&block_scope, msg); } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) { const msg = msg: { - const msg = try sema.errMsg(type_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(type_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotPacked(msg, type_src, field_ty); @@ -36214,7 +36221,7 @@ fn unionFields( for (tag_info.names.get(ip), 0..) |field_name, field_index| { if (explicit_tags_seen[field_index]) continue; - try sema.addFieldErrNote(.fromInterned(tag_ty), field_index, msg, "field '{}' missing, declared here", .{ + try sema.addFieldErrNote(.fromInterned(tag_ty), field_index, msg, "field '{f}' missing, declared here", .{ field_name.fmt(ip), }); } @@ -36250,7 +36257,7 @@ fn generateUnionTagTypeNumbered( const name = try ip.getOrPutStringFmt( gpa, pt.tid, - "@typeInfo({}).@\"union\".tag_type.?", + "@typeInfo({f}).@\"union\".tag_type.?", .{union_name.fmt(ip)}, .no_embedded_nulls, ); @@ -36286,7 +36293,7 @@ fn generateUnionTagTypeSimple( const name = try ip.getOrPutStringFmt( gpa, pt.tid, - "@typeInfo({}).@\"union\".tag_type.?", + "@typeInfo({f}).@\"union\".tag_type.?", .{union_name.fmt(ip)}, .no_embedded_nulls, ); @@ -36820,13 +36827,13 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr .needed_well_defined => |ty| return sema.fail( block, src, - "comptime dereference requires '{}' to have a well-defined layout", + "comptime dereference requires '{f}' to have a well-defined layout", .{ty.fmt(pt)}, ), .out_of_bounds => |ty| return sema.fail( block, src, - "dereference of '{}' exceeds bounds of containing decl of type '{}'", + "dereference of '{f}' exceeds bounds of containing decl of type '{f}'", .{ ptr_ty.fmt(pt), ty.fmt(pt) }, ), } @@ -36846,7 +36853,7 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value .success => |mv| return .{ .val = try mv.intern(pt, sema.arena) }, .runtime_load => return .runtime_load, .undef => return sema.failWithUseOfUndef(block, src), - .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {}", .{err_name.fmt(ip)}), + .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {f}", .{err_name.fmt(ip)}), .null_payload => return sema.fail(block, src, "attempt to use null value", .{}), .inactive_union_field => return sema.fail(block, src, "access of inactive union field", .{}), .needed_well_defined => |ty| return .{ .needed_well_defined = ty }, @@ -36971,12 +36978,12 @@ fn intFromFloatScalar( const float = val.toFloat(f128, zcu); if (std.math.isNan(float)) { - return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{ + return sema.fail(block, src, "float value NaN cannot be stored in integer type '{f}'", .{ int_ty.fmt(pt), }); } if (std.math.isInf(float)) { - return sema.fail(block, src, "float value Inf cannot be stored in integer type '{}'", .{ + return sema.fail(block, src, "float value Inf cannot be stored in integer type '{f}'", .{ int_ty.fmt(pt), }); } @@ -36991,7 +36998,7 @@ fn intFromFloatScalar( .exact => return sema.fail( block, src, - "fractional component prevents float value '{}' from coercion to type '{}'", + "fractional component prevents float value '{f}' from coercion to type '{f}'", .{ val.fmtValueSema(pt, sema), int_ty.fmt(pt) }, ), .truncate => {}, @@ -37003,7 +37010,7 @@ fn intFromFloatScalar( const int_info = int_ty.intInfo(zcu); if (!big_int.toConst().fitsInTwosComp(int_info.signedness, int_info.bits)) { - return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{ + return sema.fail(block, src, "float value '{f}' cannot be stored in integer type '{f}'", .{ val.fmtValueSema(pt, sema), int_ty.fmt(pt), }); } @@ -37335,9 +37342,9 @@ fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc, var first_path: std.ArrayListUnmanaged(u8) = .empty; if (intermediate_value_count == 0) { - try first_path.writer(arena).print("{i}", .{start_value_name.fmt(ip)}); + try first_path.print(arena, "{fi}", .{start_value_name.fmt(ip)}); } else { - try first_path.writer(arena).print("v{}", .{intermediate_value_count - 1}); + try first_path.print(arena, "v{}", .{intermediate_value_count - 1}); } const comptime_ptr = try sema.notePathToComptimeAllocPtrInner(val, &first_path); @@ -37362,30 +37369,26 @@ fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc, error.AnalysisFail => unreachable, }; - var second_path: std.ArrayListUnmanaged(u8) = .empty; + var second_path_aw: std.io.AllocatingWriter = undefined; + second_path_aw.init(arena); const inter_name = try std.fmt.allocPrint(arena, "v{d}", .{intermediate_value_count}); const deriv_start = @import("print_value.zig").printPtrDerivation( derivation, - second_path.writer(arena), + &second_path_aw.buffered_writer, pt, .lvalue, .{ .str = inter_name }, 20, - ) catch |err| switch (err) { - error.OutOfMemory => |e| return e, - error.AnalysisFail => unreachable, - error.ComptimeReturn => unreachable, - error.ComptimeBreak => unreachable, - }; + ) catch |err| return @errorCast(err); switch (deriv_start) { .int, .nav_ptr => unreachable, .uav_ptr => |uav| { - try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items }); + try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path_aw.getWritten() }); return .{ .new_val = .fromInterned(uav.val) }; }, .comptime_alloc_ptr => |cta_info| { - try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items }); + try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path_aw.getWritten() }); const cta = sema.getComptimeAlloc(cta_info.idx); if (cta.is_const) { return .{ .new_val = cta_info.val }; @@ -37395,7 +37398,7 @@ fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc, } }, .comptime_field_ptr => { - try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items }); + try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path_aw.getWritten() }); try sema.errNote(src, msg, "'{s}' is a comptime field", .{inter_name}); return .done; }, @@ -37435,7 +37438,7 @@ fn notePathToComptimeAllocPtrInner(sema: *Sema, val: Value, path: *std.ArrayList const backing_enum = union_ty.unionTagTypeHypothetical(zcu); const field_idx = backing_enum.enumTagFieldIndex(.fromInterned(un.tag), zcu).?; const field_name = backing_enum.enumFieldName(field_idx, zcu); - try path.writer(arena).print(".{i}", .{field_name.fmt(ip)}); + try path.print(arena, ".{fi}", .{field_name.fmt(ip)}); return sema.notePathToComptimeAllocPtrInner(.fromInterned(un.val), path); }, .aggregate => |agg| { @@ -37450,17 +37453,17 @@ fn notePathToComptimeAllocPtrInner(sema: *Sema, val: Value, path: *std.ArrayList }; const agg_ty: Type = .fromInterned(agg.ty); switch (agg_ty.zigTypeTag(zcu)) { - .array, .vector => try path.writer(arena).print("[{d}]", .{elem_idx}), + .array, .vector => try path.print(arena, "[{d}]", .{elem_idx}), .pointer => switch (elem_idx) { Value.slice_ptr_index => try path.appendSlice(arena, ".ptr"), Value.slice_len_index => try path.appendSlice(arena, ".len"), else => unreachable, }, .@"struct" => if (agg_ty.isTuple(zcu)) { - try path.writer(arena).print("[{d}]", .{elem_idx}); + try path.print(arena, "[{d}]", .{elem_idx}); } else { const name = agg_ty.structFieldName(elem_idx, zcu).unwrap().?; - try path.writer(arena).print(".{i}", .{name.fmt(ip)}); + try path.print(arena, ".{fi}", .{name.fmt(ip)}); }, else => unreachable, } @@ -37737,7 +37740,7 @@ fn resolveDeclaredEnumInner( if (tag_type_ref != .none) { const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref); if (ty.zigTypeTag(zcu) != .int and ty.zigTypeTag(zcu) != .comptime_int) { - return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(pt)}); + return sema.fail(block, tag_ty_src, "expected integer tag type, found '{f}'", .{ty.fmt(pt)}); } break :ty ty; } else if (fields_len == 0) { @@ -37791,7 +37794,7 @@ fn resolveDeclaredEnumInner( .offset = .{ .container_field_value = conflict.prev_field_idx }, }; const msg = msg: { - const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); + const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); errdefer msg.destroy(gpa); try sema.errNote(other_field_src, msg, "other occurrence here", .{}); break :msg msg; @@ -37814,7 +37817,7 @@ fn resolveDeclaredEnumInner( .offset = .{ .container_field_value = conflict.prev_field_idx }, }; const msg = msg: { - const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); + const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); errdefer msg.destroy(gpa); try sema.errNote(other_field_src, msg, "other occurrence here", .{}); break :msg msg; @@ -37831,7 +37834,7 @@ fn resolveDeclaredEnumInner( }; if (tag_overflow) { - const msg = try sema.errMsg(value_src, "enumeration value '{}' too large for type '{}'", .{ + const msg = try sema.errMsg(value_src, "enumeration value '{f}' too large for type '{f}'", .{ last_tag_val.?.fmtValueSema(pt, sema), int_tag_ty.fmt(pt), }); return sema.failWithOwnedErrorMsg(block, msg); diff --git a/src/Sema/LowerZon.zig b/src/Sema/LowerZon.zig index 9bd876082f..cdbec43405 100644 --- a/src/Sema/LowerZon.zig +++ b/src/Sema/LowerZon.zig @@ -338,7 +338,7 @@ fn failUnsupportedResultType( const gpa = sema.gpa; const pt = sema.pt; return sema.failWithOwnedErrorMsg(self.block, msg: { - const msg = try sema.errMsg(self.import_loc, "type '{}' is not available in ZON", .{ty.fmt(pt)}); + const msg = try sema.errMsg(self.import_loc, "type '{f}' is not available in ZON", .{ty.fmt(pt)}); errdefer msg.destroy(gpa); if (opt_note) |n| try sema.errNote(self.import_loc, msg, "{s}", .{n}); break :msg msg; @@ -362,7 +362,7 @@ fn lowerExprKnownResTy(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) Com return self.lowerExprKnownResTyInner(node, res_ty) catch |err| switch (err) { error.WrongType => return self.fail( node, - "expected type '{}'", + "expected type '{f}'", .{res_ty.fmt(pt)}, ), else => |e| return e, @@ -428,7 +428,7 @@ fn lowerExprKnownResTyInner( .frame, .@"anyframe", .void, - => return self.fail(node, "type '{}' not available in ZON", .{res_ty.fmt(pt)}), + => return self.fail(node, "type '{f}' not available in ZON", .{res_ty.fmt(pt)}), } } @@ -458,7 +458,7 @@ fn lowerInt( // If lhs is unsigned and rhs is less than 0, we're out of bounds if (lhs_info.signedness == .unsigned and rhs < 0) return self.fail( node, - "type '{}' cannot represent integer value '{}'", + "type '{f}' cannot represent integer value '{}'", .{ res_ty.fmt(self.sema.pt), rhs }, ); @@ -478,7 +478,7 @@ fn lowerInt( if (rhs < min_int or rhs > max_int) { return self.fail( node, - "type '{}' cannot represent integer value '{}'", + "type '{f}' cannot represent integer value '{}'", .{ res_ty.fmt(self.sema.pt), rhs }, ); } @@ -496,7 +496,7 @@ fn lowerInt( if (!val.fitsInTwosComp(int_info.signedness, int_info.bits)) { return self.fail( node, - "type '{}' cannot represent integer value '{}'", + "type '{f}' cannot represent integer value '{f}'", .{ res_ty.fmt(self.sema.pt), val }, ); } @@ -517,7 +517,7 @@ fn lowerInt( switch (big_int.setFloat(val, .trunc)) { .inexact => return self.fail( node, - "fractional component prevents float value '{}' from coercion to type '{}'", + "fractional component prevents float value '{}' from coercion to type '{f}'", .{ val, res_ty.fmt(self.sema.pt) }, ), .exact => {}, @@ -528,7 +528,7 @@ fn lowerInt( if (!big_int.toConst().fitsInTwosComp(int_info.signedness, int_info.bits)) { return self.fail( node, - "type '{}' cannot represent integer value '{}'", + "type '{}' cannot represent integer value '{f}'", .{ val, res_ty.fmt(self.sema.pt) }, ); } @@ -550,7 +550,7 @@ fn lowerInt( if (val >= out_of_range) { return self.fail( node, - "type '{}' cannot represent integer value '{}'", + "type '{f}' cannot represent integer value '{}'", .{ res_ty.fmt(self.sema.pt), val }, ); } @@ -584,7 +584,7 @@ fn lowerFloat( .pos_inf => b: { if (res_ty.toIntern() == .comptime_float_type) return self.fail( node, - "expected type '{}'", + "expected type '{f}'", .{res_ty.fmt(self.sema.pt)}, ); break :b try self.sema.pt.floatValue(res_ty, std.math.inf(f128)); @@ -592,7 +592,7 @@ fn lowerFloat( .neg_inf => b: { if (res_ty.toIntern() == .comptime_float_type) return self.fail( node, - "expected type '{}'", + "expected type '{f}'", .{res_ty.fmt(self.sema.pt)}, ); break :b try self.sema.pt.floatValue(res_ty, -std.math.inf(f128)); @@ -600,7 +600,7 @@ fn lowerFloat( .nan => b: { if (res_ty.toIntern() == .comptime_float_type) return self.fail( node, - "expected type '{}'", + "expected type '{f}'", .{res_ty.fmt(self.sema.pt)}, ); break :b try self.sema.pt.floatValue(res_ty, std.math.nan(f128)); @@ -661,7 +661,7 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I const field_index = res_ty.enumFieldIndex(field_name_interned, self.sema.pt.zcu) orelse { return self.fail( node, - "enum {} has no member named '{}'", + "enum {f} has no member named '{f}'", .{ res_ty.fmt(self.sema.pt), std.zig.fmtId(field_name.get(self.file.zoir.?)), @@ -795,7 +795,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool const field_node = fields.vals.at(@intCast(i)); const name_index = struct_info.nameIndex(ip, field_name) orelse { - return self.fail(field_node, "unexpected field '{}'", .{field_name.fmt(ip)}); + return self.fail(field_node, "unexpected field '{f}'", .{field_name.fmt(ip)}); }; const field_type: Type = .fromInterned(struct_info.field_types.get(ip)[name_index]); @@ -816,7 +816,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool const field_names = struct_info.field_names.get(ip); for (field_values, field_names) |*value, name| { - if (value.* == .none) return self.fail(node, "missing field '{}'", .{name.fmt(ip)}); + if (value.* == .none) return self.fail(node, "missing field '{f}'", .{name.fmt(ip)}); } return self.sema.pt.intern(.{ .aggregate = .{ @@ -934,7 +934,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool. .struct_literal => b: { const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) { .struct_literal => |fields| fields, - else => return self.fail(node, "expected type '{}'", .{res_ty.fmt(self.sema.pt)}), + else => return self.fail(node, "expected type '{f}'", .{res_ty.fmt(self.sema.pt)}), }; if (fields.names.len != 1) { return error.WrongType; diff --git a/src/Type.zig b/src/Type.zig index db09ed94ac..34a06f2485 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -142,9 +142,9 @@ const FormatContext = struct { pt: Zcu.PerThread, }; -fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime f: []const u8) anyerror!usize { +fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime f: []const u8) anyerror!void { comptime assert(f.len == 0); - return print(ctx.ty, bw, ctx.pt); + try print(ctx.ty, bw, ctx.pt); } pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) { @@ -153,20 +153,14 @@ pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) { /// This is a debug function. In order to print types in a meaningful way /// we also need access to the module. -pub fn dump( - start_type: Type, - comptime unused_format_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { - _ = options; +pub fn dump(start_type: Type, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) anyerror!void { comptime assert(unused_format_string.len == 0); - return writer.print("{any}", .{start_type.ip_index}); + return bw.print("{any}", .{start_type.ip_index}); } /// Prints a name suitable for `@typeName`. /// TODO: take an `opt_sema` to pass to `fmtValue` when printing sentinels. -pub fn print(ty: Type, bw: *std.io.BufferedWriter, pt: Zcu.PerThread) anyerror!usize { +pub fn print(ty: Type, bw: *std.io.BufferedWriter, pt: Zcu.PerThread) anyerror!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; switch (ip.indexToKey(ty.toIntern())) { @@ -176,23 +170,22 @@ pub fn print(ty: Type, bw: *std.io.BufferedWriter, pt: Zcu.PerThread) anyerror!u .signed => 'i', .unsigned => 'u', }; - return bw.print("{c}{d}", .{ sign_char, int_type.bits }); + try bw.print("{c}{d}", .{ sign_char, int_type.bits }); }, .ptr_type => { - var n: usize = 0; const info = ty.ptrInfo(zcu); if (info.sentinel != .none) switch (info.flags.size) { .one, .c => unreachable, - .many => n += try bw.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(pt)}), - .slice => n += try bw.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(pt)}), + .many => try bw.print("[*:{f}]", .{Value.fromInterned(info.sentinel).fmtValue(pt)}), + .slice => try bw.print("[:{f}]", .{Value.fromInterned(info.sentinel).fmtValue(pt)}), } else switch (info.flags.size) { - .one => n += try bw.writeAll("*"), - .many => n += try bw.writeAll("[*]"), - .c => n += try bw.writeAll("[*c]"), - .slice => n += try bw.writeAll("[]"), + .one => try bw.writeAll("*"), + .many => try bw.writeAll("[*]"), + .c => try bw.writeAll("[*c]"), + .slice => try bw.writeAll("[]"), } - if (info.flags.is_allowzero and info.flags.size != .c) n += try bw.writeAll("allowzero "); + if (info.flags.is_allowzero and info.flags.size != .c) try bw.writeAll("allowzero "); if (info.flags.alignment != .none or info.packed_offset.host_size != 0 or info.flags.vector_index != .none) @@ -201,83 +194,72 @@ pub fn print(ty: Type, bw: *std.io.BufferedWriter, pt: Zcu.PerThread) anyerror!u info.flags.alignment else Type.fromInterned(info.child).abiAlignment(pt.zcu); - n += try bw.print("align({d}", .{alignment.toByteUnits() orelse 0}); + try bw.print("align({d}", .{alignment.toByteUnits() orelse 0}); if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) { - n += try bw.print(":{d}:{d}", .{ + try bw.print(":{d}:{d}", .{ info.packed_offset.bit_offset, info.packed_offset.host_size, }); } if (info.flags.vector_index == .runtime) { - n += try bw.writeAll(":?"); + try bw.writeAll(":?"); } else if (info.flags.vector_index != .none) { - n += try bw.print(":{d}", .{@intFromEnum(info.flags.vector_index)}); + try bw.print(":{d}", .{@intFromEnum(info.flags.vector_index)}); } - n += try bw.writeAll(") "); + try bw.writeAll(") "); } if (info.flags.address_space != .generic) { - n += try bw.print("addrspace(.{s}) ", .{@tagName(info.flags.address_space)}); + try bw.print("addrspace(.{s}) ", .{@tagName(info.flags.address_space)}); } - if (info.flags.is_const) n += try bw.writeAll("const "); - if (info.flags.is_volatile) n += try bw.writeAll("volatile "); + if (info.flags.is_const) try bw.writeAll("const "); + if (info.flags.is_volatile) try bw.writeAll("volatile "); - n += try print(Type.fromInterned(info.child), bw, pt); - return n; + try print(Type.fromInterned(info.child), bw, pt); }, .array_type => |array_type| { - var n: usize = 0; if (array_type.sentinel == .none) { - n += try bw.print("[{d}]", .{array_type.len}); - n += try print(Type.fromInterned(array_type.child), bw, pt); + try bw.print("[{d}]", .{array_type.len}); + try print(Type.fromInterned(array_type.child), bw, pt); } else { - n += try bw.print("[{d}:{}]", .{ + try bw.print("[{d}:{f}]", .{ array_type.len, Value.fromInterned(array_type.sentinel).fmtValue(pt), }); - n += try print(Type.fromInterned(array_type.child), bw, pt); + try print(Type.fromInterned(array_type.child), bw, pt); } - return n; }, .vector_type => |vector_type| { - var n: usize = 0; - n += try bw.print("@Vector({d}, ", .{vector_type.len}); - n += try print(Type.fromInterned(vector_type.child), bw, pt); - n += try bw.writeAll(")"); - return n; + try bw.print("@Vector({d}, ", .{vector_type.len}); + try print(Type.fromInterned(vector_type.child), bw, pt); + try bw.writeAll(")"); }, .opt_type => |child| { - var n: usize = 0; - n += try bw.writeByte('?'); - n += try print(Type.fromInterned(child), bw, pt); - return n; + try bw.writeByte('?'); + try print(Type.fromInterned(child), bw, pt); }, .error_union_type => |error_union_type| { - var n: usize = 0; - n += try print(Type.fromInterned(error_union_type.error_set_type), bw, pt); - n += try bw.writeByte('!'); + try print(Type.fromInterned(error_union_type.error_set_type), bw, pt); + try bw.writeByte('!'); if (error_union_type.payload_type == .generic_poison_type) { - n += try bw.writeAll("anytype"); + try bw.writeAll("anytype"); } else { - n += try print(Type.fromInterned(error_union_type.payload_type), bw, pt); + try print(Type.fromInterned(error_union_type.payload_type), bw, pt); } - return n; }, .inferred_error_set_type => |func_index| { const func_nav = ip.getNav(zcu.funcInfo(func_index).owner_nav); - return bw.print("@typeInfo(@typeInfo(@TypeOf({})).@\"fn\".return_type.?).error_union.error_set", .{ + return bw.print("@typeInfo(@typeInfo(@TypeOf({f})).@\"fn\".return_type.?).error_union.error_set", .{ func_nav.fqn.fmt(ip), }); }, .error_set_type => |error_set_type| { - var n: usize = 0; const names = error_set_type.names; - n += try bw.writeAll("error{"); + try bw.writeAll("error{"); for (names.get(ip), 0..) |name, i| { - if (i != 0) n += try bw.writeByte(','); - n += try bw.print("{}", .{name.fmt(ip)}); + if (i != 0) try bw.writeByte(','); + try bw.print("{f}", .{name.fmt(ip)}); } - n += try bw.writeAll("}"); - return n; + try bw.writeAll("}"); }, .simple_type => |s| switch (s) { .f16, @@ -318,91 +300,85 @@ pub fn print(ty: Type, bw: *std.io.BufferedWriter, pt: Zcu.PerThread) anyerror!u }, .struct_type => { const name = ip.loadStructType(ty.toIntern()).name; - return bw.print("{}", .{name.fmt(ip)}); + return bw.print("{f}", .{name.fmt(ip)}); }, .tuple_type => |tuple| { if (tuple.types.len == 0) { return bw.writeAll("@TypeOf(.{})"); } - var n: usize = 0; - n += try bw.writeAll("struct {"); + try bw.writeAll("struct {"); for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, val, i| { - n += try bw.writeAll(if (i == 0) " " else ", "); - if (val != .none) n += try bw.writeAll("comptime "); - n += try print(Type.fromInterned(field_ty), bw, pt); - if (val != .none) n += try bw.print(" = {}", .{Value.fromInterned(val).fmtValue(pt)}); + try bw.writeAll(if (i == 0) " " else ", "); + if (val != .none) try bw.writeAll("comptime "); + try print(Type.fromInterned(field_ty), bw, pt); + if (val != .none) try bw.print(" = {f}", .{Value.fromInterned(val).fmtValue(pt)}); } - n += try bw.writeAll(" }"); - return n; + try bw.writeAll(" }"); }, .union_type => { const name = ip.loadUnionType(ty.toIntern()).name; - return bw.print("{}", .{name.fmt(ip)}); + return bw.print("{f}", .{name.fmt(ip)}); }, .opaque_type => { const name = ip.loadOpaqueType(ty.toIntern()).name; - return bw.print("{}", .{name.fmt(ip)}); + return bw.print("{f}", .{name.fmt(ip)}); }, .enum_type => { const name = ip.loadEnumType(ty.toIntern()).name; - return bw.print("{}", .{name.fmt(ip)}); + return bw.print("{f}", .{name.fmt(ip)}); }, .func_type => |fn_info| { - var n: usize = 0; if (fn_info.is_noinline) { - n += try bw.writeAll("noinline "); + try bw.writeAll("noinline "); } - n += try bw.writeAll("fn ("); + try bw.writeAll("fn ("); const param_types = fn_info.param_types.get(&zcu.intern_pool); for (param_types, 0..) |param_ty, i| { - if (i != 0) n += try bw.writeAll(", "); + if (i != 0) try bw.writeAll(", "); if (std.math.cast(u5, i)) |index| { if (fn_info.paramIsComptime(index)) { - n += try bw.writeAll("comptime "); + try bw.writeAll("comptime "); } if (fn_info.paramIsNoalias(index)) { - n += try bw.writeAll("noalias "); + try bw.writeAll("noalias "); } } if (param_ty == .generic_poison_type) { - n += try bw.writeAll("anytype"); + try bw.writeAll("anytype"); } else { - n += try print(Type.fromInterned(param_ty), bw, pt); + try print(Type.fromInterned(param_ty), bw, pt); } } if (fn_info.is_var_args) { if (param_types.len != 0) { - n += try bw.writeAll(", "); + try bw.writeAll(", "); } - n += try bw.writeAll("..."); + try bw.writeAll("..."); } - n += try bw.writeAll(") "); + try bw.writeAll(") "); if (fn_info.cc != .auto) print_cc: { if (zcu.getTarget().cCallingConvention()) |ccc| { if (fn_info.cc.eql(ccc)) { - n += try bw.writeAll("callconv(.c) "); + try bw.writeAll("callconv(.c) "); break :print_cc; } } switch (fn_info.cc) { - .auto, .@"async", .naked, .@"inline" => n += try bw.print("callconv(.{}) ", .{std.zig.fmtId(@tagName(fn_info.cc))}), - else => n += try bw.print("callconv({any}) ", .{fn_info.cc}), + .auto, .@"async", .naked, .@"inline" => try bw.print("callconv(.{f}) ", .{std.zig.fmtId(@tagName(fn_info.cc))}), + else => try bw.print("callconv({any}) ", .{fn_info.cc}), } } if (fn_info.return_type == .generic_poison_type) { - n += try bw.writeAll("anytype"); + try bw.writeAll("anytype"); } else { - n += try print(Type.fromInterned(fn_info.return_type), bw, pt); + try print(Type.fromInterned(fn_info.return_type), bw, pt); } - return n; }, .anyframe_type => |child| { if (child == .none) return bw.writeAll("anyframe"); - var n: usize = 0; - n += try bw.writeAll("anyframe->"); - n += print(Type.fromInterned(child), bw, pt); - return n; + try bw.writeAll("anyframe->"); + try print(Type.fromInterned(child), bw, pt); }, // values, not types diff --git a/src/Zcu.zig b/src/Zcu.zig index e69a66353f..41bd25d273 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -862,7 +862,7 @@ pub const Namespace = struct { try ns.fileScope(zcu).renderFullyQualifiedDebugName(writer); break :sep ':'; }; - if (name != .empty) try writer.print("{c}{}", .{ sep, name.fmt(&zcu.intern_pool) }); + if (name != .empty) try writer.print("{c}{f}", .{ sep, name.fmt(&zcu.intern_pool) }); } pub fn internFullyQualifiedName( @@ -874,7 +874,7 @@ pub const Namespace = struct { ) !InternPool.NullTerminatedString { const ns_name = Type.fromInterned(ns.owner_type).containerTypeName(ip); if (name == .empty) return ns_name; - return ip.getOrPutStringFmt(gpa, tid, "{}.{}", .{ ns_name.fmt(ip), name.fmt(ip) }, .no_embedded_nulls); + return ip.getOrPutStringFmt(gpa, tid, "{f}.{f}", .{ ns_name.fmt(ip), name.fmt(ip) }, .no_embedded_nulls); } }; @@ -1101,11 +1101,11 @@ pub const File = struct { const gpa = pt.zcu.gpa; const ip = &pt.zcu.intern_pool; const strings = ip.getLocal(pt.tid).getMutableStrings(gpa); - const slice = try strings.addManyAsSlice(file.fullyQualifiedNameLen()); - var fbs = std.io.fixedBufferStream(slice[0]); - file.renderFullyQualifiedName(fbs.writer()) catch unreachable; - assert(fbs.pos == slice[0].len); - return ip.getOrPutTrailingString(gpa, pt.tid, @intCast(slice[0].len), .no_embedded_nulls); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed((try strings.addManyAsSlice(file.fullyQualifiedNameLen()))[0]); + file.renderFullyQualifiedName(&bw) catch unreachable; + assert(bw.end == bw.buffer.len); + return ip.getOrPutTrailingString(gpa, pt.tid, @intCast(bw.end), .no_embedded_nulls); } pub const Index = InternPool.FileIndex; @@ -1194,13 +1194,8 @@ pub const ErrorMsg = struct { gpa.destroy(err_msg); } - pub fn init( - gpa: Allocator, - src_loc: LazySrcLoc, - comptime format: []const u8, - args: anytype, - ) !ErrorMsg { - return ErrorMsg{ + pub fn init(gpa: Allocator, src_loc: LazySrcLoc, comptime format: []const u8, args: anytype) !ErrorMsg { + return .{ .src_loc = src_loc, .msg = try std.fmt.allocPrint(gpa, format, args), }; @@ -2822,7 +2817,9 @@ comptime { } pub fn loadZirCache(gpa: Allocator, cache_file: std.fs.File) !Zir { - return loadZirCacheBody(gpa, try cache_file.reader().readStruct(Zir.Header), cache_file); + var header: Zir.Header = undefined; + if (try cache_file.readAll(std.mem.asBytes(&header)) < @sizeOf(Zir.Header)) return error.EndOfStream; + return loadZirCacheBody(gpa, header, cache_file); } pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File) !Zir { @@ -3082,7 +3079,7 @@ pub fn markDependeeOutdated( marked_po: enum { not_marked_po, marked_po }, dependee: InternPool.Dependee, ) !void { - log.debug("outdated dependee: {}", .{zcu.fmtDependee(dependee)}); + log.debug("outdated dependee: {f}", .{zcu.fmtDependee(dependee)}); var it = zcu.intern_pool.dependencyIterator(dependee); while (it.next()) |depender| { if (zcu.outdated.getPtr(depender)) |po_dep_count| { @@ -3090,9 +3087,9 @@ pub fn markDependeeOutdated( .not_marked_po => {}, .marked_po => { po_dep_count.* -= 1; - log.debug("outdated {} => already outdated {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); + log.debug("outdated {f} => already outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); if (po_dep_count.* == 0) { - log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)}); + log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); try zcu.outdated_ready.put(zcu.gpa, depender, {}); } }, @@ -3113,9 +3110,9 @@ pub fn markDependeeOutdated( depender, new_po_dep_count, ); - log.debug("outdated {} => new outdated {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count }); + log.debug("outdated {f} => new outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count }); if (new_po_dep_count == 0) { - log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)}); + log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); try zcu.outdated_ready.put(zcu.gpa, depender, {}); } // If this is a Decl and was not previously PO, we must recursively @@ -3128,16 +3125,16 @@ pub fn markDependeeOutdated( } pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { - log.debug("up-to-date dependee: {}", .{zcu.fmtDependee(dependee)}); + log.debug("up-to-date dependee: {f}", .{zcu.fmtDependee(dependee)}); var it = zcu.intern_pool.dependencyIterator(dependee); while (it.next()) |depender| { if (zcu.outdated.getPtr(depender)) |po_dep_count| { // This depender is already outdated, but it now has one // less PO dependency! po_dep_count.* -= 1; - log.debug("up-to-date {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); + log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); if (po_dep_count.* == 0) { - log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)}); + log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); try zcu.outdated_ready.put(zcu.gpa, depender, {}); } continue; @@ -3151,11 +3148,11 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { }; if (ptr.* > 1) { ptr.* -= 1; - log.debug("up-to-date {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* }); + log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* }); continue; } - log.debug("up-to-date {} => {} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) }); + log.debug("up-to-date {f} => {f} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) }); // This dependency is no longer PO, i.e. is known to be up-to-date. assert(zcu.potentially_outdated.swapRemove(depender)); @@ -3184,7 +3181,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni .func => |func_index| .{ .interned = func_index }, // IES .memoized_state => |stage| .{ .memoized_state = stage }, }; - log.debug("potentially outdated dependee: {}", .{zcu.fmtDependee(dependee)}); + log.debug("potentially outdated dependee: {f}", .{zcu.fmtDependee(dependee)}); var it = ip.dependencyIterator(dependee); while (it.next()) |po| { if (zcu.outdated.getPtr(po)) |po_dep_count| { @@ -3194,17 +3191,17 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni _ = zcu.outdated_ready.swapRemove(po); } po_dep_count.* += 1; - log.debug("po {} => {} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* }); + log.debug("po {f} => {f} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* }); continue; } if (zcu.potentially_outdated.getPtr(po)) |n| { // There is now one more PO dependency. n.* += 1; - log.debug("po {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* }); + log.debug("po {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* }); continue; } try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1); - log.debug("po {} => {} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) }); + log.debug("po {f} => {f} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) }); // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO. try zcu.markTransitiveDependersPotentiallyOutdated(po); } @@ -3233,7 +3230,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { if (zcu.outdated_ready.count() > 0) { const unit = zcu.outdated_ready.keys()[0]; - log.debug("findOutdatedToAnalyze: trivial {}", .{zcu.fmtAnalUnit(unit)}); + log.debug("findOutdatedToAnalyze: trivial {f}", .{zcu.fmtAnalUnit(unit)}); return unit; } @@ -3284,7 +3281,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { } } - log.debug("findOutdatedToAnalyze: heuristic returned '{}' ({d} dependers)", .{ + log.debug("findOutdatedToAnalyze: heuristic returned '{f}' ({d} dependers)", .{ zcu.fmtAnalUnit(chosen_unit.?), chosen_unit_dependers, }); @@ -4094,7 +4091,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv const referencer = kv.value; try checked_types.putNoClobber(gpa, ty, {}); - log.debug("handle type '{}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}); + log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}); // If this type undergoes type resolution, the corresponding `AnalUnit` is automatically referenced. const has_resolution: bool = switch (ip.indexToKey(ty)) { @@ -4130,7 +4127,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv // `comptime` decls are always analyzed. const unit: AnalUnit = .wrap(.{ .@"comptime" = cu }); if (!result.contains(unit)) { - log.debug("type '{}': ref comptime %{}", .{ + log.debug("type '{f}': ref comptime %{}", .{ Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue), }); @@ -4162,7 +4159,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv }, }; if (want_analysis) { - log.debug("type '{}': ref test %{}", .{ + log.debug("type '{f}': ref test %{}", .{ Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(inst_info.inst), }); @@ -4181,7 +4178,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv if (decl.linkage == .@"export") { const unit: AnalUnit = .wrap(.{ .nav_val = nav }); if (!result.contains(unit)) { - log.debug("type '{}': ref named %{}", .{ + log.debug("type '{f}': ref named %{}", .{ Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(inst_info.inst), }); @@ -4197,7 +4194,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv if (decl.linkage == .@"export") { const unit: AnalUnit = .wrap(.{ .nav_val = nav }); if (!result.contains(unit)) { - log.debug("type '{}': ref named %{}", .{ + log.debug("type '{f}': ref named %{}", .{ Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(inst_info.inst), }); @@ -4232,7 +4229,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv try unit_queue.put(gpa, other, kv.value); // same reference location } - log.debug("handle unit '{}'", .{zcu.fmtAnalUnit(unit)}); + log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)}); if (zcu.reference_table.get(unit)) |first_ref_idx| { assert(first_ref_idx != std.math.maxInt(u32)); @@ -4240,7 +4237,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv while (ref_idx != std.math.maxInt(u32)) { const ref = zcu.all_references.items[ref_idx]; if (!result.contains(ref.referenced)) { - log.debug("unit '{}': ref unit '{}'", .{ + log.debug("unit '{f}': ref unit '{f}'", .{ zcu.fmtAnalUnit(unit), zcu.fmtAnalUnit(ref.referenced), }); @@ -4259,7 +4256,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv while (ref_idx != std.math.maxInt(u32)) { const ref = zcu.all_type_references.items[ref_idx]; if (!checked_types.contains(ref.referenced)) { - log.debug("unit '{}': ref type '{}'", .{ + log.debug("unit '{f}': ref type '{f}'", .{ zcu.fmtAnalUnit(unit), Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip), }); @@ -4347,8 +4344,8 @@ pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Formatter(formatDe return .{ .data = .{ .dependee = d, .zcu = zcu } }; } -fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { - _ = .{ fmt, options }; +fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { + _ = fmt; const zcu = data.zcu; const ip = &zcu.intern_pool; switch (data.unit.unwrap()) { @@ -4356,69 +4353,69 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co const cu = ip.getComptimeUnit(cu_id); if (cu.zir_index.resolveFull(ip)) |resolved| { const file_path = zcu.fileByIndex(resolved.file).path; - return writer.print("comptime(inst=('{}', %{}) [{}])", .{ file_path.fmt(zcu.comp), @intFromEnum(resolved.inst), @intFromEnum(cu_id) }); + return bw.print("comptime(inst=('{f}', %{}) [{}])", .{ file_path.fmt(zcu.comp), @intFromEnum(resolved.inst), @intFromEnum(cu_id) }); } else { - return writer.print("comptime(inst= [{}])", .{@intFromEnum(cu_id)}); + return bw.print("comptime(inst= [{}])", .{@intFromEnum(cu_id)}); } }, - .nav_val => |nav| return writer.print("nav_val('{}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }), - .nav_ty => |nav| return writer.print("nav_ty('{}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }), - .type => |ty| return writer.print("ty('{}' [{}])", .{ Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }), + .nav_val => |nav| return bw.print("nav_val('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }), + .nav_ty => |nav| return bw.print("nav_ty('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }), + .type => |ty| return bw.print("ty('{f}' [{}])", .{ Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }), .func => |func| { const nav = zcu.funcInfo(func).owner_nav; - return writer.print("func('{}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) }); + return bw.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) }); }, - .memoized_state => return writer.writeAll("memoized_state"), + .memoized_state => return bw.writeAll("memoized_state"), } } -fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { - _ = .{ fmt, options }; +fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { + _ = fmt; const zcu = data.zcu; const ip = &zcu.intern_pool; switch (data.dependee) { .src_hash => |ti| { const info = ti.resolveFull(ip) orelse { - return writer.writeAll("inst()"); + return bw.writeAll("inst()"); }; const file_path = zcu.fileByIndex(info.file).path; - return writer.print("inst('{}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) }); + return bw.print("inst('{f}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) }); }, .nav_val => |nav| { const fqn = ip.getNav(nav).fqn; - return writer.print("nav_val('{}')", .{fqn.fmt(ip)}); + return bw.print("nav_val('{f}')", .{fqn.fmt(ip)}); }, .nav_ty => |nav| { const fqn = ip.getNav(nav).fqn; - return writer.print("nav_ty('{}')", .{fqn.fmt(ip)}); + return bw.print("nav_ty('{f}')", .{fqn.fmt(ip)}); }, .interned => |ip_index| switch (ip.indexToKey(ip_index)) { - .struct_type, .union_type, .enum_type => return writer.print("type('{}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}), - .func => |f| return writer.print("ies('{}')", .{ip.getNav(f.owner_nav).fqn.fmt(ip)}), + .struct_type, .union_type, .enum_type => return bw.print("type('{f}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}), + .func => |f| return bw.print("ies('{f}')", .{ip.getNav(f.owner_nav).fqn.fmt(ip)}), else => unreachable, }, .zon_file => |file| { const file_path = zcu.fileByIndex(file).path; - return writer.print("zon_file('{}')", .{file_path.fmt(zcu.comp)}); + return bw.print("zon_file('{f}')", .{file_path.fmt(zcu.comp)}); }, .embed_file => |ef_idx| { const ef = ef_idx.get(zcu); - return writer.print("embed_file('{}')", .{ef.path.fmt(zcu.comp)}); + return bw.print("embed_file('{f}')", .{ef.path.fmt(zcu.comp)}); }, .namespace => |ti| { const info = ti.resolveFull(ip) orelse { - return writer.writeAll("namespace()"); + return bw.writeAll("namespace()"); }; const file_path = zcu.fileByIndex(info.file).path; - return writer.print("namespace('{}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) }); + return bw.print("namespace('{f}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) }); }, .namespace_name => |k| { const info = k.namespace.resolveFull(ip) orelse { - return writer.print("namespace(, '{}')", .{k.name.fmt(ip)}); + return bw.print("namespace(, '{f}')", .{k.name.fmt(ip)}); }; const file_path = zcu.fileByIndex(info.file).path; - return writer.print("namespace('{}', %{d}, '{}')", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst), k.name.fmt(ip) }); + return bw.print("namespace('{f}', %{d}, '{f}')", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst), k.name.fmt(ip) }); }, - .memoized_state => return writer.writeAll("memoized_state"), + .memoized_state => return bw.writeAll("memoized_state"), } } diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 052113c5e3..73ec047786 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -190,7 +190,7 @@ pub fn updateFile( // failure was a race, or ENOENT, indicating deletion of the // directory of our open handle. if (builtin.os.tag != .macos) { - std.process.fatal("cache directory '{}' unexpectedly removed during compiler execution", .{ + std.process.fatal("cache directory '{f}' unexpectedly removed during compiler execution", .{ cache_directory, }); } @@ -202,7 +202,7 @@ pub fn updateFile( }) catch |excl_err| switch (excl_err) { error.PathAlreadyExists => continue, error.FileNotFound => { - std.process.fatal("cache directory '{}' unexpectedly removed during compiler execution", .{ + std.process.fatal("cache directory '{f}' unexpectedly removed during compiler execution", .{ cache_directory, }); }, @@ -646,7 +646,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized // If this unit caused the error, it would have an entry in `failed_analysis`. // Since it does not, this must be a transitive failure. try zcu.transitive_failed_analysis.put(gpa, unit, {}); - log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(unit)}); + log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(unit)}); } break :res .{ !prev_failed, true }; }, @@ -751,7 +751,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU const anal_unit: AnalUnit = .wrap(.{ .@"comptime" = cu_id }); - log.debug("ensureComptimeUnitUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("ensureComptimeUnitUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); assert(!zcu.analysis_in_progress.contains(anal_unit)); @@ -802,7 +802,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU // If this unit caused the error, it would have an entry in `failed_analysis`. // Since it does not, this must be a transitive failure. try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); - log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); } return error.AnalysisFail; }, @@ -832,7 +832,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu const anal_unit: AnalUnit = .wrap(.{ .@"comptime" = cu_id }); const comptime_unit = ip.getComptimeUnit(cu_id); - log.debug("analyzeComptimeUnit {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("analyzeComptimeUnit {f}", .{zcu.fmtAnalUnit(anal_unit)}); const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail; const file = zcu.fileByIndex(inst_resolved.file); @@ -878,7 +878,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu .r = .{ .simple = .comptime_keyword }, } }, .src_base_inst = comptime_unit.zir_index, - .type_name_ctx = try ip.getOrPutStringFmt(gpa, pt.tid, "{}.comptime", .{ + .type_name_ctx = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}.comptime", .{ Type.fromInterned(zcu.namespacePtr(comptime_unit.namespace).owner_type).containerTypeName(ip).fmt(ip), }, .no_embedded_nulls), }; @@ -930,7 +930,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id }); const nav = ip.getNav(nav_id); - log.debug("ensureNavValUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("ensureNavValUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); // Determine whether or not this `Nav`'s value is outdated. This also includes checking if the // status is `.unresolved`, which indicates that the value is outdated because it has *never* @@ -988,7 +988,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu // If this unit caused the error, it would have an entry in `failed_analysis`. // Since it does not, this must be a transitive failure. try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); - log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); } break :res .{ !prev_failed, true }; }, @@ -1059,7 +1059,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id }); const old_nav = ip.getNav(nav_id); - log.debug("analyzeNavVal {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("analyzeNavVal {f}", .{zcu.fmtAnalUnit(anal_unit)}); const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail; const file = zcu.fileByIndex(inst_resolved.file); @@ -1240,10 +1240,10 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr // TODO: this is jank. If #20663 is rejected, let's think about how to better model `usingnamespace`. if (zir_decl.kind == .@"usingnamespace") { if (nav_ty.toIntern() != .type_type) { - return sema.fail(&block, ty_src, "expected type, found {}", .{nav_ty.fmt(pt)}); + return sema.fail(&block, ty_src, "expected type, found {f}", .{nav_ty.fmt(pt)}); } if (nav_val.toType().getNamespace(zcu) == .none) { - return sema.fail(&block, ty_src, "type {} has no namespace", .{nav_val.toType().fmt(pt)}); + return sema.fail(&block, ty_src, "type {f} has no namespace", .{nav_val.toType().fmt(pt)}); } ip.resolveNavValue(nav_id, .{ .val = nav_val.toIntern(), @@ -1339,7 +1339,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc const anal_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id }); const nav = ip.getNav(nav_id); - log.debug("ensureNavTypeUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("ensureNavTypeUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); const type_resolved_by_value: bool = from_val: { const analysis = nav.analysis orelse break :from_val false; @@ -1409,7 +1409,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc // If this unit caused the error, it would have an entry in `failed_analysis`. // Since it does not, this must be a transitive failure. try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); - log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); } break :res .{ !prev_failed, true }; }, @@ -1451,7 +1451,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr const anal_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id }); const old_nav = ip.getNav(nav_id); - log.debug("analyzeNavType {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("analyzeNavType {f}", .{zcu.fmtAnalUnit(anal_unit)}); const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail; const file = zcu.fileByIndex(inst_resolved.file); @@ -1582,7 +1582,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: Inter const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index); const anal_unit: AnalUnit = .wrap(.{ .func = func_index }); - log.debug("ensureFuncBodyUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("ensureFuncBodyUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); const func = zcu.funcInfo(maybe_coerced_func_index); @@ -1626,7 +1626,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: Inter // If this function caused the error, it would have an entry in `failed_analysis`. // Since it does not, this must be a transitive failure. try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); - log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); } // We consider the IES to be outdated if the function previously succeeded analysis; in this case, // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting @@ -1696,7 +1696,7 @@ fn analyzeFuncBody( else .none; - log.debug("analyze and generate fn body {}", .{zcu.fmtAnalUnit(anal_unit)}); + log.debug("analyze and generate fn body {f}", .{zcu.fmtAnalUnit(anal_unit)}); var air = try pt.analyzeFnBodyInner(func_index); errdefer air.deinit(gpa); @@ -2615,7 +2615,7 @@ const ScanDeclIter = struct { var gop = try iter.seen_decls.getOrPut(gpa, name); var next_suffix: u32 = 0; while (gop.found_existing) { - name = try ip.getOrPutStringFmt(gpa, pt.tid, "{}_{d}", .{ name.fmt(ip), next_suffix }, .no_embedded_nulls); + name = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}_{d}", .{ name.fmt(ip), next_suffix }, .no_embedded_nulls); gop = try iter.seen_decls.getOrPut(gpa, name); next_suffix += 1; } @@ -2764,7 +2764,7 @@ const ScanDeclIter = struct { if (existing_unit == null and (want_analysis or decl.linkage == .@"export")) { log.debug( - "scanDecl queue analyze_comptime_unit file='{s}' unit={}", + "scanDecl queue analyze_comptime_unit file='{s}' unit={f}", .{ namespace.fileScope(zcu).sub_file_path, zcu.fmtAnalUnit(unit) }, ); try comp.queueJob(.{ .analyze_comptime_unit = unit }); @@ -3182,7 +3182,7 @@ fn processExportsInner( if (gop.found_existing) { new_export.status = .failed_retryable; try zcu.failed_exports.ensureUnusedCapacity(gpa, 1); - const msg = try Zcu.ErrorMsg.create(gpa, new_export.src, "exported symbol collision: {}", .{ + const msg = try Zcu.ErrorMsg.create(gpa, new_export.src, "exported symbol collision: {f}", .{ new_export.opts.name.fmt(ip), }); errdefer msg.destroy(gpa); diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 042ee9c11e..14ce169af6 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -1011,7 +1011,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { } const abi_size = math.cast(u32, elem_ty.abiSize(zcu)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); + return self.fail("type '{f}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); }; // TODO swap this for inst.ty.ptrAlign const abi_align = elem_ty.abiAlignment(zcu); @@ -1022,7 +1022,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue { const pt = self.pt; const abi_size = math.cast(u32, elem_ty.abiSize(pt.zcu)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); + return self.fail("type '{f}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); }; const abi_align = elem_ty.abiAlignment(pt.zcu); @@ -4636,7 +4636,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) InnerError!void { const mcv = try self.resolveInst(operand); const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); - log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), mcv }); + log.debug("airDbgVar: %{f}: {f}, {}", .{ inst, ty.fmtDebug(), mcv }); try self.dbg_info_relocs.append(self.gpa, .{ .tag = tag, diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index f76732125b..eb5c629c10 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -70,9 +70,11 @@ const BranchType = enum { } }; -pub fn emitMir( - emit: *Emit, -) !void { +pub fn emitMir(emit: *Emit) InnerError!void { + return @errorCast(emit.emitMirInner()); +} + +fn emitMirInner(emit: *Emit) anyerror!void { const mir_tags = emit.mir.instructions.items(.tag); // Find smallest lowerings for branch instructions @@ -439,7 +441,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { return error.EmitFail; } -fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void { +fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) anyerror!void { const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line); const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); @@ -454,25 +456,20 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) InnerError!void { .plan9 => |dbg_out| { if (delta_pc <= 0) return; // only do this when the pc changes + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.fromArrayList(emit.bin_file.comp.gpa, &dbg_out.dbg_line); + defer dbg_out.dbg_line = aw.toArrayList(); + // increasing the line number - try link.File.Plan9.changeLine(&dbg_out.dbg_line, @intCast(delta_line)); + try link.File.Plan9.changeLine(bw, @intCast(delta_line)); // increasing the pc const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta; if (d_pc_p9 > 0) { // minus one because if its the last one, we want to leave space to change the line which is one pc quanta - var diff = @divExact(d_pc_p9, dbg_out.pc_quanta) - dbg_out.pc_quanta; - while (diff > 0) { - if (diff < 64) { - try dbg_out.dbg_line.append(@intCast(diff + 128)); - diff = 0; - } else { - try dbg_out.dbg_line.append(@intCast(64 + 128)); - diff -= 64; - } - } - if (dbg_out.pcop_change_index) |pci| - dbg_out.dbg_line.items[pci] += 1; - dbg_out.pcop_change_index = @intCast(dbg_out.dbg_line.items.len - 1); + try bw.writeByte(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta); + const dbg_line = aw.getWritten(); + if (dbg_out.pcop_change_index) |pci| dbg_line[pci] += 1; + dbg_out.pcop_change_index = @intCast(dbg_line.len - 1); } else if (d_pc_p9 == 0) { // we don't need to do anything, because adding the pc quanta does it for us } else unreachable; diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 799a75be9a..12eb0c79a7 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -997,7 +997,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { } const abi_size = math.cast(u32, elem_ty.abiSize(zcu)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); + return self.fail("type '{f}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); }; // TODO swap this for inst.ty.ptrAlign const abi_align = elem_ty.abiAlignment(zcu); @@ -1008,7 +1008,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue { const pt = self.pt; const abi_size = math.cast(u32, elem_ty.abiSize(pt.zcu)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); + return self.fail("type '{f}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); }; const abi_align = elem_ty.abiAlignment(pt.zcu); @@ -4609,7 +4609,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { const mcv = try self.resolveInst(operand); const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); - log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), mcv }); + log.debug("airDbgVar: %{f}: {f}, {}", .{ inst, ty.fmtDebug(), mcv }); try self.dbg_info_relocs.append(self.gpa, .{ .tag = tag, diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig index dc97ea3afb..d50b4b1ef6 100644 --- a/src/arch/arm/Emit.zig +++ b/src/arch/arm/Emit.zig @@ -67,9 +67,11 @@ const BranchType = enum { } }; -pub fn emitMir( - emit: *Emit, -) !void { +pub fn emitMir(emit: *Emit) InnerError!void { + return @errorCast(emit.emitMirInner()); +} + +fn emitMirInner(emit: *Emit) anyerror!void { const mir_tags = emit.mir.instructions.items(.tag); // Find smallest lowerings for branch instructions @@ -370,16 +372,20 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { .plan9 => |dbg_out| { if (delta_pc <= 0) return; // only do this when the pc changes + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.fromArrayList(self.bin_file.comp.gpa, &dbg_out.dbg_line); + defer dbg_out.dbg_line = aw.toArrayList(); + // increasing the line number - try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line); + try link.File.Plan9.changeLine(bw, delta_line); // increasing the pc const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta; if (d_pc_p9 > 0) { // minus one because if its the last one, we want to leave space to change the line which is one pc quanta - try dbg_out.dbg_line.append(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta); - if (dbg_out.pcop_change_index) |pci| - dbg_out.dbg_line.items[pci] += 1; - dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1)); + try bw.writeByte(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta); + const dbg_line = aw.getWritten(); + if (dbg_out.pcop_change_index) |pci| dbg_line[pci] += 1; + dbg_out.pcop_change_index = @intCast(dbg_line.len - 1); } else if (d_pc_p9 == 0) { // we don't need to do anything, because adding the pc quanta does it for us } else unreachable; diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index b9a16d5a75..f8b852c762 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -401,7 +401,7 @@ const InstTracking = struct { .reserved_frame => |index| inst_tracking.long = .{ .load_frame = .{ .index = index } }, else => unreachable, } - tracking_log.debug("spill %{d} from {} to {}", .{ inst, inst_tracking.short, inst_tracking.long }); + tracking_log.debug("spill %{f} from {} to {}", .{ inst, inst_tracking.short, inst_tracking.long }); try function.genCopy(function.typeOfIndex(inst), inst_tracking.long, inst_tracking.short); } @@ -435,7 +435,7 @@ const InstTracking = struct { fn trackSpill(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) !void { try function.freeValue(inst_tracking.short); inst_tracking.reuseFrame(); - tracking_log.debug("%{d} => {} (spilled)", .{ inst, inst_tracking.* }); + tracking_log.debug("%{f} => {f} (spilled)", .{ inst, inst_tracking.* }); } fn verifyMaterialize(inst_tracking: InstTracking, target: InstTracking) void { @@ -499,14 +499,14 @@ const InstTracking = struct { else => target.long, } else target.long; inst_tracking.short = target.short; - tracking_log.debug("%{d} => {} (materialize)", .{ inst, inst_tracking.* }); + tracking_log.debug("%{f} => {f} (materialize)", .{ inst, inst_tracking.* }); } fn resurrect(inst_tracking: *InstTracking, inst: Air.Inst.Index, scope_generation: u32) void { switch (inst_tracking.short) { .dead => |die_generation| if (die_generation >= scope_generation) { inst_tracking.reuseFrame(); - tracking_log.debug("%{d} => {} (resurrect)", .{ inst, inst_tracking.* }); + tracking_log.debug("%{f} => {f} (resurrect)", .{ inst, inst_tracking.* }); }, else => {}, } @@ -516,7 +516,7 @@ const InstTracking = struct { if (inst_tracking.short == .dead) return; try function.freeValue(inst_tracking.short); inst_tracking.short = .{ .dead = function.scope_generation }; - tracking_log.debug("%{d} => {} (death)", .{ inst, inst_tracking.* }); + tracking_log.debug("%{f} => {f} (death)", .{ inst, inst_tracking.* }); } fn reuse( @@ -527,15 +527,15 @@ const InstTracking = struct { ) void { inst_tracking.short = .{ .dead = function.scope_generation }; if (new_inst) |inst| - tracking_log.debug("%{d} => {} (reuse %{d})", .{ inst, inst_tracking.*, old_inst }) + tracking_log.debug("%{f} => {f} (reuse %{f})", .{ inst, inst_tracking.*, old_inst }) else - tracking_log.debug("tmp => {} (reuse %{d})", .{ inst_tracking.*, old_inst }); + tracking_log.debug("tmp => {f} (reuse %{f})", .{ inst_tracking.*, old_inst }); } fn liveOut(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) void { for (inst_tracking.getRegs()) |reg| { if (function.register_manager.isRegFree(reg)) { - tracking_log.debug("%{d} => {} (live-out)", .{ inst, inst_tracking.* }); + tracking_log.debug("%{f} => {f} (live-out)", .{ inst, inst_tracking.* }); continue; } @@ -562,18 +562,13 @@ const InstTracking = struct { // Perform side-effects of freeValue manually. function.register_manager.freeReg(reg); - tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, inst_tracking.*, tracked_inst }); + tracking_log.debug("%{f} => {f} (live-out %{f})", .{ inst, inst_tracking.*, tracked_inst }); } } - pub fn format( - inst_tracking: InstTracking, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (!std.meta.eql(inst_tracking.long, inst_tracking.short)) try writer.print("|{}| ", .{inst_tracking.long}); - try writer.print("{}", .{inst_tracking.short}); + pub fn format(inst_tracking: InstTracking, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + if (!std.meta.eql(inst_tracking.long, inst_tracking.short)) try bw.print("|{}| ", .{inst_tracking.long}); + try bw.print("{}", .{inst_tracking.short}); } }; @@ -802,7 +797,7 @@ pub fn generate( function.mir_instructions.deinit(gpa); } - wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)}); + wip_mir_log.debug("{f}:", .{fmtNav(func.owner_nav, ip)}); try function.frame_allocs.resize(gpa, FrameIndex.named_count); function.frame_allocs.set( @@ -937,12 +932,7 @@ const FormatWipMirData = struct { func: *Func, inst: Mir.Inst.Index, }; -fn formatWipMir( - data: FormatWipMirData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { +fn formatWipMir(data: FormatWipMirData, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { const pt = data.func.pt; const comp = pt.zcu.comp; var lower: Lower = .{ @@ -965,11 +955,11 @@ fn formatWipMir( lower.err_msg.?.deinit(data.func.gpa); lower.err_msg = null; } - try writer.writeAll(lower.err_msg.?.msg); + try bw.writeAll(lower.err_msg.?.msg); return; }, error.OutOfMemory, error.InvalidInstruction => |e| { - try writer.writeAll(switch (e) { + try bw.writeAll(switch (e) { error.OutOfMemory => "Out of memory", error.InvalidInstruction => "CodeGen failed to find a viable instruction.", }); @@ -977,8 +967,8 @@ fn formatWipMir( }, else => |e| return e, }).insts) |lowered_inst| { - if (!first) try writer.writeAll("\ndebug(wip_mir): "); - try writer.print(" | {}", .{lowered_inst}); + if (!first) try bw.writeAll("\ndebug(wip_mir): "); + try bw.print(" | {}", .{lowered_inst}); first = false; } } @@ -990,13 +980,8 @@ const FormatNavData = struct { ip: *const InternPool, nav_index: InternPool.Nav.Index, }; -fn formatNav( - data: FormatNavData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { - try writer.print("{}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)}); +fn formatNav(data: FormatNavData, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + try bw.print("{f}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)}); } fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Formatter(formatNav) { return .{ .data = .{ @@ -1009,12 +994,7 @@ const FormatAirData = struct { func: *Func, inst: Air.Inst.Index, }; -fn formatAir( - data: FormatAirData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { +fn formatAir(data: FormatAirData, _: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { data.func.air.dumpInst(data.inst, data.func.pt, data.func.liveness); } fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { @@ -1024,14 +1004,9 @@ fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { const FormatTrackingData = struct { func: *Func, }; -fn formatTracking( - data: FormatTrackingData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { +fn formatTracking(data: FormatTrackingData, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { var it = data.func.inst_tracking.iterator(); - while (it.next()) |entry| try writer.print("\n%{d} = {}", .{ entry.key_ptr.*, entry.value_ptr.* }); + while (it.next()) |entry| try bw.print("\n%{d} = {f}", .{ entry.key_ptr.*, entry.value_ptr.* }); } fn fmtTracking(func: *Func) std.fmt.Formatter(formatTracking) { return .{ .data = .{ .func = func } }; @@ -1049,7 +1024,7 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { .pseudo_dbg_epilogue_begin, .pseudo_dead, => false, - }) wip_mir_log.debug("{}", .{func.fmtWipMir(result_index)}); + }) wip_mir_log.debug("{f}", .{func.fmtWipMir(result_index)}); return result_index; } @@ -1172,7 +1147,7 @@ fn gen(func: *Func) !void { func.ret_mcv.long.address().offset(-func.ret_mcv.short.indirect.off), ); func.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } }; - tracking_log.debug("spill {} to {}", .{ func.ret_mcv.long, frame_index }); + tracking_log.debug("spill {} to {f}", .{ func.ret_mcv.long, frame_index }); }, else => unreachable, } @@ -1303,7 +1278,7 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void { switch (Type.fromInterned(lazy_sym.ty).zigTypeTag(zcu)) { .@"enum" => { const enum_ty = Type.fromInterned(lazy_sym.ty); - wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)}); + wip_mir_log.debug("{f}.@tagName:", .{enum_ty.fmt(pt)}); const param_regs = abi.Registers.Integer.function_arg_regs; const ret_reg = param_regs[0]; @@ -1385,7 +1360,7 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void { }); }, else => return func.fail( - "TODO implement {s} for {}", + "TODO implement {s} for {f}", .{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt) }, ), } @@ -1399,8 +1374,8 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { for (body) |inst| { if (func.liveness.isUnused(inst) and !func.air.mustLower(inst, ip)) continue; - wip_mir_log.debug("{}", .{func.fmtAir(inst)}); - verbose_tracking_log.debug("{}", .{func.fmtTracking()}); + wip_mir_log.debug("{f}", .{func.fmtAir(inst)}); + verbose_tracking_log.debug("{f}", .{func.fmtTracking()}); const old_air_bookkeeping = func.air_bookkeeping; try func.ensureProcessDeathCapacity(Air.Liveness.bpi); @@ -1679,18 +1654,18 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { var it = func.register_manager.free_registers.iterator(.{ .kind = .unset }); while (it.next()) |index| { const tracked_inst = func.register_manager.registers[index]; - tracking_log.debug("tracked inst: {}", .{tracked_inst}); + tracking_log.debug("tracked inst: {f}", .{tracked_inst}); const tracking = func.getResolvedInstValue(tracked_inst); for (tracking.getRegs()) |reg| { if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break; } else return std.debug.panic( - \\%{} takes up these regs: {any}, however this regs {any}, don't use it + \\%{f} takes up these regs: {any}, however this regs {any}, don't use it , .{ tracked_inst, tracking.getRegs(), RegisterManager.regAtTrackedIndex(@intCast(index)) }); } } } } - verbose_tracking_log.debug("{}", .{func.fmtTracking()}); + verbose_tracking_log.debug("{f}", .{func.fmtTracking()}); } fn getValue(func: *Func, value: MCValue, inst: ?Air.Inst.Index) !void { @@ -1713,7 +1688,7 @@ fn freeValue(func: *Func, value: MCValue) !void { fn feed(func: *Func, bt: *Air.Liveness.BigTomb, operand: Air.Inst.Ref) !void { if (bt.feed()) if (operand.toIndex()) |inst| { - log.debug("feed inst: %{}", .{inst}); + log.debug("feed inst: %{f}", .{inst}); try func.processDeath(inst); }; } @@ -1907,7 +1882,7 @@ fn splitType(func: *Func, ty: Type) ![2]Type { else => return func.fail("TODO: splitType class {}", .{class}), }; } else if (parts[0].abiSize(zcu) + parts[1].abiSize(zcu) == ty.abiSize(zcu)) return parts; - return func.fail("TODO implement splitType for {}", .{ty.fmt(func.pt)}); + return func.fail("TODO implement splitType for {f}", .{ty.fmt(func.pt)}); } /// Truncates the value in the register in place. @@ -2008,7 +1983,7 @@ fn allocFrameIndex(func: *Func, alloc: FrameAlloc) !FrameIndex { } const frame_index: FrameIndex = @enumFromInt(func.frame_allocs.len); try func.frame_allocs.append(func.gpa, alloc); - log.debug("allocated frame {}", .{frame_index}); + log.debug("allocated frame {f}", .{frame_index}); return frame_index; } @@ -2020,7 +1995,7 @@ fn allocMemPtr(func: *Func, inst: Air.Inst.Index) !FrameIndex { const val_ty = ptr_ty.childType(zcu); return func.allocFrameIndex(FrameAlloc.init(.{ .size = math.cast(u32, val_ty.abiSize(zcu)) orelse { - return func.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(pt)}); + return func.fail("type '{f}' too big to fit into stack frame", .{val_ty.fmt(pt)}); }, .alignment = ptr_ty.ptrAlignment(zcu).max(.@"1"), })); @@ -2160,7 +2135,7 @@ pub fn spillRegisters(func: *Func, comptime registers: []const Register) !void { /// allocated. A second call to `copyToTmpRegister` may return the same register. /// This can have a side effect of spilling instructions to the stack to free up a register. fn copyToTmpRegister(func: *Func, ty: Type, mcv: MCValue) !Register { - log.debug("copyToTmpRegister ty: {}", .{ty.fmt(func.pt)}); + log.debug("copyToTmpRegister ty: {f}", .{ty.fmt(func.pt)}); const reg = try func.register_manager.allocReg(null, func.regTempClassForType(ty)); try func.genSetReg(ty, reg, mcv); return reg; @@ -2245,7 +2220,7 @@ fn airIntCast(func: *Func, inst: Air.Inst.Index) !void { break :result null; // TODO break :result dst_mcv; - } orelse return func.fail("TODO: implement airIntCast from {} to {}", .{ + } orelse return func.fail("TODO: implement airIntCast from {f} to {f}", .{ src_ty.fmt(pt), dst_ty.fmt(pt), }); @@ -2633,7 +2608,7 @@ fn genBinOp( .add_sat, => { if (bit_size != 64 or !is_unsigned) - return func.fail("TODO: genBinOp ty: {}", .{lhs_ty.fmt(pt)}); + return func.fail("TODO: genBinOp ty: {f}", .{lhs_ty.fmt(pt)}); const tmp_reg = try func.copyToTmpRegister(rhs_ty, .{ .register = rhs_reg }); const tmp_lock = func.register_manager.lockRegAssumeUnused(tmp_reg); @@ -4065,7 +4040,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void { ); } else { return func.fail( - "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}, tag {}", + "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}, tag {f}", .{ frame_mcv, tag_ty.fmt(pt) }, ); } @@ -4186,7 +4161,7 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void { switch (scalar_ty.zigTypeTag(zcu)) { .int => if (ty.zigTypeTag(zcu) == .vector) { - return func.fail("TODO implement airAbs for {}", .{ty.fmt(pt)}); + return func.fail("TODO implement airAbs for {f}", .{ty.fmt(pt)}); } else { const int_info = scalar_ty.intInfo(zcu); const int_bits = int_info.bits; @@ -4267,7 +4242,7 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void { break :result return_mcv; }, - else => return func.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(pt)}), + else => return func.fail("TODO: implement airAbs {f}", .{scalar_ty.fmt(pt)}), } break :result .unreach; @@ -4331,7 +4306,7 @@ fn airByteSwap(func: *Func, inst: Air.Inst.Index) !void { break :result dest_mcv; }, - else => return func.fail("TODO: airByteSwap {}", .{ty.fmt(pt)}), + else => return func.fail("TODO: airByteSwap {f}", .{ty.fmt(pt)}), } }; return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); @@ -4397,7 +4372,7 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}), } }, - else => return func.fail("TODO: airUnaryMath ty: {}", .{ty.fmt(pt)}), + else => return func.fail("TODO: airUnaryMath ty: {f}", .{ty.fmt(pt)}), } break :result MCValue{ .register = dst_reg }; @@ -4497,7 +4472,7 @@ fn load(func: *Func, dst_mcv: MCValue, ptr_mcv: MCValue, ptr_ty: Type) InnerErro const zcu = pt.zcu; const dst_ty = ptr_ty.childType(zcu); - log.debug("loading {}:{} into {}", .{ ptr_mcv, ptr_ty.fmt(pt), dst_mcv }); + log.debug("loading {}:{f} into {}", .{ ptr_mcv, ptr_ty.fmt(pt), dst_mcv }); switch (ptr_mcv) { .none, @@ -4550,7 +4525,7 @@ fn airStore(func: *Func, inst: Air.Inst.Index, safety: bool) !void { fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type) !void { const zcu = func.pt.zcu; const src_ty = ptr_ty.childType(zcu); - log.debug("storing {}:{} in {}:{}", .{ src_mcv, src_ty.fmt(func.pt), ptr_mcv, ptr_ty.fmt(func.pt) }); + log.debug("storing {}:{f} in {}:{f}", .{ src_mcv, src_ty.fmt(func.pt), ptr_mcv, ptr_ty.fmt(func.pt) }); switch (ptr_mcv) { .none => unreachable, @@ -7305,7 +7280,7 @@ fn airBitCast(func: *Func, inst: Air.Inst.Index) !void { const bit_size = dst_ty.bitSize(zcu); if (abi_size * 8 <= bit_size) break :result dst_mcv; - return func.fail("TODO: airBitCast {} to {}", .{ src_ty.fmt(pt), dst_ty.fmt(pt) }); + return func.fail("TODO: airBitCast {f} to {f}", .{ src_ty.fmt(pt), dst_ty.fmt(pt) }); }; return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } @@ -8121,7 +8096,7 @@ fn airAggregateInit(func: *Func, inst: Air.Inst.Index) !void { ); break :result .{ .load_frame = .{ .index = frame_index } }; }, - else => return func.fail("TODO: airAggregate {}", .{result_ty.fmt(pt)}), + else => return func.fail("TODO: airAggregate {f}", .{result_ty.fmt(pt)}), } }; @@ -8322,7 +8297,7 @@ fn resolveCallingConventionValues( }; result.return_value = switch (ret_tracking_i) { - else => return func.fail("ty {} took {} tracking return indices", .{ ret_ty.fmt(pt), ret_tracking_i }), + else => return func.fail("ty {f} took {} tracking return indices", .{ ret_ty.fmt(pt), ret_tracking_i }), 1 => ret_tracking[0], 2 => InstTracking.init(.{ .register_pair = .{ ret_tracking[0].short.register, ret_tracking[1].short.register, @@ -8377,7 +8352,7 @@ fn resolveCallingConventionValues( else => return func.fail("TODO: C calling convention arg class {}", .{class}), } else { arg.* = switch (arg_mcv_i) { - else => return func.fail("ty {} took {} tracking arg indices", .{ ty.fmt(pt), arg_mcv_i }), + else => return func.fail("ty {f} took {} tracking arg indices", .{ ty.fmt(pt), arg_mcv_i }), 1 => arg_mcv[0], 2 => .{ .register_pair = .{ arg_mcv[0].register, arg_mcv[1].register } }, }; diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig index 0561eb2019..aa3244ca86 100644 --- a/src/arch/riscv64/Emit.zig +++ b/src/arch/riscv64/Emit.zig @@ -18,20 +18,28 @@ pub const Error = Lower.Error || error{ }; pub fn emitMir(emit: *Emit) Error!void { + return @errorCast(emit.emitMirInner()); +} + +fn emitMirInner(emit: *Emit) anyerror!void { const gpa = emit.bin_file.comp.gpa; + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.fromArrayList(gpa, emit.code); + defer emit.code.* = aw.toArrayList(); + log.debug("mir instruction len: {}", .{emit.lower.mir.instructions.len}); for (0..emit.lower.mir.instructions.len) |mir_i| { const mir_index: Mir.Inst.Index = @intCast(mir_i); try emit.code_offset_mapping.putNoClobber( emit.lower.allocator, mir_index, - @intCast(emit.code.items.len), + @intCast(bw.count), ); const lowered = try emit.lower.lowerMir(mir_index, .{ .allow_frame_locs = true }); var lowered_relocs = lowered.relocs; for (lowered.insts, 0..) |lowered_inst, lowered_index| { - const start_offset: u32 = @intCast(emit.code.items.len); - try lowered_inst.encode(emit.code.writer(gpa)); + const start_offset: u32 = @intCast(bw.count); + try lowered_inst.encode(bw); while (lowered_relocs.len > 0 and lowered_relocs[0].lowered_inst_index == lowered_index) : ({ @@ -123,7 +131,7 @@ pub fn emitMir(emit: *Emit) Error!void { log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column, }); - try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); + try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column, bw.count); }, .plan9 => {}, .none => {}, @@ -132,6 +140,7 @@ pub fn emitMir(emit: *Emit) Error!void { .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine( mir_inst.data.pseudo_dbg_line_column.line, mir_inst.data.pseudo_dbg_line_column.column, + bw.count, ), .pseudo_dbg_epilogue_begin => { switch (emit.debug_output) { @@ -140,7 +149,7 @@ pub fn emitMir(emit: *Emit) Error!void { log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column, }); - try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); + try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column, bw.count); }, .plan9 => {}, .none => {}, @@ -150,7 +159,7 @@ pub fn emitMir(emit: *Emit) Error!void { } } } - try emit.fixupRelocs(); + try emit.fixupRelocs(aw.getWritten()); } pub fn deinit(emit: *Emit) void { @@ -170,14 +179,14 @@ const Reloc = struct { fmt: encoding.Lir.Format, }; -fn fixupRelocs(emit: *Emit) Error!void { +fn fixupRelocs(emit: *Emit, written: []u8) Error!void { for (emit.relocs.items) |reloc| { - log.debug("target inst: {}", .{emit.lower.mir.instructions.get(reloc.target)}); + log.debug("target inst: {f}", .{emit.lower.mir.instructions.get(reloc.target)}); const target = emit.code_offset_mapping.get(reloc.target) orelse return emit.fail("relocation target not found!", .{}); const disp = @as(i32, @intCast(target)) - @as(i32, @intCast(reloc.source)); - const code: *[4]u8 = emit.code.items[reloc.source + reloc.offset ..][0..4]; + const code: *[4]u8 = written[reloc.source + reloc.offset ..][0..4]; switch (reloc.fmt) { .J => riscv_util.writeInstJ(code, @bitCast(disp)), @@ -187,9 +196,9 @@ fn fixupRelocs(emit: *Emit) Error!void { } } -fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { +fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32, pc: usize) Error!void { const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line); - const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; + const delta_pc = pc - emit.prev_di_pc; log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); switch (emit.debug_output) { .dwarf => |dw| { diff --git a/src/arch/riscv64/Lower.zig b/src/arch/riscv64/Lower.zig index ff3d79ba41..08bb3e2b93 100644 --- a/src/arch/riscv64/Lower.zig +++ b/src/arch/riscv64/Lower.zig @@ -61,7 +61,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { defer lower.result_relocs_len = undefined; const inst = lower.mir.instructions.get(index); - log.debug("lowerMir {}", .{inst}); + log.debug("lowerMir {f}", .{inst}); switch (inst.tag) { else => try lower.generic(inst), .pseudo_dbg_line_column, diff --git a/src/arch/riscv64/Mir.zig b/src/arch/riscv64/Mir.zig index 2ad75e4677..d3ebaac6c5 100644 --- a/src/arch/riscv64/Mir.zig +++ b/src/arch/riscv64/Mir.zig @@ -92,14 +92,9 @@ pub const Inst = struct { }, }; - pub fn format( - inst: Inst, - comptime fmt: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(inst: Inst, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { assert(fmt.len == 0); - try writer.print("Tag: {s}, Data: {s}", .{ @tagName(inst.tag), @tagName(inst.data) }); + try bw.print("Tag: {s}, Data: {s}", .{ @tagName(inst.tag), @tagName(inst.data) }); } }; diff --git a/src/arch/riscv64/bits.zig b/src/arch/riscv64/bits.zig index 328ffa5e03..a3e39c9f75 100644 --- a/src/arch/riscv64/bits.zig +++ b/src/arch/riscv64/bits.zig @@ -256,21 +256,12 @@ pub const FrameIndex = enum(u32) { return @intFromEnum(fi) < named_count; } - pub fn format( - fi: FrameIndex, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - try writer.writeAll("FrameIndex"); - if (fi.isNamed()) { - try writer.writeByte('.'); - try writer.writeAll(@tagName(fi)); - } else { - try writer.writeByte('('); - try std.fmt.formatType(@intFromEnum(fi), fmt, options, writer, 0); - try writer.writeByte(')'); - } + pub fn format(fi: FrameIndex, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + try bw.writeAll("FrameIndex"); + if (fi.isNamed()) + try bw.print(".{s}", .{@tagName(fi)}) + else + try bw.print("({d})", .{@intFromEnum(fi)}); } }; diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 5115c432a7..238bbaee9e 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -1001,7 +1001,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void { switch (self.args[arg_index]) { .stack_offset => |off| { const abi_size = math.cast(u32, ty.abiSize(zcu)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(pt)}); + return self.fail("type '{f}' too big to fit into stack frame", .{ty.fmt(pt)}); }; const offset = off + abi_size; break :blk .{ .stack_offset = offset }; @@ -2748,7 +2748,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { } const abi_size = math.cast(u32, elem_ty.abiSize(zcu)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); + return self.fail("type '{f}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); }; // TODO swap this for inst.ty.ptrAlign const abi_align = elem_ty.abiAlignment(zcu); @@ -2760,7 +2760,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { const zcu = pt.zcu; const elem_ty = self.typeOfIndex(inst); const abi_size = math.cast(u32, elem_ty.abiSize(zcu)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); + return self.fail("type '{f}' too big to fit into stack frame", .{elem_ty.fmt(pt)}); }; const abi_align = elem_ty.abiAlignment(zcu); self.stack_align = self.stack_align.max(abi_align); @@ -4111,7 +4111,7 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { while (true) { i -= 1; if (self.branch_stack.items[i].inst_table.get(inst)) |mcv| { - log.debug("getResolvedInstValue %{} => {}", .{ inst, mcv }); + log.debug("getResolvedInstValue %{f} => {}", .{ inst, mcv }); assert(mcv != .dead); return mcv; } @@ -4382,7 +4382,7 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { const prev_value = self.getResolvedInstValue(inst); const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; branch.inst_table.putAssumeCapacity(inst, .dead); - log.debug("%{} death: {} -> .dead", .{ inst, prev_value }); + log.debug("%{f} death: {} -> .dead", .{ inst, prev_value }); switch (prev_value) { .register => |reg| { self.register_manager.freeReg(reg); diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 9452066bc5..027a709e2c 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1463,7 +1463,7 @@ fn allocStack(cg: *CodeGen, ty: Type) !WValue { } const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse { - return cg.fail("Type {} with ABI size of {d} exceeds stack frame size", .{ + return cg.fail("Type {f} with ABI size of {d} exceeds stack frame size", .{ ty.fmt(pt), ty.abiSize(zcu), }); }; @@ -1497,7 +1497,7 @@ fn allocStackPtr(cg: *CodeGen, inst: Air.Inst.Index) !WValue { const abi_alignment = ptr_ty.ptrAlignment(zcu); const abi_size = std.math.cast(u32, pointee_ty.abiSize(zcu)) orelse { - return cg.fail("Type {} with ABI size of {d} exceeds stack frame size", .{ + return cg.fail("Type {f} with ABI size of {d} exceeds stack frame size", .{ pointee_ty.fmt(pt), pointee_ty.abiSize(zcu), }); }; @@ -2404,7 +2404,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr try cg.memcpy(lhs, rhs, .{ .imm32 = @as(u32, @intCast(ty.abiSize(zcu))) }); }, else => if (abi_size > 8) { - return cg.fail("TODO: `store` for type `{}` with abisize `{d}`", .{ + return cg.fail("TODO: `store` for type `{f}` with abisize `{d}`", .{ ty.fmt(pt), abi_size, }); @@ -2597,7 +2597,7 @@ fn binOp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WV return cg.binOpBigInt(lhs, rhs, ty, op); } else { return cg.fail( - "TODO: Implement binary operation for type: {}", + "TODO: Implement binary operation for type: {f}", .{ty.fmt(pt)}, ); } @@ -2817,7 +2817,7 @@ fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { switch (scalar_ty.zigTypeTag(zcu)) { .int => if (ty.zigTypeTag(zcu) == .vector) { - return cg.fail("TODO implement airAbs for {}", .{ty.fmt(pt)}); + return cg.fail("TODO implement airAbs for {f}", .{ty.fmt(pt)}); } else { const int_bits = ty.intInfo(zcu).bits; const wasm_bits = toWasmBits(int_bits) orelse { @@ -3244,7 +3244,7 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue { return .{ .imm32 = @intFromBool(!val.isNull(zcu)) }; }, .aggregate => switch (ip.indexToKey(ty.ip_index)) { - .array_type => return cg.fail("Wasm TODO: LowerConstant for {}", .{ty.fmt(pt)}), + .array_type => return cg.fail("Wasm TODO: LowerConstant for {f}", .{ty.fmt(pt)}), .vector_type => { assert(determineSimdStoreStrategy(ty, zcu, cg.target) == .direct); var buf: [16]u8 = undefined; @@ -3608,7 +3608,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } else { const int_info = operand_ty.intInfo(zcu); const wasm_bits = toWasmBits(int_info.bits) orelse { - return cg.fail("TODO: Implement binary NOT for {}", .{operand_ty.fmt(pt)}); + return cg.fail("TODO: Implement binary NOT for {f}", .{operand_ty.fmt(pt)}); }; switch (wasm_bits) { @@ -3874,7 +3874,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { }, else => result: { const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, zcu)) orelse { - return cg.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(pt)}); + return cg.fail("Field type '{f}' too big to fit into stack frame", .{field_ty.fmt(pt)}); }; if (isByRef(field_ty, zcu, cg.target)) { switch (operand) { @@ -4360,7 +4360,7 @@ fn isNull(cg: *CodeGen, operand: WValue, optional_ty: Type, opcode: std.wasm.Opc // a pointer to the stack value if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse { - return cg.fail("Optional type {} too big to fit into stack frame", .{optional_ty.fmt(pt)}); + return cg.fail("Optional type {f} too big to fit into stack frame", .{optional_ty.fmt(pt)}); }; try cg.addMemArg(.i32_load8_u, .{ .offset = operand.offset() + offset, .alignment = 1 }); } @@ -4430,7 +4430,7 @@ fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void } const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse { - return cg.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(pt)}); + return cg.fail("Optional type {f} too big to fit into stack frame", .{opt_ty.fmt(pt)}); }; try cg.emitWValue(operand); @@ -4462,7 +4462,7 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { break :result cg.reuseOperand(ty_op.operand, operand); } const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse { - return cg.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(pt)}); + return cg.fail("Optional type {f} too big to fit into stack frame", .{op_ty.fmt(pt)}); }; // Create optional type, set the non-null bit, and store the operand inside the optional type @@ -6196,7 +6196,7 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { _ = try cg.load(overflow_ret, Type.i32, 0); try cg.addLocal(.local_set, overflow_bit.local.value); break :blk res; - } else return cg.fail("TODO: @mulWithOverflow for {}", .{ty.fmt(pt)}); + } else return cg.fail("TODO: @mulWithOverflow for {f}", .{ty.fmt(pt)}); var bin_op_local = try mul.toLocal(cg, ty); defer bin_op_local.free(cg); @@ -6749,7 +6749,7 @@ fn airMod(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const add = try cg.binOp(rem, rhs, ty, .add); break :result try cg.binOp(add, rhs, ty, .rem); } - return cg.fail("TODO: @mod for {}", .{ty.fmt(pt)}); + return cg.fail("TODO: @mod for {f}", .{ty.fmt(pt)}); }; return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); @@ -6767,7 +6767,7 @@ fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const lhs = try cg.resolveInst(bin_op.lhs); const rhs = try cg.resolveInst(bin_op.rhs); const wasm_bits = toWasmBits(int_info.bits) orelse { - return cg.fail("TODO: mul_sat for {}", .{ty.fmt(pt)}); + return cg.fail("TODO: mul_sat for {f}", .{ty.fmt(pt)}); }; switch (wasm_bits) { @@ -6804,7 +6804,7 @@ fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { }, 64 => { if (!(int_info.bits == 64 and int_info.signedness == .signed)) { - return cg.fail("TODO: mul_sat for {}", .{ty.fmt(pt)}); + return cg.fail("TODO: mul_sat for {f}", .{ty.fmt(pt)}); } const overflow_ret = try cg.allocStack(Type.i32); _ = try cg.callIntrinsic( @@ -6822,7 +6822,7 @@ fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { }, 128 => { if (!(int_info.bits == 128 and int_info.signedness == .signed)) { - return cg.fail("TODO: mul_sat for {}", .{ty.fmt(pt)}); + return cg.fail("TODO: mul_sat for {f}", .{ty.fmt(pt)}); } const overflow_ret = try cg.allocStack(Type.i32); const ret = try cg.callIntrinsic( diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index 8024f2db9e..60d05238fc 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -14,16 +14,20 @@ const codegen = @import("../../codegen.zig"); mir: Mir, wasm: *Wasm, -/// The binary representation that will be emitted by this module. -code: *std.ArrayListUnmanaged(u8), +/// The binary representation of this module is written here. +bw: *std.io.BufferedWriter, pub const Error = error{ OutOfMemory, }; pub fn lowerToCode(emit: *Emit) Error!void { + return @errorCast(emit.lowerToCodeInner()); +} + +fn lowerToCodeInner(emit: *Emit) anyerror!void { const mir = &emit.mir; - const code = emit.code; + const bw = emit.bw; const wasm = emit.wasm; const comp = wasm.base.comp; const gpa = comp.gpa; @@ -41,18 +45,19 @@ pub fn lowerToCode(emit: *Emit) Error!void { }, .block, .loop => { const block_type = datas[inst].block_type; - try code.ensureUnusedCapacity(gpa, 2); - code.appendAssumeCapacity(@intFromEnum(tags[inst])); - code.appendAssumeCapacity(@intFromEnum(block_type)); + try bw.writeAll(&.{ + @intFromEnum(tags[inst]), + @intFromEnum(block_type), + }); inst += 1; continue :loop tags[inst]; }, .uav_ref => { if (is_obj) { - try uavRefObj(wasm, code, datas[inst].ip_index, 0, is_wasm32); + try uavRefObj(wasm, bw, datas[inst].ip_index, 0, is_wasm32); } else { - try uavRefExe(wasm, code, datas[inst].ip_index, 0, is_wasm32); + try uavRefExe(wasm, bw, datas[inst].ip_index, 0, is_wasm32); } inst += 1; continue :loop tags[inst]; @@ -60,20 +65,20 @@ pub fn lowerToCode(emit: *Emit) Error!void { .uav_ref_off => { const extra = mir.extraData(Mir.UavRefOff, datas[inst].payload).data; if (is_obj) { - try uavRefObj(wasm, code, extra.value, extra.offset, is_wasm32); + try uavRefObj(wasm, bw, extra.value, extra.offset, is_wasm32); } else { - try uavRefExe(wasm, code, extra.value, extra.offset, is_wasm32); + try uavRefExe(wasm, bw, extra.value, extra.offset, is_wasm32); } inst += 1; continue :loop tags[inst]; }, .nav_ref => { - try navRefOff(wasm, code, .{ .nav_index = datas[inst].nav_index, .offset = 0 }, is_wasm32); + try navRefOff(wasm, bw, .{ .nav_index = datas[inst].nav_index, .offset = 0 }, is_wasm32); inst += 1; continue :loop tags[inst]; }, .nav_ref_off => { - try navRefOff(wasm, code, mir.extraData(Mir.NavRefOff, datas[inst].payload).data, is_wasm32); + try navRefOff(wasm, bw, mir.extraData(Mir.NavRefOff, datas[inst].payload).data, is_wasm32); inst += 1; continue :loop tags[inst]; }, @@ -81,11 +86,11 @@ pub fn lowerToCode(emit: *Emit) Error!void { const indirect_func_idx: Wasm.ZcuIndirectFunctionSetIndex = @enumFromInt( wasm.zcu_indirect_function_set.getIndex(datas[inst].nav_index).?, ); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); if (is_obj) { @panic("TODO"); } else { - leb.writeUleb128(code.fixedWriter(), 1 + @intFromEnum(indirect_func_idx)) catch unreachable; + try bw.writeLeb128(1 + @intFromEnum(indirect_func_idx)); } inst += 1; continue :loop tags[inst]; @@ -95,52 +100,48 @@ pub fn lowerToCode(emit: *Emit) Error!void { continue :loop tags[inst]; }, .errors_len => { - try code.ensureUnusedCapacity(gpa, 6); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); // MIR is lowered during flush, so there is indeed only one thread at this time. - const errors_len = 1 + comp.zcu.?.intern_pool.global_error_set.getNamesFromMainThread().len; - leb.writeIleb128(code.fixedWriter(), errors_len) catch unreachable; + const errors_len: u32 = @intCast(1 + comp.zcu.?.intern_pool.global_error_set.getNamesFromMainThread().len); + try bw.writeLeb128(@as(i32, @bitCast(errors_len))); inst += 1; continue :loop tags[inst]; }, .error_name_table_ref => { wasm.error_name_table_ref_count += 1; - try code.ensureUnusedCapacity(gpa, 11); const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; - code.appendAssumeCapacity(@intFromEnum(opcode)); + try bw.writeByte(@intFromEnum(opcode)); if (is_obj) { try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), + .offset = @intCast(bw.count), .pointee = .{ .symbol_index = try wasm.errorNameTableSymbolIndex() }, .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64, .addend = 0, }); - code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10); + try bw.splatByteAll(0, if (is_wasm32) 5 else 10); inst += 1; continue :loop tags[inst]; } else { const addr: u32 = wasm.errorNameTableAddr(); - leb.writeIleb128(code.fixedWriter(), addr) catch unreachable; + try bw.writeLeb128(@as(i32, @bitCast(addr))); inst += 1; continue :loop tags[inst]; } }, .br_if, .br, .memory_grow, .memory_size => { - try code.ensureUnusedCapacity(gpa, 11); - code.appendAssumeCapacity(@intFromEnum(tags[inst])); - leb.writeUleb128(code.fixedWriter(), datas[inst].label) catch unreachable; + try bw.writeByte(@intFromEnum(tags[inst])); + try bw.writeLeb128(datas[inst].label); inst += 1; continue :loop tags[inst]; }, .local_get, .local_set, .local_tee => { - try code.ensureUnusedCapacity(gpa, 11); - code.appendAssumeCapacity(@intFromEnum(tags[inst])); - leb.writeUleb128(code.fixedWriter(), datas[inst].local) catch unreachable; + try bw.writeByte(@intFromEnum(tags[inst])); + try bw.writeLeb128(datas[inst].local); inst += 1; continue :loop tags[inst]; @@ -150,29 +151,27 @@ pub fn lowerToCode(emit: *Emit) Error!void { const extra_index = datas[inst].payload; const extra = mir.extraData(Mir.JumpTable, extra_index); const labels = mir.extra[extra.end..][0..extra.data.length]; - try code.ensureUnusedCapacity(gpa, 11 + 10 * labels.len); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br_table)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.br_table)); // -1 because default label is not part of length/depth. - leb.writeUleb128(code.fixedWriter(), extra.data.length - 1) catch unreachable; - for (labels) |label| leb.writeUleb128(code.fixedWriter(), label) catch unreachable; + try bw.writeLeb128(extra.data.length - 1); + for (labels) |label| try bw.writeLeb128(label); inst += 1; continue :loop tags[inst]; }, .call_nav => { - try code.ensureUnusedCapacity(gpa, 6); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.call)); if (is_obj) { try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), + .offset = @intCast(bw.count), .pointee = .{ .symbol_index = try wasm.navSymbolIndex(datas[inst].nav_index) }, .tag = .function_index_leb, .addend = 0, }); - code.appendNTimesAssumeCapacity(0, 5); + try bw.splatByteAll(0, 5); } else { - appendOutputFunctionIndex(code, .fromIpNav(wasm, datas[inst].nav_index)); + try appendOutputFunctionIndex(bw, .fromIpNav(wasm, datas[inst].nav_index)); } inst += 1; @@ -180,7 +179,6 @@ pub fn lowerToCode(emit: *Emit) Error!void { }, .call_indirect => { - try code.ensureUnusedCapacity(gpa, 11); const fn_info = comp.zcu.?.typeToFunc(.fromInterned(datas[inst].ip_index)).?; const func_ty_index = wasm.getExistingFunctionType( fn_info.cc, @@ -188,38 +186,37 @@ pub fn lowerToCode(emit: *Emit) Error!void { .fromInterned(fn_info.return_type), target, ).?; - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call_indirect)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.call_indirect)); if (is_obj) { try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), + .offset = @intCast(bw.count), .pointee = .{ .type_index = func_ty_index }, .tag = .type_index_leb, .addend = 0, }); - code.appendNTimesAssumeCapacity(0, 5); + try bw.splatByteAll(0, 5); } else { const index: Wasm.Flush.FuncTypeIndex = .fromTypeIndex(func_ty_index, &wasm.flush_buffer); - leb.writeUleb128(code.fixedWriter(), @intFromEnum(index)) catch unreachable; + try bw.writeLeb128(@intFromEnum(index)); } - leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // table index + try bw.writeUleb128(0); // table index inst += 1; continue :loop tags[inst]; }, .call_tag_name => { - try code.ensureUnusedCapacity(gpa, 6); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.call)); if (is_obj) { try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), + .offset = @intCast(bw.count), .pointee = .{ .symbol_index = try wasm.tagNameSymbolIndex(datas[inst].ip_index) }, .tag = .function_index_leb, .addend = 0, }); - code.appendNTimesAssumeCapacity(0, 5); + try bw.splatByteAll(0, 5); } else { - appendOutputFunctionIndex(code, .fromTagNameType(wasm, datas[inst].ip_index)); + try appendOutputFunctionIndex(bw, .fromTagNameType(wasm, datas[inst].ip_index)); } inst += 1; @@ -232,18 +229,17 @@ pub fn lowerToCode(emit: *Emit) Error!void { // table initialized based on the `Mir.Intrinsic` enum. const symbol_name = try wasm.internString(@tagName(datas[inst].intrinsic)); - try code.ensureUnusedCapacity(gpa, 6); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.call)); if (is_obj) { try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), + .offset = @intCast(bw.count), .pointee = .{ .symbol_index = try wasm.symbolNameIndex(symbol_name) }, .tag = .function_index_leb, .addend = 0, }); - code.appendNTimesAssumeCapacity(0, 5); + try bw.splatByteAll(0, 5); } else { - appendOutputFunctionIndex(code, .fromSymbolName(wasm, symbol_name)); + try appendOutputFunctionIndex(bw, .fromSymbolName(wasm, symbol_name)); } inst += 1; @@ -251,19 +247,17 @@ pub fn lowerToCode(emit: *Emit) Error!void { }, .global_set_sp => { - try code.ensureUnusedCapacity(gpa, 6); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_set)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.global_set)); if (is_obj) { try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), + .offset = @intCast(bw.count), .pointee = .{ .symbol_index = try wasm.stackPointerSymbolIndex() }, .tag = .global_index_leb, .addend = 0, }); - code.appendNTimesAssumeCapacity(0, 5); + try bw.splatByteAll(0, 5); } else { - const sp_global: Wasm.GlobalIndex = .stack_pointer; - std.leb.writeULEB128(code.fixedWriter(), @intFromEnum(sp_global)) catch unreachable; + try bw.writeLeb128(@intFromEnum(Wasm.GlobalIndex.stack_pointer)); } inst += 1; @@ -271,36 +265,32 @@ pub fn lowerToCode(emit: *Emit) Error!void { }, .f32_const => { - try code.ensureUnusedCapacity(gpa, 5); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.f32_const)); - std.mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @bitCast(datas[inst].float32), .little); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.f32_const)); + try bw.writeInt(u32, @bitCast(datas[inst].float32), .little); inst += 1; continue :loop tags[inst]; }, .f64_const => { - try code.ensureUnusedCapacity(gpa, 9); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.f64_const)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.f64_const)); const float64 = mir.extraData(Mir.Float64, datas[inst].payload).data; - std.mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), float64.toInt(), .little); + try bw.writeInt(u64, float64.toInt(), .little); inst += 1; continue :loop tags[inst]; }, .i32_const => { - try code.ensureUnusedCapacity(gpa, 6); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); - leb.writeIleb128(code.fixedWriter(), datas[inst].imm32) catch unreachable; + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeLeb128(datas[inst].imm32); inst += 1; continue :loop tags[inst]; }, .i64_const => { - try code.ensureUnusedCapacity(gpa, 11); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_const)); const int64: i64 = @bitCast(mir.extraData(Mir.Imm64, datas[inst].payload).data.toInt()); - leb.writeIleb128(code.fixedWriter(), int64) catch unreachable; + try bw.writeLeb128(int64); inst += 1; continue :loop tags[inst]; @@ -330,9 +320,8 @@ pub fn lowerToCode(emit: *Emit) Error!void { .i64_store16, .i64_store32, => { - try code.ensureUnusedCapacity(gpa, 1 + 20); - code.appendAssumeCapacity(@intFromEnum(tags[inst])); - encodeMemArg(code, mir.extraData(Mir.MemArg, datas[inst].payload).data); + try bw.writeByte(@intFromEnum(tags[inst])); + try encodeMemArg(bw, mir.extraData(Mir.MemArg, datas[inst].payload).data); inst += 1; continue :loop tags[inst]; }, @@ -466,43 +455,42 @@ pub fn lowerToCode(emit: *Emit) Error!void { .i64_clz, .i64_ctz, => { - try code.append(gpa, @intFromEnum(tags[inst])); + try bw.writeByte(@intFromEnum(tags[inst])); inst += 1; continue :loop tags[inst]; }, .misc_prefix => { - try code.ensureUnusedCapacity(gpa, 6 + 6); const extra_index = datas[inst].payload; - const opcode = mir.extra[extra_index]; - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.misc_prefix)); - leb.writeUleb128(code.fixedWriter(), opcode) catch unreachable; - switch (@as(std.wasm.MiscOpcode, @enumFromInt(opcode))) { + const opcode: std.wasm.MiscOpcode = @enumFromInt(mir.extra[extra_index]); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); + try bw.writeLeb128(@intFromEnum(opcode)); + switch (opcode) { // bulk-memory opcodes .data_drop => { const segment = mir.extra[extra_index + 1]; - leb.writeUleb128(code.fixedWriter(), segment) catch unreachable; + try bw.writeLeb128(segment); inst += 1; continue :loop tags[inst]; }, .memory_init => { const segment = mir.extra[extra_index + 1]; - leb.writeUleb128(code.fixedWriter(), segment) catch unreachable; - leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // memory index + try bw.writeLeb128(segment); + try bw.writeByte(0); // memory index inst += 1; continue :loop tags[inst]; }, .memory_fill => { - leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // memory index + try bw.writeByte(0); // memory index inst += 1; continue :loop tags[inst]; }, .memory_copy => { - leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // dst memory index - leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // src memory index + try bw.writeByte(0); // dst memory index + try bw.writeByte(0); // src memory index inst += 1; continue :loop tags[inst]; @@ -534,12 +522,11 @@ pub fn lowerToCode(emit: *Emit) Error!void { comptime unreachable; }, .simd_prefix => { - try code.ensureUnusedCapacity(gpa, 6 + 20); const extra_index = datas[inst].payload; - const opcode = mir.extra[extra_index]; - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.simd_prefix)); - leb.writeUleb128(code.fixedWriter(), opcode) catch unreachable; - switch (@as(std.wasm.SimdOpcode, @enumFromInt(opcode))) { + const opcode: std.wasm.SimdOpcode = @enumFromInt(mir.extra[extra_index]); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.simd_prefix)); + try bw.writeLeb128(@intFromEnum(opcode)); + switch (opcode) { .v128_store, .v128_load, .v128_load8_splat, @@ -547,12 +534,12 @@ pub fn lowerToCode(emit: *Emit) Error!void { .v128_load32_splat, .v128_load64_splat, => { - encodeMemArg(code, mir.extraData(Mir.MemArg, extra_index + 1).data); + try encodeMemArg(bw, mir.extraData(Mir.MemArg, extra_index + 1).data); inst += 1; continue :loop tags[inst]; }, .v128_const, .i8x16_shuffle => { - code.appendSliceAssumeCapacity(std.mem.asBytes(mir.extra[extra_index + 1 ..][0..4])); + try bw.writeAll(std.mem.asBytes(mir.extra[extra_index + 1 ..][0..4])); inst += 1; continue :loop tags[inst]; }, @@ -571,7 +558,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { .f64x2_extract_lane, .f64x2_replace_lane, => { - code.appendAssumeCapacity(@intCast(mir.extra[extra_index + 1])); + try bw.writeByte(@intCast(mir.extra[extra_index + 1])); inst += 1; continue :loop tags[inst]; }, @@ -819,13 +806,11 @@ pub fn lowerToCode(emit: *Emit) Error!void { comptime unreachable; }, .atomics_prefix => { - try code.ensureUnusedCapacity(gpa, 6 + 20); - const extra_index = datas[inst].payload; - const opcode = mir.extra[extra_index]; - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix)); - leb.writeUleb128(code.fixedWriter(), opcode) catch unreachable; - switch (@as(std.wasm.AtomicsOpcode, @enumFromInt(opcode))) { + const opcode: std.wasm.AtomicsOpcode = @enumFromInt(mir.extra[extra_index]); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); + try bw.writeLeb128(@intFromEnum(opcode)); + switch (opcode) { .i32_atomic_load, .i64_atomic_load, .i32_atomic_load8_u, @@ -892,15 +877,12 @@ pub fn lowerToCode(emit: *Emit) Error!void { .i64_atomic_rmw32_cmpxchg_u, => { const mem_arg = mir.extraData(Mir.MemArg, extra_index + 1).data; - encodeMemArg(code, mem_arg); + try encodeMemArg(bw, mem_arg); inst += 1; continue :loop tags[inst]; }, .atomic_fence => { - // Hard-codes memory index 0 since multi-memory proposal is - // not yet accepted nor implemented. - const memory_index: u32 = 0; - leb.writeUleb128(code.fixedWriter(), memory_index) catch unreachable; + try bw.writeByte(0); // memory index inst += 1; continue :loop tags[inst]; }, @@ -915,44 +897,36 @@ pub fn lowerToCode(emit: *Emit) Error!void { } /// Asserts 20 unused capacity. -fn encodeMemArg(code: *std.ArrayListUnmanaged(u8), mem_arg: Mir.MemArg) void { - assert(code.unusedCapacitySlice().len >= 20); - // Wasm encodes alignment as power of 2, rather than natural alignment. - const encoded_alignment = @ctz(mem_arg.alignment); - leb.writeUleb128(code.fixedWriter(), encoded_alignment) catch unreachable; - leb.writeUleb128(code.fixedWriter(), mem_arg.offset) catch unreachable; +fn encodeMemArg(bw: *std.io.BufferedWriter, mem_arg: Mir.MemArg) anyerror!void { + try bw.writeLeb128(Wasm.Alignment.fromNonzeroByteUnits(mem_arg.alignment).toLog2Units()); + try bw.writeLeb128(mem_arg.offset); } -fn uavRefObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void { +fn uavRefObj(wasm: *Wasm, bw: *std.io.BufferedWriter, value: InternPool.Index, offset: i32, is_wasm32: bool) !void { const comp = wasm.base.comp; const gpa = comp.gpa; const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; - try code.ensureUnusedCapacity(gpa, 11); - code.appendAssumeCapacity(@intFromEnum(opcode)); + try bw.writeByte(@intFromEnum(opcode)); try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), + .offset = @intCast(bw.count), .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(value) }, .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64, .addend = offset, }); - code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10); + try bw.splatByteAll(0, if (is_wasm32) 5 else 10); } -fn uavRefExe(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void { - const comp = wasm.base.comp; - const gpa = comp.gpa; +fn uavRefExe(wasm: *Wasm, bw: *std.io.BufferedWriter, value: InternPool.Index, offset: i32, is_wasm32: bool) !void { const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; - - try code.ensureUnusedCapacity(gpa, 11); - code.appendAssumeCapacity(@intFromEnum(opcode)); + try bw.writeByte(@intFromEnum(opcode)); const addr = wasm.uavAddr(value); - leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(@as(i64, addr) + offset))) catch unreachable; + try bw.writeLeb128(@as(u32, @intCast(@as(i64, addr) + offset))); } -fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff, is_wasm32: bool) !void { +fn navRefOff(wasm: *Wasm, bw: *std.io.BufferedWriter, data: Mir.NavRefOff, is_wasm32: bool) !void { const comp = wasm.base.comp; const zcu = comp.zcu.?; const ip = &zcu.intern_pool; @@ -961,24 +935,22 @@ fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff const nav_ty = ip.getNav(data.nav_index).typeOf(ip); assert(!ip.isFunctionType(nav_ty)); - try code.ensureUnusedCapacity(gpa, 11); - const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; - code.appendAssumeCapacity(@intFromEnum(opcode)); + try bw.writeByte(@intFromEnum(opcode)); if (is_obj) { try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), + .offset = @intCast(bw.count), .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) }, .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64, .addend = data.offset, }); - code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10); + try bw.splatByteAll(0, if (is_wasm32) 5 else 10); } else { const addr = wasm.navAddr(data.nav_index); - leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(@as(i64, addr) + data.offset))) catch unreachable; + try bw.writeLeb128(@as(i32, @bitCast(@as(u32, @intCast(@as(i64, addr) + data.offset))))); } } -fn appendOutputFunctionIndex(code: *std.ArrayListUnmanaged(u8), i: Wasm.OutputFunctionIndex) void { - leb.writeUleb128(code.fixedWriter(), @intFromEnum(i)) catch unreachable; +fn appendOutputFunctionIndex(bw: *std.io.BufferedWriter, i: Wasm.OutputFunctionIndex) anyerror!void { + return bw.writeLeb128(@intFromEnum(i)); } diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 90c777aa45..387febe0a7 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -524,52 +524,47 @@ pub const MCValue = union(enum) { }; } - pub fn format( - mcv: MCValue, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(mcv: MCValue, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { switch (mcv) { - .none, .unreach, .dead, .undef => try writer.print("({s})", .{@tagName(mcv)}), - .immediate => |pl| try writer.print("0x{x}", .{pl}), - .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}), - inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}), - .register_pair => |pl| try writer.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }), - .register_triple => |pl| try writer.print("{s}:{s}:{s}", .{ + .none, .unreach, .dead, .undef => try bw.print("({s})", .{@tagName(mcv)}), + .immediate => |pl| try bw.print("0x{x}", .{pl}), + .memory => |pl| try bw.print("[ds:0x{x}]", .{pl}), + inline .eflags, .register => |pl| try bw.print("{s}", .{@tagName(pl)}), + .register_pair => |pl| try bw.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }), + .register_triple => |pl| try bw.print("{s}:{s}:{s}", .{ @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]), }), - .register_quadruple => |pl| try writer.print("{s}:{s}:{s}:{s}", .{ + .register_quadruple => |pl| try bw.print("{s}:{s}:{s}:{s}", .{ @tagName(pl[3]), @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]), }), - .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }), - .register_overflow => |pl| try writer.print("{s}:{s}", .{ + .register_offset => |pl| try bw.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }), + .register_overflow => |pl| try bw.print("{s}:{s}", .{ @tagName(pl.eflags), @tagName(pl.reg), }), - .register_mask => |pl| try writer.print("mask({s},{}):{c}{s}", .{ + .register_mask => |pl| try bw.print("mask({s},{f}):{c}{s}", .{ @tagName(pl.info.kind), pl.info.scalar, @as(u8, if (pl.info.inverted) '!' else ' '), @tagName(pl.reg), }), - .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), - .indirect_load_frame => |pl| try writer.print("[[{} + 0x{x}]]", .{ pl.index, pl.off }), - .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }), - .lea_frame => |pl| try writer.print("{} + 0x{x}", .{ pl.index, pl.off }), - .load_nav => |pl| try writer.print("[nav:{d}]", .{@intFromEnum(pl)}), - .lea_nav => |pl| try writer.print("nav:{d}", .{@intFromEnum(pl)}), - .load_uav => |pl| try writer.print("[uav:{d}]", .{@intFromEnum(pl.val)}), - .lea_uav => |pl| try writer.print("uav:{d}", .{@intFromEnum(pl.val)}), - .load_lazy_sym => |pl| try writer.print("[lazy:{s}:{d}]", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), - .lea_lazy_sym => |pl| try writer.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), - .load_extern_func => |pl| try writer.print("[extern:{d}]", .{@intFromEnum(pl)}), - .lea_extern_func => |pl| try writer.print("extern:{d}", .{@intFromEnum(pl)}), - .elementwise_args => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{ + .indirect => |pl| try bw.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), + .indirect_load_frame => |pl| try bw.print("[[{} + 0x{x}]]", .{ pl.index, pl.off }), + .load_frame => |pl| try bw.print("[{} + 0x{x}]", .{ pl.index, pl.off }), + .lea_frame => |pl| try bw.print("{} + 0x{x}", .{ pl.index, pl.off }), + .load_nav => |pl| try bw.print("[nav:{d}]", .{@intFromEnum(pl)}), + .lea_nav => |pl| try bw.print("nav:{d}", .{@intFromEnum(pl)}), + .load_uav => |pl| try bw.print("[uav:{d}]", .{@intFromEnum(pl.val)}), + .lea_uav => |pl| try bw.print("uav:{d}", .{@intFromEnum(pl.val)}), + .load_lazy_sym => |pl| try bw.print("[lazy:{s}:{d}]", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), + .lea_lazy_sym => |pl| try bw.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), + .load_extern_func => |pl| try bw.print("[extern:{d}]", .{@intFromEnum(pl)}), + .lea_extern_func => |pl| try bw.print("extern:{d}", .{@intFromEnum(pl)}), + .elementwise_args => |pl| try bw.print("elementwise:{d}:[{} + 0x{x}]", .{ pl.regs, pl.frame_index, pl.frame_off, }), - .reserved_frame => |pl| try writer.print("(dead:{})", .{pl}), - .air_ref => |pl| try writer.print("(air:0x{x})", .{@intFromEnum(pl)}), + .reserved_frame => |pl| try bw.print("(dead:{})", .{pl}), + .air_ref => |pl| try bw.print("(air:0x{x})", .{@intFromEnum(pl)}), } } }; @@ -639,7 +634,7 @@ const InstTracking = struct { .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } }, else => unreachable, } - tracking_log.debug("spill {} from {} to {}", .{ inst, self.short, self.long }); + tracking_log.debug("spill {f} from {f} to {f}", .{ inst, self.short, self.long }); try cg.genCopy(cg.typeOfIndex(inst), self.long, self.short, .{}); for (self.short.getRegs()) |reg| if (reg.isClass(.x87)) try cg.asmRegister(.{ .f_, .free }, reg); } @@ -672,7 +667,7 @@ const InstTracking = struct { else => {}, // TODO process stack allocation death } self.reuseFrame(); - tracking_log.debug("{} => {} (spilled)", .{ inst, self.* }); + tracking_log.debug("{f} => {f} (spilled)", .{ inst, self.* }); } fn verifyMaterialize(self: InstTracking, target: InstTracking) void { @@ -749,7 +744,7 @@ const InstTracking = struct { else => target.long, } else target.long; self.short = target.short; - tracking_log.debug("{} => {} (materialize)", .{ inst, self.* }); + tracking_log.debug("{f} => {f} (materialize)", .{ inst, self.* }); } fn resurrect(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index, scope_generation: u32) !void { @@ -757,7 +752,7 @@ const InstTracking = struct { .dead => |die_generation| if (die_generation >= scope_generation) { self.reuseFrame(); try function.getValue(self.short, inst); - tracking_log.debug("{} => {} (resurrect)", .{ inst, self.* }); + tracking_log.debug("{f} => {f} (resurrect)", .{ inst, self.* }); }, else => {}, } @@ -768,7 +763,7 @@ const InstTracking = struct { try function.freeValue(self.short, opts); if (self.long == .none) self.long = self.short; self.short = .{ .dead = function.scope_generation }; - tracking_log.debug("{} => {} (death)", .{ inst, self.* }); + tracking_log.debug("{f} => {f} (death)", .{ inst, self.* }); } fn reuse( @@ -778,13 +773,13 @@ const InstTracking = struct { old_inst: Air.Inst.Index, ) void { self.short = .{ .dead = function.scope_generation }; - tracking_log.debug("{?} => {} (reuse {})", .{ new_inst, self.*, old_inst }); + tracking_log.debug("{?f} => {f} (reuse {f})", .{ new_inst, self.*, old_inst }); } fn liveOut(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index) void { for (self.getRegs()) |reg| { if (function.register_manager.isRegFree(reg)) { - tracking_log.debug("{} => {} (live-out)", .{ inst, self.* }); + tracking_log.debug("{f} => {f} (live-out)", .{ inst, self.* }); continue; } @@ -812,18 +807,13 @@ const InstTracking = struct { // Perform side-effects of freeValue manually. function.register_manager.freeReg(reg); - tracking_log.debug("{} => {} (live-out {})", .{ inst, self.*, tracked_inst }); + tracking_log.debug("{f} => {f} (live-out {f})", .{ inst, self.*, tracked_inst }); } } - pub fn format( - tracking: InstTracking, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (!std.meta.eql(tracking.long, tracking.short)) try writer.print("|{}| ", .{tracking.long}); - try writer.print("{}", .{tracking.short}); + pub fn format(tracking: InstTracking, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + if (!std.meta.eql(tracking.long, tracking.short)) try bw.print("|{f}| ", .{tracking.long}); + try bw.print("{f}", .{tracking.short}); } }; @@ -939,7 +929,7 @@ pub fn generate( function.inst_tracking.putAssumeCapacityNoClobber(temp.toIndex(), .init(.none)); } - wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)}); + wip_mir_log.debug("{f}:", .{fmtNav(func.owner_nav, ip)}); try function.frame_allocs.resize(gpa, FrameIndex.named_count); function.frame_allocs.set( @@ -1097,13 +1087,8 @@ const FormatNavData = struct { ip: *const InternPool, nav_index: InternPool.Nav.Index, }; -fn formatNav( - data: FormatNavData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { - try writer.print("{}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)}); +fn formatNav(data: FormatNavData, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + try bw.print("{f}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)}); } fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Formatter(formatNav) { return .{ .data = .{ @@ -1116,12 +1101,7 @@ const FormatAirData = struct { self: *CodeGen, inst: Air.Inst.Index, }; -fn formatAir( - data: FormatAirData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { +fn formatAir(data: FormatAirData, _: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness); } fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { @@ -1132,12 +1112,7 @@ const FormatWipMirData = struct { self: *CodeGen, inst: Mir.Inst.Index, }; -fn formatWipMir( - data: FormatWipMirData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { +fn formatWipMir(data: FormatWipMirData, bw: *std.io.BufferedWriter, comptime _: []const u8) !void { var lower: Lower = .{ .target = data.self.target, .allocator = data.self.gpa, @@ -1152,11 +1127,11 @@ fn formatWipMir( lower.err_msg.?.deinit(data.self.gpa); lower.err_msg = null; } - try writer.writeAll(lower.err_msg.?.msg); + try bw.writeAll(lower.err_msg.?.msg); return; }, error.OutOfMemory, error.InvalidInstruction, error.CannotEncode => |e| { - try writer.writeAll(switch (e) { + try bw.writeAll(switch (e) { error.OutOfMemory => "Out of memory", error.InvalidInstruction => "CodeGen failed to find a viable instruction.", error.CannotEncode => "CodeGen failed to encode the instruction.", @@ -1165,14 +1140,14 @@ fn formatWipMir( }, else => |e| return e, }).insts) |lowered_inst| { - if (!first) try writer.writeAll("\ndebug(wip_mir): "); - try writer.print(" | {}", .{lowered_inst}); + if (!first) try bw.writeAll("\ndebug(wip_mir): "); + try bw.print(" | {f}", .{lowered_inst}); first = false; } if (first) { const ip = &data.self.pt.zcu.intern_pool; const mir_inst = lower.mir.instructions.get(data.inst); - try writer.print(" | .{s}", .{@tagName(mir_inst.ops)}); + try bw.print(" | .{s}", .{@tagName(mir_inst.ops)}); switch (mir_inst.ops) { else => unreachable, .pseudo_dbg_prologue_end_none, @@ -1184,20 +1159,20 @@ fn formatWipMir( .pseudo_dbg_var_none, .pseudo_dead_none, => {}, - .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column => try writer.print( + .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column => try bw.print( " {[line]d}, {[column]d}", mir_inst.data.line_column, ), - .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try writer.print(" {}", .{ + .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try bw.print(" {f}", .{ ip.getNav(ip.indexToKey(mir_inst.data.ip_index).func.owner_nav).name.fmt(ip), }), - .pseudo_dbg_arg_i_s, .pseudo_dbg_var_i_s => try writer.print(" {d}", .{ + .pseudo_dbg_arg_i_s, .pseudo_dbg_var_i_s => try bw.print(" {d}", .{ @as(i32, @bitCast(mir_inst.data.i.i)), }), - .pseudo_dbg_arg_i_u, .pseudo_dbg_var_i_u => try writer.print(" {d}", .{ + .pseudo_dbg_arg_i_u, .pseudo_dbg_var_i_u => try bw.print(" {d}", .{ mir_inst.data.i.i, }), - .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => try writer.print(" {d}", .{ + .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => try bw.print(" {d}", .{ mir_inst.data.i64, }), .pseudo_dbg_arg_ro, .pseudo_dbg_var_ro => { @@ -1205,22 +1180,22 @@ fn formatWipMir( .base = .{ .reg = mir_inst.data.ro.reg }, .disp = mir_inst.data.ro.off, }) }; - try writer.print(" {}", .{mem_op.fmt(.m)}); + try bw.print(" {f}", .{mem_op.fmt(.m)}); }, .pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => { const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{ .base = .{ .frame = mir_inst.data.fa.index }, .disp = mir_inst.data.fa.off, }) }; - try writer.print(" {}", .{mem_op.fmt(.m)}); + try bw.print(" {f}", .{mem_op.fmt(.m)}); }, .pseudo_dbg_arg_m, .pseudo_dbg_var_m => { const mem_op: encoder.Instruction.Operand = .{ .mem = lower.mir.extraData(Mir.Memory, mir_inst.data.x.payload).data.decode(), }; - try writer.print(" {}", .{mem_op.fmt(.m)}); + try bw.print(" {f}", .{mem_op.fmt(.m)}); }, - .pseudo_dbg_arg_val, .pseudo_dbg_var_val => try writer.print(" {}", .{ + .pseudo_dbg_arg_val, .pseudo_dbg_var_val => try bw.print(" {}", .{ Value.fromInterned(mir_inst.data.ip_index).fmtValue(data.self.pt), }), } @@ -1233,14 +1208,9 @@ fn fmtWipMir(self: *CodeGen, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMi const FormatTrackingData = struct { self: *CodeGen, }; -fn formatTracking( - data: FormatTrackingData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { +fn formatTracking(data: FormatTrackingData, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { var it = data.self.inst_tracking.iterator(); - while (it.next()) |entry| try writer.print("\n{} = {}", .{ entry.key_ptr.*, entry.value_ptr.* }); + while (it.next()) |entry| try bw.print("\n{f} = {f}", .{ entry.key_ptr.*, entry.value_ptr.* }); } fn fmtTracking(self: *CodeGen) std.fmt.Formatter(formatTracking) { return .{ .data = .{ .self = self } }; @@ -1251,7 +1221,7 @@ fn addInst(self: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { try self.mir_instructions.ensureUnusedCapacity(gpa, 1); const result_index: Mir.Inst.Index = @intCast(self.mir_instructions.len); self.mir_instructions.appendAssumeCapacity(inst); - if (inst.ops != .pseudo_dead_none) wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)}); + if (inst.ops != .pseudo_dead_none) wip_mir_log.debug("{f}", .{self.fmtWipMir(result_index)}); return result_index; } @@ -2056,7 +2026,7 @@ fn gen( .{}, ); self.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } }; - tracking_log.debug("spill {} to {}", .{ self.ret_mcv.long, frame_index }); + tracking_log.debug("spill {f} to {f}", .{ self.ret_mcv.long, frame_index }); }, else => unreachable, } @@ -2334,8 +2304,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { for (body) |inst| { if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) continue; - wip_mir_log.debug("{}", .{cg.fmtAir(inst)}); - verbose_tracking_log.debug("{}", .{cg.fmtTracking()}); + wip_mir_log.debug("{f}", .{cg.fmtAir(inst)}); + verbose_tracking_log.debug("{f}", .{cg.fmtTracking()}); cg.reused_operands = .initEmpty(); try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1); @@ -4339,7 +4309,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -4351,7 +4321,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { else => unreachable, .add, .add_optimized => {}, .add_wrap => res[0].wrapInt(cg) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} wrap {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} wrap {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), res[0].tracking(cg), @@ -14947,7 +14917,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -14959,7 +14929,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { else => unreachable, .sub, .sub_optimized => {}, .sub_wrap => res[0].wrapInt(cg) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} wrap {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} wrap {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), res[0].tracking(cg), @@ -24587,7 +24557,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty.fmt(pt), ops[0].tracking(cg), @@ -27287,7 +27257,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty.fmt(pt), ops[0].tracking(cg), @@ -27296,7 +27266,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { else => |e| return e, }; res[0].wrapInt(cg) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} wrap {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} wrap {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), res[0].tracking(cg), @@ -33606,7 +33576,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { assert(air_tag == .div_exact); res[0] = ops[0].divTruncInts(&ops[1], cg) catch |err| break :err err; }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty.fmt(pt), ops[0].tracking(cg), @@ -34837,7 +34807,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { } }) else err: { res[0] = ops[0].divTruncInts(&ops[1], cg) catch |err| break :err err; }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty.fmt(pt), ops[0].tracking(cg), @@ -36148,7 +36118,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { } }, } }, }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -37614,7 +37584,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } })) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty.fmt(pt), ops[0].tracking(cg), @@ -39248,7 +39218,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -42077,7 +42047,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -42191,7 +42161,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .lea, .dst0p, .leai(.src0, .dst0), ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -42320,7 +42290,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .lea, .dst0p, .leai(.src0, .dst0), ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -46485,7 +46455,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -50644,7 +50614,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -51493,7 +51463,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .mov, .memad(.dst0q, .add_src0_size, -8), .tmp0q, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty_pl.ty.toType().fmt(pt), ops[0].tracking(cg), @@ -52398,7 +52368,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .mov, .memad(.dst0q, .add_src0_size, -8), .tmp0q, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty_pl.ty.toType().fmt(pt), ops[0].tracking(cg), @@ -55995,7 +55965,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .@"or", .tmp2q, .tmp1q, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty_pl.ty.toType().fmt(pt), ops[0].tracking(cg), @@ -59735,7 +59705,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { } }, } }, }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -60298,7 +60268,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), cg.typeOf(bin_op.rhs).fmt(pt), @@ -60660,7 +60630,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ns, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), cg.typeOf(bin_op.rhs).fmt(pt), @@ -60672,7 +60642,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { switch (air_tag) { else => unreachable, .shl => res[0].wrapInt(cg) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} wrap {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} wrap {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), res[0].tracking(cg), @@ -65329,7 +65299,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._b, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), ty_op.ty.toType().fmt(pt), ops[0].tracking(cg), @@ -68483,7 +68453,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), cg.typeOf(ty_op.operand).fmt(pt), ops[0].tracking(cg), @@ -68880,7 +68850,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .@"0:", ._, .lea, .dst0d, .leasia(.dst0, .@"8", .tmp0, .add_8_src0_size), ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), cg.typeOf(ty_op.operand).fmt(pt), ops[0].tracking(cg), @@ -69768,7 +69738,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), cg.typeOf(ty_op.operand).fmt(pt), ops[0].tracking(cg), @@ -70417,7 +70387,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), ty_op.ty.toType().fmt(pt), ops[0].tracking(cg), @@ -73519,7 +73489,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), ty_op.ty.toType().fmt(pt), ops[0].tracking(cg), @@ -74457,7 +74427,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), cg.typeOf(un_op).fmt(pt), ops[0].tracking(cg), @@ -75183,7 +75153,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { } }, } }, }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), cg.typeOf(un_op).fmt(pt), ops[0].tracking(cg), @@ -76734,7 +76704,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), cg.typeOf(ty_op.operand).fmt(pt), ops[0].tracking(cg), @@ -77926,7 +77896,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { } }, } }, }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), cg.typeOf(un_op).fmt(pt), ops[0].tracking(cg), @@ -78466,7 +78436,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nc, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), cg.typeOf(un_op).fmt(pt), ops[0].tracking(cg), @@ -78913,7 +78883,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { } else err: { res[0] = ops[0].cmpInts(cmp_op, &ops[1], cg) catch |err| break :err err; }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -79470,7 +79440,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { res[0] = ops[0].cmpInts(cmp_op, &ops[1], cg) catch |err| break :err err; }, }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty.fmt(pt), ops[0].tracking(cg), @@ -88546,7 +88516,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty_op.ty.toType().fmt(pt), cg.typeOf(ty_op.operand).fmt(pt), @@ -90221,7 +90191,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty_op.ty.toType().fmt(pt), cg.typeOf(ty_op.operand).fmt(pt), @@ -94899,7 +94869,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), dst_ty.fmt(pt), src_ty.fmt(pt), @@ -100565,7 +100535,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._nz, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty_op.ty.toType().fmt(pt), cg.typeOf(ty_op.operand).fmt(pt), @@ -111427,7 +111397,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty_op.ty.toType().fmt(pt), cg.typeOf(ty_op.operand).fmt(pt), @@ -123446,7 +123416,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{ @tagName(air_tag), ty_op.ty.toType().fmt(pt), cg.typeOf(ty_op.operand).fmt(pt), @@ -166464,7 +166434,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .@"test", .src0p, .src0p, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), cg.typeOf(un_op).fmt(pt), ops[0].tracking(cg), @@ -166552,7 +166522,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .call, .tmp0d, ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), cg.typeOf(un_op).fmt(pt), ops[0].tracking(cg), @@ -166654,7 +166624,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .lea, .dst1d, .leai(.dst1, .tmp1), ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), cg.typeOf(un_op).fmt(pt), ops[0].tracking(cg), @@ -166752,7 +166722,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .@"test", .src0d, .src0d, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{ @tagName(air_tag), ty_op.ty.toType().fmt(pt), ops[0].tracking(cg), @@ -166804,7 +166774,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { } } }, - .@"packed" => return cg.fail("failed to select {s} {}", .{ + .@"packed" => return cg.fail("failed to select {s} {f}", .{ @tagName(air_tag), agg_ty.fmt(pt), }), @@ -166825,7 +166795,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { elem_disp += @intCast(field_type.abiSize(zcu)); } }, - else => return cg.fail("failed to select {s} {}", .{ + else => return cg.fail("failed to select {s} {f}", .{ @tagName(air_tag), agg_ty.fmt(pt), }), @@ -168123,7 +168093,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._ae, .j, .@"0b", ._, ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f} {f}", .{ @tagName(air_tag), cg.typeOf(bin_op.lhs).fmt(pt), ops[0].tracking(cg), @@ -168223,7 +168193,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ ._, ._, .cmp, .src0d, .lea(.tmp1d), ._, ._ }, } }, } }) catch |err| switch (err) { - error.SelectFailed => return cg.fail("failed to select {s} {}", .{ + error.SelectFailed => return cg.fail("failed to select {s} {f}", .{ @tagName(air_tag), ops[0].tracking(cg), }), @@ -168242,12 +168212,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .ref => { const result = try cg.allocRegOrMem(err_ret_trace_index, true); try cg.genCopy(.usize, result, ops[0].tracking(cg).short, .{}); - tracking_log.debug("{} => {} (birth)", .{ err_ret_trace_index, result }); + tracking_log.debug("{f} => {f} (birth)", .{ err_ret_trace_index, result }); cg.inst_tracking.putAssumeCapacityNoClobber(err_ret_trace_index, .init(result)); }, .temp => |temp_index| { const temp_tracking = temp_index.tracking(cg); - tracking_log.debug("{} => {} (birth)", .{ err_ret_trace_index, temp_tracking.short }); + tracking_log.debug("{f} => {f} (birth)", .{ err_ret_trace_index, temp_tracking.short }); cg.inst_tracking.putAssumeCapacityNoClobber(err_ret_trace_index, temp_tracking.*); assert(cg.reuseTemp(err_ret_trace_index, temp_index.toIndex(), temp_tracking)); }, @@ -168917,7 +168887,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { try cg.resetTemps(@enumFromInt(0)); cg.checkInvariantsAfterAirInst(); } - verbose_tracking_log.debug("{}", .{cg.fmtTracking()}); + verbose_tracking_log.debug("{f}", .{cg.fmtTracking()}); } fn genLazy(cg: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { @@ -168927,7 +168897,7 @@ fn genLazy(cg: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { switch (ip.indexToKey(lazy_sym.ty)) { .enum_type => { const enum_ty: Type = .fromInterned(lazy_sym.ty); - wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)}); + wip_mir_log.debug("{f}.@tagName:", .{enum_ty.fmt(pt)}); const param_regs = abi.getCAbiIntParamRegs(.auto); const param_locks = cg.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); @@ -168976,7 +168946,7 @@ fn genLazy(cg: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { }, .error_set_type => |error_set_type| { const err_ty: Type = .fromInterned(lazy_sym.ty); - wip_mir_log.debug("{}.@errorCast:", .{err_ty.fmt(pt)}); + wip_mir_log.debug("{f}.@errorCast:", .{err_ty.fmt(pt)}); const param_regs = abi.getCAbiIntParamRegs(.auto); const param_locks = cg.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); @@ -169016,7 +168986,7 @@ fn genLazy(cg: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { try cg.asmOpOnly(.{ ._, .ret }); }, else => return cg.fail( - "TODO implement {s} for {}", + "TODO implement {s} for {f}", .{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt) }, ), } @@ -169076,7 +169046,7 @@ fn finishAirResult(self: *CodeGen, inst: Air.Inst.Index, result: MCValue) void { .none, .dead, .unreach => {}, else => unreachable, // Why didn't the result die? } else { - tracking_log.debug("{} => {} (birth)", .{ inst, result }); + tracking_log.debug("{f} => {f} (birth)", .{ inst, result }); self.inst_tracking.putAssumeCapacityNoClobber(inst, .init(result)); // In some cases, an operand may be reused as the result. // If that operand died and was a register, it was freed by @@ -169226,7 +169196,7 @@ fn allocMemPtr(self: *CodeGen, inst: Air.Inst.Index) !FrameIndex { const val_ty = ptr_ty.childType(zcu); return self.allocFrameIndex(.init(.{ .size = std.math.cast(u32, val_ty.abiSize(zcu)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(pt)}); + return self.fail("type '{f}' too big to fit into stack frame", .{val_ty.fmt(pt)}); }, .alignment = ptr_ty.ptrAlignment(zcu).max(.@"1"), })); @@ -169244,7 +169214,7 @@ fn allocRegOrMemAdvanced(self: *CodeGen, ty: Type, inst: ?Air.Inst.Index, reg_ok const pt = self.pt; const zcu = pt.zcu; const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse { - return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(pt)}); + return self.fail("type '{f}' too big to fit into stack frame", .{ty.fmt(pt)}); }; if (reg_ok) need_mem: { @@ -169749,7 +169719,7 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void { ); } break :result dst_mcv; - } orelse return self.fail("TODO implement airFpext from {} to {}", .{ + } orelse return self.fail("TODO implement airFpext from {f} to {f}", .{ src_ty.fmt(pt), dst_ty.fmt(pt), }); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); @@ -170004,7 +169974,7 @@ fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void { ); break :result dst_mcv; - }) orelse return self.fail("TODO implement airIntCast from {} to {}", .{ + }) orelse return self.fail("TODO implement airIntCast from {f} to {f}", .{ src_ty.fmt(pt), dst_ty.fmt(pt), }); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); @@ -170076,7 +170046,7 @@ fn airTrunc(self: *CodeGen, inst: Air.Inst.Index) !void { else => null, }, else => null, - }) orelse return self.fail("TODO implement airTrunc for {}", .{dst_ty.fmt(pt)}); + }) orelse return self.fail("TODO implement airTrunc for {f}", .{dst_ty.fmt(pt)}); const dst_info = dst_elem_ty.intInfo(zcu); const src_info = src_elem_ty.intInfo(zcu); @@ -170497,7 +170467,7 @@ fn airAddSat(self: *CodeGen, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ty = self.typeOf(bin_op.lhs); if (ty.zigTypeTag(zcu) == .vector or ty.abiSize(zcu) > 8) return self.fail( - "TODO implement airAddSat for {}", + "TODO implement airAddSat for {f}", .{ty.fmt(pt)}, ); @@ -170575,7 +170545,7 @@ fn airSubSat(self: *CodeGen, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ty = self.typeOf(bin_op.lhs); if (ty.zigTypeTag(zcu) == .vector or ty.abiSize(zcu) > 8) return self.fail( - "TODO implement airSubSat for {}", + "TODO implement airSubSat for {f}", .{ty.fmt(pt)}, ); @@ -170726,7 +170696,7 @@ fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void { } if (ty.zigTypeTag(zcu) == .vector or ty.abiSize(zcu) > 8) return self.fail( - "TODO implement airMulSat for {}", + "TODO implement airMulSat for {f}", .{ty.fmt(pt)}, ); @@ -171020,7 +170990,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void { const tuple_ty = self.typeOfIndex(inst); const dst_ty = self.typeOf(bin_op.lhs); const result: MCValue = switch (dst_ty.zigTypeTag(zcu)) { - .vector => return self.fail("TODO implement airMulWithOverflow for {}", .{dst_ty.fmt(pt)}), + .vector => return self.fail("TODO implement airMulWithOverflow for {f}", .{dst_ty.fmt(pt)}), .int => result: { const dst_info = dst_ty.intInfo(zcu); if (dst_info.bits > 128 and dst_info.signedness == .unsigned) { @@ -171373,7 +171343,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void { else => { // For now, this is the only supported multiply that doesn't fit in a register. if (dst_info.bits > 128 or src_bits != 64) - return self.fail("TODO implement airWithOverflow from {} to {}", .{ + return self.fail("TODO implement airWithOverflow from {f} to {f}", .{ src_ty.fmt(pt), dst_ty.fmt(pt), }); @@ -171774,7 +171744,7 @@ fn airShlShrBinOp(self: *CodeGen, inst: Air.Inst.Index) !void { }, else => {}, } - return self.fail("TODO implement airShlShrBinOp for {}", .{lhs_ty.fmt(pt)}); + return self.fail("TODO implement airShlShrBinOp for {f}", .{lhs_ty.fmt(pt)}); }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } @@ -172034,7 +172004,7 @@ fn airUnwrapErrUnionErr(self: *CodeGen, inst: Air.Inst.Index) !void { .index = frame_addr.index, .off = frame_addr.off + @as(i32, @intCast(err_off)), } }, - else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}), + else => return self.fail("TODO implement unwrap_err_err for {f}", .{operand}), } }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); @@ -172196,7 +172166,7 @@ fn genUnwrapErrUnionPayloadMir( else .{ .register = try self.copyToTmpRegister(payload_ty, result_mcv) }; }, - else => return self.fail("TODO implement genUnwrapErrUnionPayloadMir for {}", .{err_union}), + else => return self.fail("TODO implement genUnwrapErrUnionPayloadMir for {f}", .{err_union}), } }; @@ -172362,7 +172332,7 @@ fn airSliceLen(self: *CodeGen, inst: Air.Inst.Index) !void { .index = frame_addr.index, .off = frame_addr.off + 8, } }, - else => return self.fail("TODO implement slice_len for {}", .{src_mcv}), + else => return self.fail("TODO implement slice_len for {f}", .{src_mcv}), }; if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) { switch (src_mcv) { @@ -172645,7 +172615,7 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void { }.to64(), ), }, - else => return self.fail("TODO airArrayElemVal for {s} of {}", .{ + else => return self.fail("TODO airArrayElemVal for {s} of {f}", .{ @tagName(array_mat_mcv), array_ty.fmt(pt), }), } @@ -172688,7 +172658,7 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void { .load_extern_func, .lea_extern_func, => try self.genSetReg(addr_reg, .usize, array_mcv.address(), .{}), - else => return self.fail("TODO airArrayElemVal_val for {s} of {}", .{ + else => return self.fail("TODO airArrayElemVal_val for {s} of {f}", .{ @tagName(array_mcv), array_ty.fmt(pt), }), } @@ -172881,7 +172851,7 @@ fn airGetUnionTag(self: *CodeGen, inst: Air.Inst.Index) !void { } return self.fail( - "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", + "TODO implement get_union_tag for ABI larger than 8 bytes and operand {f}", .{operand}, ); }, @@ -172893,7 +172863,7 @@ fn airGetUnionTag(self: *CodeGen, inst: Air.Inst.Index) !void { .register = registerAlias(result.register, @intCast(layout.tag_size)), }; }, - else => return self.fail("TODO implement get_union_tag for {}", .{operand}), + else => return self.fail("TODO implement get_union_tag for {f}", .{operand}), } }; @@ -172909,7 +172879,7 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void { const dst_ty = self.typeOfIndex(inst); const src_ty = self.typeOf(ty_op.operand); - if (src_ty.zigTypeTag(zcu) == .vector) return self.fail("TODO implement airClz for {}", .{ + if (src_ty.zigTypeTag(zcu) == .vector) return self.fail("TODO implement airClz for {f}", .{ src_ty.fmt(pt), }); @@ -173105,7 +173075,7 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void { const dst_ty = self.typeOfIndex(inst); const src_ty = self.typeOf(ty_op.operand); - if (src_ty.zigTypeTag(zcu) == .vector) return self.fail("TODO implement airCtz for {}", .{ + if (src_ty.zigTypeTag(zcu) == .vector) return self.fail("TODO implement airCtz for {f}", .{ src_ty.fmt(pt), }); @@ -173277,7 +173247,7 @@ fn airPopCount(self: *CodeGen, inst: Air.Inst.Index) !void { const src_ty = self.typeOf(ty_op.operand); const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu)); if (src_ty.zigTypeTag(zcu) == .vector or src_abi_size > 16) - return self.fail("TODO implement airPopCount for {}", .{src_ty.fmt(pt)}); + return self.fail("TODO implement airPopCount for {f}", .{src_ty.fmt(pt)}); const src_mcv = try self.resolveInst(ty_op.operand); const mat_src_mcv = switch (src_mcv) { @@ -173430,7 +173400,7 @@ fn genByteSwap( const has_movbe = self.hasFeature(.movbe); if (src_ty.zigTypeTag(zcu) == .vector) return self.fail( - "TODO implement genByteSwap for {}", + "TODO implement genByteSwap for {f}", .{src_ty.fmt(pt)}, ); @@ -173739,7 +173709,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag, operand: A const result = result: { const scalar_bits = ty.scalarType(zcu).floatBits(self.target); if (scalar_bits == 80) { - if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement floatSign for {}", .{ + if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement floatSign for {f}", .{ ty.fmt(pt), }); @@ -173763,7 +173733,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag, operand: A const abi_size: u32 = switch (ty.abiSize(zcu)) { 1...16 => 16, 17...32 => 32, - else => return self.fail("TODO implement floatSign for {}", .{ + else => return self.fail("TODO implement floatSign for {f}", .{ ty.fmt(pt), }), }; @@ -173822,7 +173792,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag, operand: A .abs => .{ .v_pd, .@"and" }, else => unreachable, }, - 80 => return self.fail("TODO implement floatSign for {}", .{ty.fmt(pt)}), + 80 => return self.fail("TODO implement floatSign for {f}", .{ty.fmt(pt)}), else => unreachable, }, registerAlias(dst_reg, abi_size), @@ -173848,7 +173818,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag, operand: A .abs => .{ ._pd, .@"and" }, else => unreachable, }, - 80 => return self.fail("TODO implement floatSign for {}", .{ty.fmt(pt)}), + 80 => return self.fail("TODO implement floatSign for {f}", .{ty.fmt(pt)}), else => unreachable, }, registerAlias(dst_reg, abi_size), @@ -173928,7 +173898,7 @@ fn genRoundLibcall(self: *CodeGen, ty: Type, src_mcv: MCValue, mode: bits.RoundM if (self.getRoundTag(ty)) |_| return .none; if (ty.zigTypeTag(zcu) != .float) - return self.fail("TODO implement genRound for {}", .{ty.fmt(pt)}); + return self.fail("TODO implement genRound for {f}", .{ty.fmt(pt)}); var sym_buf: ["__trunc?".len]u8 = undefined; return try self.genCall(.{ .extern_func = .{ @@ -174164,7 +174134,7 @@ fn airAbs(self: *CodeGen, inst: Air.Inst.Index) !void { }, .float => return self.floatSign(inst, .abs, ty_op.operand, ty), }, - }) orelse return self.fail("TODO implement airAbs for {}", .{ty.fmt(pt)}); + }) orelse return self.fail("TODO implement airAbs for {f}", .{ty.fmt(pt)}); const abi_size: u32 = @intCast(ty.abiSize(zcu)); const src_mcv = try self.resolveInst(ty_op.operand); @@ -174323,7 +174293,7 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void { else => unreachable, }, else => unreachable, - }) orelse return self.fail("TODO implement airSqrt for {}", .{ty.fmt(pt)}); + }) orelse return self.fail("TODO implement airSqrt for {f}", .{ty.fmt(pt)}); switch (mir_tag[0]) { .v_ss, .v_sd => if (src_mcv.isBase()) try self.asmRegisterRegisterMemory( mir_tag, @@ -174481,7 +174451,7 @@ fn packedLoad(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) return; } - if (val_abi_size > 8) return self.fail("TODO implement packed load of {}", .{val_ty.fmt(pt)}); + if (val_abi_size > 8) return self.fail("TODO implement packed load of {f}", .{val_ty.fmt(pt)}); const limb_abi_size: u31 = @min(val_abi_size, 8); const limb_abi_bits = limb_abi_size * 8; @@ -174753,7 +174723,7 @@ fn packedStore(self: *CodeGen, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) limb_mem, registerAlias(tmp_reg, limb_abi_size), ); - } else return self.fail("TODO: implement packed store of {}", .{src_ty.fmt(pt)}); + } else return self.fail("TODO: implement packed store of {f}", .{src_ty.fmt(pt)}); } } @@ -174856,7 +174826,7 @@ fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_a const zcu = pt.zcu; const src_ty = self.typeOf(src_air); if (src_ty.zigTypeTag(zcu) == .vector) - return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(pt)}); + return self.fail("TODO implement genUnOp for {f}", .{src_ty.fmt(pt)}); var src_mcv = try self.resolveInst(src_air); switch (src_mcv) { @@ -174943,7 +174913,7 @@ fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_a fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void { const pt = self.pt; const abi_size: u32 = @intCast(dst_ty.abiSize(pt.zcu)); - if (abi_size > 8) return self.fail("TODO implement {} for {}", .{ mir_tag, dst_ty.fmt(pt) }); + if (abi_size > 8) return self.fail("TODO implement {} for {f}", .{ mir_tag, dst_ty.fmt(pt) }); switch (dst_mcv) { .none, .unreach, @@ -175672,7 +175642,7 @@ fn genBinOp( }, floatLibcAbiSuffix(lhs_ty), }), - else => return self.fail("TODO implement genBinOp for {s} {}", .{ + else => return self.fail("TODO implement genBinOp for {s} {f}", .{ @tagName(air_tag), lhs_ty.fmt(pt), }), } catch unreachable; @@ -175785,7 +175755,7 @@ fn genBinOp( ); break :adjusted .{ .register = dst_reg }; }, - 80, 128 => return self.fail("TODO implement genBinOp for {s} of {}", .{ + 80, 128 => return self.fail("TODO implement genBinOp for {s} of {f}", .{ @tagName(air_tag), lhs_ty.fmt(pt), }), else => unreachable, @@ -175819,7 +175789,7 @@ fn genBinOp( if (sse_op and ((lhs_ty.scalarType(zcu).isRuntimeFloat() and lhs_ty.scalarType(zcu).floatBits(self.target) == 80) or lhs_ty.abiSize(zcu) > self.vectorSize(.float))) - return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(air_tag), lhs_ty.fmt(pt) }); + return self.fail("TODO implement genBinOp for {s} {f}", .{ @tagName(air_tag), lhs_ty.fmt(pt) }); const maybe_mask_reg = switch (air_tag) { else => null, @@ -176199,7 +176169,7 @@ fn genBinOp( } }, - else => return self.fail("TODO implement genBinOp for {s} {}", .{ + else => return self.fail("TODO implement genBinOp for {s} {f}", .{ @tagName(air_tag), lhs_ty.fmt(pt), }), } @@ -176953,7 +176923,7 @@ fn genBinOp( else => unreachable, }, }, - }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ + }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{ @tagName(air_tag), lhs_ty.fmt(pt), }); @@ -177086,7 +177056,7 @@ fn genBinOp( else => unreachable, }, else => unreachable, - }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ + }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{ @tagName(air_tag), lhs_ty.fmt(pt), }), mask_reg, @@ -177118,7 +177088,7 @@ fn genBinOp( else => unreachable, }, else => unreachable, - }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ + }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{ @tagName(air_tag), lhs_ty.fmt(pt), }), dst_reg, @@ -177154,7 +177124,7 @@ fn genBinOp( else => unreachable, }, else => unreachable, - }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ + }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{ @tagName(air_tag), lhs_ty.fmt(pt), }), mask_reg, @@ -177185,7 +177155,7 @@ fn genBinOp( else => unreachable, }, else => unreachable, - }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ + }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{ @tagName(air_tag), lhs_ty.fmt(pt), }), dst_reg, @@ -177215,7 +177185,7 @@ fn genBinOp( else => unreachable, }, else => unreachable, - }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ + }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{ @tagName(air_tag), lhs_ty.fmt(pt), }); try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_reg, mask_reg); @@ -178022,7 +177992,7 @@ fn airArg(self: *CodeGen, inst: Air.Inst.Index) !void { break :result dst_mcv; }, - else => return self.fail("TODO implement arg for {}", .{src_mcv}), + else => return self.fail("TODO implement arg for {f}", .{src_mcv}), } }; return self.finishAir(inst, result, .{ .none, .none, .none }); @@ -179079,7 +179049,7 @@ fn genCondBrMir(self: *CodeGen, ty: Type, mcv: MCValue) !Mir.Inst.Index { const reg = try self.copyToTmpRegister(ty, mcv); return self.genCondBrMir(ty, .{ .register = reg }); } - return self.fail("TODO implement condbr when condition is {} with abi larger than 8 bytes", .{mcv}); + return self.fail("TODO implement condbr when condition is {f} with abi larger than 8 bytes", .{mcv}); }, else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(mcv)}), } @@ -179166,7 +179136,7 @@ fn isErr(self: *CodeGen, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCVal } }, .{ .immediate = 0 }, ), - else => return self.fail("TODO implement isErr for {}", .{eu_mcv}), + else => return self.fail("TODO implement isErr for {f}", .{eu_mcv}), } if (maybe_inst) |inst| self.eflags_inst = inst; @@ -180916,7 +180886,7 @@ fn moveStrategy(cg: *CodeGen, ty: Type, class: Register.Class, aligned: bool) !M }, .ip, .cr, .dr => {}, } - return cg.fail("TODO moveStrategy for {}", .{ty.fmt(pt)}); + return cg.fail("TODO moveStrategy for {f}", .{ty.fmt(pt)}); } const CopyOptions = struct { @@ -181048,7 +181018,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C break :src_info .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; }, .air_ref => |src_ref| return self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref), opts), - else => return self.fail("TODO implement genCopy for {s} of {}", .{ + else => return self.fail("TODO implement genCopy for {s} of {f}", .{ @tagName(src_mcv), ty.fmt(pt), }), }; @@ -181424,7 +181394,7 @@ fn genSetReg( 80 => null, else => unreachable, }, - }) orelse return self.fail("TODO implement genSetReg for {}", .{ty.fmt(pt)}), + }) orelse return self.fail("TODO implement genSetReg for {f}", .{ty.fmt(pt)}), dst_alias, registerAlias(src_reg, abi_size), ), @@ -181854,7 +181824,7 @@ fn genSetMem( opts, ); }, - else => return self.fail("TODO implement genSetMem for {s} of {}", .{ + else => return self.fail("TODO implement genSetMem for {s} of {f}", .{ @tagName(src_mcv), ty.fmt(pt), }), }, @@ -182167,7 +182137,7 @@ fn airFloatFromInt(self: *CodeGen, inst: Air.Inst.Index) !void { 32, 64 => src_size > 8, else => unreachable, }) { - if (src_bits > 128) return self.fail("TODO implement airFloatFromInt from {} to {}", .{ + if (src_bits > 128) return self.fail("TODO implement airFloatFromInt from {f} to {f}", .{ src_ty.fmt(pt), dst_ty.fmt(pt), }); @@ -182209,7 +182179,7 @@ fn airFloatFromInt(self: *CodeGen, inst: Air.Inst.Index) !void { else => unreachable, }, else => null, - }) orelse return self.fail("TODO implement airFloatFromInt from {} to {}", .{ + }) orelse return self.fail("TODO implement airFloatFromInt from {f} to {f}", .{ src_ty.fmt(pt), dst_ty.fmt(pt), }); const dst_alias = dst_reg.to128(); @@ -182247,7 +182217,7 @@ fn airIntFromFloat(self: *CodeGen, inst: Air.Inst.Index) !void { 32, 64 => dst_size > 8, else => unreachable, }) { - if (dst_bits > 128) return self.fail("TODO implement airIntFromFloat from {} to {}", .{ + if (dst_bits > 128) return self.fail("TODO implement airIntFromFloat from {f} to {f}", .{ src_ty.fmt(pt), dst_ty.fmt(pt), }); @@ -182531,7 +182501,7 @@ fn atomicOp( else => null, }, else => unreachable, - }) orelse return self.fail("TODO implement atomicOp of {s} for {}", .{ + }) orelse return self.fail("TODO implement atomicOp of {s} for {f}", .{ @tagName(op), val_ty.fmt(pt), }); try self.genSetReg(sse_reg, val_ty, .{ .register = .rax }, .{}); @@ -183286,7 +183256,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void { else => unreachable, }, } - return self.fail("TODO implement airSplat for {}", .{vector_ty.fmt(pt)}); + return self.fail("TODO implement airSplat for {f}", .{vector_ty.fmt(pt)}); }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } @@ -183322,12 +183292,12 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { else try self.copyToTmpRegister(pred_ty, pred_mcv) else - return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)}), + return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)}), else => unreachable, }, .register_mask => |pred_reg_mask| { if (pred_reg_mask.info.scalar.bitSize(self.target) != 8 * elem_abi_size) - return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)}); + return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)}); const mask_reg: Register = if (need_xmm0 and pred_reg_mask.reg.id() != comptime Register.xmm0.id()) mask_reg: { try self.register_manager.getKnownReg(.xmm0, null); @@ -183401,7 +183371,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { else null else - null) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)}); + null) orelse return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)}); if (has_avx) { const rhs_alias = if (reuse_mcv.isRegister()) registerAlias(reuse_mcv.getReg().?, abi_size) @@ -183554,7 +183524,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { else => unreachable, }), ); - } else return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)}); + } else return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)}); const elem_bits: u16 = @intCast(elem_abi_size * 8); if (!pred_fits_in_elem) if (self.hasFeature(.ssse3)) { const mask_len = elem_abi_size * vec_len; @@ -183583,7 +183553,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { mask_alias, mask_mem, ); - } else return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)}); + } else return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)}); { const mask_elem_ty = try pt.intType(.unsigned, elem_bits); const mask_ty = try pt.vectorType(.{ .len = vec_len, .child = mask_elem_ty.toIntern() }); @@ -183706,7 +183676,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { else => null, }, }, - }) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)}); + }) orelse return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)}); if (has_avx) { const rhs_alias = if (rhs_mcv.isRegister()) registerAlias(rhs_mcv.getReg().?, abi_size) @@ -184551,7 +184521,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void { } break :result null; - }) orelse return self.fail("TODO implement airShuffle from {} and {} to {} with {}", .{ + }) orelse return self.fail("TODO implement airShuffle from {f} and {f} to {f} with {f}", .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt), dst_ty.fmt(pt), @@ -184800,7 +184770,7 @@ fn airMulAdd(self: *CodeGen, inst: Air.Inst.Index) !void { 32, 64 => !self.hasFeature(.fma), else => unreachable, }) { - if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement airMulAdd for {}", .{ + if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement airMulAdd for {f}", .{ ty.fmt(pt), }); @@ -184930,7 +184900,7 @@ fn airMulAdd(self: *CodeGen, inst: Air.Inst.Index) !void { else => unreachable, } else - unreachable) orelse return self.fail("TODO implement airMulAdd for {}", .{ty.fmt(pt)}); + unreachable) orelse return self.fail("TODO implement airMulAdd for {f}", .{ty.fmt(pt)}); var mops: [3]MCValue = undefined; for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv; @@ -185130,7 +185100,7 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void { assert(classes.len == 1); unreachable; }, - else => return self.fail("TODO implement c_va_arg for {} on SysV", .{promote_ty.fmt(pt)}), + else => return self.fail("TODO implement c_va_arg for {f} on SysV", .{promote_ty.fmt(pt)}), } if (unused) break :result .unreach; @@ -185779,7 +185749,7 @@ fn splitType(self: *CodeGen, comptime parts_len: usize, ty: Type) ![parts_len]Ty for (parts) |part| part_sizes += part.abiSize(zcu); if (part_sizes == ty.abiSize(zcu)) return parts; }; - return self.fail("TODO implement splitType({d}, {})", .{ parts_len, ty.fmt(pt) }); + return self.fail("TODO implement splitType({d}, {f})", .{ parts_len, ty.fmt(pt) }); } /// Truncates the value in the register in place. @@ -186153,7 +186123,7 @@ const Temp = struct { cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1); const mcv = temp.tracking(cg).short; switch (mcv) { - else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), + else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }), .register => |reg| { const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); @@ -186227,7 +186197,7 @@ const Temp = struct { const new_temp_index = cg.next_temp_index; cg.temp_type[@intFromEnum(new_temp_index)] = limb_ty; switch (temp.tracking(cg).short) { - else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), + else => |mcv| std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }), .immediate => |imm| { assert(limb_index == 0); new_temp_index.tracking(cg).* = .init(.{ .immediate = imm }); @@ -186568,7 +186538,7 @@ const Temp = struct { }, else => {}, } - std.debug.panic("{s}: {} {}\n", .{ @src().fn_name, temp_tracking, overflow_temp_tracking }); + std.debug.panic("{s}: {f} {f}\n", .{ @src().fn_name, temp_tracking, overflow_temp_tracking }); } fn asMask(temp: Temp, info: MaskInfo, cg: *CodeGen) void { @@ -186658,7 +186628,7 @@ const Temp = struct { while (try ptr.toLea(cg)) {} const val_mcv = val.tracking(cg).short; switch (val_mcv) { - else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), + else => |mcv| std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }), .register => |val_reg| try ptr.loadReg(val_ty, registerAlias( val_reg, @intCast(val_ty.abiSize(cg.pt.zcu)), @@ -186698,7 +186668,7 @@ const Temp = struct { {}) { const val_mcv = val.tracking(cg).short; switch (val_mcv) { - else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), + else => |mcv| std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }), .undef => if (opts.safe) { var pat = try cg.tempInit(.u8, .{ .immediate = 0xaa }); var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); @@ -186772,7 +186742,7 @@ const Temp = struct { assert(!val_ty.optionalReprIsPayload(cg.pt.zcu)); break :first_ty opt_child; }, - else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }), + else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }), }); const first_size: u31 = @intCast(first_ty.abiSize(cg.pt.zcu)); try ptr.storeRegs(first_ty, &.{registerAlias(val_reg_ov.reg, first_size)}, cg); @@ -186804,7 +186774,7 @@ const Temp = struct { fn readTo(src: *Temp, val_ty: Type, val_mcv: MCValue, opts: AccessOptions, cg: *CodeGen) InnerError!void { switch (val_mcv) { - else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), + else => |mcv| std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }), .register => |val_reg| try src.readReg(opts.disp, val_ty, registerAlias( val_reg, @intCast(cg.unalignedSize(val_ty)), @@ -186844,7 +186814,7 @@ const Temp = struct { {}) { const val_mcv = val.tracking(cg).short; switch (val_mcv) { - else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), + else => |mcv| std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }), .none => {}, .undef => if (opts.safe) { var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(opts.disp)); @@ -186905,7 +186875,7 @@ const Temp = struct { assert(!val_ty.optionalReprIsPayload(cg.pt.zcu)); break :first_ty opt_child; }, - else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }), + else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }), }); const first_size: u31 = @intCast(first_ty.abiSize(cg.pt.zcu)); try dst.writeReg(opts.disp, first_ty, registerAlias(val_reg_ov.reg, first_size), cg); @@ -191677,12 +191647,12 @@ const Temp = struct { break :result result; }, }; - tracking_log.debug("{} => {} (birth)", .{ inst, result }); + tracking_log.debug("{f} => {f} (birth)", .{ inst, result }); cg.inst_tracking.putAssumeCapacityNoClobber(inst, .init(result)); }, .temp => |temp_index| { const temp_tracking = temp_index.tracking(cg); - tracking_log.debug("{} => {} (birth)", .{ inst, temp_tracking.short }); + tracking_log.debug("{f} => {f} (birth)", .{ inst, temp_tracking.short }); cg.inst_tracking.putAssumeCapacityNoClobber(inst, .init(temp_tracking.short)); assert(cg.reuseTemp(inst, temp_index.toIndex(), temp_tracking)); }, @@ -191757,7 +191727,7 @@ fn resetTemps(cg: *CodeGen, from_index: Temp.Index) InnerError!void { const temp: Temp.Index = @enumFromInt(temp_index); if (temp.isValid(cg)) { any_valid = true; - tracking_log.err("failed to kill {}: {}", .{ + tracking_log.err("failed to kill {f}: {f}", .{ temp.toIndex(), cg.temp_type[temp_index].fmt(cg.pt), }); diff --git a/src/arch/x86_64/Disassembler.zig b/src/arch/x86_64/Disassembler.zig index 545f6c0e96..163689de19 100644 --- a/src/arch/x86_64/Disassembler.zig +++ b/src/arch/x86_64/Disassembler.zig @@ -31,10 +31,11 @@ pub fn init(code: []const u8) Disassembler { } pub fn next(dis: *Disassembler) Error!?Instruction { - const prefixes = dis.parsePrefixes() catch |err| switch (err) { - error.EndOfStream => return null, - else => |e| return e, - }; + return @errorCast(dis.nextInner()); +} + +fn nextInner(dis: *Disassembler) anyerror!?Instruction { + const prefixes = try dis.parsePrefixes(); const enc = try dis.parseEncoding(prefixes) orelse return error.UnknownOpcode; switch (enc.data.op_en) { @@ -283,66 +284,53 @@ const Prefixes = struct { fn parsePrefixes(dis: *Disassembler) !Prefixes { const rex_prefix_mask: u4 = 0b0100; - var stream = std.io.fixedBufferStream(dis.code[dis.pos..]); - const reader = stream.reader(); - var res: Prefixes = .{}; + for (dis.code[dis.pos..], dis.pos..) |byte, pos| switch (byte) { + 0xf0, 0xf2, 0xf3, 0x2e, 0x36, 0x26, 0x64, 0x65, 0x3e, 0x66, 0x67 => { + // Legacy prefix + if (res.rex.present) return error.LegacyPrefixAfterRex; + switch (byte) { + 0xf0 => res.legacy.prefix_f0 = true, + 0xf2 => res.legacy.prefix_f2 = true, + 0xf3 => res.legacy.prefix_f3 = true, + 0x2e => res.legacy.prefix_2e = true, + 0x36 => res.legacy.prefix_36 = true, + 0x26 => res.legacy.prefix_26 = true, + 0x64 => res.legacy.prefix_64 = true, + 0x65 => res.legacy.prefix_65 = true, + 0x3e => res.legacy.prefix_3e = true, + 0x66 => res.legacy.prefix_66 = true, + 0x67 => res.legacy.prefix_67 = true, + else => unreachable, + } + }, + else => { + if (rex_prefix_mask == @as(u4, @truncate(byte >> 4))) { + // REX prefix + res.rex.w = byte & 0b1000 != 0; + res.rex.r = byte & 0b100 != 0; + res.rex.x = byte & 0b10 != 0; + res.rex.b = byte & 0b1 != 0; + res.rex.present = true; + continue; + } - while (true) { - const next_byte = try reader.readByte(); - dis.pos += 1; - - switch (next_byte) { - 0xf0, 0xf2, 0xf3, 0x2e, 0x36, 0x26, 0x64, 0x65, 0x3e, 0x66, 0x67 => { - // Legacy prefix - if (res.rex.present) return error.LegacyPrefixAfterRex; - switch (next_byte) { - 0xf0 => res.legacy.prefix_f0 = true, - 0xf2 => res.legacy.prefix_f2 = true, - 0xf3 => res.legacy.prefix_f3 = true, - 0x2e => res.legacy.prefix_2e = true, - 0x36 => res.legacy.prefix_36 = true, - 0x26 => res.legacy.prefix_26 = true, - 0x64 => res.legacy.prefix_64 = true, - 0x65 => res.legacy.prefix_65 = true, - 0x3e => res.legacy.prefix_3e = true, - 0x66 => res.legacy.prefix_66 = true, - 0x67 => res.legacy.prefix_67 = true, - else => unreachable, - } - }, - else => { - if (rex_prefix_mask == @as(u4, @truncate(next_byte >> 4))) { - // REX prefix - res.rex.w = next_byte & 0b1000 != 0; - res.rex.r = next_byte & 0b100 != 0; - res.rex.x = next_byte & 0b10 != 0; - res.rex.b = next_byte & 0b1 != 0; - res.rex.present = true; - continue; - } - - // TODO VEX prefix - - dis.pos -= 1; - break; - }, - } - } + // TODO VEX prefix + dis.pos = pos; + break; + }, + }; return res; } fn parseEncoding(dis: *Disassembler, prefixes: Prefixes) !?Encoding { const o_mask: u8 = 0b1111_1000; - var opcode: [3]u8 = .{ 0, 0, 0 }; - var stream = std.io.fixedBufferStream(dis.code[dis.pos..]); - const reader = stream.reader(); comptime var opc_count = 0; inline while (opc_count < 3) : (opc_count += 1) { - const byte = try reader.readByte(); + const byte = dis.code[dis.pos]; opcode[opc_count] = byte; dis.pos += 1; @@ -387,30 +375,27 @@ fn parseGpRegister(low_enc: u3, is_extended: bool, rex: Rex, bit_size: u64) Regi }; } -fn parseImm(dis: *Disassembler, kind: Encoding.Op) !Immediate { - var stream = std.io.fixedBufferStream(dis.code[dis.pos..]); - var creader = std.io.countingReader(stream.reader()); - const reader = creader.reader(); - const imm = switch (kind) { - .imm8s, .rel8 => Immediate.s(try reader.readInt(i8, .little)), - .imm16s, .rel16 => Immediate.s(try reader.readInt(i16, .little)), - .imm32s, .rel32 => Immediate.s(try reader.readInt(i32, .little)), - .imm8 => Immediate.u(try reader.readInt(u8, .little)), - .imm16 => Immediate.u(try reader.readInt(u16, .little)), - .imm32 => Immediate.u(try reader.readInt(u32, .little)), - .imm64 => Immediate.u(try reader.readInt(u64, .little)), +fn parseImm(dis: *Disassembler, kind: Encoding.Op) anyerror!Immediate { + var br: std.io.BufferedReader = undefined; + br.initFixed(dis.code[dis.pos..]); + defer dis.pos += br.seek; + return switch (kind) { + .imm8s, .rel8 => .s(try br.takeInt(i8, .little)), + .imm16s, .rel16 => .s(try br.takeInt(i16, .little)), + .imm32s, .rel32 => .s(try br.takeInt(i32, .little)), + .imm8 => .u(try br.takeInt(u8, .little)), + .imm16 => .u(try br.takeInt(u16, .little)), + .imm32 => .u(try br.takeInt(u32, .little)), + .imm64 => .u(try br.takeInt(u64, .little)), else => unreachable, }; - dis.pos += std.math.cast(usize, creader.bytes_read) orelse return error.Overflow; - return imm; } -fn parseOffset(dis: *Disassembler) !u64 { - var stream = std.io.fixedBufferStream(dis.code[dis.pos..]); - const reader = stream.reader(); - const offset = try reader.readInt(u64, .little); - dis.pos += 8; - return offset; +fn parseOffset(dis: *Disassembler) anyerror!u64 { + var br: std.io.BufferedReader = undefined; + br.initFixed(dis.code[dis.pos..]); + defer dis.pos += br.seek; + return br.takeInt(u64, .little); } const ModRm = packed struct { @@ -482,26 +467,22 @@ fn parseSibByte(dis: *Disassembler) !Sib { return Sib{ .scale = scale, .index = index, .base = base }; } -fn parseDisplacement(dis: *Disassembler, modrm: ModRm, sib: ?Sib) !i32 { - var stream = std.io.fixedBufferStream(dis.code[dis.pos..]); - var creader = std.io.countingReader(stream.reader()); - const reader = creader.reader(); - const disp = disp: { - if (sib) |info| { - if (info.base == 0b101 and modrm.mod == 0) { - break :disp try reader.readInt(i32, .little); - } +fn parseDisplacement(dis: *Disassembler, modrm: ModRm, sib: ?Sib) anyerror!i32 { + var br: std.io.BufferedReader = undefined; + br.initFixed(dis.code[dis.pos..]); + defer dis.pos += br.seek; + if (sib) |info| { + if (info.base == 0b101 and modrm.mod == 0) { + return br.takeInt(i32, .little); } - if (modrm.rip()) { - break :disp try reader.readInt(i32, .little); - } - break :disp switch (modrm.mod) { - 0b00 => 0, - 0b01 => try reader.readInt(i8, .little), - 0b10 => try reader.readInt(i32, .little), - 0b11 => unreachable, - }; + } + if (modrm.rip()) { + return br.takeInt(i32, .little); + } + return switch (modrm.mod) { + 0b00 => 0, + 0b01 => try br.takeInt(i8, .little), + 0b10 => try br.takeInt(i32, .little), + 0b11 => unreachable, }; - dis.pos += std.math.cast(usize, creader.bytes_read) orelse return error.Overflow; - return disp; } diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 7ba8d460de..bacac7d296 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -424,19 +424,19 @@ pub fn emitMir(emit: *Emit) Error!void { .line = mir_inst.data.line_column.line, .column = mir_inst.data.line_column.column, .is_stmt = true, - }), + }, emit.code.items.len), .pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine(.{ .line = mir_inst.data.line_column.line, .column = mir_inst.data.line_column.column, .is_stmt = false, - }), + }, emit.code.items.len), .pseudo_dbg_epilogue_begin_none => switch (emit.debug_output) { .dwarf => |dwarf| { try dwarf.setEpilogueBegin(); log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ emit.prev_di_loc.line, emit.prev_di_loc.column, }); - try emit.dbgAdvancePCAndLine(emit.prev_di_loc); + try emit.dbgAdvancePCAndLine(emit.prev_di_loc, emit.code.items.len); }, .plan9 => {}, .none => {}, @@ -909,9 +909,9 @@ const Loc = struct { is_stmt: bool, }; -fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { +fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc, pc: usize) anyerror!void { const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line); - const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; + const delta_pc = pc - emit.prev_di_pc; log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); switch (emit.debug_output) { .dwarf => |dwarf| { @@ -919,30 +919,25 @@ fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column); try dwarf.advancePCAndLine(delta_line, delta_pc); emit.prev_di_loc = loc; - emit.prev_di_pc = emit.code.items.len; + emit.prev_di_pc = pc; }, .plan9 => |dbg_out| { if (delta_pc <= 0) return; // only do this when the pc changes + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.fromArrayList(emit.lower.bin_file.comp.gpa, &dbg_out.dbg_line); + defer dbg_out.dbg_line = aw.toArrayList(); + // increasing the line number - try link.File.Plan9.changeLine(&dbg_out.dbg_line, @intCast(delta_line)); + try link.File.Plan9.changeLine(bw, @intCast(delta_line)); // increasing the pc const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta; if (d_pc_p9 > 0) { // minus one because if its the last one, we want to leave space to change the line which is one pc quanta - var diff = @divExact(d_pc_p9, dbg_out.pc_quanta) - dbg_out.pc_quanta; - while (diff > 0) { - if (diff < 64) { - try dbg_out.dbg_line.append(@intCast(diff + 128)); - diff = 0; - } else { - try dbg_out.dbg_line.append(@intCast(64 + 128)); - diff -= 64; - } - } - if (dbg_out.pcop_change_index) |pci| - dbg_out.dbg_line.items[pci] += 1; - dbg_out.pcop_change_index = @intCast(dbg_out.dbg_line.items.len - 1); + try bw.writeByte(@as(u8, @intCast(@divExact(d_pc_p9, dbg_out.pc_quanta) + 128)) - dbg_out.pc_quanta); + const dbg_line = aw.getWritten(); + if (dbg_out.pcop_change_index) |pci| dbg_line[pci] += 1; + dbg_out.pcop_change_index = @intCast(dbg_line.len - 1); } else if (d_pc_p9 == 0) { // we don't need to do anything, because adding the pc quanta does it for us } else unreachable; @@ -951,7 +946,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { dbg_out.end_line = loc.line; // only do this if the pc changed emit.prev_di_loc = loc; - emit.prev_di_pc = emit.code.items.len; + emit.prev_di_pc = pc; }, .none => {}, } diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig index 1b7d5ed3d4..5bd9baaf83 100644 --- a/src/arch/x86_64/Encoding.zig +++ b/src/arch/x86_64/Encoding.zig @@ -158,20 +158,14 @@ pub fn modRmExt(encoding: Encoding) u3 { }; } -pub fn format( - encoding: Encoding, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +pub fn format(encoding: Encoding, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { _ = fmt; var opc = encoding.opcode(); if (encoding.data.mode.isVex()) { - try writer.writeAll("VEX."); + try bw.writeAll("VEX."); - try writer.writeAll(switch (encoding.data.mode) { + try bw.writeAll(switch (encoding.data.mode) { .vex_128_w0, .vex_128_w1, .vex_128_wig => "128", .vex_256_w0, .vex_256_w1, .vex_256_wig => "256", .vex_lig_w0, .vex_lig_w1, .vex_lig_wig => "LIG", @@ -182,25 +176,25 @@ pub fn format( switch (opc[0]) { else => {}, 0x66, 0xf3, 0xf2 => { - try writer.print(".{X:0>2}", .{opc[0]}); + try bw.print(".{X:0>2}", .{opc[0]}); opc = opc[1..]; }, } - try writer.print(".{}", .{std.fmt.fmtSliceHexUpper(opc[0 .. opc.len - 1])}); + try bw.print(".{X}", .{opc[0 .. opc.len - 1]}); opc = opc[opc.len - 1 ..]; - try writer.writeAll(".W"); - try writer.writeAll(switch (encoding.data.mode) { + try bw.writeAll(".W"); + try bw.writeAll(switch (encoding.data.mode) { .vex_128_w0, .vex_256_w0, .vex_lig_w0, .vex_lz_w0 => "0", .vex_128_w1, .vex_256_w1, .vex_lig_w1, .vex_lz_w1 => "1", .vex_128_wig, .vex_256_wig, .vex_lig_wig, .vex_lz_wig => "IG", else => unreachable, }); - try writer.writeByte(' '); - } else if (encoding.data.mode.isLong()) try writer.writeAll("REX.W + "); - for (opc) |byte| try writer.print("{x:0>2} ", .{byte}); + try bw.writeByte(' '); + } else if (encoding.data.mode.isLong()) try bw.writeAll("REX.W + "); + for (opc) |byte| try bw.print("{x:0>2} ", .{byte}); switch (encoding.data.op_en) { .z, .fd, .td, .i, .zi, .ii, .d => {}, @@ -217,10 +211,10 @@ pub fn format( .r64 => "rd", else => unreachable, }; - try writer.print("+{s} ", .{tag}); + try bw.print("+{s} ", .{tag}); }, - .ia, .m, .mi, .m1, .mc, .vm, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}), - .mr, .rm, .rmi, .mri, .mrc, .rm0, .rvm, .rvmr, .rvmi, .mvr, .rmv => try writer.writeAll("/r "), + .ia, .m, .mi, .m1, .mc, .vm, .vmi => try bw.print("/{d} ", .{encoding.modRmExt()}), + .mr, .rm, .rmi, .mri, .mrc, .rm0, .rvm, .rvmr, .rvmi, .mvr, .rmv => try bw.writeAll("/r "), } switch (encoding.data.op_en) { @@ -249,24 +243,24 @@ pub fn format( .rel32 => "cd", else => unreachable, }; - try writer.print("{s} ", .{tag}); + try bw.print("{s} ", .{tag}); }, - .rvmr => try writer.writeAll("/is4 "), + .rvmr => try bw.writeAll("/is4 "), .z, .fd, .td, .o, .zo, .oz, .m, .m1, .mc, .mr, .rm, .mrc, .rm0, .vm, .rvm, .mvr, .rmv => {}, } - try writer.print("{s} ", .{@tagName(encoding.mnemonic)}); + try bw.print("{s} ", .{@tagName(encoding.mnemonic)}); for (encoding.data.ops) |op| switch (op) { .none => break, - else => try writer.print("{s} ", .{@tagName(op)}), + else => try bw.print("{s} ", .{@tagName(op)}), }; const op_en = switch (encoding.data.op_en) { .zi => .i, else => |op_en| op_en, }; - try writer.print("{s}", .{@tagName(op_en)}); + try bw.print("{s}", .{@tagName(op_en)}); } pub const Mnemonic = enum { @@ -1014,19 +1008,21 @@ pub const Feature = enum { }; fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Operand) usize { - var inst = Instruction{ + var inst: Instruction = .{ .prefix = prefix, .encoding = encoding, .ops = @splat(.none), }; @memcpy(inst.ops[0..ops.len], ops); - var cwriter = std.io.countingWriter(std.io.null_writer); - inst.encode(cwriter.writer(), .{ + var buf: [15]u8 = undefined; + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(&buf); + inst.encode(&bw, .{ .allow_frame_locs = true, .allow_symbols = true, - }) catch unreachable; // Not allowed to fail here unless OOM. - return @as(usize, @intCast(cwriter.bytes_written)); + }) catch unreachable; + return @intCast(bw.end); } const mnemonic_to_encodings_map = init: { diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig index 18e7a364cb..9592a5e40c 100644 --- a/src/arch/x86_64/bits.zig +++ b/src/arch/x86_64/bits.zig @@ -728,21 +728,12 @@ pub const FrameIndex = enum(u32) { return @intFromEnum(fi) < named_count; } - pub fn format( - fi: FrameIndex, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - try writer.writeAll("FrameIndex"); - if (fi.isNamed()) { - try writer.writeByte('.'); - try writer.writeAll(@tagName(fi)); - } else { - try writer.writeByte('('); - try std.fmt.formatType(@intFromEnum(fi), fmt, options, writer, 0); - try writer.writeByte(')'); - } + pub fn format(fi: FrameIndex, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { + try bw.writeAll("FrameIndex"); + if (fi.isNamed()) + try bw.print(".{s}", .{@tagName(fi)}) + else + try bw.print("({d})", .{@intFromEnum(fi)}); } }; @@ -844,21 +835,13 @@ pub const Memory = struct { }; } - pub fn format( - s: Size, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(s: Size, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { if (s == .none) return; - try writer.writeAll(@tagName(s)); + try bw.writeAll(@tagName(s)); switch (s) { .none => unreachable, .ptr, .gpr => {}, - else => { - try writer.writeByte(' '); - try writer.writeAll("ptr"); - }, + else => try bw.writeAll(" ptr"), } } }; diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index ab3eeaa586..8c7d06259f 100644 --- a/src/arch/x86_64/encoder.zig +++ b/src/arch/x86_64/encoder.zig @@ -226,16 +226,10 @@ pub const Instruction = struct { }; } - fn format( - op: Operand, - comptime unused_format_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + fn format(op: Operand, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) anyerror!void { _ = op; + _ = bw; _ = unused_format_string; - _ = options; - _ = writer; @compileError("do not format Operand directly; use fmt() instead"); } @@ -244,78 +238,72 @@ pub const Instruction = struct { enc_op: Encoding.Op, }; - fn fmtContext( - ctx: FormatContext, - comptime unused_format_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn fmtContext(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) anyerror!void { _ = unused_format_string; - _ = options; const op = ctx.op; const enc_op = ctx.enc_op; switch (op) { .none => {}, - .reg => |reg| try writer.writeAll(@tagName(reg)), + .reg => |reg| try bw.writeAll(@tagName(reg)), .mem => |mem| switch (mem) { .rip => |rip| { - try writer.print("{} [rip", .{rip.ptr_size}); - if (rip.disp != 0) try writer.print(" {c} 0x{x}", .{ + try bw.print("{f} [rip", .{rip.ptr_size}); + if (rip.disp != 0) try bw.print(" {c} 0x{x}", .{ @as(u8, if (rip.disp < 0) '-' else '+'), @abs(rip.disp), }); - try writer.writeByte(']'); + try bw.writeByte(']'); }, .sib => |sib| { - try writer.print("{} ", .{sib.ptr_size}); + try bw.print("{f} ", .{sib.ptr_size}); if (mem.isSegmentRegister()) { - return writer.print("{s}:0x{x}", .{ @tagName(sib.base.reg), sib.disp }); + return bw.print("{s}:0x{x}", .{ @tagName(sib.base.reg), sib.disp }); } - try writer.writeByte('['); + try bw.writeByte('['); var any = true; switch (sib.base) { .none => any = false, - .reg => |reg| try writer.print("{s}", .{@tagName(reg)}), - .frame => |frame_index| try writer.print("{}", .{frame_index}), - .table => try writer.print("Table", .{}), - .rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}), - .nav => |nav| try writer.print("Nav({d})", .{@intFromEnum(nav)}), - .uav => |uav| try writer.print("Uav({d})", .{@intFromEnum(uav.val)}), - .lazy_sym => |lazy_sym| try writer.print("LazySym({s}, {d})", .{ + .reg => |reg| try bw.print("{s}", .{@tagName(reg)}), + .frame => |frame_index| try bw.print("{}", .{frame_index}), + .table => try bw.print("Table", .{}), + .rip_inst => |inst_index| try bw.print("RipInst({d})", .{inst_index}), + .nav => |nav| try bw.print("Nav({d})", .{@intFromEnum(nav)}), + .uav => |uav| try bw.print("Uav({d})", .{@intFromEnum(uav.val)}), + .lazy_sym => |lazy_sym| try bw.print("LazySym({s}, {d})", .{ @tagName(lazy_sym.kind), @intFromEnum(lazy_sym.ty), }), - .extern_func => |extern_func| try writer.print("ExternFunc({d})", .{@intFromEnum(extern_func)}), + .extern_func => |extern_func| try bw.print("ExternFunc({d})", .{@intFromEnum(extern_func)}), } if (mem.scaleIndex()) |si| { - if (any) try writer.writeAll(" + "); - try writer.print("{s} * {d}", .{ @tagName(si.index), si.scale }); + if (any) try bw.writeAll(" + "); + try bw.print("{s} * {d}", .{ @tagName(si.index), si.scale }); any = true; } if (sib.disp != 0 or !any) { if (any) - try writer.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')}) + try bw.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')}) else if (sib.disp < 0) - try writer.writeByte('-'); - try writer.print("0x{x}", .{@abs(sib.disp)}); + try bw.writeByte('-'); + try bw.print("0x{x}", .{@abs(sib.disp)}); any = true; } - try writer.writeByte(']'); + try bw.writeByte(']'); }, - .moffs => |moffs| try writer.print("{s}:0x{x}", .{ + .moffs => |moffs| try bw.print("{s}:0x{x}", .{ @tagName(moffs.seg), moffs.offset, }), }, .imm => |imm| if (enc_op.isSigned()) { const imms = imm.asSigned(enc_op.immBitSize()); - if (imms < 0) try writer.writeByte('-'); - try writer.print("0x{x}", .{@abs(imms)}); - } else try writer.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}), + if (imms < 0) try bw.writeByte('-'); + try bw.print("0x{x}", .{@abs(imms)}); + } else try bw.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}), .bytes => unreachable, } } @@ -361,7 +349,7 @@ pub const Instruction = struct { }, }, }; - log.debug("selected encoding: {}", .{encoding}); + log.debug("selected encoding: {f}", .{encoding}); var inst: Instruction = .{ .prefix = prefix, @@ -372,30 +360,23 @@ pub const Instruction = struct { return inst; } - pub fn format( - inst: Instruction, - comptime unused_format_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(inst: Instruction, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) anyerror!void { _ = unused_format_string; - _ = options; switch (inst.prefix) { .none, .directive => {}, - else => try writer.print("{s} ", .{@tagName(inst.prefix)}), + else => try bw.print("{s} ", .{@tagName(inst.prefix)}), } - try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)}); + try bw.print("{s}", .{@tagName(inst.encoding.mnemonic)}); for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| { if (op == .none) break; - if (i > 0) try writer.writeByte(','); - try writer.writeByte(' '); - try writer.print("{}", .{op.fmt(enc)}); + if (i > 0) try bw.writeByte(','); + try bw.print(" {f}", .{op.fmt(enc)}); } } - pub fn encode(inst: Instruction, writer: anytype, comptime opts: Options) !void { + pub fn encode(inst: Instruction, bw: *std.io.BufferedWriter, comptime opts: Options) !void { assert(inst.prefix != .directive); - const encoder = Encoder(@TypeOf(writer), opts){ .writer = writer }; + const encoder: Encoder(opts) = .{ .bw = bw }; const enc = inst.encoding; const data = enc.data; @@ -801,9 +782,9 @@ pub const LegacyPrefixes = packed struct { pub const Options = struct { allow_frame_locs: bool = false, allow_symbols: bool = false }; -fn Encoder(comptime T: type, comptime opts: Options) type { +fn Encoder(comptime opts: Options) type { return struct { - writer: T, + bw: *std.io.BufferedWriter, const Self = @This(); pub const options = opts; @@ -813,44 +794,44 @@ fn Encoder(comptime T: type, comptime opts: Options) type { // -------- /// Encodes legacy prefixes - pub fn legacyPrefixes(self: Self, prefixes: LegacyPrefixes) !void { + pub fn legacyPrefixes(self: Self, prefixes: LegacyPrefixes) anyerror!void { if (@as(u16, @bitCast(prefixes)) != 0) { // Hopefully this path isn't taken very often, so we'll do it the slow way for now // LOCK - if (prefixes.prefix_f0) try self.writer.writeByte(0xf0); + if (prefixes.prefix_f0) try self.bw.writeByte(0xf0); // REPNZ, REPNE, REP, Scalar Double-precision - if (prefixes.prefix_f2) try self.writer.writeByte(0xf2); + if (prefixes.prefix_f2) try self.bw.writeByte(0xf2); // REPZ, REPE, REP, Scalar Single-precision - if (prefixes.prefix_f3) try self.writer.writeByte(0xf3); + if (prefixes.prefix_f3) try self.bw.writeByte(0xf3); // CS segment override or Branch not taken - if (prefixes.prefix_2e) try self.writer.writeByte(0x2e); + if (prefixes.prefix_2e) try self.bw.writeByte(0x2e); // DS segment override - if (prefixes.prefix_36) try self.writer.writeByte(0x36); + if (prefixes.prefix_36) try self.bw.writeByte(0x36); // ES segment override - if (prefixes.prefix_26) try self.writer.writeByte(0x26); + if (prefixes.prefix_26) try self.bw.writeByte(0x26); // FS segment override - if (prefixes.prefix_64) try self.writer.writeByte(0x64); + if (prefixes.prefix_64) try self.bw.writeByte(0x64); // GS segment override - if (prefixes.prefix_65) try self.writer.writeByte(0x65); + if (prefixes.prefix_65) try self.bw.writeByte(0x65); // Branch taken - if (prefixes.prefix_3e) try self.writer.writeByte(0x3e); + if (prefixes.prefix_3e) try self.bw.writeByte(0x3e); // Operand size override - if (prefixes.prefix_66) try self.writer.writeByte(0x66); + if (prefixes.prefix_66) try self.bw.writeByte(0x66); // Address size override - if (prefixes.prefix_67) try self.writer.writeByte(0x67); + if (prefixes.prefix_67) try self.bw.writeByte(0x67); } } /// Use 16 bit operand size /// /// Note that this flag is overridden by REX.W, if both are present. - pub fn prefix16BitMode(self: Self) !void { - try self.writer.writeByte(0x66); + pub fn prefix16BitMode(self: Self) anyerror!void { + try self.bw.writeByte(0x66); } /// Encodes a REX prefix byte given all the fields @@ -859,7 +840,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// or one of reg, index, r/m, base, or opcode-reg might be extended. /// /// See struct `Rex` for a description of each field. - pub fn rex(self: Self, fields: Rex) !void { + pub fn rex(self: Self, fields: Rex) anyerror!void { if (!fields.present and !fields.isSet()) return; var byte: u8 = 0b0100_0000; @@ -869,32 +850,32 @@ fn Encoder(comptime T: type, comptime opts: Options) type { if (fields.x) byte |= 0b0010; if (fields.b) byte |= 0b0001; - try self.writer.writeByte(byte); + try self.bw.writeByte(byte); } /// Encodes a VEX prefix given all the fields /// /// See struct `Vex` for a description of each field. - pub fn vex(self: Self, fields: Vex) !void { + pub fn vex(self: Self, fields: Vex) anyerror!void { if (fields.is3Byte()) { - try self.writer.writeByte(0b1100_0100); + try self.bw.writeByte(0b1100_0100); - try self.writer.writeByte( + try self.bw.writeByte( @as(u8, ~@intFromBool(fields.r)) << 7 | @as(u8, ~@intFromBool(fields.x)) << 6 | @as(u8, ~@intFromBool(fields.b)) << 5 | @as(u8, @intFromEnum(fields.m)) << 0, ); - try self.writer.writeByte( + try self.bw.writeByte( @as(u8, @intFromBool(fields.w)) << 7 | @as(u8, ~@as(u4, @intCast(fields.v.enc()))) << 3 | @as(u8, @intFromBool(fields.l)) << 2 | @as(u8, @intFromEnum(fields.p)) << 0, ); } else { - try self.writer.writeByte(0b1100_0101); - try self.writer.writeByte( + try self.bw.writeByte(0b1100_0101); + try self.bw.writeByte( @as(u8, ~@intFromBool(fields.r)) << 7 | @as(u8, ~@as(u4, @intCast(fields.v.enc()))) << 3 | @as(u8, @intFromBool(fields.l)) << 2 | @@ -908,8 +889,8 @@ fn Encoder(comptime T: type, comptime opts: Options) type { // ------ /// Encodes a 1 byte opcode - pub fn opcode_1byte(self: Self, opcode: u8) !void { - try self.writer.writeByte(opcode); + pub fn opcode_1byte(self: Self, opcode: u8) anyerror!void { + try self.bw.writeByte(opcode); } /// Encodes a 2 byte opcode @@ -917,8 +898,8 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// e.g. IMUL has the opcode 0x0f 0xaf, so you use /// /// encoder.opcode_2byte(0x0f, 0xaf); - pub fn opcode_2byte(self: Self, prefix: u8, opcode: u8) !void { - try self.writer.writeAll(&.{ prefix, opcode }); + pub fn opcode_2byte(self: Self, prefix: u8, opcode: u8) anyerror!void { + try self.bw.writeAll(&.{ prefix, opcode }); } /// Encodes a 3 byte opcode @@ -926,16 +907,16 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// e.g. MOVSD has the opcode 0xf2 0x0f 0x10 /// /// encoder.opcode_3byte(0xf2, 0x0f, 0x10); - pub fn opcode_3byte(self: Self, prefix_1: u8, prefix_2: u8, opcode: u8) !void { - try self.writer.writeAll(&.{ prefix_1, prefix_2, opcode }); + pub fn opcode_3byte(self: Self, prefix_1: u8, prefix_2: u8, opcode: u8) anyerror!void { + try self.bw.writeAll(&.{ prefix_1, prefix_2, opcode }); } /// Encodes a 1 byte opcode with a reg field /// /// Remember to add a REX prefix byte if reg is extended! - pub fn opcode_withReg(self: Self, opcode: u8, reg: u3) !void { + pub fn opcode_withReg(self: Self, opcode: u8, reg: u3) anyerror!void { assert(opcode & 0b111 == 0); - try self.writer.writeByte(opcode | reg); + try self.bw.writeByte(opcode | reg); } // ------ @@ -945,8 +926,8 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// Construct a ModR/M byte given all the fields /// /// Remember to add a REX prefix byte if reg or rm are extended! - pub fn modRm(self: Self, mod: u2, reg_or_opx: u3, rm: u3) !void { - try self.writer.writeByte(@as(u8, mod) << 6 | @as(u8, reg_or_opx) << 3 | rm); + pub fn modRm(self: Self, mod: u2, reg_or_opx: u3, rm: u3) anyerror!void { + try self.bw.writeByte(@as(u8, mod) << 6 | @as(u8, reg_or_opx) << 3 | rm); } /// Construct a ModR/M byte using direct r/m addressing @@ -954,7 +935,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// /// Note reg's effective address is always just reg for the ModR/M byte. /// Remember to add a REX prefix byte if reg or rm are extended! - pub fn modRm_direct(self: Self, reg_or_opx: u3, rm: u3) !void { + pub fn modRm_direct(self: Self, reg_or_opx: u3, rm: u3) anyerror!void { try self.modRm(0b11, reg_or_opx, rm); } @@ -963,7 +944,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// /// Note reg's effective address is always just reg for the ModR/M byte. /// Remember to add a REX prefix byte if reg or rm are extended! - pub fn modRm_indirectDisp0(self: Self, reg_or_opx: u3, rm: u3) !void { + pub fn modRm_indirectDisp0(self: Self, reg_or_opx: u3, rm: u3) anyerror!void { assert(rm != 4 and rm != 5); try self.modRm(0b00, reg_or_opx, rm); } @@ -973,7 +954,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// /// Note reg's effective address is always just reg for the ModR/M byte. /// Remember to add a REX prefix byte if reg or rm are extended! - pub fn modRm_SIBDisp0(self: Self, reg_or_opx: u3) !void { + pub fn modRm_SIBDisp0(self: Self, reg_or_opx: u3) anyerror!void { try self.modRm(0b00, reg_or_opx, 0b100); } @@ -982,7 +963,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// /// Note reg's effective address is always just reg for the ModR/M byte. /// Remember to add a REX prefix byte if reg or rm are extended! - pub fn modRm_RIPDisp32(self: Self, reg_or_opx: u3) !void { + pub fn modRm_RIPDisp32(self: Self, reg_or_opx: u3) anyerror!void { try self.modRm(0b00, reg_or_opx, 0b101); } @@ -991,7 +972,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// /// Note reg's effective address is always just reg for the ModR/M byte. /// Remember to add a REX prefix byte if reg or rm are extended! - pub fn modRm_indirectDisp8(self: Self, reg_or_opx: u3, rm: u3) !void { + pub fn modRm_indirectDisp8(self: Self, reg_or_opx: u3, rm: u3) anyerror!void { assert(rm != 4); try self.modRm(0b01, reg_or_opx, rm); } @@ -1001,7 +982,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// /// Note reg's effective address is always just reg for the ModR/M byte. /// Remember to add a REX prefix byte if reg or rm are extended! - pub fn modRm_SIBDisp8(self: Self, reg_or_opx: u3) !void { + pub fn modRm_SIBDisp8(self: Self, reg_or_opx: u3) anyerror!void { try self.modRm(0b01, reg_or_opx, 0b100); } @@ -1010,7 +991,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// /// Note reg's effective address is always just reg for the ModR/M byte. /// Remember to add a REX prefix byte if reg or rm are extended! - pub fn modRm_indirectDisp32(self: Self, reg_or_opx: u3, rm: u3) !void { + pub fn modRm_indirectDisp32(self: Self, reg_or_opx: u3, rm: u3) anyerror!void { assert(rm != 4); try self.modRm(0b10, reg_or_opx, rm); } @@ -1020,7 +1001,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// /// Note reg's effective address is always just reg for the ModR/M byte. /// Remember to add a REX prefix byte if reg or rm are extended! - pub fn modRm_SIBDisp32(self: Self, reg_or_opx: u3) !void { + pub fn modRm_SIBDisp32(self: Self, reg_or_opx: u3) anyerror!void { try self.modRm(0b10, reg_or_opx, 0b100); } @@ -1031,15 +1012,15 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// Construct a SIB byte given all the fields /// /// Remember to add a REX prefix byte if index or base are extended! - pub fn sib(self: Self, scale: u2, index: u3, base: u3) !void { - try self.writer.writeByte(@as(u8, scale) << 6 | @as(u8, index) << 3 | base); + pub fn sib(self: Self, scale: u2, index: u3, base: u3) anyerror!void { + try self.bw.writeByte(@as(u8, scale) << 6 | @as(u8, index) << 3 | base); } /// Construct a SIB byte with scale * index + base, no frills. /// r/m effective address: [base + scale * index] /// /// Remember to add a REX prefix byte if index or base are extended! - pub fn sib_scaleIndexBase(self: Self, scale: u2, index: u3, base: u3) !void { + pub fn sib_scaleIndexBase(self: Self, scale: u2, index: u3, base: u3) anyerror!void { assert(base != 5); try self.sib(scale, index, base); @@ -1049,7 +1030,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// r/m effective address: [scale * index + disp32] /// /// Remember to add a REX prefix byte if index or base are extended! - pub fn sib_scaleIndexDisp32(self: Self, scale: u2, index: u3) !void { + pub fn sib_scaleIndexDisp32(self: Self, scale: u2, index: u3) anyerror!void { // scale is actually ignored // index = 4 means no index if and only if we haven't extended the register // TODO enforce this @@ -1061,7 +1042,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// r/m effective address: [base] /// /// Remember to add a REX prefix byte if index or base are extended! - pub fn sib_base(self: Self, base: u3) !void { + pub fn sib_base(self: Self, base: u3) anyerror!void { assert(base != 5); // scale is actually ignored @@ -1073,7 +1054,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// r/m effective address: [disp32] /// /// Remember to add a REX prefix byte if index or base are extended! - pub fn sib_disp32(self: Self) !void { + pub fn sib_disp32(self: Self) anyerror!void { // scale is actually ignored // index = 4 means no index // base = 5 means no base, if mod == 0. @@ -1084,7 +1065,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// r/m effective address: [base + scale * index + disp8] /// /// Remember to add a REX prefix byte if index or base are extended! - pub fn sib_scaleIndexBaseDisp8(self: Self, scale: u2, index: u3, base: u3) !void { + pub fn sib_scaleIndexBaseDisp8(self: Self, scale: u2, index: u3, base: u3) anyerror!void { try self.sib(scale, index, base); } @@ -1092,7 +1073,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// r/m effective address: [base + disp8] /// /// Remember to add a REX prefix byte if index or base are extended! - pub fn sib_baseDisp8(self: Self, base: u3) !void { + pub fn sib_baseDisp8(self: Self, base: u3) anyerror!void { // scale is ignored // index = 4 means no index try self.sib(0, 4, base); @@ -1102,7 +1083,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// r/m effective address: [base + scale * index + disp32] /// /// Remember to add a REX prefix byte if index or base are extended! - pub fn sib_scaleIndexBaseDisp32(self: Self, scale: u2, index: u3, base: u3) !void { + pub fn sib_scaleIndexBaseDisp32(self: Self, scale: u2, index: u3, base: u3) anyerror!void { try self.sib(scale, index, base); } @@ -1110,7 +1091,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// r/m effective address: [base + disp32] /// /// Remember to add a REX prefix byte if index or base are extended! - pub fn sib_baseDisp32(self: Self, base: u3) !void { + pub fn sib_baseDisp32(self: Self, base: u3) anyerror!void { // scale is ignored // index = 4 means no index try self.sib(0, 4, base); @@ -1123,43 +1104,43 @@ fn Encoder(comptime T: type, comptime opts: Options) type { /// Encode an 8 bit displacement /// /// It is sign-extended to 64 bits by the cpu. - pub fn disp8(self: Self, disp: i8) !void { - try self.writer.writeByte(@as(u8, @bitCast(disp))); + pub fn disp8(self: Self, disp: i8) anyerror!void { + try self.bw.writeByte(@as(u8, @bitCast(disp))); } /// Encode an 32 bit displacement /// /// It is sign-extended to 64 bits by the cpu. - pub fn disp32(self: Self, disp: i32) !void { - try self.writer.writeInt(i32, disp, .little); + pub fn disp32(self: Self, disp: i32) anyerror!void { + try self.bw.writeInt(i32, disp, .little); } /// Encode an 8 bit immediate /// /// It is sign-extended to 64 bits by the cpu. - pub fn imm8(self: Self, imm: u8) !void { - try self.writer.writeByte(imm); + pub fn imm8(self: Self, imm: u8) anyerror!void { + try self.bw.writeByte(imm); } /// Encode an 16 bit immediate /// /// It is sign-extended to 64 bits by the cpu. - pub fn imm16(self: Self, imm: u16) !void { - try self.writer.writeInt(u16, imm, .little); + pub fn imm16(self: Self, imm: u16) anyerror!void { + try self.bw.writeInt(u16, imm, .little); } /// Encode an 32 bit immediate /// /// It is sign-extended to 64 bits by the cpu. - pub fn imm32(self: Self, imm: u32) !void { - try self.writer.writeInt(u32, imm, .little); + pub fn imm32(self: Self, imm: u32) anyerror!void { + try self.bw.writeInt(u32, imm, .little); } /// Encode an 64 bit immediate /// /// It is sign-extended to 64 bits by the cpu. - pub fn imm64(self: Self, imm: u64) !void { - try self.writer.writeInt(u64, imm, .little); + pub fn imm64(self: Self, imm: u64) anyerror!void { + try self.bw.writeInt(u64, imm, .little); } }; } @@ -2217,10 +2198,10 @@ const Assembler = struct { }; } - pub fn assemble(as: *Assembler, writer: anytype) !void { + pub fn assemble(as: *Assembler, bw: *std.io.BufferedWriter) !void { while (try as.next()) |parsed_inst| { const inst: Instruction = try .new(.none, parsed_inst.mnemonic, &parsed_inst.ops); - try inst.encode(writer, .{}); + try inst.encode(bw, .{}); } } diff --git a/src/codegen.zig b/src/codegen.zig index 74a5b90d25..5ea98b1a52 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -225,14 +225,6 @@ pub fn generateLazyFunction( } } -fn writeFloat(comptime F: type, f: F, target: *const std.Target, endian: std.builtin.Endian, code: []u8) void { - _ = target; - const bits = @typeInfo(F).float.bits; - const Int = @Type(.{ .int = .{ .signedness = .unsigned, .bits = bits } }); - const int: Int = @bitCast(f); - mem.writeInt(Int, code[0..@divExact(bits, 8)], int, endian); -} - pub fn generateLazySymbol( bin_file: *link.File, pt: Zcu.PerThread, @@ -256,7 +248,7 @@ pub fn generateLazySymbol( const target = &comp.root_mod.resolved_target.result; const endian = target.cpu.arch.endian(); - log.debug("generateLazySymbol: kind = {s}, ty = {}", .{ + log.debug("generateLazySymbol: kind = {s}, ty = {f}", .{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt), }); @@ -296,7 +288,7 @@ pub fn generateLazySymbol( code.appendAssumeCapacity(0); } } else { - return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {}", .{ + return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {f}", .{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt), }); } @@ -321,19 +313,31 @@ pub fn generateSymbol( const tracy = trace(@src()); defer tracy.end(); + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.fromArrayList(pt.zcu.gpa, code); + defer code.* = aw.toArrayList(); + return @errorCast(generateSymbolInner(bin_file, pt, src_loc, val, bw, reloc_parent)); +} +pub fn generateSymbolInner( + bin_file: *link.File, + pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, + val: Value, + bw: *std.io.BufferedWriter, + reloc_parent: link.File.RelocInfo.Parent, +) anyerror!void { const zcu = pt.zcu; - const gpa = zcu.gpa; const ip = &zcu.intern_pool; const ty = val.typeOf(zcu); const target = zcu.getTarget(); const endian = target.cpu.arch.endian(); - log.debug("generateSymbol: val = {}", .{val.fmtValue(pt)}); + log.debug("generateSymbol: val = {f}", .{val.fmtValue(pt)}); if (val.isUndefDeep(zcu)) { const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; - try code.appendNTimes(gpa, 0xaa, abi_size); + try bw.splatByteAll(0xaa, abi_size); return; } @@ -363,7 +367,7 @@ pub fn generateSymbol( .null => unreachable, // non-runtime value .@"unreachable" => unreachable, // non-runtime value .empty_tuple => return, - .false, .true => try code.append(gpa, switch (simple_value) { + .false, .true => try bw.writeByte(switch (simple_value) { .false => 0, .true => 1, else => unreachable, @@ -379,11 +383,12 @@ pub fn generateSymbol( const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; var space: Value.BigIntSpace = undefined; const int_val = val.toBigInt(&space, zcu); - int_val.writeTwosComplement(try code.addManyAsSlice(gpa, abi_size), endian); + int_val.writeTwosComplement((try bw.writableSlice(abi_size))[0..abi_size], endian); + bw.advance(abi_size); }, .err => |err| { const int = try pt.getErrorValue(err.name); - try code.writer(gpa).writeInt(u16, @intCast(int), endian); + try bw.writeInt(u16, @intCast(int), endian); }, .error_union => |error_union| { const payload_ty = ty.errorUnionPayload(zcu); @@ -393,7 +398,7 @@ pub fn generateSymbol( }; if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { - try code.writer(gpa).writeInt(u16, err_val, endian); + try bw.writeInt(u16, err_val, endian); return; } @@ -403,57 +408,49 @@ pub fn generateSymbol( // error value first when its type is larger than the error union's payload if (error_align.order(payload_align) == .gt) { - try code.writer(gpa).writeInt(u16, err_val, endian); + try bw.writeInt(u16, err_val, endian); } // emit payload part of the error union { - const begin = code.items.len; - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(switch (error_union.val) { + const begin = bw.count; + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(switch (error_union.val) { .err_name => try pt.intern(.{ .undef = payload_ty.toIntern() }), .payload => |payload| payload, - }), code, reloc_parent); - const unpadded_end = code.items.len - begin; + }), bw, reloc_parent); + const unpadded_end = bw.count - begin; const padded_end = abi_align.forward(unpadded_end); - const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; - - if (padding > 0) { - try code.appendNTimes(gpa, 0, padding); - } + try bw.splatByteAll(0, math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow); } // Payload size is larger than error set, so emit our error set last if (error_align.compare(.lte, payload_align)) { - const begin = code.items.len; - try code.writer(gpa).writeInt(u16, err_val, endian); - const unpadded_end = code.items.len - begin; + const begin = bw.count; + try bw.writeInt(u16, err_val, endian); + const unpadded_end = bw.count - begin; const padded_end = abi_align.forward(unpadded_end); - const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; - - if (padding > 0) { - try code.appendNTimes(gpa, 0, padding); - } + try bw.splatByteAll(0, math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow); } }, .enum_tag => |enum_tag| { const int_tag_ty = ty.intTagType(zcu); - try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent); + try generateSymbolInner(bin_file, pt, src_loc, try pt.getCoerced(.fromInterned(enum_tag.int), int_tag_ty), bw, reloc_parent); }, .float => |float| switch (float.storage) { - .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(gpa, 2)), - .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(gpa, 4)), - .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(gpa, 8)), + .f16 => |f16_val| try bw.writeInt(u16, @bitCast(f16_val), endian), + .f32 => |f32_val| try bw.writeInt(u32, @bitCast(f32_val), endian), + .f64 => |f64_val| try bw.writeInt(u64, @bitCast(f64_val), endian), .f80 => |f80_val| { - writeFloat(f80, f80_val, target, endian, try code.addManyAsArray(gpa, 10)); + try bw.writeInt(u80, @bitCast(f80_val), endian); const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; - try code.appendNTimes(gpa, 0, abi_size - 10); + try bw.splatByteAll(0, abi_size - 10); }, - .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)), + .f128 => |f128_val| try bw.writeInt(u128, @bitCast(f128_val), endian), }, - .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0), + .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), bw, reloc_parent, 0), .slice => |slice| { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.ptr), code, reloc_parent); - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.len), code, reloc_parent); + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(slice.ptr), bw, reloc_parent); + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(slice.len), bw, reloc_parent); }, .opt => { const payload_type = ty.optionalChild(zcu); @@ -462,44 +459,44 @@ pub fn generateSymbol( if (ty.optionalReprIsPayload(zcu)) { if (payload_val) |value| { - try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent); + try generateSymbolInner(bin_file, pt, src_loc, value, bw, reloc_parent); } else { - try code.appendNTimes(gpa, 0, abi_size); + try bw.splatByteAll(0, abi_size); } } else { const padding = abi_size - (math.cast(usize, payload_type.abiSize(zcu)) orelse return error.Overflow) - 1; if (payload_type.hasRuntimeBits(zcu)) { - const value = payload_val orelse Value.fromInterned(try pt.intern(.{ + const value: Value = payload_val orelse .fromInterned(try pt.intern(.{ .undef = payload_type.toIntern(), })); - try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent); + try generateSymbolInner(bin_file, pt, src_loc, value, bw, reloc_parent); } - try code.writer(gpa).writeByte(@intFromBool(payload_val != null)); - try code.appendNTimes(gpa, 0, padding); + try bw.writeByte(@intFromBool(payload_val != null)); + try bw.splatByteAll(0, padding); } }, .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) { .array_type => |array_type| switch (aggregate.storage) { - .bytes => |bytes| try code.appendSlice(gpa, bytes.toSlice(array_type.lenIncludingSentinel(), ip)), + .bytes => |bytes| try bw.writeAll(bytes.toSlice(array_type.lenIncludingSentinel(), ip)), .elems, .repeated_elem => { var index: u64 = 0; while (index < array_type.lenIncludingSentinel()) : (index += 1) { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(switch (aggregate.storage) { + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(switch (aggregate.storage) { .bytes => unreachable, .elems => |elems| elems[@intCast(index)], .repeated_elem => |elem| if (index < array_type.len) elem else array_type.sentinel, - }), code, reloc_parent); + }), bw, reloc_parent); } }, }, .vector_type => |vector_type| { const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; if (vector_type.child == .bool_type) { - const bytes = try code.addManyAsSlice(gpa, abi_size); - @memset(bytes, 0xaa); + const buffer = (try bw.writableSlice(abi_size))[0..abi_size]; + @memset(buffer, 0xaa); var index: usize = 0; const len = math.cast(usize, vector_type.len) orelse return error.Overflow; while (index < len) : (index += 1) { @@ -507,7 +504,7 @@ pub fn generateSymbol( .big => len - 1 - index, .little => index, }; - const byte = &bytes[bit_index / 8]; + const byte = &buffer[bit_index / 8]; const mask = @as(u8, 1) << @truncate(bit_index); if (switch (switch (aggregate.storage) { .bytes => unreachable, @@ -535,31 +532,31 @@ pub fn generateSymbol( }, }) byte.* |= mask else byte.* &= ~mask; } + bw.advance(abi_size); } else { switch (aggregate.storage) { - .bytes => |bytes| try code.appendSlice(gpa, bytes.toSlice(vector_type.len, ip)), + .bytes => |bytes| try bw.writeAll(bytes.toSlice(vector_type.len, ip)), .elems, .repeated_elem => { var index: u64 = 0; while (index < vector_type.len) : (index += 1) { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(switch (aggregate.storage) { + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(switch (aggregate.storage) { .bytes => unreachable, .elems => |elems| elems[ math.cast(usize, index) orelse return error.Overflow ], .repeated_elem => |elem| elem, - }), code, reloc_parent); + }), bw, reloc_parent); } }, } - const padding = abi_size - + try bw.splatByteAll(0, abi_size - (math.cast(usize, Type.fromInterned(vector_type.child).abiSize(zcu) * vector_type.len) orelse - return error.Overflow); - if (padding > 0) try code.appendNTimes(gpa, 0, padding); + return error.Overflow)); } }, .tuple_type => |tuple| { - const struct_begin = code.items.len; + const struct_begin = bw.count; for ( tuple.types.get(ip), tuple.values.get(ip), @@ -577,17 +574,13 @@ pub fn generateSymbol( .repeated_elem => |elem| elem, }; - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); - const unpadded_field_end = code.items.len - struct_begin; + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(field_val), bw, reloc_parent); + const unpadded_field_end = bw.count - struct_begin; // Pad struct members if required const padded_field_end = ty.structFieldOffset(index + 1, zcu); - const padding = math.cast(usize, padded_field_end - unpadded_field_end) orelse - return error.Overflow; - - if (padding > 0) { - try code.appendNTimes(gpa, 0, padding); - } + try bw.splatByteAll(0, math.cast(usize, padded_field_end - unpadded_field_end) orelse + return error.Overflow); } }, .struct_type => { @@ -595,8 +588,9 @@ pub fn generateSymbol( switch (struct_type.layout) { .@"packed" => { const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; - const current_pos = code.items.len; - try code.appendNTimes(gpa, 0, abi_size); + const current_end, const current_count = .{ bw.end, bw.count }; + const buffer = (try bw.writableSlice(abi_size))[0..abi_size]; + @memset(buffer, 0); var bits: u16 = 0; for (struct_type.field_types.get(ip), 0..) |field_ty, index| { @@ -616,22 +610,25 @@ pub fn generateSymbol( error.DivisionByZero => unreachable, error.UnexpectedRemainder => return error.RelocationNotByteAligned, }; - code.items.len = current_pos + field_offset; - // TODO: code.lockPointers(); + bw.end = current_end + field_offset; + bw.count = current_count + field_offset; defer { - assert(code.items.len == current_pos + field_offset + @divExact(target.ptrBitWidth(), 8)); - // TODO: code.unlockPointers(); - code.items.len = current_pos + abi_size; + const field_size = @divExact(target.ptrBitWidth(), 8); + assert(bw.end == current_end + field_offset + field_size); + assert(bw.count == current_count + field_offset + field_size); + bw.end = current_end; + bw.count = current_count; } - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(field_val), bw, reloc_parent); } else { - Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), pt, code.items[current_pos..], bits) catch unreachable; + Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), pt, buffer, bits) catch unreachable; } bits += @intCast(Type.fromInterned(field_ty).bitSize(zcu)); } + bw.advance(abi_size); }, .auto, .@"extern" => { - const struct_begin = code.items.len; + const struct_begin = bw.count; const field_types = struct_type.field_types.get(ip); const offsets = struct_type.offsets.get(ip); @@ -649,24 +646,22 @@ pub fn generateSymbol( .repeated_elem => |elem| elem, }; - const padding = math.cast( + try bw.splatByteAll(0, math.cast( usize, - offsets[field_index] - (code.items.len - struct_begin), - ) orelse return error.Overflow; - if (padding > 0) try code.appendNTimes(gpa, 0, padding); + offsets[field_index] - (bw.count - struct_begin), + ) orelse return error.Overflow); - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(field_val), bw, reloc_parent); } const size = struct_type.sizeUnordered(ip); const alignment = struct_type.flagsUnordered(ip).alignment.toByteUnits().?; - const padding = math.cast( + try bw.splatByteAll(0, math.cast( usize, std.mem.alignForward(u64, size, @max(alignment, 1)) - - (code.items.len - struct_begin), - ) orelse return error.Overflow; - if (padding > 0) try code.appendNTimes(gpa, 0, padding); + (bw.count - struct_begin), + ) orelse return error.Overflow); }, } }, @@ -676,38 +671,31 @@ pub fn generateSymbol( const layout = ty.unionGetLayout(zcu); if (layout.payload_size == 0) { - return generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); + return generateSymbolInner(bin_file, pt, src_loc, .fromInterned(un.tag), bw, reloc_parent); } // Check if we should store the tag first. if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(un.tag), bw, reloc_parent); } const union_obj = zcu.typeToUnion(ty).?; if (un.tag != .none) { - const field_index = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?; + const field_index = ty.unionTagFieldIndex(.fromInterned(un.tag), zcu).?; const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBits(zcu)) { - try code.appendNTimes(gpa, 0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); + try bw.splatByteAll(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); } else { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent); - - const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(zcu)) orelse return error.Overflow; - if (padding > 0) { - try code.appendNTimes(gpa, 0, padding); - } + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(un.val), bw, reloc_parent); + try bw.splatByteAll(0, math.cast(usize, layout.payload_size - field_ty.abiSize(zcu)) orelse return error.Overflow); } } else { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent); + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(un.val), bw, reloc_parent); } if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); - - if (layout.padding > 0) { - try code.appendNTimes(gpa, 0, layout.padding); - } + try generateSymbolInner(bin_file, pt, src_loc, .fromInterned(un.tag), bw, reloc_parent); + try bw.splatByteAll(0, layout.padding); } }, .memoized_call => unreachable, @@ -719,32 +707,32 @@ fn lowerPtr( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, ptr_val: InternPool.Index, - code: *std.ArrayListUnmanaged(u8), + bw: *std.io.BufferedWriter, reloc_parent: link.File.RelocInfo.Parent, prev_offset: u64, -) GenerateSymbolError!void { +) anyerror!void { const zcu = pt.zcu; const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr; const offset: u64 = prev_offset + ptr.byte_offset; return switch (ptr.base_addr) { - .nav => |nav| try lowerNavRef(bin_file, pt, nav, code, reloc_parent, offset), - .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, code, reloc_parent, offset), - .int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), code, reloc_parent), + .nav => |nav| try lowerNavRef(bin_file, pt, nav, bw, reloc_parent, offset), + .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, bw, reloc_parent, offset), + .int => try generateSymbolInner(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), bw, reloc_parent), .eu_payload => |eu_ptr| try lowerPtr( bin_file, pt, src_loc, eu_ptr, - code, + bw, reloc_parent, offset + errUnionPayloadOffset( Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu).errorUnionPayload(zcu), zcu, ), ), - .opt_payload => |opt_ptr| try lowerPtr(bin_file, pt, src_loc, opt_ptr, code, reloc_parent, offset), + .opt_payload => |opt_ptr| try lowerPtr(bin_file, pt, src_loc, opt_ptr, bw, reloc_parent, offset), .field => |field| { - const base_ptr = Value.fromInterned(field.base); + const base_ptr: Value = .fromInterned(field.base); const base_ty = base_ptr.typeOf(zcu).childType(zcu); const field_off: u64 = switch (base_ty.zigTypeTag(zcu)) { .pointer => off: { @@ -761,7 +749,7 @@ fn lowerPtr( }, else => unreachable, }; - return lowerPtr(bin_file, pt, src_loc, field.base, code, reloc_parent, offset + field_off); + return lowerPtr(bin_file, pt, src_loc, field.base, bw, reloc_parent, offset + field_off); }, .arr_elem, .comptime_field, .comptime_alloc => unreachable, }; @@ -772,12 +760,11 @@ fn lowerUavRef( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, uav: InternPool.Key.Ptr.BaseAddr.Uav, - code: *std.ArrayListUnmanaged(u8), + bw: *std.io.BufferedWriter, reloc_parent: link.File.RelocInfo.Parent, offset: u64, -) GenerateSymbolError!void { +) anyerror!void { const zcu = pt.zcu; - const gpa = zcu.gpa; const ip = &zcu.intern_pool; const comp = lf.comp; const target = &comp.root_mod.resolved_target.result; @@ -786,13 +773,9 @@ fn lowerUavRef( const uav_ty = Type.fromInterned(ip.typeOf(uav_val)); const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn"; - log.debug("lowerUavRef: ty = {}", .{uav_ty.fmt(pt)}); - try code.ensureUnusedCapacity(gpa, ptr_width_bytes); + log.debug("lowerUavRef: ty = {f}", .{uav_ty.fmt(pt)}); - if (!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) { - code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes); - return; - } + if (!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) return bw.splatByteAll(0xaa, ptr_width_bytes); switch (lf.tag) { .c => unreachable, @@ -801,9 +784,8 @@ fn lowerUavRef( dev.check(link.File.Tag.wasm.devFeature()); const wasm = lf.cast(.wasm).?; assert(reloc_parent == .none); - try wasm.addUavReloc(code.items.len, uav.val, uav.orig_ty, @intCast(offset)); - code.appendNTimesAssumeCapacity(0, ptr_width_bytes); - return; + try wasm.addUavReloc(bw.count, uav.val, uav.orig_ty, @intCast(offset)); + return bw.splatByteAll(0, ptr_width_bytes); }, else => {}, } @@ -816,14 +798,14 @@ fn lowerUavRef( const vaddr = try lf.getUavVAddr(uav_val, .{ .parent = reloc_parent, - .offset = code.items.len, + .offset = bw.count, .addend = @intCast(offset), }); const endian = target.cpu.arch.endian(); switch (ptr_width_bytes) { - 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian), - 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian), - 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian), + 2 => try bw.writeInt(u16, @intCast(vaddr), endian), + 4 => try bw.writeInt(u32, @intCast(vaddr), endian), + 8 => try bw.writeInt(u64, vaddr, endian), else => unreachable, } } @@ -832,10 +814,10 @@ fn lowerNavRef( lf: *link.File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, - code: *std.ArrayListUnmanaged(u8), + bw: *std.io.BufferedWriter, reloc_parent: link.File.RelocInfo.Parent, offset: u64, -) GenerateSymbolError!void { +) anyerror!void { const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; @@ -845,12 +827,9 @@ fn lowerNavRef( const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip)); const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn"; - try code.ensureUnusedCapacity(gpa, ptr_width_bytes); + log.debug("lowerNavRef: ty = {f}", .{nav_ty.fmt(pt)}); - if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) { - code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes); - return; - } + if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) return bw.splatByteAll(0xaa, ptr_width_bytes); switch (lf.tag) { .c => unreachable, @@ -867,13 +846,13 @@ fn lowerNavRef( } else { try wasm.func_table_fixups.append(gpa, .{ .table_index = @enumFromInt(gop.index), - .offset = @intCast(code.items.len), + .offset = @intCast(bw.count), }); } } else { if (is_obj) { try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), + .offset = @intCast(bw.count), .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) }, .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64, .addend = @intCast(offset), @@ -882,27 +861,26 @@ fn lowerNavRef( try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1); wasm.nav_fixups.appendAssumeCapacity(.{ .navs_exe_index = try wasm.refNavExe(nav_index), - .offset = @intCast(code.items.len), + .offset = @intCast(bw.count), .addend = @intCast(offset), }); } } - code.appendNTimesAssumeCapacity(0, ptr_width_bytes); - return; + return bw.splatByteAll(0, ptr_width_bytes); }, else => {}, } const vaddr = lf.getNavVAddr(pt, nav_index, .{ .parent = reloc_parent, - .offset = code.items.len, + .offset = bw.count, .addend = @intCast(offset), }) catch @panic("TODO rework getNavVAddr"); const endian = target.cpu.arch.endian(); switch (ptr_width_bytes) { - 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian), - 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian), - 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian), + 2 => try bw.writeInt(u16, @intCast(vaddr), endian), + 4 => try bw.writeInt(u32, @intCast(vaddr), endian), + 8 => try bw.writeInt(u64, vaddr, endian), else => unreachable, } } @@ -1084,7 +1062,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo const ip = &zcu.intern_pool; const ty = val.typeOf(zcu); - log.debug("lowerValue(@as({}, {}))", .{ ty.fmt(pt), val.fmtValue(pt) }); + log.debug("lowerValue(@as({f}, {f}))", .{ ty.fmt(pt), val.fmtValue(pt) }); if (val.isUndef(zcu)) return .undef; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index ef8cfeb470..efd26bc1b4 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -746,12 +746,14 @@ pub const Object = struct { try wip.finish(); } - fn genModuleLevelAssembly(object: *Object) !void { - const writer = object.builder.setModuleAsm(); + fn genModuleLevelAssembly(object: *Object) Allocator.Error!void { + var aw: std.io.AllocatingWriter = undefined; + const bw = object.builder.setModuleAsm(&aw); + errdefer aw.deinit(); for (object.pt.zcu.global_assembly.values()) |assembly| { - try writer.print("{s}\n", .{assembly}); + bw.print("{s}\n", .{assembly}) catch |err| return @errorCast(err); } - try object.builder.finishModuleAsm(); + try object.builder.finishModuleAsm(&aw); } pub const EmitOptions = struct { @@ -939,7 +941,7 @@ pub const Object = struct { if (std.mem.eql(u8, path, "-")) { o.builder.dump(); } else { - _ = try o.builder.printToFile(path); + _ = o.builder.printToFile(path); } } @@ -2677,9 +2679,9 @@ pub const Object = struct { fn allocTypeName(o: *Object, ty: Type) Allocator.Error![:0]const u8 { var aw: std.io.AllocatingWriter = undefined; - const bw = aw.init(o.gpa); + aw.init(o.gpa); defer aw.deinit(); - try ty.print(bw, o.pt); + ty.print(&aw.buffered_writer, o.pt) catch |err| return @errorCast(err); return aw.toOwnedSliceSentinel(0); } @@ -4479,7 +4481,7 @@ pub const Object = struct { const target = &zcu.root_mod.resolved_target.result; const function_index = try o.builder.addFunction( try o.builder.fnType(ret_ty, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal), - try o.builder.strtabStringFmt("__zig_tag_name_{}", .{enum_type.name.fmt(ip)}), + try o.builder.strtabStringFmt("__zig_tag_name_{f}", .{enum_type.name.fmt(ip)}), toLlvmAddressSpace(.generic, target), ); @@ -4630,7 +4632,7 @@ pub const NavGen = struct { if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") { if (lib_name.toSlice(ip)) |lib_name_slice| { if (!std.mem.eql(u8, lib_name_slice, "c")) { - break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice }); + break :decl_name try o.builder.strtabStringFmt("{f}|{s}", .{ nav.name.fmt(ip), lib_name_slice }); } } } @@ -7469,7 +7471,7 @@ pub const FuncGen = struct { llvm_param_types[llvm_param_i] = llvm_elem_ty; } - try llvm_constraints.writer(self.gpa).print(",{d}", .{output_index}); + try llvm_constraints.print(self.gpa, ",{d}", .{output_index}); // In the case of indirect inputs, LLVM requires the callsite to have // an elementtype() attribute. @@ -7570,7 +7572,7 @@ pub const FuncGen = struct { // we should validate the assembly in Sema; by now it is too late return self.todo("unknown input or output name: '{s}'", .{name}); }; - try rendered_template.writer().print("{d}", .{index}); + try rendered_template.print("{d}", .{index}); if (byte == ':') { try rendered_template.append(':'); modifier_start = i + 1; @@ -10377,7 +10379,7 @@ pub const FuncGen = struct { const target = &zcu.root_mod.resolved_target.result; const function_index = try o.builder.addFunction( try o.builder.fnType(.i1, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal), - try o.builder.strtabStringFmt("__zig_is_named_enum_value_{}", .{enum_type.name.fmt(ip)}), + try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_type.name.fmt(ip)}), toLlvmAddressSpace(.generic, target), ); diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 8a782c54aa..d0e20e21a1 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -817,7 +817,7 @@ const NavGen = struct { const result_ty_id = try self.resolveType(ty, repr); const ip = &zcu.intern_pool; - log.debug("lowering constant: ty = {}, val = {}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) }); + log.debug("lowering constant: ty = {f}, val = {f}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) }); if (val.isUndefDeep(zcu)) { return self.spv.constUndef(result_ty_id); } @@ -1147,7 +1147,7 @@ const NavGen = struct { return result_ptr_id; } - return self.fail("cannot perform pointer cast: '{}' to '{}'", .{ + return self.fail("cannot perform pointer cast: '{f}' to '{f}'", .{ parent_ptr_ty.fmt(pt), oac.new_ptr_ty.fmt(pt), }); @@ -1259,11 +1259,11 @@ const NavGen = struct { } // Turn a Zig type's name into a cache reference. - fn resolveTypeName(self: *NavGen, ty: Type) ![]const u8 { - var name = std.ArrayList(u8).init(self.gpa); - defer name.deinit(); - try ty.print(name.writer(), self.pt); - return try name.toOwnedSlice(); + fn resolveTypeName(self: *NavGen, ty: Type) Allocator.Error![]const u8 { + var aw: std.io.AllocatingWriter = undefined; + aw.init(self.gpa); + ty.print(&aw.buffered_writer, self.pt) catch |err| return @errorCast(err); + return aw.toOwnedSlice(); } /// Create an integer type suitable for storing at least 'bits' bits. @@ -1462,7 +1462,7 @@ const NavGen = struct { const pt = self.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; - log.debug("resolveType: ty = {}", .{ty.fmt(pt)}); + log.debug("resolveType: ty = {f}", .{ty.fmt(pt)}); const target = self.spv.target; const section = &self.spv.sections.types_globals_constants; @@ -3068,7 +3068,7 @@ const NavGen = struct { try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); try self.spv.addFunction(spv_decl_index, self.func); - try self.spv.debugNameFmt(initializer_id, "initializer of {}", .{nav.fqn.fmt(ip)}); + try self.spv.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)}); try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{ .id_result_type = ptr_ty_id, diff --git a/src/codegen/spirv/spec.zig b/src/codegen/spirv/spec.zig index 970f5bfe7f..7c8bcedc35 100644 --- a/src/codegen/spirv/spec.zig +++ b/src/codegen/spirv/spec.zig @@ -18,15 +18,10 @@ pub const IdResult = enum(Word) { none, _, - pub fn format( - self: IdResult, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(self: IdResult, bw: *std.io.BufferedWriter, comptime _: []const u8) anyerror!void { switch (self) { - .none => try writer.writeAll("(none)"), - else => try writer.print("%{}", .{@intFromEnum(self)}), + .none => try bw.writeAll("(none)"), + else => try bw.print("%{}", .{@intFromEnum(self)}), } } }; diff --git a/src/crash_report.zig b/src/crash_report.zig index 22e6ebcf80..8309d07cb4 100644 --- a/src/crash_report.zig +++ b/src/crash_report.zig @@ -80,18 +80,18 @@ fn dumpStatusReport() !void { var fba = std.heap.FixedBufferAllocator.init(&crash_heap); const allocator = fba.allocator(); - const stderr = std.fs.File.stderr.writer().unbuffered(); + var stderr = std.fs.File.stderr().writer().unbuffered(); const block: *Sema.Block = anal.block; const zcu = anal.sema.pt.zcu; const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu) orelse { const file = zcu.fileByIndex(block.src_base_inst.resolveFile(&zcu.intern_pool)); - try stderr.print("Analyzing lost instruction in file '{}'. This should not happen!\n\n", .{file.path.fmt(zcu.comp)}); + try stderr.print("Analyzing lost instruction in file '{f}'. This should not happen!\n\n", .{file.path.fmt(zcu.comp)}); return; }; try stderr.writeAll("Analyzing "); - try stderr.print("Analyzing '{}'\n", .{file.path.fmt(zcu.comp)}); + try stderr.print("Analyzing '{f}'\n", .{file.path.fmt(zcu.comp)}); print_zir.renderInstructionContext( allocator, @@ -100,14 +100,14 @@ fn dumpStatusReport() !void { file, src_base_node, 6, // indent - stderr, + &stderr, ) catch |err| switch (err) { error.OutOfMemory => try stderr.writeAll(" \n"), else => |e| return e, }; try stderr.print( \\ For full context, use the command - \\ zig ast-check -t {} + \\ zig ast-check -t {f} \\ \\ , .{file.path.fmt(zcu.comp)}); @@ -116,7 +116,7 @@ fn dumpStatusReport() !void { while (parent) |curr| { fba.reset(); const cur_block_file = zcu.fileByIndex(curr.block.src_base_inst.resolveFile(&zcu.intern_pool)); - try stderr.print(" in {}\n", .{cur_block_file.path.fmt(zcu.comp)}); + try stderr.print(" in {f}\n", .{cur_block_file.path.fmt(zcu.comp)}); _, const cur_block_src_base_node = Zcu.LazySrcLoc.resolveBaseNode(curr.block.src_base_inst, zcu) orelse { try stderr.writeAll(" > [lost instruction; this should not happen]\n"); parent = curr.parent; @@ -129,7 +129,7 @@ fn dumpStatusReport() !void { cur_block_file, cur_block_src_base_node, 6, // indent - stderr, + &stderr, ) catch |err| switch (err) { error.OutOfMemory => try stderr.writeAll(" \n"), else => |e| return e, @@ -139,7 +139,7 @@ fn dumpStatusReport() !void { parent = curr.parent; } - try stderr.writeAll("\n"); + try stderr.writeByte('\n'); } var crash_heap: [16 * 4096]u8 = undefined; @@ -268,7 +268,8 @@ const StackContext = union(enum) { debug.dumpCurrentStackTrace(ct.ret_addr); }, .exception => |context| { - debug.dumpStackTraceFromBase(context); + var stderr = std.fs.File.stderr().writer().unbuffered(); + debug.dumpStackTraceFromBase(context, &stderr); }, .not_supported => { std.fs.File.stderr().writeAll("Stack trace not supported on this platform.\n") catch {}; @@ -378,7 +379,7 @@ const PanicSwitch = struct { state.recover_stage = .release_mutex; - const stderr = std.fs.File.stderr().writer().unbuffered(); + var stderr = std.fs.File.stderr().writer().unbuffered(); if (builtin.single_threaded) { stderr.print("panic: ", .{}) catch goTo(releaseMutex, .{state}); } else { @@ -405,7 +406,7 @@ const PanicSwitch = struct { recover(state, trace, stack, msg); state.recover_stage = .release_mutex; - const stderr = std.fs.File.stderr().writer().unbuffered(); + var stderr = std.fs.File.stderr().writer().unbuffered(); stderr.writeAll("\nOriginal Error:\n") catch {}; goTo(reportStack, .{state}); } @@ -521,7 +522,7 @@ const PanicSwitch = struct { var stderr = std.fs.File.stderr().writer().unbuffered(); stderr.writeAll("\nPanicked while dumping inner panic stack: ") catch {}; stderr.writeAll(msg) catch {}; - stderr.writeAll("\n") catch {}; + stderr.writeByte('\n') catch {}; // If we succeed, restore all the way to dumping the stack. state.recover_verbosity = .message_and_stack; diff --git a/src/fmt.zig b/src/fmt.zig index 0461ab0a7b..d582a8df3b 100644 --- a/src/fmt.zig +++ b/src/fmt.zig @@ -89,7 +89,7 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { fatal("cannot use --stdin with positional arguments", .{}); } - const source_code = std.zig.readSourceFileToEndAlloc(gpa, .stdin(), null) catch |err| { + const source_code = std.zig.readSourceFileToEndAlloc(gpa, .stdin(), 0) catch |err| { fatal("unable to read stdin: {}", .{err}); }; defer gpa.free(source_code); @@ -134,9 +134,9 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { process.exit(2); } var aw: std.io.AllocatingWriter = undefined; - const bw = aw.init(gpa); + aw.init(gpa); defer aw.deinit(); - try tree.render(gpa, bw, .{}); + try tree.render(gpa, &aw.buffered_writer, .{}); const formatted = aw.getWritten(); if (check_flag) { diff --git a/src/libs/glibc.zig b/src/libs/glibc.zig index da6ee74962..bed242e8e6 100644 --- a/src/libs/glibc.zig +++ b/src/libs/glibc.zig @@ -736,13 +736,13 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye .lt => continue, .gt => { // TODO Expose via compile error mechanism instead of log. - log.warn("invalid target glibc version: {}", .{target_version}); + log.warn("invalid target glibc version: {f}", .{target_version}); return error.InvalidTargetGLibCVersion; }, } } else blk: { const latest_index = metadata.all_versions.len - 1; - log.warn("zig cannot build new glibc version {}; providing instead {}", .{ + log.warn("zig cannot build new glibc version {f}; providing instead {f}", .{ target_version, metadata.all_versions[latest_index], }); break :blk latest_index; @@ -752,9 +752,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye var map_contents = std.ArrayList(u8).init(arena); for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| { if (ver.patch == 0) { - try map_contents.writer().print("GLIBC_{d}.{d} {{ }};\n", .{ ver.major, ver.minor }); + try map_contents.print("GLIBC_{d}.{d} {{ }};\n", .{ ver.major, ver.minor }); } else { - try map_contents.writer().print("GLIBC_{d}.{d}.{d} {{ }};\n", .{ ver.major, ver.minor, ver.patch }); + try map_contents.print("GLIBC_{d}.{d}.{d} {{ }};\n", .{ ver.major, ver.minor, ver.patch }); } } try o_directory.handle.writeFile(.{ .sub_path = all_map_basename, .data = map_contents.items }); @@ -773,7 +773,6 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye try stubs_asm.appendSlice(".text\n"); var sym_i: usize = 0; - var sym_name_buf = std.ArrayList(u8).init(arena); var opt_symbol_name: ?[]const u8 = null; var versions_buffer: [32]u8 = undefined; var versions_len: usize = undefined; @@ -794,24 +793,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye // twice, which causes a "duplicate symbol" assembler error. var versions_written = std.AutoArrayHashMap(Version, void).init(arena); - var inc_fbs = std.io.fixedBufferStream(metadata.inclusions); - var inc_reader = inc_fbs.reader(); + var inc_br: std.io.BufferedReader = undefined; + inc_br.initFixed(metadata.inclusions); - const fn_inclusions_len = try inc_reader.readInt(u16, .little); + const fn_inclusions_len = try inc_br.takeInt(u16, .little); while (sym_i < fn_inclusions_len) : (sym_i += 1) { const sym_name = opt_symbol_name orelse n: { - sym_name_buf.clearRetainingCapacity(); - try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null); - - opt_symbol_name = sym_name_buf.items; + opt_symbol_name = try inc_br.takeSentinel(0); versions_buffer = undefined; versions_len = 0; - - break :n sym_name_buf.items; + break :n opt_symbol_name.?; }; - const targets = try std.leb.readUleb128(u64, inc_reader); - var lib_index = try inc_reader.readByte(); + const targets = try inc_br.takeLeb128(u64); + var lib_index = try inc_br.takeByte(); const is_terminal = (lib_index & (1 << 7)) != 0; if (is_terminal) { @@ -825,7 +820,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0); while (true) { - const byte = try inc_reader.readByte(); + const byte = try inc_br.takeByte(); const last = (byte & 0b1000_0000) != 0; const ver_i = @as(u7, @truncate(byte)); if (ok_lib_and_target and ver_i <= target_ver_index) { @@ -880,7 +875,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye "{s}_{d}_{d}", .{ sym_name, ver.major, ver.minor }, ); - try stubs_asm.writer().print( + try stubs_asm.print( \\.balign {d} \\.globl {s} \\.type {s}, %function @@ -905,7 +900,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye "{s}_{d}_{d}_{d}", .{ sym_name, ver.major, ver.minor, ver.patch }, ); - try stubs_asm.writer().print( + try stubs_asm.print( \\.balign {d} \\.globl {s} \\.type {s}, %function @@ -950,7 +945,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye // versions where the symbol didn't exist. We only care about modern glibc versions, so use // a strong reference. if (std.mem.eql(u8, lib.name, "c")) { - try stubs_asm.writer().print( + try stubs_asm.print( \\.balign {d} \\.globl _IO_stdin_used \\{s} _IO_stdin_used @@ -963,7 +958,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye try stubs_asm.appendSlice(".data\n"); - const obj_inclusions_len = try inc_reader.readInt(u16, .little); + const obj_inclusions_len = try inc_br.takeInt(u16, .little); var sizes = try arena.alloc(u16, metadata.all_versions.len); @@ -973,18 +968,14 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye versions_len = undefined; while (sym_i < obj_inclusions_len) : (sym_i += 1) { const sym_name = opt_symbol_name orelse n: { - sym_name_buf.clearRetainingCapacity(); - try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null); - - opt_symbol_name = sym_name_buf.items; + opt_symbol_name = try inc_br.takeSentinel(0); versions_buffer = undefined; versions_len = 0; - - break :n sym_name_buf.items; + break :n opt_symbol_name.?; }; - const targets = try std.leb.readUleb128(u64, inc_reader); - const size = try std.leb.readUleb128(u16, inc_reader); - var lib_index = try inc_reader.readByte(); + const targets = try inc_br.takeLeb128(u64); + const size = try inc_br.takeLeb128(u16); + var lib_index = try inc_br.takeByte(); const is_terminal = (lib_index & (1 << 7)) != 0; if (is_terminal) { @@ -998,7 +989,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0); while (true) { - const byte = try inc_reader.readByte(); + const byte = try inc_br.takeByte(); const last = (byte & 0b1000_0000) != 0; const ver_i = @as(u7, @truncate(byte)); if (ok_lib_and_target and ver_i <= target_ver_index) { @@ -1055,7 +1046,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye "{s}_{d}_{d}", .{ sym_name, ver.major, ver.minor }, ); - try stubs_asm.writer().print( + try stubs_asm.print( \\.balign {d} \\.globl {s} \\.type {s}, %object @@ -1083,7 +1074,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye "{s}_{d}_{d}_{d}", .{ sym_name, ver.major, ver.minor, ver.patch }, ); - try stubs_asm.writer().print( + try stubs_asm.print( \\.balign {d} \\.globl {s} \\.type {s}, %object diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 40c4c11629..27497bda90 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -401,7 +401,7 @@ fn findDef( }; var override_path: std.io.AllocatingWriter = undefined; - const override_path_writer = override_path.init(gpa); + override_path.init(gpa); defer override_path.deinit(); const s = path.sep_str; @@ -410,9 +410,9 @@ fn findDef( // Try the archtecture-specific path first. const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def"; if (zig_lib_directory.path) |p| { - try override_path_writer.print("{s}" ++ s ++ fmt_path, .{ p, lib_path, lib_name }); + try override_path.buffered_writer.print("{s}" ++ s ++ fmt_path, .{ p, lib_path, lib_name }); } else { - try override_path_writer.print(fmt_path, .{ lib_path, lib_name }); + try override_path.buffered_writer.print(fmt_path, .{ lib_path, lib_name }); } if (std.fs.cwd().access(override_path.getWritten(), .{})) |_| { return override_path.toOwnedSlice(); @@ -427,9 +427,9 @@ fn findDef( override_path.clearRetainingCapacity(); const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def"; if (zig_lib_directory.path) |p| { - try override_path_writer.print("{s}" ++ s ++ fmt_path, .{ p, lib_name }); + try override_path.buffered_writer.print("{s}" ++ s ++ fmt_path, .{ p, lib_name }); } else { - try override_path_writer.print(fmt_path, .{lib_name}); + try override_path.buffered_writer.print(fmt_path, .{lib_name}); } if (std.fs.cwd().access(override_path.getWritten(), .{})) |_| { return override_path.toOwnedSlice(); @@ -444,9 +444,9 @@ fn findDef( override_path.clearRetainingCapacity(); const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in"; if (zig_lib_directory.path) |p| { - try override_path_writer.print("{s}" ++ s ++ fmt_path, .{ p, lib_name }); + try override_path.buffered_writer.print("{s}" ++ s ++ fmt_path, .{ p, lib_name }); } else { - try override_path_writer.print(fmt_path, .{lib_name}); + try override_path.buffered_writer.print(fmt_path, .{lib_name}); } if (std.fs.cwd().access(override_path.getWritten(), .{})) |_| { return override_path.toOwnedSlice(); diff --git a/src/libs/musl.zig b/src/libs/musl.zig index b6ef84ac3b..33be1158d0 100644 --- a/src/libs/musl.zig +++ b/src/libs/musl.zig @@ -115,7 +115,8 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro var c_source_files = std.ArrayList(Compilation.CSourceFile).init(comp.gpa); defer c_source_files.deinit(); - var override_path = std.ArrayList(u8).init(comp.gpa); + var override_path: std.io.AllocatingWriter = undefined; + override_path.init(comp.gpa); defer override_path.deinit(); const s = path.sep_str; @@ -139,26 +140,23 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro } if (!is_arch_specific) { // Look for an arch specific override. - override_path.shrinkRetainingCapacity(0); - try override_path.writer().print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.s", .{ + override_path.clearRetainingCapacity(); + try override_path.buffered_writer.print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.s", .{ dirname, arch_name, noextbasename, }); - if (source_table.contains(override_path.items)) - continue; + if (source_table.contains(override_path.getWritten())) continue; - override_path.shrinkRetainingCapacity(0); - try override_path.writer().print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.S", .{ + override_path.clearRetainingCapacity(); + try override_path.buffered_writer.print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.S", .{ dirname, arch_name, noextbasename, }); - if (source_table.contains(override_path.items)) - continue; + if (source_table.contains(override_path.getWritten())) continue; - override_path.shrinkRetainingCapacity(0); - try override_path.writer().print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.c", .{ + override_path.clearRetainingCapacity(); + try override_path.buffered_writer.print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.c", .{ dirname, arch_name, noextbasename, }); - if (source_table.contains(override_path.items)) - continue; + if (source_table.contains(override_path.getWritten())) continue; } var args = std.ArrayList([]const u8).init(arena); diff --git a/src/link.zig b/src/link.zig index b66ad649d9..d76762f11d 100644 --- a/src/link.zig +++ b/src/link.zig @@ -323,7 +323,7 @@ pub const Diags = struct { const main_msg = try m; errdefer gpa.free(main_msg); try diags.msgs.ensureUnusedCapacity(gpa, 1); - const note = try std.fmt.allocPrint(gpa, "while parsing {}", .{path}); + const note = try std.fmt.allocPrint(gpa, "while parsing {f}", .{path}); errdefer gpa.free(note); const notes = try gpa.create([1]Msg); errdefer gpa.destroy(notes); @@ -838,7 +838,7 @@ pub const File = struct { const cached_pp_file_path = the_key.status.success.object_path; cached_pp_file_path.root_dir.handle.copyFile(cached_pp_file_path.sub_path, emit.root_dir.handle, emit.sub_path, .{}) catch |err| { const diags = &base.comp.link_diags; - return diags.fail("failed to copy '{'}' to '{'}': {s}", .{ + return diags.fail("failed to copy '{f'}' to '{f'}': {s}", .{ @as(Path, cached_pp_file_path), @as(Path, emit), @errorName(err), }); }; @@ -1351,7 +1351,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { .search_strategy = .paths_first, }) catch |archive_err| switch (archive_err) { error.LinkFailure => return, // error reported via diags - else => |e| diags.addParseError(dso_path, "failed to parse archive {}: {s}", .{ archive_path, @errorName(e) }), + else => |e| diags.addParseError(dso_path, "failed to parse archive {f}: {s}", .{ archive_path, @errorName(e) }), }; }, error.LinkFailure => return, // error reported via diags @@ -1874,7 +1874,7 @@ pub fn resolveInputs( )) |lib_result| { switch (lib_result) { .ok => {}, - .no_match => fatal("{}: file not found", .{pq.path}), + .no_match => fatal("{f}: file not found", .{pq.path}), } } continue; @@ -1928,10 +1928,10 @@ fn resolveLibInput( .root_dir = lib_directory, .sub_path = try std.fmt.allocPrint(arena, "lib{s}.tbd", .{lib_name}), }; - try checked_paths.print(gpa, "\n {}", .{test_path}); + try checked_paths.print(gpa, "\n {f}", .{test_path}); var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { error.FileNotFound => break :tbd, - else => |e| fatal("unable to search for tbd library '{}': {s}", .{ test_path, @errorName(e) }), + else => |e| fatal("unable to search for tbd library '{f}': {s}", .{ test_path, @errorName(e) }), }; errdefer file.close(); return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); @@ -1947,7 +1947,7 @@ fn resolveLibInput( }, }), }; - try checked_paths.print(gpa, "\n {}", .{test_path}); + try checked_paths.print(gpa, "\n {f}", .{test_path}); switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{ .path = test_path, .query = name_query.query, @@ -1964,10 +1964,10 @@ fn resolveLibInput( .root_dir = lib_directory, .sub_path = try std.fmt.allocPrint(arena, "lib{s}.so", .{lib_name}), }; - try checked_paths.print(gpa, "\n {}", .{test_path}); + try checked_paths.print(gpa, "\n {f}", .{test_path}); var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { error.FileNotFound => break :so, - else => |e| fatal("unable to search for so library '{}': {s}", .{ + else => |e| fatal("unable to search for so library '{f}': {s}", .{ test_path, @errorName(e), }), }; @@ -1982,10 +1982,10 @@ fn resolveLibInput( .root_dir = lib_directory, .sub_path = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}), }; - try checked_paths.print(gpa, "\n {}", .{test_path}); + try checked_paths.print(gpa, "\n {f}", .{test_path}); var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { error.FileNotFound => break :mingw, - else => |e| fatal("unable to search for static library '{}': {s}", .{ test_path, @errorName(e) }), + else => |e| fatal("unable to search for static library '{f}': {s}", .{ test_path, @errorName(e) }), }; errdefer file.close(); return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); @@ -2037,7 +2037,7 @@ fn resolvePathInput( .shared_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color), .object => { var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err| - fatal("failed to open object {}: {s}", .{ pq.path, @errorName(err) }); + fatal("failed to open object {f}: {s}", .{ pq.path, @errorName(err) }); errdefer file.close(); try resolved_inputs.append(gpa, .{ .object = .{ .path = pq.path, @@ -2049,7 +2049,7 @@ fn resolvePathInput( }, .res => { var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err| - fatal("failed to open windows resource {}: {s}", .{ pq.path, @errorName(err) }); + fatal("failed to open windows resource {f}: {s}", .{ pq.path, @errorName(err) }); errdefer file.close(); try resolved_inputs.append(gpa, .{ .res = .{ .path = pq.path, @@ -2057,7 +2057,7 @@ fn resolvePathInput( } }); return null; }, - else => fatal("{}: unrecognized file extension", .{pq.path}), + else => fatal("{f}: unrecognized file extension", .{pq.path}), } } @@ -2086,13 +2086,13 @@ fn resolvePathInputLib( }) { var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { error.FileNotFound => return .no_match, - else => |e| fatal("unable to search for {s} library '{'}': {s}", .{ + else => |e| fatal("unable to search for {s} library '{f'}': {s}", .{ @tagName(link_mode), test_path, @errorName(e), }), }; errdefer file.close(); try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len)); - const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{'}': {s}", .{ + const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{f'}': {s}", .{ test_path, @errorName(err), }); const buf = ld_script_bytes.items[0..n]; @@ -2101,14 +2101,14 @@ fn resolvePathInputLib( return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query); } const stat = file.stat() catch |err| - fatal("failed to stat {}: {s}", .{ test_path, @errorName(err) }); + fatal("failed to stat {f}: {s}", .{ test_path, @errorName(err) }); const size = std.math.cast(u32, stat.size) orelse - fatal("{}: linker script too big", .{test_path}); + fatal("{f}: linker script too big", .{test_path}); try ld_script_bytes.resize(gpa, size); const buf2 = ld_script_bytes.items[n..]; const n2 = file.preadAll(buf2, n) catch |err| - fatal("failed to read {}: {s}", .{ test_path, @errorName(err) }); - if (n2 != buf2.len) fatal("failed to read {}: unexpected end of file", .{test_path}); + fatal("failed to read {f}: {s}", .{ test_path, @errorName(err) }); + if (n2 != buf2.len) fatal("failed to read {f}: unexpected end of file", .{test_path}); var diags = Diags.init(gpa); defer diags.deinit(); const ld_script_result = LdScript.parse(gpa, &diags, test_path, ld_script_bytes.items); @@ -2128,7 +2128,7 @@ fn resolvePathInputLib( } var ld_script = ld_script_result catch |err| - fatal("{}: failed to parse linker script: {s}", .{ test_path, @errorName(err) }); + fatal("{f}: failed to parse linker script: {s}", .{ test_path, @errorName(err) }); defer ld_script.deinit(gpa); try unresolved_inputs.ensureUnusedCapacity(gpa, ld_script.args.len); @@ -2159,7 +2159,7 @@ fn resolvePathInputLib( var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { error.FileNotFound => return .no_match, - else => |e| fatal("unable to search for {s} library {}: {s}", .{ + else => |e| fatal("unable to search for {s} library {f}: {s}", .{ @tagName(link_mode), test_path, @errorName(e), }), }; @@ -2192,19 +2192,19 @@ pub fn openDso(path: Path, needed: bool, weak: bool, reexport: bool) !Input.Dso pub fn openObjectInput(diags: *Diags, path: Path) error{LinkFailure}!Input { return .{ .object = openObject(path, false, false) catch |err| { - return diags.failParse(path, "failed to open {}: {s}", .{ path, @errorName(err) }); + return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) }); } }; } pub fn openArchiveInput(diags: *Diags, path: Path, must_link: bool, hidden: bool) error{LinkFailure}!Input { return .{ .archive = openObject(path, must_link, hidden) catch |err| { - return diags.failParse(path, "failed to open {}: {s}", .{ path, @errorName(err) }); + return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) }); } }; } pub fn openDsoInput(diags: *Diags, path: Path, needed: bool, weak: bool, reexport: bool) error{LinkFailure}!Input { return .{ .dso = openDso(path, needed, weak, reexport) catch |err| { - return diags.failParse(path, "failed to open {}: {s}", .{ path, @errorName(err) }); + return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) }); } }; } diff --git a/src/link/Coff.zig b/src/link/Coff.zig index ff71b0ca63..650dfe7c0f 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1213,7 +1213,7 @@ fn updateLazySymbolAtom( var code_buffer: std.ArrayListUnmanaged(u8) = .empty; defer code_buffer.deinit(gpa); - const name = try allocPrint(gpa, "__lazy_{s}_{}", .{ + const name = try allocPrint(gpa, "__lazy_{s}_{f}", .{ @tagName(sym.kind), Type.fromInterned(sym.ty).fmt(pt), }); @@ -1333,7 +1333,7 @@ fn updateNavCode( const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - log.debug("updateNavCode {} 0x{x}", .{ nav.fqn.fmt(ip), nav_index }); + log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index }); const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; const required_alignment = switch (pt.navAlignment(nav_index)) { @@ -1361,7 +1361,7 @@ fn updateNavCode( error.OutOfMemory => return error.OutOfMemory, else => |e| return coff.base.cgFail(nav_index, "failed to grow atom: {s}", .{@errorName(e)}), }; - log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), sym.value, vaddr }); + log.debug("growing {f} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), sym.value, vaddr }); log.debug(" (required alignment 0x{x}", .{required_alignment}); if (vaddr != sym.value) { @@ -1389,7 +1389,7 @@ fn updateNavCode( else => |e| return coff.base.cgFail(nav_index, "failed to allocate atom: {s}", .{@errorName(e)}), }; errdefer coff.freeAtom(atom_index); - log.debug("allocated atom for {} at 0x{x}", .{ nav.fqn.fmt(ip), vaddr }); + log.debug("allocated atom for {f} at 0x{x}", .{ nav.fqn.fmt(ip), vaddr }); coff.getAtomPtr(atom_index).size = code_len; sym.value = vaddr; @@ -1454,7 +1454,7 @@ pub fn updateExports( for (export_indices) |export_idx| { const exp = export_idx.ptr(zcu); - log.debug("adding new export '{}'", .{exp.opts.name.fmt(&zcu.intern_pool)}); + log.debug("adding new export '{f}'", .{exp.opts.name.fmt(&zcu.intern_pool)}); if (exp.opts.section.toSlice(&zcu.intern_pool)) |section_name| { if (!mem.eql(u8, section_name, ".text")) { @@ -1530,7 +1530,7 @@ pub fn deleteExport( const gpa = coff.base.comp.gpa; const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null }; const sym = coff.getSymbolPtr(sym_loc); - log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)}); + log.debug("deleting export '{f}'", .{name.fmt(&zcu.intern_pool)}); assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED); sym.* = .{ .name = [_]u8{0} ** 8, @@ -1748,7 +1748,7 @@ pub fn getNavVAddr( const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index }); + log.debug("getNavVAddr {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); const sym_index = if (nav.getExtern(ip)) |e| try coff.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip)) else @@ -2175,15 +2175,14 @@ fn writeDataDirectoriesHeaders(coff: *Coff) !void { fn writeHeader(coff: *Coff) !void { const target = &coff.base.comp.root_mod.resolved_target.result; const gpa = coff.base.comp.gpa; - var buffer = std.ArrayList(u8).init(gpa); - defer buffer.deinit(); - const writer = buffer.writer(); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, coff.getSizeOfHeaders())); + defer gpa.free(bw.buffer); - try buffer.ensureTotalCapacity(coff.getSizeOfHeaders()); - writer.writeAll(&msdos_stub) catch unreachable; - mem.writeInt(u32, buffer.items[0x3c..][0..4], msdos_stub.len, .little); + bw.writeAll(&msdos_stub) catch unreachable; + mem.writeInt(u32, bw.buffer[0x3c..][0..4], msdos_stub.len, .little); - writer.writeAll("PE\x00\x00") catch unreachable; + bw.writeAll("PE\x00\x00") catch unreachable; var flags = coff_util.CoffHeaderFlags{ .EXECUTABLE_IMAGE = 1, .DEBUG_STRIPPED = 1, // TODO @@ -2208,7 +2207,7 @@ fn writeHeader(coff: *Coff) !void { .flags = flags, }; - writer.writeAll(mem.asBytes(&coff_header)) catch unreachable; + bw.writeAll(mem.asBytes(&coff_header)) catch unreachable; const dll_flags: coff_util.DllFlags = .{ .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all? @@ -2271,7 +2270,7 @@ fn writeHeader(coff: *Coff) !void { .loader_flags = 0, .number_of_rva_and_sizes = @intCast(coff.data_directories.len), }; - writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; + bw.writeAll(mem.asBytes(&opt_header)) catch unreachable; }, .p64 => { var opt_header = coff_util.OptionalHeaderPE64{ @@ -2305,11 +2304,12 @@ fn writeHeader(coff: *Coff) !void { .loader_flags = 0, .number_of_rva_and_sizes = @intCast(coff.data_directories.len), }; - writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; + bw.writeAll(mem.asBytes(&opt_header)) catch unreachable; }, } - try coff.pwriteAll(buffer.items, 0); + assert(bw.end == bw.buffer.len); + try coff.pwriteAll(bw.buffer, 0); } pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { @@ -2605,7 +2605,7 @@ fn logSymtab(coff: *Coff) void { } log.debug("GOT entries:", .{}); - log.debug("{}", .{coff.got_table}); + log.debug("{f}", .{coff.got_table}); } fn logSections(coff: *Coff) void { @@ -2625,7 +2625,7 @@ fn logImportTables(coff: *const Coff) void { log.debug("import tables:", .{}); for (coff.import_tables.keys(), 0..) |off, i| { const itable = coff.import_tables.values()[i]; - log.debug("{}", .{itable.fmtDebug(.{ + log.debug("{f}", .{itable.fmtDebug(.{ .coff = coff, .index = i, .name_off = off, @@ -3066,27 +3066,20 @@ const ImportTable = struct { ctx: Context, }; - fn format(itab: ImportTable, comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { + fn format(itab: ImportTable, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) anyerror!void { _ = itab; + _ = bw; _ = unused_format_string; - _ = options; - _ = writer; @compileError("do not format ImportTable directly; use itab.fmtDebug()"); } - fn format2( - fmt_ctx: FormatContext, - comptime unused_format_string: []const u8, - options: fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - _ = options; + fn format2(fmt_ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) anyerror!void { comptime assert(unused_format_string.len == 0); const lib_name = fmt_ctx.ctx.coff.temp_strtab.getAssumeExists(fmt_ctx.ctx.name_off); const base_vaddr = getBaseAddress(fmt_ctx.ctx); - try writer.print("IAT({s}.dll) @{x}:", .{ lib_name, base_vaddr }); + try bw.print("IAT({s}.dll) @{x}:", .{ lib_name, base_vaddr }); for (fmt_ctx.itab.entries.items, 0..) |entry, i| { - try writer.print("\n {d}@{?x} => {s}", .{ + try bw.print("\n {d}@{?x} => {s}", .{ i, fmt_ctx.itab.getImportAddress(entry, fmt_ctx.ctx), fmt_ctx.ctx.coff.getSymbolName(entry), diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index e788360358..385848b7cb 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -132,7 +132,7 @@ const DebugInfo = struct { return AbbrevCode.decl_bytes + dwarf.sectionOffsetBytes(); } - fn declAbbrevCode(debug_info: *DebugInfo, unit: Unit.Index, entry: Entry.Index) !AbbrevCode { + fn declAbbrevCode(debug_info: *DebugInfo, unit: Unit.Index, entry: Entry.Index) anyerror!AbbrevCode { const dwarf: *Dwarf = @fieldParentPtr("debug_info", debug_info); const unit_ptr = debug_info.section.getUnit(unit); const entry_ptr = unit_ptr.getEntry(entry); @@ -142,8 +142,9 @@ const DebugInfo = struct { &abbrev_code_buf, debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off, ) != abbrev_code_buf.len) return error.InputOutput; - var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf); - return @enumFromInt(std.leb.readUleb128(@typeInfo(AbbrevCode).@"enum".tag_type, abbrev_code_fbs.reader()) catch unreachable); + var abbrev_code_br: std.io.BufferedReader = undefined; + abbrev_code_br.initFixed(&abbrev_code_buf); + return @enumFromInt(abbrev_code_br.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable); } const trailer_bytes = 1 + 1; @@ -226,7 +227,7 @@ const StringSection = struct { str_sec.section.deinit(gpa); } - fn addString(str_sec: *StringSection, dwarf: *Dwarf, str: []const u8) UpdateError!Entry.Index { + fn addString(str_sec: *StringSection, dwarf: *Dwarf, str: []const u8) anyerror!Entry.Index { const gop = try str_sec.map.getOrPutAdapted(dwarf.gpa, str, Adapter{ .str_sec = str_sec }); const entry: Entry.Index = @enumFromInt(gop.index); if (!gop.found_existing) { @@ -368,7 +369,7 @@ pub const Section = struct { return &sec.units.items[@intFromEnum(unit)]; } - fn resizeEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, len: u32) UpdateError!void { + fn resizeEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, len: u32) anyerror!void { const unit_ptr = sec.getUnit(unit); const entry_ptr = unit_ptr.getEntry(entry); if (len > 0) { @@ -389,13 +390,13 @@ pub const Section = struct { assert(entry_ptr.len == len); } - fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) UpdateError!void { + fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) anyerror!void { try sec.resizeEntry(unit, entry, dwarf, @intCast(contents.len)); const unit_ptr = sec.getUnit(unit); try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents); } - fn freeEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf) UpdateError!void { + fn freeEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf) anyerror!void { const unit_ptr = sec.getUnit(unit); const entry_ptr = unit_ptr.getEntry(entry); if (entry_ptr.len > 0) { @@ -648,35 +649,36 @@ const Unit = struct { assert(len >= unit.trailer_len); if (sec == &dwarf.debug_line.section) { var buf: [1 + uleb128Bytes(std.math.maxInt(u32)) + 1]u8 = undefined; - var fbs = std.io.fixedBufferStream(&buf); - const writer = fbs.writer(); - writer.writeByte(DW.LNS.extended_op) catch unreachable; - const extended_op_bytes = fbs.pos; + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(&buf); + bw.writeByte(DW.LNS.extended_op) catch unreachable; + const extended_op_bytes = bw.end; var op_len_bytes: u5 = 1; while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) { - .lt => break uleb128(writer, len - extended_op_bytes - op_len_bytes) catch unreachable, + .lt => break bw.writeLeb128(len - extended_op_bytes - op_len_bytes) catch unreachable, .eq => { // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte op_len_bytes += 1; - std.leb.writeUnsignedExtended(buf[fbs.pos..][0..op_len_bytes], len - extended_op_bytes - op_len_bytes); - fbs.pos += op_len_bytes; + std.leb.writeUnsignedExtended((bw.writableSlice(op_len_bytes) catch unreachable)[0..op_len_bytes], len - extended_op_bytes - op_len_bytes); + bw.advance(op_len_bytes); break; }, .gt => op_len_bytes += 1, }; - assert(fbs.pos == extended_op_bytes + op_len_bytes); - writer.writeByte(DW.LNE.padding) catch unreachable; - assert(fbs.pos >= unit.trailer_len and fbs.pos <= len); - return dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off(dwarf) + start); + assert(bw.end == extended_op_bytes + op_len_bytes); + bw.writeByte(DW.LNE.padding) catch unreachable; + assert(bw.end >= unit.trailer_len and bw.end <= len); + return dwarf.getFile().?.pwriteAll(bw.getWritten(), sec.off(dwarf) + start); } - var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, len); - defer trailer.deinit(); + var trailer_bw: std.io.BufferedWriter = undefined; + trailer_bw.initFixed(try dwarf.gpa.alloc(u8, len)); + defer dwarf.gpa.free(trailer_bw.buffer); const fill_byte: u8 = if (sec == &dwarf.debug_abbrev.section) fill: { assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1); - trailer.appendAssumeCapacity(@intFromEnum(AbbrevCode.null)); + trailer_bw.writeByte(@intFromEnum(AbbrevCode.null)) catch unreachable; break :fill @intFromEnum(AbbrevCode.null); } else if (sec == &dwarf.debug_aranges.section) fill: { - trailer.appendNTimesAssumeCapacity(0, @intFromEnum(dwarf.address_size) * 2); + trailer_bw.splatByteAll(0, @intFromEnum(dwarf.address_size) * 2) catch unreachable; break :fill 0; } else if (sec == &dwarf.debug_frame.section) fill: { switch (dwarf.debug_frame.header.format) { @@ -684,49 +686,49 @@ const Unit = struct { .debug_frame, .eh_frame => |format| { const unit_len = len - dwarf.unitLengthBytes(); switch (dwarf.format) { - .@"32" => std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian), + .@"32" => trailer_bw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, .@"64" => { - std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian); - std.mem.writeInt(u64, trailer.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian); + trailer_bw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable; + trailer_bw.writeInt(u64, unit_len, dwarf.endian) catch unreachable; }, } switch (format) { .none => unreachable, .debug_frame => { switch (dwarf.format) { - .@"32" => std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian), - .@"64" => std.mem.writeInt(u64, trailer.addManyAsArrayAssumeCapacity(8), std.math.maxInt(u64), dwarf.endian), + .@"32" => trailer_bw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable, + .@"64" => trailer_bw.writeInt(u64, std.math.maxInt(u64), dwarf.endian) catch unreachable, } - trailer.appendAssumeCapacity(4); - trailer.appendSliceAssumeCapacity("\x00"); - trailer.appendAssumeCapacity(@intFromEnum(dwarf.address_size)); - trailer.appendAssumeCapacity(0); + trailer_bw.writeByte(4) catch unreachable; + trailer_bw.writeAll("\x00") catch unreachable; + trailer_bw.writeByte(@intFromEnum(dwarf.address_size)) catch unreachable; + trailer_bw.writeByte(0) catch unreachable; }, .eh_frame => { - std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), 0, dwarf.endian); - trailer.appendAssumeCapacity(1); - trailer.appendSliceAssumeCapacity("\x00"); + trailer_bw.writeInt(u32, 0, dwarf.endian) catch unreachable; + trailer_bw.writeByte(1) catch unreachable; + trailer_bw.writeAll("\x00") catch unreachable; }, } - uleb128(trailer.fixedWriter(), 1) catch unreachable; - sleb128(trailer.fixedWriter(), 1) catch unreachable; - uleb128(trailer.fixedWriter(), 0) catch unreachable; + trailer_bw.writeUleb128(1) catch unreachable; + trailer_bw.writeSleb128(1) catch unreachable; + trailer_bw.writeUleb128(0) catch unreachable; }, } - trailer.appendNTimesAssumeCapacity(DW.CFA.nop, unit.trailer_len - trailer.items.len); + trailer_bw.splatByteAll(DW.CFA.nop, unit.trailer_len - trailer_bw.end) catch unreachable; break :fill DW.CFA.nop; } else if (sec == &dwarf.debug_info.section) fill: { assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1); - trailer.appendNTimesAssumeCapacity(@intFromEnum(AbbrevCode.null), 2); + trailer_bw.splatByteAll(@intFromEnum(AbbrevCode.null), 2) catch unreachable; break :fill @intFromEnum(AbbrevCode.null); } else if (sec == &dwarf.debug_rnglists.section) fill: { - trailer.appendAssumeCapacity(DW.RLE.end_of_list); + trailer_bw.writeByte(DW.RLE.end_of_list) catch unreachable; break :fill DW.RLE.end_of_list; } else unreachable; - assert(trailer.items.len == unit.trailer_len); - trailer.appendNTimesAssumeCapacity(fill_byte, len - unit.trailer_len); - assert(trailer.items.len == len); - try dwarf.getFile().?.pwriteAll(trailer.items, sec.off(dwarf) + start); + assert(trailer_bw.end == unit.trailer_len); + trailer_bw.splatByteAll(fill_byte, len - unit.trailer_len) catch unreachable; + assert(trailer_bw.end == len); + try dwarf.getFile().?.pwriteAll(trailer_bw.buffer, sec.off(dwarf) + start); } fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { @@ -805,7 +807,7 @@ const Entry = struct { } }; - fn pad(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void { + fn pad(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) anyerror!void { assert(entry.len > 0); const start = entry.off + entry.len; if (sec == &dwarf.debug_frame.section) { @@ -833,55 +835,58 @@ const Entry = struct { 1 + uleb128Bytes(std.math.maxInt(u32)) + 1, ) ]u8 = undefined; - var fbs = std.io.fixedBufferStream(&buf); - const writer = fbs.writer(); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(&buf); if (sec == &dwarf.debug_info.section) switch (len) { 0 => {}, - 1 => uleb128(writer, try dwarf.refAbbrevCode(.pad_1)) catch unreachable, + 1 => bw.writeLeb128(try dwarf.refAbbrevCode(.pad_1)) catch unreachable, else => { - uleb128(writer, try dwarf.refAbbrevCode(.pad_n)) catch unreachable; - const abbrev_code_bytes = fbs.pos; + bw.writeLeb128(try dwarf.refAbbrevCode(.pad_n)) catch unreachable; + const abbrev_code_bytes = bw.end; var block_len_bytes: u5 = 1; while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) { - .lt => break uleb128(writer, len - abbrev_code_bytes - block_len_bytes) catch unreachable, + .lt => break bw.writeLeb128(len - abbrev_code_bytes - block_len_bytes) catch unreachable, .eq => { // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte block_len_bytes += 1; - std.leb.writeUnsignedExtended(buf[fbs.pos..][0..block_len_bytes], len - abbrev_code_bytes - block_len_bytes); - fbs.pos += block_len_bytes; + std.leb.writeUnsignedExtended((try bw.writableSlice(block_len_bytes))[0..block_len_bytes], len - abbrev_code_bytes - block_len_bytes); + bw.advance(block_len_bytes); break; }, .gt => block_len_bytes += 1, }; - assert(fbs.pos == abbrev_code_bytes + block_len_bytes); + assert(bw.end == abbrev_code_bytes + block_len_bytes); }, } else if (sec == &dwarf.debug_line.section) switch (len) { 0 => {}, - 1 => writer.writeByte(DW.LNS.const_add_pc) catch unreachable, + 1 => bw.writeByte(DW.LNS.const_add_pc) catch unreachable, else => { - writer.writeByte(DW.LNS.extended_op) catch unreachable; - const extended_op_bytes = fbs.pos; + bw.writeByte(DW.LNS.extended_op) catch unreachable; + const extended_op_bytes = bw.end; var op_len_bytes: u5 = 1; while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) { - .lt => break uleb128(writer, len - extended_op_bytes - op_len_bytes) catch unreachable, + .lt => break bw.writeLeb128(len - extended_op_bytes - op_len_bytes) catch unreachable, .eq => { // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte op_len_bytes += 1; - std.leb.writeUnsignedExtended(buf[fbs.pos..][0..op_len_bytes], len - extended_op_bytes - op_len_bytes); - fbs.pos += op_len_bytes; + std.leb.writeUnsignedExtended( + (bw.writableSlice(op_len_bytes) catch unreachable)[0..op_len_bytes], + len - extended_op_bytes - op_len_bytes, + ); + bw.advance(op_len_bytes); break; }, .gt => op_len_bytes += 1, }; - assert(fbs.pos == extended_op_bytes + op_len_bytes); - if (len > 2) writer.writeByte(DW.LNE.padding) catch unreachable; + assert(bw.end == extended_op_bytes + op_len_bytes); + if (len > 2) bw.writeByte(DW.LNE.padding) catch unreachable; }, } else assert(!sec.pad_entries_to_ideal and len == 0); - assert(fbs.pos <= len); - try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off(dwarf) + unit.off + unit.header_len + start); + assert(bw.end <= len); + try dwarf.getFile().?.pwriteAll(bw.getWritten(), sec.off(dwarf) + unit.off + unit.header_len + start); } - fn resize(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void { + fn resize(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) anyerror!void { assert(len > 0); assert(sec.alignment.check(len)); if (entry_ptr.len == len) return; @@ -973,7 +978,7 @@ const Entry = struct { else .main; if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry) - log.err("missing Type({}({d}))", .{ + log.err("missing Type({f}({d}))", .{ Type.fromInterned(ty).fmt(.{ .tid = .main, .zcu = zcu }), @intFromEnum(ty), }); @@ -981,7 +986,7 @@ const Entry = struct { for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| { const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFile(ip)).mod.?) catch unreachable; if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry) - log.err("missing Nav({}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }); + log.err("missing Nav({f}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }); } } @panic("missing dwarf relocation target"); @@ -1133,150 +1138,149 @@ pub const Loc = union(enum) { }; } - fn writeReg(reg: u32, op0: u8, opx: u8, writer: anytype) @TypeOf(writer).Error!void { + fn writeReg(bw: *std.io.BufferedWriter, reg: u32, op0: u8, opx: u8) anyerror!void { if (std.math.cast(u5, reg)) |small_reg| { - try writer.writeByte(op0 + small_reg); + try bw.writeByte(op0 + small_reg); } else { - try writer.writeByte(opx); - try uleb128(writer, reg); + try bw.writeByte(opx); + try bw.writeLeb128(reg); } } - fn write(loc: Loc, adapter: anytype) UpdateError!void { - const writer = adapter.writer(); + fn write(loc: Loc, bw: *std.io.BufferedWriter, adapter: anytype) anyerror!void { switch (loc) { .empty => {}, .addr_reloc => |sym_index| { - try writer.writeByte(DW.OP.addr); + try bw.writeByte(DW.OP.addr); try adapter.addrSym(sym_index); }, .deref => |addr| { try addr.write(adapter); - try writer.writeByte(DW.OP.deref); + try bw.writeByte(DW.OP.deref); }, .constu => |constu| if (std.math.cast(u5, constu)) |lit| { - try writer.writeByte(@as(u8, DW.OP.lit0) + lit); + try bw.writeByte(@as(u8, DW.OP.lit0) + lit); } else if (std.math.cast(u8, constu)) |const1u| { - try writer.writeAll(&.{ DW.OP.const1u, const1u }); + try bw.writeAll(&.{ DW.OP.const1u, const1u }); } else if (std.math.cast(u16, constu)) |const2u| { - try writer.writeByte(DW.OP.const2u); - try writer.writeInt(u16, const2u, adapter.endian()); + try bw.writeByte(DW.OP.const2u); + try bw.writeInt(u16, const2u, adapter.endian()); } else if (std.math.cast(u21, constu)) |const3u| { - try writer.writeByte(DW.OP.constu); - try uleb128(writer, const3u); + try bw.writeByte(DW.OP.constu); + try bw.writeLeb128(const3u); } else if (std.math.cast(u32, constu)) |const4u| { - try writer.writeByte(DW.OP.const4u); - try writer.writeInt(u32, const4u, adapter.endian()); + try bw.writeByte(DW.OP.const4u); + try bw.writeInt(u32, const4u, adapter.endian()); } else if (std.math.cast(u49, constu)) |const7u| { - try writer.writeByte(DW.OP.constu); - try uleb128(writer, const7u); + try bw.writeByte(DW.OP.constu); + try bw.writeLeb128(const7u); } else { - try writer.writeByte(DW.OP.const8u); - try writer.writeInt(u64, constu, adapter.endian()); + try bw.writeByte(DW.OP.const8u); + try bw.writeInt(u64, constu, adapter.endian()); }, .consts => |consts| if (std.math.cast(i8, consts)) |const1s| { - try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) }); + try bw.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) }); } else if (std.math.cast(i16, consts)) |const2s| { - try writer.writeByte(DW.OP.const2s); - try writer.writeInt(i16, const2s, adapter.endian()); + try bw.writeByte(DW.OP.const2s); + try bw.writeInt(i16, const2s, adapter.endian()); } else if (std.math.cast(i21, consts)) |const3s| { - try writer.writeByte(DW.OP.consts); - try sleb128(writer, const3s); + try bw.writeByte(DW.OP.consts); + try bw.writeLeb128(const3s); } else if (std.math.cast(i32, consts)) |const4s| { - try writer.writeByte(DW.OP.const4s); - try writer.writeInt(i32, const4s, adapter.endian()); + try bw.writeByte(DW.OP.const4s); + try bw.writeInt(i32, const4s, adapter.endian()); } else if (std.math.cast(i49, consts)) |const7s| { - try writer.writeByte(DW.OP.consts); - try sleb128(writer, const7s); + try bw.writeByte(DW.OP.consts); + try bw.writeLeb128(const7s); } else { - try writer.writeByte(DW.OP.const8s); - try writer.writeInt(i64, consts, adapter.endian()); + try bw.writeByte(DW.OP.const8s); + try bw.writeInt(i64, consts, adapter.endian()); }, .plus => |plus| done: { if (plus[0].getConst(u0)) |_| { - try plus[1].write(adapter); + try plus[1].write(bw, adapter); break :done; } if (plus[1].getConst(u0)) |_| { - try plus[0].write(adapter); + try plus[0].write(bw, adapter); break :done; } if (plus[0].getBaseReg()) |breg| { if (plus[1].getConst(i65)) |offset| { - try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); - try sleb128(writer, offset); + try writeReg(bw, breg, DW.OP.breg0, DW.OP.bregx); + try bw.writeLeb128(offset); break :done; } } if (plus[1].getBaseReg()) |breg| { if (plus[0].getConst(i65)) |offset| { - try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); - try sleb128(writer, offset); + try writeReg(bw, breg, DW.OP.breg0, DW.OP.bregx); + try bw.writeLeb128(offset); break :done; } } if (plus[0].getConst(u64)) |uconst| { - try plus[1].write(adapter); - try writer.writeByte(DW.OP.plus_uconst); - try uleb128(writer, uconst); + try plus[1].write(bw, adapter); + try bw.writeByte(DW.OP.plus_uconst); + try bw.writeLeb128(uconst); break :done; } if (plus[1].getConst(u64)) |uconst| { - try plus[0].write(adapter); - try writer.writeByte(DW.OP.plus_uconst); - try uleb128(writer, uconst); + try plus[0].write(bw, adapter); + try bw.writeByte(DW.OP.plus_uconst); + try bw.writeLeb128(uconst); break :done; } - try plus[0].write(adapter); - try plus[1].write(adapter); - try writer.writeByte(DW.OP.plus); + try plus[0].write(bw, adapter); + try plus[1].write(bw, adapter); + try bw.writeByte(DW.OP.plus); }, - .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer), + .reg => |reg| try writeReg(bw, reg, DW.OP.reg0, DW.OP.regx), .breg => |breg| { - try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); - try sleb128(writer, 0); + try writeReg(bw, breg, DW.OP.breg0, DW.OP.bregx); + try bw.writeSleb128(0); }, - .push_object_address => try writer.writeByte(DW.OP.push_object_address), + .push_object_address => try bw.writeByte(DW.OP.push_object_address), .call => |call| { for (call.args) |arg| try arg.write(adapter); - try writer.writeByte(DW.OP.call_ref); + try bw.writeByte(DW.OP.call_ref); try adapter.infoEntry(call.unit, call.entry); }, .form_tls_address => |addr| { - try addr.write(adapter); - try writer.writeByte(DW.OP.form_tls_address); + try addr.write(bw, adapter); + try bw.writeByte(DW.OP.form_tls_address); }, .implicit_value => |value| { - try writer.writeByte(DW.OP.implicit_value); - try uleb128(writer, value.len); - try writer.writeAll(value); + try bw.writeByte(DW.OP.implicit_value); + try bw.writeLeb128(value.len); + try bw.writeAll(value); }, .stack_value => |value| { - try value.write(adapter); - try writer.writeByte(DW.OP.stack_value); + try value.write(bw, adapter); + try bw.writeByte(DW.OP.stack_value); }, .implicit_pointer => |implicit_pointer| { - try writer.writeByte(DW.OP.implicit_pointer); - try adapter.infoEntry(implicit_pointer.unit, implicit_pointer.entry); - try sleb128(writer, implicit_pointer.offset); + try bw.writeByte(DW.OP.implicit_pointer); + try adapter.infoEntry(bw, implicit_pointer.unit, implicit_pointer.entry); + try bw.writeLeb128(implicit_pointer.offset); }, .wasm_ext => |wasm_ext| { - try writer.writeByte(DW.OP.WASM_location); + try bw.writeByte(DW.OP.WASM_location); switch (wasm_ext) { .local => |local| { - try writer.writeByte(DW.OP.WASM_local); - try uleb128(writer, local); + try bw.writeByte(DW.OP.WASM_local); + try bw.writeLeb128(local); }, .global => |global| if (std.math.cast(u21, global)) |global_u21| { - try writer.writeByte(DW.OP.WASM_global); - try uleb128(writer, global_u21); + try bw.writeByte(DW.OP.WASM_global); + try bw.writeLeb128(global_u21); } else { - try writer.writeByte(DW.OP.WASM_global_u32); - try writer.writeInt(u32, global, adapter.endian()); + try bw.writeByte(DW.OP.WASM_global_u32); + try bw.writeInt(u32, global, adapter.endian()); }, .operand_stack => |operand_stack| { - try writer.writeByte(DW.OP.WASM_operand_stack); - try uleb128(writer, operand_stack); + try bw.writeByte(DW.OP.WASM_operand_stack); + try bw.writeLeb128(operand_stack); }, } }, @@ -1308,22 +1312,22 @@ pub const Cfa = union(enum) { const RegOff = struct { reg: u32, off: i64 }; const RegExpr = struct { reg: u32, expr: Loc }; - fn write(cfa: Cfa, wip_nav: *WipNav) UpdateError!void { - const writer = wip_nav.debug_frame.writer(wip_nav.dwarf.gpa); + fn write(cfa: Cfa, wip_nav: *WipNav) anyerror!void { + const bw = &wip_nav.debug_frame.buffered_writer; switch (cfa) { - .nop => try writer.writeByte(DW.CFA.nop), + .nop => try bw.writeByte(DW.CFA.nop), .advance_loc => |loc| { const delta = @divExact(loc - wip_nav.cfi.loc, wip_nav.dwarf.debug_frame.header.code_alignment_factor); if (delta == 0) {} else if (std.math.cast(u6, delta)) |small_delta| - try writer.writeByte(@as(u8, DW.CFA.advance_loc) + small_delta) + try bw.writeByte(@as(u8, DW.CFA.advance_loc) + small_delta) else if (std.math.cast(u8, delta)) |ubyte_delta| - try writer.writeAll(&.{ DW.CFA.advance_loc1, ubyte_delta }) + try bw.writeAll(&.{ DW.CFA.advance_loc1, ubyte_delta }) else if (std.math.cast(u16, delta)) |uhalf_delta| { - try writer.writeByte(DW.CFA.advance_loc2); - try writer.writeInt(u16, uhalf_delta, wip_nav.dwarf.endian); + try bw.writeByte(DW.CFA.advance_loc2); + try bw.writeInt(u16, uhalf_delta, wip_nav.dwarf.endian); } else if (std.math.cast(u32, delta)) |uword_delta| { - try writer.writeByte(DW.CFA.advance_loc4); - try writer.writeInt(u32, uword_delta, wip_nav.dwarf.endian); + try bw.writeByte(DW.CFA.advance_loc4); + try bw.writeInt(u32, uword_delta, wip_nav.dwarf.endian); } wip_nav.cfi.loc = loc; }, @@ -1335,41 +1339,41 @@ pub const Cfa = union(enum) { }, wip_nav.dwarf.debug_frame.header.data_alignment_factor); if (std.math.cast(u63, factored_off)) |unsigned_off| { if (std.math.cast(u6, reg_off.reg)) |small_reg| { - try writer.writeByte(@as(u8, DW.CFA.offset) + small_reg); + try bw.writeByte(@as(u8, DW.CFA.offset) + small_reg); } else { - try writer.writeByte(DW.CFA.offset_extended); - try uleb128(writer, reg_off.reg); + try bw.writeByte(DW.CFA.offset_extended); + try bw.writeLeb128(reg_off.reg); } - try uleb128(writer, unsigned_off); + try bw.writeLeb128(unsigned_off); } else { - try writer.writeByte(DW.CFA.offset_extended_sf); - try uleb128(writer, reg_off.reg); - try sleb128(writer, factored_off); + try bw.writeByte(DW.CFA.offset_extended_sf); + try bw.writeLeb128(reg_off.reg); + try bw.writeLeb128(factored_off); } }, .restore => |reg| if (std.math.cast(u6, reg)) |small_reg| - try writer.writeByte(@as(u8, DW.CFA.restore) + small_reg) + try bw.writeByte(@as(u8, DW.CFA.restore) + small_reg) else { - try writer.writeByte(DW.CFA.restore_extended); - try uleb128(writer, reg); + try bw.writeByte(DW.CFA.restore_extended); + try bw.writeLeb128(reg); }, .undefined => |reg| { - try writer.writeByte(DW.CFA.undefined); - try uleb128(writer, reg); + try bw.writeByte(DW.CFA.undefined); + try bw.writeLeb128(reg); }, .same_value => |reg| { - try writer.writeByte(DW.CFA.same_value); - try uleb128(writer, reg); + try bw.writeByte(DW.CFA.same_value); + try bw.writeLeb128(reg); }, .register => |regs| if (regs[0] != regs[1]) { - try writer.writeByte(DW.CFA.register); - for (regs) |reg| try uleb128(writer, reg); + try bw.writeByte(DW.CFA.register); + for (regs) |reg| try bw.writeLeb128(reg); } else { - try writer.writeByte(DW.CFA.same_value); - try uleb128(writer, regs[0]); + try bw.writeByte(DW.CFA.same_value); + try bw.writeLeb128(regs[0]); }, - .remember_state => try writer.writeByte(DW.CFA.remember_state), - .restore_state => try writer.writeByte(DW.CFA.restore_state), + .remember_state => try bw.writeByte(DW.CFA.remember_state), + .restore_state => try bw.writeByte(DW.CFA.restore_state), .def_cfa, .def_cfa_register, .def_cfa_offset, .adjust_cfa_offset => { const reg_off: RegOff = switch (cfa) { else => unreachable, @@ -1382,51 +1386,51 @@ pub const Cfa = union(enum) { const unsigned_off = std.math.cast(u63, reg_off.off); if (reg_off.off == wip_nav.cfi.cfa.off) { if (changed_reg) { - try writer.writeByte(DW.CFA.def_cfa_register); - try uleb128(writer, reg_off.reg); + try bw.writeByte(DW.CFA.def_cfa_register); + try bw.writeLeb128(reg_off.reg); } } else if (switch (wip_nav.dwarf.debug_frame.header.data_alignment_factor) { 0 => unreachable, 1 => unsigned_off != null, else => |data_alignment_factor| @rem(reg_off.off, data_alignment_factor) != 0, }) { - try writer.writeByte(if (changed_reg) DW.CFA.def_cfa else DW.CFA.def_cfa_offset); - if (changed_reg) try uleb128(writer, reg_off.reg); - try uleb128(writer, unsigned_off.?); + try bw.writeByte(if (changed_reg) DW.CFA.def_cfa else DW.CFA.def_cfa_offset); + if (changed_reg) try bw.writeLeb128(reg_off.reg); + try bw.writeLeb128(unsigned_off.?); } else { - try writer.writeByte(if (changed_reg) DW.CFA.def_cfa_sf else DW.CFA.def_cfa_offset_sf); - if (changed_reg) try uleb128(writer, reg_off.reg); - try sleb128(writer, @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor)); + try bw.writeByte(if (changed_reg) DW.CFA.def_cfa_sf else DW.CFA.def_cfa_offset_sf); + if (changed_reg) try bw.writeLeb128(reg_off.reg); + try bw.writeLeb128(@divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor)); } wip_nav.cfi.cfa = reg_off; }, .def_cfa_expression => |expr| { - try writer.writeByte(DW.CFA.def_cfa_expression); + try bw.writeByte(DW.CFA.def_cfa_expression); try wip_nav.frameExprLoc(expr); }, .expression => |reg_expr| { - try writer.writeByte(DW.CFA.expression); - try uleb128(writer, reg_expr.reg); + try bw.writeByte(DW.CFA.expression); + try bw.writeLeb128(reg_expr.reg); try wip_nav.frameExprLoc(reg_expr.expr); }, .val_offset => |reg_off| { const factored_off = @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor); if (std.math.cast(u63, factored_off)) |unsigned_off| { - try writer.writeByte(DW.CFA.val_offset); - try uleb128(writer, reg_off.reg); - try uleb128(writer, unsigned_off); + try bw.writeByte(DW.CFA.val_offset); + try bw.writeLeb128(reg_off.reg); + try bw.writeLeb128(unsigned_off); } else { - try writer.writeByte(DW.CFA.val_offset_sf); - try uleb128(writer, reg_off.reg); - try sleb128(writer, factored_off); + try bw.writeByte(DW.CFA.val_offset_sf); + try bw.writeLeb128(reg_off.reg); + try bw.writeLeb128(factored_off); } }, .val_expression => |reg_expr| { - try writer.writeByte(DW.CFA.val_expression); - try uleb128(writer, reg_expr.reg); + try bw.writeByte(DW.CFA.val_expression); + try bw.writeLeb128(reg_expr.reg); try wip_nav.frameExprLoc(reg_expr.expr); }, - .escape => |bytes| try writer.writeAll(bytes), + .escape => |bytes| try bw.writeAll(bytes), } } }; @@ -1449,19 +1453,27 @@ pub const WipNav = struct { loc: u32, cfa: Cfa.RegOff, }, - debug_frame: std.ArrayListUnmanaged(u8), - debug_info: std.ArrayListUnmanaged(u8), - debug_line: std.ArrayListUnmanaged(u8), - debug_loclists: std.ArrayListUnmanaged(u8), + debug_frame: std.io.AllocatingWriter, + debug_info: std.io.AllocatingWriter, + debug_line: std.io.AllocatingWriter, + debug_loclists: std.io.AllocatingWriter, pending_lazy: PendingLazy, + pub fn init(wip_nav: *WipNav) void { + const gpa = wip_nav.dwarf.gpa; + wip_nav.debug_frame.init(gpa); + wip_nav.debug_info.init(gpa); + wip_nav.debug_line.init(gpa); + wip_nav.debug_loclists.init(gpa); + } + pub fn deinit(wip_nav: *WipNav) void { const gpa = wip_nav.dwarf.gpa; if (wip_nav.func != .none) wip_nav.blocks.deinit(gpa); - wip_nav.debug_frame.deinit(gpa); - wip_nav.debug_info.deinit(gpa); - wip_nav.debug_line.deinit(gpa); - wip_nav.debug_loclists.deinit(gpa); + wip_nav.debug_frame.deinit(); + wip_nav.debug_info.deinit(); + wip_nav.debug_line.deinit(); + wip_nav.debug_loclists.deinit(); wip_nav.pending_lazy.types.deinit(gpa); wip_nav.pending_lazy.values.deinit(gpa); } @@ -1470,8 +1482,8 @@ pub const WipNav = struct { assert(wip_nav.func != .none); if (wip_nav.dwarf.debug_frame.header.format == .none) return; const loc_cfa: Cfa = .{ .advance_loc = loc }; - try loc_cfa.write(wip_nav); - try cfa.write(wip_nav); + loc_cfa.write(wip_nav) catch |err| return @errorCast(err); + cfa.write(wip_nav) catch |err| return @errorCast(err); } pub const LocalVarTag = enum { arg, local_var }; @@ -1529,7 +1541,7 @@ pub const WipNav = struct { pub fn genVarArgsDebugInfo(wip_nav: *WipNav) UpdateError!void { assert(wip_nav.func != .none); - try wip_nav.abbrevCode(.is_var_args); + wip_nav.abbrevCode(.is_var_args) catch |err| return @errorCast(err); wip_nav.any_children = true; } @@ -1538,7 +1550,7 @@ pub const WipNav = struct { delta_line: i33, delta_pc: u64, ) error{OutOfMemory}!void { - const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); + const dlbw = &wip_nav.debug_line.buffered_writer; const header = wip_nav.dwarf.debug_line.header; assert(header.maximum_operations_per_instruction == 1); @@ -1548,8 +1560,8 @@ pub const WipNav = struct { delta_line - header.line_base >= header.line_range) remaining: { assert(delta_line != 0); - try dlw.writeByte(DW.LNS.advance_line); - try sleb128(dlw, delta_line); + dlbw.writeByte(DW.LNS.advance_line) catch |err| return @errorCast(err); + dlbw.writeLeb128(delta_line) catch |err| return @errorCast(err); break :remaining 0; } else delta_line); @@ -1557,68 +1569,68 @@ pub const WipNav = struct { header.maximum_operations_per_instruction + delta_op; const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range; const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: { - try dlw.writeByte(DW.LNS.advance_pc); - try uleb128(dlw, op_advance); + dlbw.writeByte(DW.LNS.advance_pc) catch |err| return @errorCast(err); + dlbw.writeLeb128(op_advance) catch |err| return @errorCast(err); break :remaining 0; } else if (op_advance >= max_op_advance) remaining: { - try dlw.writeByte(DW.LNS.const_add_pc); + dlbw.writeByte(DW.LNS.const_add_pc) catch |err| return @errorCast(err); break :remaining op_advance - max_op_advance; } else op_advance); - if (remaining_delta_line == 0 and remaining_op_advance == 0) - try dlw.writeByte(DW.LNS.copy) - else - try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) + - (header.line_range * remaining_op_advance) + header.opcode_base)); + dlbw.writeByte( + if (remaining_delta_line == 0 and remaining_op_advance == 0) + DW.LNS.copy + else + @intCast((remaining_delta_line - header.line_base) + + (header.line_range * remaining_op_advance) + header.opcode_base), + ) catch |err| return @errorCast(err); } - pub fn setColumn(wip_nav: *WipNav, column: u32) error{OutOfMemory}!void { - const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); - try dlw.writeByte(DW.LNS.set_column); - try uleb128(dlw, column + 1); + pub fn setColumn(wip_nav: *WipNav, column: u32) std.mem.Allocator.Error!void { + const dlbw = &wip_nav.debug_line.buffered_writer; + dlbw.writeByte(DW.LNS.set_column) catch |err| return @errorCast(err); + dlbw.writeLeb128(column + 1) catch |err| return @errorCast(err); } - pub fn negateStmt(wip_nav: *WipNav) error{OutOfMemory}!void { - const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); - try dlw.writeByte(DW.LNS.negate_stmt); + pub fn negateStmt(wip_nav: *WipNav) std.mem.Allocator.Error!void { + return @errorCast(wip_nav.debug_line.buffered_writer.writeByte(DW.LNS.negate_stmt)); } - pub fn setPrologueEnd(wip_nav: *WipNav) error{OutOfMemory}!void { - const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); - try dlw.writeByte(DW.LNS.set_prologue_end); + pub fn setPrologueEnd(wip_nav: *WipNav) std.mem.Allocator.Error!void { + return @errorCast(wip_nav.debug_line.buffered_writer.writeByte(DW.LNS.set_prologue_end)); } - pub fn setEpilogueBegin(wip_nav: *WipNav) error{OutOfMemory}!void { - const dlw = wip_nav.debug_line.writer(wip_nav.dwarf.gpa); - try dlw.writeByte(DW.LNS.set_epilogue_begin); + pub fn setEpilogueBegin(wip_nav: *WipNav) std.mem.Allocator.Error!void { + return @errorCast(wip_nav.debug_line.buffered_writer.writeByte(DW.LNS.set_epilogue_begin)); } - pub fn enterBlock(wip_nav: *WipNav, code_off: u64) UpdateError!void { + pub fn enterBlock(wip_nav: *WipNav, code_off: u64) anyerror!void { const dwarf = wip_nav.dwarf; - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; const block = try wip_nav.blocks.addOne(dwarf.gpa); - block.abbrev_code = @intCast(wip_nav.debug_info.items.len); + block.abbrev_code = @intCast(dibw.count); try wip_nav.abbrevCode(.block); block.low_pc_off = code_off; try wip_nav.infoAddrSym(wip_nav.func_sym_index, code_off); - block.high_pc = @intCast(wip_nav.debug_info.items.len); - try diw.writeInt(u32, 0, dwarf.endian); + block.high_pc = @intCast(dibw.count); + try dibw.writeInt(u32, 0, dwarf.endian); wip_nav.any_children = false; } - pub fn leaveBlock(wip_nav: *WipNav, code_off: u64) UpdateError!void { + pub fn leaveBlock(wip_nav: *WipNav, code_off: u64) anyerror!void { const block_bytes = comptime uleb128Bytes(@intFromEnum(AbbrevCode.block)); const block = wip_nav.blocks.pop().?; + const dib = wip_nav.debug_info.getWritten(); if (wip_nav.any_children) - try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), @intFromEnum(AbbrevCode.null)) + try wip_nav.debug_info.buffered_writer.writeLeb128(@intFromEnum(AbbrevCode.null)) else std.leb.writeUnsignedFixed( block_bytes, - wip_nav.debug_info.items[block.abbrev_code..][0..block_bytes], + dib[block.abbrev_code..][0..block_bytes], try wip_nav.dwarf.refAbbrevCode(.empty_block), ); - std.mem.writeInt(u32, wip_nav.debug_info.items[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian); + std.mem.writeInt(u32, dib[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian); wip_nav.any_children = true; } @@ -1628,42 +1640,43 @@ pub const WipNav = struct { code_off: u64, line: u32, column: u32, - ) UpdateError!void { + ) anyerror!void { const dwarf = wip_nav.dwarf; const zcu = wip_nav.pt.zcu; - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; const block = try wip_nav.blocks.addOne(dwarf.gpa); - block.abbrev_code = @intCast(wip_nav.debug_info.items.len); + block.abbrev_code = @intCast(dibw.count); try wip_nav.abbrevCode(.inlined_func); try wip_nav.refNav(zcu.funcInfo(func).owner_nav); - try uleb128(diw, zcu.navSrcLine(zcu.funcInfo(wip_nav.func).owner_nav) + line + 1); - try uleb128(diw, column + 1); + try dibw.writeLeb128(zcu.navSrcLine(zcu.funcInfo(wip_nav.func).owner_nav) + line + 1); + try dibw.writeLeb128(column + 1); block.low_pc_off = code_off; try wip_nav.infoAddrSym(wip_nav.func_sym_index, code_off); - block.high_pc = @intCast(wip_nav.debug_info.items.len); - try diw.writeInt(u32, 0, dwarf.endian); + block.high_pc = @intCast(dibw.count); + try dibw.writeInt(u32, 0, dwarf.endian); try wip_nav.setInlineFunc(func); wip_nav.any_children = false; } - pub fn leaveInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64) UpdateError!void { + pub fn leaveInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64) anyerror!void { const inlined_func_bytes = comptime uleb128Bytes(@intFromEnum(AbbrevCode.inlined_func)); const block = wip_nav.blocks.pop().?; + const dib = wip_nav.debug_info.getWritten(); if (wip_nav.any_children) - try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), @intFromEnum(AbbrevCode.null)) + try wip_nav.debug_info.buffered_writer.writeLeb128(@intFromEnum(AbbrevCode.null)) else std.leb.writeUnsignedFixed( inlined_func_bytes, - wip_nav.debug_info.items[block.abbrev_code..][0..inlined_func_bytes], + dib[block.abbrev_code..][0..inlined_func_bytes], try wip_nav.dwarf.refAbbrevCode(.empty_inlined_func), ); - std.mem.writeInt(u32, wip_nav.debug_info.items[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian); + std.mem.writeInt(u32, dib[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian); try wip_nav.setInlineFunc(func); wip_nav.any_children = true; } - pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void { + pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) anyerror!void { const zcu = wip_nav.pt.zcu; const dwarf = wip_nav.dwarf; if (wip_nav.func == func) return; @@ -1672,22 +1685,22 @@ pub const WipNav = struct { const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav); const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod.?); - const dlw = wip_nav.debug_line.writer(dwarf.gpa); + const dlbw = &wip_nav.debug_line.buffered_writer; if (dwarf.incremental()) { const new_nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, new_func_info.owner_nav); errdefer _ = if (!new_nav_gop.found_existing) dwarf.navs.pop(); if (!new_nav_gop.found_existing) new_nav_gop.value_ptr.* = try dwarf.addCommonEntry(new_unit); - try dlw.writeByte(DW.LNS.extended_op); - try uleb128(dlw, 1 + dwarf.sectionOffsetBytes()); - try dlw.writeByte(DW.LNE.ZIG_set_decl); + try dlbw.writeByte(DW.LNS.extended_op); + try dlbw.writeLeb128(1 + dwarf.sectionOffsetBytes()); + try dlbw.writeByte(DW.LNE.ZIG_set_decl); try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{ - .source_off = @intCast(wip_nav.debug_line.items.len), + .source_off = @intCast(dlbw.count), .target_sec = .debug_info, .target_unit = new_unit, .target_entry = new_nav_gop.value_ptr.toOptional(), }); - try dlw.writeByteNTimes(0, dwarf.sectionOffsetBytes()); + try dlbw.splatByteAll(0, dwarf.sectionOffsetBytes()); return; } @@ -1698,15 +1711,15 @@ pub const WipNav = struct { try mod_info.dirs.put(dwarf.gpa, new_unit, {}); const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file); - try dlw.writeByte(DW.LNS.set_file); - try uleb128(dlw, file_gop.index); + try dlbw.writeByte(DW.LNS.set_file); + try dlbw.writeLeb128(file_gop.index); } const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav); const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav); if (new_src_line != old_src_line) { - try dlw.writeByte(DW.LNS.advance_line); - try sleb128(dlw, new_src_line - old_src_line); + try dlbw.writeByte(DW.LNS.advance_line); + try dlbw.writeLeb128(new_src_line - old_src_line); } wip_nav.func = func; @@ -1724,16 +1737,23 @@ pub const WipNav = struct { try wip_nav.externalReloc(&wip_nav.dwarf.debug_frame.section, reloc); } - fn abbrevCode(wip_nav: *WipNav, abbrev_code: AbbrevCode) UpdateError!void { - try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), try wip_nav.dwarf.refAbbrevCode(abbrev_code)); + fn abbrevCode(wip_nav: *WipNav, abbrev_code: AbbrevCode) anyerror!void { + try wip_nav.debug_info.buffered_writer.writeLeb128(try wip_nav.dwarf.refAbbrevCode(abbrev_code)); } - fn sectionOffset(wip_nav: *WipNav, comptime sec: Section.Index, target_sec: Section.Index, target_unit: Unit.Index, target_entry: Entry.Index, target_off: u32) UpdateError!void { + fn sectionOffset( + wip_nav: *WipNav, + comptime sec: Section.Index, + target_sec: Section.Index, + target_unit: Unit.Index, + target_entry: Entry.Index, + target_off: u32, + ) anyerror!void { const dwarf = wip_nav.dwarf; const gpa = dwarf.gpa; const entry_ptr = @field(dwarf, @tagName(sec)).section.getUnit(wip_nav.unit).getEntry(wip_nav.entry); - const bytes = &@field(wip_nav, @tagName(sec)); - const source_off: u32 = @intCast(bytes.items.len); + const bw = &@field(wip_nav, @tagName(sec)).buffered_writer; + const source_off: u32 = @intCast(bw.count); if (target_sec != sec) { try entry_ptr.cross_section_relocs.append(gpa, .{ .source_off = source_off, @@ -1756,112 +1776,108 @@ pub const WipNav = struct { .target_off = target_off, }); } - try bytes.appendNTimes(gpa, 0, dwarf.sectionOffsetBytes()); + try bw.splatByteAll(0, dwarf.sectionOffsetBytes()); } - fn infoSectionOffset(wip_nav: *WipNav, target_sec: Section.Index, target_unit: Unit.Index, target_entry: Entry.Index, target_off: u32) UpdateError!void { + fn infoSectionOffset(wip_nav: *WipNav, target_sec: Section.Index, target_unit: Unit.Index, target_entry: Entry.Index, target_off: u32) anyerror!void { try wip_nav.sectionOffset(.debug_info, target_sec, target_unit, target_entry, target_off); } - fn strp(wip_nav: *WipNav, str: []const u8) UpdateError!void { + fn strp(wip_nav: *WipNav, str: []const u8) anyerror!void { try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0); } const ExprLocCounter = struct { - stream: *std.io.BufferedWriter, section_offset_bytes: u32, address_size: AddressSize, - counter: usize, - fn init(dwarf: *Dwarf, stream: *std.io.BufferedWriter) ExprLocCounter { + fn init(dwarf: *Dwarf) ExprLocCounter { return .{ - .stream = stream, .section_offset_bytes = dwarf.sectionOffsetBytes(), .address_size = dwarf.address_size, }; } - fn writer(counter: *ExprLocCounter) *std.io.BufferedWriter { - return counter.stream; - } fn endian(_: ExprLocCounter) std.builtin.Endian { return @import("builtin").cpu.arch.endian(); } - fn addrSym(counter: *ExprLocCounter, _: u32) error{}!void { - counter.count += @intFromEnum(counter.address_size); + fn addrSym(counter: ExprLocCounter, bw: *std.io.BufferedWriter, _: u32) error{}!void { + bw.count += @intFromEnum(counter.address_size); } - fn infoEntry(counter: *ExprLocCounter, _: Unit.Index, _: Entry.Index) error{}!void { - counter.count += counter.section_offset_bytes; + fn infoEntry(counter: ExprLocCounter, bw: *std.io.BufferedWriter, _: Unit.Index, _: Entry.Index) error{}!void { + bw.count += counter.section_offset_bytes; } }; - fn infoExprLoc(wip_nav: *WipNav, loc: Loc) UpdateError!void { - var buffer: [std.atomic.cache_line]u8 = undefined; - var counter_bw = std.io.Writer.null.buffered(&buffer); - var counter: ExprLocCounter = .init(wip_nav.dwarf, &counter_bw); - counter.count += try loc.write(&counter); + fn infoExprLoc(wip_nav: *WipNav, loc: Loc) anyerror!void { + const bw = &wip_nav.debug_info.buffered_writer; + const counter: ExprLocCounter = .init(wip_nav.dwarf); + const start = bw.count; + try loc.write(bw, counter); + const len = bw.count - start; + bw.count = start; + wip_nav.debug_info.shrinkRetainingCapacity(start); const adapter: struct { wip_nav: *WipNav, - fn writer(ctx: @This()) std.ArrayListUnmanaged(u8).Writer { - return ctx.wip_nav.debug_info.writer(ctx.wip_nav.dwarf.gpa); - } fn endian(ctx: @This()) std.builtin.Endian { return ctx.wip_nav.dwarf.endian; } - fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void { + fn addrSym(ctx: @This(), _: *std.io.BufferedWriter, sym_index: u32) anyerror!void { try ctx.wip_nav.infoAddrSym(sym_index, 0); } - fn infoEntry(ctx: @This(), unit: Unit.Index, entry: Entry.Index) UpdateError!void { + fn infoEntry(ctx: @This(), _: *std.io.BufferedWriter, unit: Unit.Index, entry: Entry.Index) anyerror!void { try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); } } = .{ .wip_nav = wip_nav }; - try uleb128(adapter.writer(), counter.count); - _ = try loc.write(adapter); + try bw.writeLeb128(len); + try loc.write(bw, adapter); } - fn infoAddrSym(wip_nav: *WipNav, sym_index: u32, sym_off: u64) UpdateError!void { + fn infoAddrSym(wip_nav: *WipNav, sym_index: u32, sym_off: u64) anyerror!void { + const dibw = &wip_nav.debug_info.buffered_writer; try wip_nav.infoExternalReloc(.{ - .source_off = @intCast(wip_nav.debug_info.items.len), + .source_off = @intCast(dibw.count), .target_sym = sym_index, .target_off = sym_off, }); - try wip_nav.debug_info.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size)); + try dibw.splatByteAll(0, @intFromEnum(wip_nav.dwarf.address_size)); } fn frameExprLoc(wip_nav: *WipNav, loc: Loc) UpdateError!void { - var buffer: [std.atomic.cache_line]u8 = undefined; - var counter_bw = std.io.Writer.null.buffered(&buffer); - var counter: ExprLocCounter = .init(wip_nav.dwarf, &counter_bw); - counter.count += try loc.write(&counter); + const bw = &wip_nav.debug_frame.buffered_writer; + const counter: ExprLocCounter = .init(wip_nav.dwarf); + const start = bw.count; + try loc.write(bw, counter); + const len = bw.count - start; + bw.count = start; + wip_nav.debug_frame.shrinkRetainingCapacity(start); const adapter: struct { wip_nav: *WipNav, - fn writer(ctx: @This()) std.ArrayListUnmanaged(u8).Writer { - return ctx.wip_nav.debug_frame.writer(ctx.wip_nav.dwarf.gpa); - } fn endian(ctx: @This()) std.builtin.Endian { return ctx.wip_nav.dwarf.endian; } - fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void { + fn addrSym(ctx: @This(), _: *std.io.BufferedWriter, sym_index: u32) anyerror!void { try ctx.wip_nav.frameAddrSym(sym_index, 0); } - fn infoEntry(ctx: @This(), unit: Unit.Index, entry: Entry.Index) UpdateError!void { + fn infoEntry(ctx: @This(), _: *std.io.BufferedWriter, unit: Unit.Index, entry: Entry.Index) anyerror!void { try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0); } } = .{ .wip_nav = wip_nav }; - try uleb128(adapter.writer(), counter.count); - _ = try loc.write(adapter); + try bw.writeLeb128(len); + try loc.write(bw, adapter); } - fn frameAddrSym(wip_nav: *WipNav, sym_index: u32, sym_off: u64) UpdateError!void { + fn frameAddrSym(wip_nav: *WipNav, sym_index: u32, sym_off: u64) anyerror!void { + const dfbw = &wip_nav.debug_frame.buffered_writer; try wip_nav.frameExternalReloc(.{ - .source_off = @intCast(wip_nav.debug_frame.items.len), + .source_off = @intCast(dfbw.count), .target_sym = sym_index, .target_off = sym_off, }); - try wip_nav.debug_frame.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size)); + try dfbw.splatByteAll(0, @intFromEnum(wip_nav.dwarf.address_size)); } - fn getNavEntry(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) UpdateError!struct { Unit.Index, Entry.Index } { + fn getNavEntry(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) anyerror!struct { Unit.Index, Entry.Index } { const zcu = wip_nav.pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); @@ -1873,12 +1889,12 @@ pub const WipNav = struct { return .{ unit, entry }; } - fn refNav(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) UpdateError!void { + fn refNav(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) anyerror!void { const unit, const entry = try wip_nav.getNavEntry(nav_index); try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); } - fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } { + fn getTypeEntry(wip_nav: *WipNav, ty: Type) anyerror!struct { Unit.Index, Entry.Index } { const zcu = wip_nav.pt.zcu; const ip = &zcu.intern_pool; const maybe_inst_index = ty.typeDeclInst(zcu); @@ -1900,12 +1916,12 @@ pub const WipNav = struct { return .{ unit, entry }; } - fn refType(wip_nav: *WipNav, ty: Type) UpdateError!void { + fn refType(wip_nav: *WipNav, ty: Type) anyerror!void { const unit, const entry = try wip_nav.getTypeEntry(ty); try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); } - fn getValueEntry(wip_nav: *WipNav, value: Value) UpdateError!struct { Unit.Index, Entry.Index } { + fn getValueEntry(wip_nav: *WipNav, value: Value) anyerror!struct { Unit.Index, Entry.Index } { const zcu = wip_nav.pt.zcu; const ip = &zcu.intern_pool; const ty = value.typeOf(zcu); @@ -1921,47 +1937,50 @@ pub const WipNav = struct { return .{ unit, entry }; } - fn refValue(wip_nav: *WipNav, value: Value) UpdateError!void { + fn refValue(wip_nav: *WipNav, value: Value) anyerror!void { const unit, const entry = try wip_nav.getValueEntry(value); try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); } - fn refForward(wip_nav: *WipNav) std.mem.Allocator.Error!u32 { + fn refForward(wip_nav: *WipNav) anyerror!u32 { const dwarf = wip_nav.dwarf; + const dibw = &wip_nav.debug_info.buffered_writer; const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs; const reloc_index: u32 = @intCast(cross_entry_relocs.items.len); try cross_entry_relocs.append(dwarf.gpa, .{ - .source_off = @intCast(wip_nav.debug_info.items.len), + .source_off = @intCast(dibw.count), .target_entry = undefined, .target_off = undefined, }); - try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, dwarf.sectionOffsetBytes()); + try dibw.splatByteAll(0, dwarf.sectionOffsetBytes()); return reloc_index; } fn finishForward(wip_nav: *WipNav, reloc_index: u32) void { const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs.items[reloc_index]; reloc.target_entry = wip_nav.entry.toOptional(); - reloc.target_off = @intCast(wip_nav.debug_info.items.len); + reloc.target_off = @intCast(wip_nav.debug_info.buffered_writer.count); } - fn blockValue(wip_nav: *WipNav, src_loc: Zcu.LazySrcLoc, val: Value) UpdateError!void { + fn blockValue(wip_nav: *WipNav, src_loc: Zcu.LazySrcLoc, val: Value) anyerror!void { const ty = val.typeOf(wip_nav.pt.zcu); - const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; const bytes = if (ty.hasRuntimeBits(wip_nav.pt.zcu)) ty.abiSize(wip_nav.pt.zcu) else 0; - try uleb128(diw, bytes); + try dibw.writeLeb128(bytes); if (bytes == 0) return; - const old_len = wip_nav.debug_info.items.len; + var dial = wip_nav.debug_info.toArrayList(); + defer _ = wip_nav.debug_info.fromArrayList(wip_nav.dwarf.gpa, &dial); + const old_len = dial.items.len; try codegen.generateSymbol( wip_nav.dwarf.bin_file, wip_nav.pt, src_loc, val, - &wip_nav.debug_info, + &dial, .{ .debug_output = .{ .dwarf = wip_nav } }, ); if (old_len + bytes != wip_nav.debug_info.items.len) { - std.debug.print("{} [{}]: {} != {}\n", .{ ty.fmt(wip_nav.pt), ty.toIntern(), bytes, wip_nav.debug_info.items.len - old_len }); + std.debug.print("{f} [{}]: {} != {}\n", .{ ty.fmt(wip_nav.pt), ty.toIntern(), bytes, wip_nav.debug_info.items.len - old_len }); unreachable; } } @@ -1977,9 +1996,9 @@ pub const WipNav = struct { abbrev_code: AbbrevCodeForForm, ty: Type, big_int: std.math.big.int.Const, - ) UpdateError!void { + ) anyerror!void { const zcu = wip_nav.pt.zcu; - const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; const signedness = switch (ty.toIntern()) { .comptime_int_type, .comptime_float_type => .signed, else => ty.intInfo(zcu).signedness, @@ -1990,7 +2009,7 @@ pub const WipNav = struct { .signed => abbrev_code.sdata, .unsigned => abbrev_code.udata, }); - try wip_nav.debug_info.ensureUnusedCapacity(wip_nav.dwarf.gpa, std.math.divCeil(usize, bits, 7) catch unreachable); + _ = try dibw.writableSlice(std.math.divCeil(usize, bits, 7) catch unreachable); var bit: usize = 0; var carry: u1 = 1; while (bit < bits) { @@ -2007,16 +2026,17 @@ pub const WipNav = struct { break :twos_comp_part twos_comp_part; }; bit += 7; - wip_nav.debug_info.appendAssumeCapacity(@as(u8, if (bit < bits) 0x80 else 0x00) | twos_comp_part); + dibw.writeByte(@as(u8, if (bit < bits) 0x80 else 0x00) | twos_comp_part) catch unreachable; } } else { try wip_nav.abbrevCode(abbrev_code.block); const bytes = @max(ty.abiSize(zcu), std.math.divCeil(usize, bits, 8) catch unreachable); - try uleb128(diw, bytes); + try dibw.writeLeb128(bytes); big_int.writeTwosComplement( - try wip_nav.debug_info.addManyAsSlice(wip_nav.dwarf.gpa, @intCast(bytes)), + try dibw.writableSlice(@intCast(bytes)), wip_nav.dwarf.endian, ); + dibw.advance(@intCast(bytes)); } } @@ -2025,7 +2045,7 @@ pub const WipNav = struct { loaded_enum: InternPool.LoadedEnumType, abbrev_code: AbbrevCodeForForm, field_index: usize, - ) UpdateError!void { + ) anyerror!void { const zcu = wip_nav.pt.zcu; const ip = &zcu.intern_pool; var big_int_space: Value.BigIntSpace = undefined; @@ -2045,11 +2065,11 @@ pub const WipNav = struct { nav: *const InternPool.Nav, file: Zcu.File.Index, decl: *const std.zig.Zir.Inst.Declaration.Unwrapped, - ) UpdateError!void { + ) anyerror!void { const zcu = wip_nav.pt.zcu; const ip = &zcu.intern_pool; const dwarf = wip_nav.dwarf; - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; const orig_entry = wip_nav.entry; defer wip_nav.entry = orig_entry; @@ -2100,15 +2120,15 @@ pub const WipNav = struct { try wip_nav.abbrevCode(if (is_generic_decl) abbrev_code.generic_decl else abbrev_code.decl); try wip_nav.refType((if (is_generic_decl) null else parent_type) orelse .fromInterned(zcu.fileRootType(file))); - assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); - try diw.writeInt(u32, decl.src_line + 1, dwarf.endian); - try uleb128(diw, decl.src_column + 1); - try diw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private); + assert(dibw.count == DebugInfo.declEntryLineOff(dwarf)); + try dibw.writeInt(u32, decl.src_line + 1, dwarf.endian); + try dibw.writeLeb128(decl.src_column + 1); + try dibw.writeByte(if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private); try wip_nav.strp(nav.name.toSlice(ip)); if (!is_generic_decl) return; const generic_decl_entry = wip_nav.entry; - try dwarf.debug_info.section.replaceEntry(wip_nav.unit, generic_decl_entry, dwarf, wip_nav.debug_info.items); + try dwarf.debug_info.section.replaceEntry(wip_nav.unit, generic_decl_entry, dwarf, wip_nav.debug_info.getWritten()); wip_nav.debug_info.clearRetainingCapacity(); wip_nav.entry = orig_entry; try wip_nav.abbrevCode(abbrev_code.decl_instance); @@ -2123,7 +2143,7 @@ pub const WipNav = struct { const empty: PendingLazy = .{ .types = .empty, .values = .empty }; }; - fn updateLazy(wip_nav: *WipNav, src_loc: Zcu.LazySrcLoc) UpdateError!void { + fn updateLazy(wip_nav: *WipNav, src_loc: Zcu.LazySrcLoc) anyerror!void { while (true) if (wip_nav.pending_lazy.types.pop()) |pending_ty| try wip_nav.dwarf.updateLazyType(wip_nav.pt, src_loc, pending_ty, &wip_nav.pending_lazy) else if (wip_nav.pending_lazy.values.pop()) |pending_val| @@ -2346,7 +2366,7 @@ pub fn deinit(dwarf: *Dwarf) void { dwarf.* = undefined; } -fn getUnit(dwarf: *Dwarf, mod: *Module) !Unit.Index { +fn getUnit(dwarf: *Dwarf, mod: *Module) anyerror!Unit.Index { const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod); const unit: Unit.Index = @enumFromInt(mod_gop.index); if (!mod_gop.found_existing) { @@ -2412,18 +2432,69 @@ pub fn initWipNav( nav_index: InternPool.Nav.Index, sym_index: u32, ) error{ OutOfMemory, CodegenFail }!?WipNav { - return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) { + return dwarf.initWipNavInner(pt, nav_index, sym_index) catch |err| switch (@as(UpdateError, @errorCast(err))) { error.OutOfMemory => return error.OutOfMemory, - else => |e| return pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}), + else => |e| return pt.zcu.codegenFail(nav_index, "failed to init dwarf nav: {s}", .{@errorName(e)}), }; } +pub fn finishWipNavFunc( + dwarf: *Dwarf, + pt: Zcu.PerThread, + nav_index: InternPool.Nav.Index, + code_size: u64, + wip_nav: *WipNav, +) error{ OutOfMemory, CodegenFail }!void { + return dwarf.finishWipNavFuncInner(pt, nav_index, code_size, wip_nav) catch |err| switch (@as(UpdateError, @errorCast(err))) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| return pt.zcu.codegenFail(nav_index, "failed to finish dwarf func nav: {s}", .{@errorName(e)}), + }; +} + +pub fn finishWipNav( + dwarf: *Dwarf, + pt: Zcu.PerThread, + nav_index: InternPool.Nav.Index, + wip_nav: *WipNav, +) error{ OutOfMemory, CodegenFail }!void { + return dwarf.finishWipNavInner(pt, nav_index, wip_nav) catch |err| switch (@as(UpdateError, @errorCast(err))) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| return pt.zcu.codegenFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}), + }; +} + +pub fn updateComptimeNav( + dwarf: *Dwarf, + pt: Zcu.PerThread, + nav_index: InternPool.Nav.Index, +) error{ OutOfMemory, CodegenFail }!void { + return dwarf.updateComptimeNavInner(pt, nav_index) catch |err| switch (@as(UpdateError, @errorCast(err))) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| return pt.zcu.codegenFail(nav_index, "failed to update dwarf comptime nav: {s}", .{@errorName(e)}), + }; +} + +pub fn updateContainerType( + dwarf: *Dwarf, + pt: Zcu.PerThread, + type_index: InternPool.Index, +) error{ OutOfMemory, CodegenFail }!void { + return dwarf.updateContainerType(pt, type_index) catch |err| switch (@as(UpdateError, @errorCast(err))) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| return pt.zcu.codegenFailType(type_index, "failed to update dwarf comptime nav: {s}", .{@errorName(e)}), + }; +} + +pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { + return @errorCast(dwarf.flushModuleInner(pt)); +} + fn initWipNavInner( dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, sym_index: u32, -) !?WipNav { +) anyerror!?WipNav { const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -2431,7 +2502,7 @@ fn initWipNavInner( const inst_info = nav.srcInst(ip).resolveFull(ip).?; const file = zcu.fileByIndex(inst_info.file); const decl = file.zir.?.getDeclaration(inst_info.inst); - log.debug("initWipNav({s}:{d}:{d} %{d} = {})", .{ + log.debug("initWipNav({s}:{d}:{d} %{d} = {f})", .{ file.sub_file_path, decl.src_line + 1, decl.src_column + 1, @@ -2472,17 +2543,17 @@ fn initWipNavInner( .func_high_pc = undefined, .blocks = undefined, .cfi = undefined, - .debug_frame = .empty, - .debug_info = .empty, - .debug_line = .empty, - .debug_loclists = .empty, + .debug_frame = undefined, + .debug_info = undefined, + .debug_line = undefined, + .debug_loclists = undefined, .pending_lazy = .empty, }; errdefer wip_nav.deinit(); switch (nav_key) { else => { - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; try wip_nav.declCommon(.{ .decl = .decl_var, .generic_decl = .generic_decl_var, @@ -2497,9 +2568,9 @@ fn initWipNavInner( .@"const" => { const const_ty_reloc_index = try wip_nav.refForward(); try wip_nav.infoExprLoc(loc); - try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse + try dibw.writeLeb128(nav.status.fully_resolved.alignment.toByteUnits() orelse ty.abiAlignment(zcu).toByteUnits().?); - try diw.writeByte(@intFromBool(decl.linkage != .normal)); + try dibw.writeByte(@intFromBool(decl.linkage != .normal)); wip_nav.finishForward(const_ty_reloc_index); try wip_nav.abbrevCode(.is_const); try wip_nav.refType(ty); @@ -2507,9 +2578,9 @@ fn initWipNavInner( .@"var" => { try wip_nav.refType(ty); try wip_nav.infoExprLoc(loc); - try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse + try dibw.writeLeb128(dibw, nav.status.fully_resolved.alignment.toByteUnits() orelse ty.abiAlignment(zcu).toByteUnits().?); - try diw.writeByte(@intFromBool(decl.linkage != .normal)); + try dibw.writeByte(@intFromBool(decl.linkage != .normal)); }, } }, @@ -2534,39 +2605,39 @@ fn initWipNavInner( .none => {}, .debug_frame, .eh_frame => |format| { const entry = dwarf.debug_frame.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry); - const dfw = wip_nav.debug_frame.writer(dwarf.gpa); + const dfbw = &wip_nav.debug_frame.buffered_writer; switch (dwarf.format) { - .@"32" => try dfw.writeInt(u32, undefined, dwarf.endian), + .@"32" => try dfbw.writeInt(u32, undefined, dwarf.endian), .@"64" => { - try dfw.writeInt(u32, std.math.maxInt(u32), dwarf.endian); - try dfw.writeInt(u64, undefined, dwarf.endian); + try dfbw.writeInt(u32, std.math.maxInt(u32), dwarf.endian); + try dfbw.writeInt(u64, undefined, dwarf.endian); }, } switch (format) { .none => unreachable, .debug_frame => { try entry.cross_entry_relocs.append(dwarf.gpa, .{ - .source_off = @intCast(wip_nav.debug_frame.items.len), + .source_off = @intCast(dfbw.count), }); - try dfw.writeByteNTimes(0, dwarf.sectionOffsetBytes()); + try dfbw.splatByteAll(0, dwarf.sectionOffsetBytes()); try wip_nav.frameAddrSym(sym_index, 0); - try dfw.writeByteNTimes(undefined, @intFromEnum(dwarf.address_size)); + try dfbw.splatByteAll(undefined, @intFromEnum(dwarf.address_size)); }, .eh_frame => { - try dfw.writeInt(u32, undefined, dwarf.endian); + try dfbw.writeInt(u32, undefined, dwarf.endian); try wip_nav.frameExternalReloc(.{ - .source_off = @intCast(wip_nav.debug_frame.items.len), + .source_off = @intCast(dfbw.count), .target_sym = sym_index, }); - try dfw.writeInt(u32, 0, dwarf.endian); - try dfw.writeInt(u32, undefined, dwarf.endian); - try uleb128(dfw, 0); + try dfbw.writeInt(u32, 0, dwarf.endian); + try dfbw.writeInt(u32, undefined, dwarf.endian); + try dfbw.writeUleb128(0); }, } }, } - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; try wip_nav.declCommon(.{ .decl = .decl_func, .generic_decl = .generic_decl_func, @@ -2576,47 +2647,47 @@ fn initWipNavInner( try wip_nav.refType(.fromInterned(func_type.return_type)); try wip_nav.infoAddrSym(sym_index, 0); wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len); - try diw.writeInt(u32, 0, dwarf.endian); + try dibw.writeInt(u32, 0, dwarf.endian); const target = &mod.resolved_target.result; - try uleb128(diw, switch (nav.status.fully_resolved.alignment) { + try dibw.writeLeb128(switch (nav.status.fully_resolved.alignment) { .none => target_info.defaultFunctionAlignment(target), else => |a| a.maxStrict(target_info.minFunctionAlignment(target)), }.toByteUnits().?); - try diw.writeByte(@intFromBool(decl.linkage != .normal)); - try diw.writeByte(@intFromBool(func_type.return_type == .noreturn_type)); + try dibw.writeByte(@intFromBool(decl.linkage != .normal)); + try dibw.writeByte(@intFromBool(func_type.return_type == .noreturn_type)); - const dlw = wip_nav.debug_line.writer(dwarf.gpa); - try dlw.writeByte(DW.LNS.extended_op); + const dlbw = &wip_nav.debug_line.buffered_writer; + try dlbw.writeByte(DW.LNS.extended_op); if (dwarf.incremental()) { - try uleb128(dlw, 1 + dwarf.sectionOffsetBytes()); - try dlw.writeByte(DW.LNE.ZIG_set_decl); + try dlbw.writeLeb128(1 + dwarf.sectionOffsetBytes()); + try dlbw.writeByte(DW.LNE.ZIG_set_decl); try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{ - .source_off = @intCast(wip_nav.debug_line.items.len), + .source_off = @intCast(dlbw.count), .target_sec = .debug_info, .target_unit = wip_nav.unit, .target_entry = wip_nav.entry.toOptional(), }); - try dlw.writeByteNTimes(0, dwarf.sectionOffsetBytes()); + try dlbw.splatByteAll(0, dwarf.sectionOffsetBytes()); - try dlw.writeByte(DW.LNS.set_column); - try uleb128(dlw, func.lbrace_column + 1); + try dlbw.writeByte(DW.LNS.set_column); + try dlbw.writeLeb128(func.lbrace_column + 1); try wip_nav.advancePCAndLine(func.lbrace_line, 0); } else { - try uleb128(dlw, 1 + @intFromEnum(dwarf.address_size)); - try dlw.writeByte(DW.LNE.set_address); + try dlbw.writeLeb128(1 + @intFromEnum(dwarf.address_size)); + try dlbw.writeByte(DW.LNE.set_address); try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{ - .source_off = @intCast(wip_nav.debug_line.items.len), + .source_off = @intCast(dlbw.count), .target_sym = sym_index, }); - try dlw.writeByteNTimes(0, @intFromEnum(dwarf.address_size)); + try dlbw.splatByteAll(0, @intFromEnum(dwarf.address_size)); const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file); - try dlw.writeByte(DW.LNS.set_file); - try uleb128(dlw, file_gop.index); + try dlbw.writeByte(DW.LNS.set_file); + try dlbw.writeLeb128(file_gop.index); - try dlw.writeByte(DW.LNS.set_column); - try uleb128(dlw, func.lbrace_column + 1); + try dlbw.writeByte(DW.LNS.set_column); + try dlbw.writeLeb128(func.lbrace_column + 1); try wip_nav.advancePCAndLine(@intCast(decl.src_line + func.lbrace_line), 0); } @@ -2625,18 +2696,18 @@ fn initWipNavInner( return wip_nav; } -pub fn finishWipNavFunc( +fn finishWipNavFuncInner( dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, code_size: u64, wip_nav: *WipNav, -) UpdateError!void { +) anyerror!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); assert(wip_nav.func != .none); - log.debug("finishWipNavFunc({})", .{nav.fqn.fmt(ip)}); + log.debug("finishWipNavFunc({f})", .{nav.fqn.fmt(ip)}); { const external_relocs = &dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs; @@ -2654,12 +2725,9 @@ pub fn finishWipNavFunc( switch (dwarf.debug_frame.header.format) { .none => {}, .debug_frame, .eh_frame => |format| { - try wip_nav.debug_frame.appendNTimes( - dwarf.gpa, - DW.CFA.nop, - @intCast(dwarf.debug_frame.section.alignment.forward(wip_nav.debug_frame.items.len) - wip_nav.debug_frame.items.len), - ); - const contents = wip_nav.debug_frame.items; + const dfbw = &wip_nav.debug_frame.buffered_writer; + try dfbw.splatByteAll(DW.CFA.nop, @intCast(dwarf.debug_frame.section.alignment.forward(dfbw.count) - dfbw.count)); + const contents = wip_nav.debug_frame.getWritten(); try dwarf.debug_frame.section.resizeEntry(wip_nav.unit, wip_nav.entry, dwarf, @intCast(contents.len)); const unit = dwarf.debug_frame.section.getUnit(wip_nav.unit); const entry = unit.getEntry(wip_nav.entry); @@ -2686,14 +2754,15 @@ pub fn finishWipNavFunc( }, } { - std.mem.writeInt(u32, wip_nav.debug_info.items[wip_nav.func_high_pc..][0..4], @intCast(code_size), dwarf.endian); + std.mem.writeInt(u32, wip_nav.debug_info.getWritten()[wip_nav.func_high_pc..][0..4], @intCast(code_size), dwarf.endian); if (wip_nav.any_children) { - const diw = wip_nav.debug_info.writer(dwarf.gpa); - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + const dibw = &wip_nav.debug_info.buffered_writer; + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); } else { - const abbrev_code_buf = wip_nav.debug_info.items[0..AbbrevCode.decl_bytes]; - var abbrev_code_fbs = std.io.fixedBufferStream(abbrev_code_buf); - const abbrev_code: AbbrevCode = @enumFromInt(std.leb.readUleb128(@typeInfo(AbbrevCode).@"enum".tag_type, abbrev_code_fbs.reader()) catch unreachable); + const abbrev_code_buf = wip_nav.debug_info.getWritten()[0..AbbrevCode.decl_bytes]; + var abbrev_code_br: std.io.BufferedReader = undefined; + abbrev_code_br.initFixed(abbrev_code_buf); + const abbrev_code: AbbrevCode = @enumFromInt(abbrev_code_br.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable); std.leb.writeUnsignedFixed( AbbrevCode.decl_bytes, abbrev_code_buf, @@ -2725,41 +2794,35 @@ pub fn finishWipNavFunc( ); } - try dwarf.finishWipNav(pt, nav_index, wip_nav); + try dwarf.finishWipNavInner(pt, nav_index, wip_nav); } -pub fn finishWipNav( +fn finishWipNavInner( dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, wip_nav: *WipNav, -) UpdateError!void { +) anyerror!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)}); + log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)}); - try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); - if (wip_nav.debug_line.items.len > 0) { - const dlw = wip_nav.debug_line.writer(dwarf.gpa); - try dlw.writeByte(DW.LNS.extended_op); - try uleb128(dlw, 1); - try dlw.writeByte(DW.LNE.end_sequence); - try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.items); + try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.getWritten()); + const debug_line = wip_nav.debug_line.getWritten(); + if (debug_line.len > 0) { + const dlbw = &wip_nav.debug_line.buffered_writer; + try dlbw.writeByte(DW.LNS.extended_op); + try dlbw.writeUleb128(1); + try dlbw.writeByte(DW.LNE.end_sequence); + try dwarf.debug_line.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_line.getWritten()); } - try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.items); + try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.getWritten()); try wip_nav.updateLazy(zcu.navSrcLoc(nav_index)); } -pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error{ OutOfMemory, CodegenFail }!void { - return updateComptimeNavInner(dwarf, pt, nav_index) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - else => |e| return pt.zcu.codegenFail(nav_index, "failed to update dwarf: {s}", .{@errorName(e)}), - }; -} - -fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { +fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) anyerror!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav_src_loc = zcu.navSrcLoc(nav_index); @@ -2769,7 +2832,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo const inst_info = nav.srcInst(ip).resolveFull(ip).?; const file = zcu.fileByIndex(inst_info.file); const decl = file.zir.?.getDeclaration(inst_info.inst); - log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {})", .{ + log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {f})", .{ file.sub_file_path, decl.src_line + 1, decl.src_column + 1, @@ -2797,12 +2860,13 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo .func_high_pc = undefined, .blocks = undefined, .cfi = undefined, - .debug_frame = .empty, - .debug_info = .empty, - .debug_line = .empty, - .debug_loclists = .empty, + .debug_frame = undefined, + .debug_info = undefined, + .debug_line = undefined, + .debug_loclists = undefined, .pending_lazy = .empty, }; + wip_nav.init(); defer wip_nav.deinit(); const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index); @@ -2846,7 +2910,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo } wip_nav.entry = nav_gop.value_ptr.*; - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; switch (loaded_struct.layout) { .auto, .@"extern" => { @@ -2859,9 +2923,9 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo .generic_decl = .generic_decl_const, .decl_instance = .decl_instance_struct, }, &nav, inst_info.file, &decl); - if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else { - try uleb128(diw, nav_val.toType().abiSize(zcu)); - try uleb128(diw, nav_val.toType().abiAlignment(zcu).toByteUnits().?); + if (loaded_struct.field_types.len == 0) try dibw.writeByte(@intFromBool(false)) else { + try dibw.writeLeb128(nav_val.toType().abiSize(zcu)); + try dibw.writeLeb128(nav_val.toType().abiAlignment(zcu).toByteUnits().?); for (0..loaded_struct.field_types.len) |field_index| { const is_comptime = loaded_struct.fieldIsComptime(ip, field_index); const field_init = loaded_struct.fieldInit(ip, field_index); @@ -2897,8 +2961,8 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo } try wip_nav.refType(field_type); if (!is_comptime) { - try uleb128(diw, loaded_struct.offsets.get(ip)[field_index]); - try uleb128(diw, loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse + try dibw.writeLeb128(loaded_struct.offsets.get(ip)[field_index]); + try dibw.writeLeb128(loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse field_type.abiAlignment(zcu).toByteUnits().?); } if (has_comptime_state) @@ -2906,7 +2970,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo else if (has_runtime_bits) try wip_nav.blockValue(nav_src_loc, .fromInterned(field_init)); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); } }, .@"packed" => { @@ -2922,10 +2986,10 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip)); const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); - try uleb128(diw, field_bit_offset); + try dibw.writeLeb128(field_bit_offset); field_bit_offset += @intCast(field_type.bitSize(zcu)); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, } break :tag .done; @@ -2948,7 +3012,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo type_gop.value_ptr.* = nav_gop.value_ptr.*; } wip_nav.entry = nav_gop.value_ptr.*; - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; try wip_nav.declCommon(if (loaded_enum.names.len > 0) .{ .decl = .decl_enum, .generic_decl = .generic_decl_const, @@ -2967,7 +3031,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo }, field_index); try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip)); } - if (loaded_enum.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null)); + if (loaded_enum.names.len > 0) try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); break :tag .done; }, .union_type => tag: { @@ -2987,15 +3051,15 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo type_gop.value_ptr.* = nav_gop.value_ptr.*; } wip_nav.entry = nav_gop.value_ptr.*; - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; try wip_nav.declCommon(.{ .decl = .decl_union, .generic_decl = .generic_decl_const, .decl_instance = .decl_instance_union, }, &nav, inst_info.file, &decl); const union_layout = Type.getUnionLayout(loaded_union, zcu); - try uleb128(diw, union_layout.abi_size); - try uleb128(diw, union_layout.abi_align.toByteUnits().?); + try dibw.writeLeb128(union_layout.abi_size); + try dibw.writeLeb128(union_layout.abi_align.toByteUnits().?); const loaded_tag = loaded_union.loadTagType(ip); if (loaded_union.hasTag(ip)) { try wip_nav.abbrevCode(.tagged_union); @@ -3003,13 +3067,13 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo .debug_info, wip_nav.unit, wip_nav.entry, - @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()), + @intCast(dibw.count + dwarf.sectionOffsetBytes()), ); { try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("tag"); try wip_nav.refType(.fromInterned(loaded_union.enum_tag_ty)); - try uleb128(diw, union_layout.tagOffset()); + try dibw.writeLeb128(union_layout.tagOffset()); for (0..loaded_union.field_types.len) |field_index| { try wip_nav.enumConstValue(loaded_tag, .{ @@ -3022,23 +3086,23 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip)); const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); - try uleb128(diw, union_layout.payloadOffset()); - try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse + try dibw.writeLeb128(union_layout.payloadOffset()); + try dibw.writeLeb128(loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); } } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); } else for (0..loaded_union.field_types.len) |field_index| { try wip_nav.abbrevCode(.untagged_union_field); try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip)); const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]); try wip_nav.refType(field_type); - try uleb128(diw, loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse + try dibw.writeLeb128(loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse field_type.abiAlignment(zcu).toByteUnits().?); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); break :tag .done; }, .opaque_type => tag: { @@ -3058,13 +3122,13 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo type_gop.value_ptr.* = nav_gop.value_ptr.*; } wip_nav.entry = nav_gop.value_ptr.*; - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; try wip_nav.declCommon(.{ .decl = .decl_namespace_struct, .generic_decl = .generic_decl_const, .decl_instance = .decl_instance_namespace_struct, }, &nav, inst_info.file, &decl); - try diw.writeByte(@intFromBool(true)); + try dibw.writeByte(@intFromBool(true)); break :tag .done; }, .undef, @@ -3102,7 +3166,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo const is_nullary = !func_type.is_var_args and for (0..func_type.param_types.len) |param_index| { if (!func_type.paramIsComptime(std.math.cast(u5, param_index) orelse break false)) break false; } else true; - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; try wip_nav.declCommon(if (is_nullary) .{ .decl = .decl_nullary_func_generic, .generic_decl = .generic_decl_func, @@ -3121,7 +3185,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index])); } if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args); - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); } break :tag .done; }, @@ -3146,7 +3210,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo try wip_nav.refType(nav_val.toType()); }, .decl_var => { - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; try wip_nav.declCommon(.{ .decl = .decl_var, .generic_decl = .generic_decl_var, @@ -3156,12 +3220,12 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo const nav_ty = nav_val.typeOf(zcu); try wip_nav.refType(nav_ty); try wip_nav.blockValue(nav_src_loc, nav_val); - try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse + try dibw.writeLeb128(nav.status.fully_resolved.alignment.toByteUnits() orelse nav_ty.abiAlignment(zcu).toByteUnits().?); - try diw.writeByte(@intFromBool(decl.linkage != .normal)); + try dibw.writeByte(@intFromBool(decl.linkage != .normal)); }, .decl_const => { - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; const nav_ty = nav_val.typeOf(zcu); const has_runtime_bits = nav_ty.hasRuntimeBits(zcu); const has_comptime_state = nav_ty.comptimeOnly(zcu) and try nav_ty.onePossibleValue(pt) == null; @@ -3184,9 +3248,9 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo }, &nav, inst_info.file, &decl); try wip_nav.strp(nav.fqn.toSlice(ip)); const nav_ty_reloc_index = try wip_nav.refForward(); - try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse + try dibw.writeLeb128(nav.status.fully_resolved.alignment.toByteUnits() orelse nav_ty.abiAlignment(zcu).toByteUnits().?); - try diw.writeByte(@intFromBool(decl.linkage != .normal)); + try dibw.writeByte(@intFromBool(decl.linkage != .normal)); if (has_runtime_bits) try wip_nav.blockValue(nav_src_loc, nav_val); if (has_comptime_state) try wip_nav.refValue(nav_val); wip_nav.finishForward(nav_ty_reloc_index); @@ -3202,7 +3266,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo try wip_nav.refNav(owner_nav); }, } - try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); + try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.getWritten()); try wip_nav.updateLazy(nav_src_loc); } @@ -3212,14 +3276,14 @@ fn updateLazyType( src_loc: Zcu.LazySrcLoc, type_index: InternPool.Index, pending_lazy: *WipNav.PendingLazy, -) UpdateError!void { +) anyerror!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; assert(ip.typeOf(type_index) == .type_type); const ty: Type = .fromInterned(type_index); switch (type_index) { .generic_poison_type => log.debug("updateLazyType({s})", .{"anytype"}), - else => log.debug("updateLazyType({})", .{ty.fmt(pt)}), + else => log.debug("updateLazyType({f})", .{ty.fmt(pt)}), } var wip_nav: WipNav = .{ @@ -3233,21 +3297,22 @@ fn updateLazyType( .func_high_pc = undefined, .blocks = undefined, .cfi = undefined, - .debug_frame = .empty, - .debug_info = .empty, - .debug_line = .empty, - .debug_loclists = .empty, + .debug_frame = undefined, + .debug_info = undefined, + .debug_line = undefined, + .debug_loclists = undefined, .pending_lazy = pending_lazy.*, }; + wip_nav.init(); defer { pending_lazy.* = wip_nav.pending_lazy; wip_nav.pending_lazy = .empty; wip_nav.deinit(); } - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; const name = switch (type_index) { .generic_poison_type => "", - else => try std.fmt.allocPrint(dwarf.gpa, "{}", .{ty.fmt(pt)}), + else => try std.fmt.allocPrint(dwarf.gpa, "{f}", .{ty.fmt(pt)}), }; defer dwarf.gpa.free(name); @@ -3259,12 +3324,12 @@ fn updateLazyType( .int_type => |int_type| { try wip_nav.abbrevCode(.numeric_type); try wip_nav.strp(name); - try diw.writeByte(switch (int_type.signedness) { + try dibw.writeByte(switch (int_type.signedness) { inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)), }); - try uleb128(diw, int_type.bits); - try uleb128(diw, ty.abiSize(zcu)); - try uleb128(diw, ty.abiAlignment(zcu).toByteUnits().?); + try dibw.writeLeb128(int_type.bits); + try dibw.writeLeb128(ty.abiSize(zcu)); + try dibw.writeLeb128(ty.abiAlignment(zcu).toByteUnits().?); }, .ptr_type => |ptr_type| switch (ptr_type.flags.size) { .one, .many, .c => { @@ -3272,14 +3337,14 @@ fn updateLazyType( try wip_nav.abbrevCode(if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type); try wip_nav.strp(name); if (ptr_type.sentinel != .none) try wip_nav.blockValue(src_loc, .fromInterned(ptr_type.sentinel)); - try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse + try dibw.writeLeb128(ptr_type.flags.alignment.toByteUnits() orelse ptr_child_type.abiAlignment(zcu).toByteUnits().?); - try diw.writeByte(@intFromEnum(ptr_type.flags.address_space)); + try dibw.writeByte(@intFromEnum(ptr_type.flags.address_space)); if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset( .debug_info, wip_nav.unit, wip_nav.entry, - @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()), + @intCast(dibw.count + dwarf.sectionOffsetBytes()), ) else try wip_nav.refType(ptr_child_type); if (ptr_type.flags.is_const) { try wip_nav.abbrevCode(.is_const); @@ -3287,7 +3352,7 @@ fn updateLazyType( .debug_info, wip_nav.unit, wip_nav.entry, - @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()), + @intCast(dibw.count + dwarf.sectionOffsetBytes()), ) else try wip_nav.refType(ptr_child_type); } if (ptr_type.flags.is_volatile) { @@ -3298,19 +3363,19 @@ fn updateLazyType( .slice => { try wip_nav.abbrevCode(.generated_struct_type); try wip_nav.strp(name); - try uleb128(diw, ty.abiSize(zcu)); - try uleb128(diw, ty.abiAlignment(zcu).toByteUnits().?); + try dibw.writeLeb128(ty.abiSize(zcu)); + try dibw.writeLeb128(ty.abiAlignment(zcu).toByteUnits().?); try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("ptr"); const ptr_field_type = ty.slicePtrFieldType(zcu); try wip_nav.refType(ptr_field_type); - try uleb128(diw, 0); + try dibw.writeUleb128(0); try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("len"); const len_field_type: Type = .usize; try wip_nav.refType(len_field_type); - try uleb128(diw, len_field_type.abiAlignment(zcu).forward(ptr_field_type.abiSize(zcu))); - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(len_field_type.abiAlignment(zcu).forward(ptr_field_type.abiSize(zcu))); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, }, .array_type => |array_type| { @@ -3321,8 +3386,8 @@ fn updateLazyType( try wip_nav.refType(array_child_type); try wip_nav.abbrevCode(.array_index); try wip_nav.refType(.usize); - try uleb128(diw, array_type.len); - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(array_type.len); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .vector_type => |vector_type| { try wip_nav.abbrevCode(.vector_type); @@ -3330,22 +3395,22 @@ fn updateLazyType( try wip_nav.refType(.fromInterned(vector_type.child)); try wip_nav.abbrevCode(.array_index); try wip_nav.refType(.usize); - try uleb128(diw, vector_type.len); - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(vector_type.len); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .opt_type => |opt_child_type_index| { const opt_child_type: Type = .fromInterned(opt_child_type_index); const opt_repr = optRepr(opt_child_type, zcu); try wip_nav.abbrevCode(.generated_union_type); try wip_nav.strp(name); - try uleb128(diw, ty.abiSize(zcu)); - try uleb128(diw, ty.abiAlignment(zcu).toByteUnits().?); + try dibw.writeLeb128(ty.abiSize(zcu)); + try dibw.writeLeb128(ty.abiAlignment(zcu).toByteUnits().?); switch (opt_repr) { .opv_null => { try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("null"); try wip_nav.refType(.null); - try uleb128(diw, 0); + try dibw.writeUleb128(0); }, .unpacked, .error_set, .pointer => { try wip_nav.abbrevCode(.tagged_union); @@ -3353,7 +3418,7 @@ fn updateLazyType( .debug_info, wip_nav.unit, wip_nav.entry, - @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()), + @intCast(dibw.count + dwarf.sectionOffsetBytes()), ); { try wip_nav.abbrevCode(.generated_field); @@ -3362,7 +3427,7 @@ fn updateLazyType( .opv_null => unreachable, .unpacked => { try wip_nav.refType(.bool); - try uleb128(diw, if (opt_child_type.hasRuntimeBits(zcu)) + try dibw.writeLeb128(if (opt_child_type.hasRuntimeBits(zcu)) opt_child_type.abiSize(zcu) else 0); @@ -3372,37 +3437,37 @@ fn updateLazyType( .signedness = .unsigned, .bits = zcu.errorSetBits(), } }))); - try uleb128(diw, 0); + try dibw.writeUleb128(0); }, .pointer => { try wip_nav.refType(.usize); - try uleb128(diw, 0); + try dibw.writeUleb128(0); }, } try wip_nav.abbrevCode(.unsigned_tagged_union_field); - try uleb128(diw, 0); + try dibw.writeUleb128(0); { try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("null"); try wip_nav.refType(.null); - try uleb128(diw, 0); + try dibw.writeUleb128(0); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); try wip_nav.abbrevCode(.tagged_union_default_field); { try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("?"); try wip_nav.refType(opt_child_type); - try uleb128(diw, 0); + try dibw.writeUleb128(0); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .anyframe_type => unreachable, .error_union_type => |error_union_type| { @@ -3421,11 +3486,11 @@ fn updateLazyType( if (error_union_type.error_set_type != .generic_poison_type and error_union_type.payload_type != .generic_poison_type) { - try uleb128(diw, ty.abiSize(zcu)); - try uleb128(diw, ty.abiAlignment(zcu).toByteUnits().?); + try dibw.writeLeb128(ty.abiSize(zcu)); + try dibw.writeLeb128(ty.abiAlignment(zcu).toByteUnits().?); } else { - try uleb128(diw, 0); - try uleb128(diw, 1); + try dibw.writeUleb128(0); + try dibw.writeUleb128(1); } { try wip_nav.abbrevCode(.tagged_union); @@ -3433,7 +3498,7 @@ fn updateLazyType( .debug_info, wip_nav.unit, wip_nav.entry, - @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()), + @intCast(dibw.count + dwarf.sectionOffsetBytes()), ); { try wip_nav.abbrevCode(.generated_field); @@ -3442,30 +3507,30 @@ fn updateLazyType( .signedness = .unsigned, .bits = zcu.errorSetBits(), } }))); - try uleb128(diw, error_union_error_set_offset); + try dibw.writeLeb128(error_union_error_set_offset); try wip_nav.abbrevCode(.unsigned_tagged_union_field); - try uleb128(diw, 0); + try dibw.writeUleb128(0); { try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("value"); try wip_nav.refType(error_union_payload_type); - try uleb128(diw, error_union_payload_offset); + try dibw.writeLeb128(error_union_payload_offset); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); try wip_nav.abbrevCode(.tagged_union_default_field); { try wip_nav.abbrevCode(.generated_field); try wip_nav.strp("error"); try wip_nav.refType(error_union_error_set_type); - try uleb128(diw, error_union_error_set_offset); + try dibw.writeLeb128(error_union_error_set_offset); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .simple_type => |simple_type| switch (simple_type) { .f16, @@ -3489,7 +3554,7 @@ fn updateLazyType( => { try wip_nav.abbrevCode(.numeric_type); try wip_nav.strp(name); - try diw.writeByte(if (type_index == .bool_type) + try dibw.writeByte(if (type_index == .bool_type) DW.ATE.boolean else if (ty.isRuntimeFloat()) DW.ATE.float @@ -3499,9 +3564,9 @@ fn updateLazyType( DW.ATE.unsigned else unreachable); - try uleb128(diw, ty.bitSize(zcu)); - try uleb128(diw, ty.abiSize(zcu)); - try uleb128(diw, ty.abiAlignment(zcu).toByteUnits().?); + try dibw.writeLeb128(ty.bitSize(zcu)); + try dibw.writeLeb128(ty.abiSize(zcu)); + try dibw.writeLeb128(ty.abiAlignment(zcu).toByteUnits().?); }, .anyopaque, .void, @@ -3527,12 +3592,12 @@ fn updateLazyType( .tuple_type => |tuple_type| if (tuple_type.types.len == 0) { try wip_nav.abbrevCode(.generated_empty_struct_type); try wip_nav.strp(name); - try diw.writeByte(@intFromBool(false)); + try dibw.writeByte(@intFromBool(false)); } else { try wip_nav.abbrevCode(.generated_struct_type); try wip_nav.strp(name); - try uleb128(diw, ty.abiSize(zcu)); - try uleb128(diw, ty.abiAlignment(zcu).toByteUnits().?); + try dibw.writeLeb128(ty.abiSize(zcu)); + try dibw.writeLeb128(ty.abiAlignment(zcu).toByteUnits().?); var field_byte_offset: u64 = 0; for (0..tuple_type.types.len) |field_index| { const comptime_value = tuple_type.values.get(ip)[field_index]; @@ -3561,8 +3626,8 @@ fn updateLazyType( if (comptime_value == .none) { const field_align = field_type.abiAlignment(zcu); field_byte_offset = field_align.forward(field_byte_offset); - try uleb128(diw, field_byte_offset); - try uleb128(diw, field_type.abiAlignment(zcu).toByteUnits().?); + try dibw.writeLeb128(field_byte_offset); + try dibw.writeLeb128(field_type.abiAlignment(zcu).toByteUnits().?); field_byte_offset += field_type.abiSize(zcu); } if (has_comptime_state) @@ -3570,7 +3635,7 @@ fn updateLazyType( else if (has_runtime_bits) try wip_nav.blockValue(src_loc, .fromInterned(comptime_value)); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .enum_type => { const loaded_enum = ip.loadEnumType(type_index); @@ -3585,7 +3650,7 @@ fn updateLazyType( }, field_index); try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip)); } - if (loaded_enum.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null)); + if (loaded_enum.names.len > 0) try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .func_type => |func_type| { const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args; @@ -3653,7 +3718,7 @@ fn updateLazyType( else => .nocall, }; }; - try diw.writeByte(@intFromEnum(cc)); + try dibw.writeByte(@intFromEnum(cc)); try wip_nav.refType(.fromInterned(func_type.return_type)); if (!is_nullary) { for (0..func_type.param_types.len) |param_index| { @@ -3661,7 +3726,7 @@ fn updateLazyType( try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index])); } if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args); - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); } }, .error_set_type => |error_set_type| { @@ -3674,10 +3739,10 @@ fn updateLazyType( for (0..error_set_type.names.len) |field_index| { const field_name = error_set_type.names.get(ip)[field_index]; try wip_nav.abbrevCode(.unsigned_enum_field); - try uleb128(diw, ip.getErrorValueIfExists(field_name).?); + try dibw.writeLeb128(ip.getErrorValueIfExists(field_name).?); try wip_nav.strp(field_name.toSlice(ip)); } - if (error_set_type.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null)); + if (error_set_type.names.len > 0) try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .inferred_error_set_type => |func| { try wip_nav.abbrevCode(.inferred_error_set_type); @@ -3709,7 +3774,7 @@ fn updateLazyType( .memoized_call, => unreachable, } - try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); + try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.getWritten()); } fn updateLazyValue( @@ -3718,11 +3783,11 @@ fn updateLazyValue( src_loc: Zcu.LazySrcLoc, value_index: InternPool.Index, pending_lazy: *WipNav.PendingLazy, -) UpdateError!void { +) anyerror!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; assert(ip.typeOf(value_index) != .type_type); - log.debug("updateLazyValue(@as({}, {}))", .{ + log.debug("updateLazyValue(@as({f}, {f}))", .{ Value.fromInterned(value_index).typeOf(zcu).fmt(pt), Value.fromInterned(value_index).fmtValue(pt), }); @@ -3737,18 +3802,19 @@ fn updateLazyValue( .func_high_pc = undefined, .blocks = undefined, .cfi = undefined, - .debug_frame = .empty, - .debug_info = .empty, - .debug_line = .empty, - .debug_loclists = .empty, + .debug_frame = undefined, + .debug_info = undefined, + .debug_line = undefined, + .debug_loclists = undefined, .pending_lazy = pending_lazy.*, }; + wip_nav.init(); defer { pending_lazy.* = wip_nav.pending_lazy; wip_nav.pending_lazy = .empty; wip_nav.deinit(); } - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; var big_int_space: Value.BigIntSpace = undefined; switch (ip.indexToKey(value_index)) { .int_type, @@ -3786,7 +3852,7 @@ fn updateLazyValue( .err => |err| { try wip_nav.abbrevCode(.udata_comptime_value); try wip_nav.refType(.fromInterned(err.ty)); - try uleb128(diw, try pt.getErrorValue(err.name)); + try dibw.writeLeb128(try pt.getErrorValue(err.name)); }, .error_union => |error_union| { try wip_nav.abbrevCode(.aggregate_comptime_value); @@ -3798,8 +3864,8 @@ fn updateLazyValue( { try wip_nav.abbrevCode(.comptime_value_field_runtime_bits); try wip_nav.strp("is_error"); - try uleb128(diw, err_abi_size); - dwarf.writeInt(try wip_nav.debug_info.addManyAsSlice(dwarf.gpa, err_abi_size), err_value); + try dibw.writeLeb128(err_abi_size); + try dwarf.writeIntTo(dibw, err_abi_size, err_value); } payload_field: switch (error_union.val) { .err_name => {}, @@ -3823,8 +3889,8 @@ fn updateLazyValue( { try wip_nav.abbrevCode(.comptime_value_field_runtime_bits); try wip_nav.strp("error"); - try uleb128(diw, err_abi_size); - dwarf.writeInt(try wip_nav.debug_info.addManyAsSlice(dwarf.gpa, err_abi_size), err_value); + try dibw.writeLeb128(err_abi_size); + try dwarf.writeIntTo(dibw, err_abi_size, err_value); } switch (error_union.val) { .err_name => {}, @@ -3834,7 +3900,7 @@ fn updateLazyValue( }, } try wip_nav.refType(.fromInterned(error_union.ty)); - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .enum_literal => |enum_literal| { try wip_nav.abbrevCode(.string_comptime_value); @@ -3855,24 +3921,24 @@ fn updateLazyValue( switch (float.storage) { .f16 => |f16_val| { try wip_nav.abbrevCode(.data2_comptime_value); - try diw.writeInt(u16, @bitCast(f16_val), dwarf.endian); + try dibw.writeInt(u16, @bitCast(f16_val), dwarf.endian); }, .f32 => |f32_val| { try wip_nav.abbrevCode(.data4_comptime_value); - try diw.writeInt(u32, @bitCast(f32_val), dwarf.endian); + try dibw.writeInt(u32, @bitCast(f32_val), dwarf.endian); }, .f64 => |f64_val| { try wip_nav.abbrevCode(.data8_comptime_value); - try diw.writeInt(u64, @bitCast(f64_val), dwarf.endian); + try dibw.writeInt(u64, @bitCast(f64_val), dwarf.endian); }, .f80 => |f80_val| { try wip_nav.abbrevCode(.block_comptime_value); - try uleb128(diw, @divExact(80, 8)); - try diw.writeInt(u80, @bitCast(f80_val), dwarf.endian); + try dibw.writeUleb128(@divExact(80, 8)); + try dibw.writeInt(u80, @bitCast(f80_val), dwarf.endian); }, .f128 => |f128_val| { try wip_nav.abbrevCode(.data16_comptime_value); - try diw.writeInt(u128, @bitCast(f128_val), dwarf.endian); + try dibw.writeInt(u128, @bitCast(f128_val), dwarf.endian); }, } try wip_nav.refType(.fromInterned(float.ty)); @@ -3889,14 +3955,14 @@ fn updateLazyValue( const uav_ty: Type = .fromInterned(ip.typeOf(uav.val)); if (try uav_ty.onePossibleValue(pt)) |_| { try wip_nav.abbrevCode(.udata_comptime_value); - try uleb128(diw, ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment.toByteUnits() orelse + try dibw.writeLeb128(ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment.toByteUnits() orelse uav_ty.abiAlignment(zcu).toByteUnits().?); break :location; } else break try wip_nav.getValueEntry(.fromInterned(uav.val)); }, .int => { try wip_nav.abbrevCode(.udata_comptime_value); - try uleb128(diw, byte_offset); + try dibw.writeLeb128(byte_offset); break :location; }, .eu_payload => |eu_ptr| { @@ -3935,7 +4001,7 @@ fn updateLazyValue( try wip_nav.strp("len"); try wip_nav.blockValue(src_loc, .fromInterned(slice.len)); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .opt => |opt| { const opt_child_type: Type = .fromInterned(ip.indexToKey(opt.ty).opt_type); @@ -3945,7 +4011,7 @@ fn updateLazyValue( try wip_nav.abbrevCode(.comptime_value_field_runtime_bits); try wip_nav.strp("has_value"); switch (optRepr(opt_child_type, zcu)) { - .opv_null => try uleb128(diw, 0), + .opv_null => try dibw.writeUleb128(0), .unpacked => try wip_nav.blockValue(src_loc, .makeBool(opt.val != .none)), .error_set => try wip_nav.blockValue(src_loc, .fromInterned(value_index)), .pointer => if (opt_child_type.comptimeOnly(zcu)) { @@ -3955,8 +4021,8 @@ fn updateLazyValue( .none => 0, else => opt_child_type.ptrAlignment(zcu).toByteUnits().?, }); - try uleb128(diw, bytes.len); - try diw.writeAll(bytes); + try dibw.writeLeb128(bytes.len); + try dibw.writeAll(bytes); } else try wip_nav.blockValue(src_loc, .fromInterned(value_index)), } } @@ -3975,7 +4041,7 @@ fn updateLazyValue( else try wip_nav.blockValue(src_loc, .fromInterned(opt.val)); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .aggregate => |aggregate| { try wip_nav.abbrevCode(.aggregate_comptime_value); @@ -4060,7 +4126,7 @@ fn updateLazyValue( }, else => unreachable, } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .un => |un| { try wip_nav.abbrevCode(.aggregate_comptime_value); @@ -4085,11 +4151,11 @@ fn updateLazyValue( else try wip_nav.blockValue(src_loc, .fromInterned(un.val)); } - try uleb128(diw, @intFromEnum(AbbrevCode.null)); + try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); }, .memoized_call => unreachable, // not a value } - try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); + try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.getWritten()); } fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { @@ -4109,12 +4175,12 @@ fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { }; } -pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternPool.Index) UpdateError!void { +fn updateContainerTypeInner(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternPool.Index) anyerror!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; const ty: Type = .fromInterned(type_index); const ty_src_loc = ty.srcLoc(zcu); - log.debug("updateContainerType({})", .{ty.fmt(pt)}); + log.debug("updateContainerType({f})", .{ty.fmt(pt)}); const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip).?; const file = zcu.fileByIndex(inst_info.file); @@ -4432,29 +4498,31 @@ pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void { _ = nav_index; } -fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(AbbrevCode).@"enum".tag_type { +fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) anyerror!@typeInfo(AbbrevCode).@"enum".tag_type { assert(abbrev_code != .null); const entry: Entry.Index = @enumFromInt(@intFromEnum(abbrev_code)); if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @intFromEnum(abbrev_code); - var debug_abbrev: std.ArrayList(u8) = .init(dwarf.gpa); - defer debug_abbrev.deinit(); - const daw = debug_abbrev.writer(); + var daaw: std.io.AllocatingWriter = undefined; + daaw.init(dwarf.gpa); + defer daaw.deinit(); + const dabw = &daaw.buffered_writer; const abbrev = AbbrevCode.abbrevs.get(abbrev_code); - try uleb128(daw, @intFromEnum(abbrev_code)); - try uleb128(daw, @intFromEnum(abbrev.tag)); - try daw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no); - for (abbrev.attrs) |*attr| inline for (attr) |info| try uleb128(daw, @intFromEnum(info)); - for (0..2) |_| try uleb128(daw, 0); - try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, entry, dwarf, debug_abbrev.items); + try dabw.writeLeb128(@intFromEnum(abbrev_code)); + try dabw.writeLeb128(@intFromEnum(abbrev.tag)); + try dabw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no); + for (abbrev.attrs) |*attr| inline for (attr) |info| try dabw.writeLeb128(@intFromEnum(info)); + for (0..2) |_| try dabw.writeUleb128(0); + try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, entry, dwarf, daaw.getWritten()); return @intFromEnum(abbrev_code); } pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { + const gpa = dwarf.gpa; const zcu = pt.zcu; const ip = &zcu.intern_pool; { - const type_gop = try dwarf.types.getOrPut(dwarf.gpa, .anyerror_type); + const type_gop = try dwarf.types.getOrPut(gpa, .anyerror_type); if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(.main); var wip_nav: WipNav = .{ .dwarf = dwarf, @@ -4467,14 +4535,15 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { .func_high_pc = undefined, .blocks = undefined, .cfi = undefined, - .debug_frame = .empty, - .debug_info = .empty, - .debug_line = .empty, - .debug_loclists = .empty, + .debug_frame = undefined, + .debug_info = undefined, + .debug_line = undefined, + .debug_loclists = undefined, .pending_lazy = .empty, }; + wip_nav.init(); defer wip_nav.deinit(); - const diw = wip_nav.debug_info.writer(dwarf.gpa); + const dibw = &wip_nav.debug_info.buffered_writer; const global_error_set_names = ip.global_error_set.getNamesFromMainThread(); try wip_nav.abbrevCode(if (global_error_set_names.len == 0) .generated_empty_enum_type else .generated_enum_type); try wip_nav.strp("anyerror"); @@ -4484,50 +4553,52 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { } }))); for (global_error_set_names, 1..) |name, value| { try wip_nav.abbrevCode(.unsigned_enum_field); - try uleb128(diw, value); + try dibw.writeLeb128(value); try wip_nav.strp(name.toSlice(ip)); } - if (global_error_set_names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null)); - try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items); + if (global_error_set_names.len > 0) try dibw.writeLeb128(@intFromEnum(AbbrevCode.null)); + try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, dibw.getWritten()); try wip_nav.updateLazy(.unneeded); } for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| { - const root_dir_path = try mod.root.toAbsolute(zcu.comp.dirs, dwarf.gpa); - defer dwarf.gpa.free(root_dir_path); + const root_dir_path = try mod.root.toAbsolute(zcu.comp.dirs, gpa); + defer gpa.free(root_dir_path); mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path); } - var header: std.ArrayList(u8) = .init(dwarf.gpa); - defer header.deinit(); + var header: std.ArrayListUnmanaged(u8) = .empty; + defer header.deinit(gpa); + var header_bw: std.io.BufferedWriter = undefined; if (dwarf.debug_aranges.section.dirty) { for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| { const unit: Unit.Index = @enumFromInt(unit_index); unit_ptr.clear(); - try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 1); - header.clearRetainingCapacity(); - try header.ensureTotalCapacity(unit_ptr.header_len); + try unit_ptr.cross_section_relocs.ensureTotalCapacity(gpa, 1); + try header.resize(gpa, unit_ptr.header_len); + header_bw.initFixed(header.items); const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| dwarf.debug_aranges.section.getUnit(next_unit).off else dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes(); switch (dwarf.format) { - .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian), + .@"32" => header_bw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, .@"64" => { - std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian); - std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian); + header_bw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable; + header_bw.writeInt(u64, unit_len, dwarf.endian) catch unreachable; }, } - std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 2, dwarf.endian); + header_bw.writeInt(u16, 2, dwarf.endian) catch unreachable; unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_sec = .debug_info, .target_unit = unit, }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); - header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 }); - header.appendNTimesAssumeCapacity(0, unit_ptr.header_len - header.items.len); - try unit_ptr.replaceHeader(&dwarf.debug_aranges.section, dwarf, header.items); + header_bw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; + header_bw.writeAll(&.{ @intFromEnum(dwarf.address_size), 0 }) catch unreachable; + header_bw.splatByteAll(0, unit_ptr.header_len - header_bw.end) catch unreachable; + assert(header_bw.end == header_bw.buffer.len); + try unit_ptr.replaceHeader(&dwarf.debug_aranges.section, dwarf, header_bw.buffer); try unit_ptr.writeTrailer(&dwarf.debug_aranges.section, dwarf); } dwarf.debug_aranges.section.dirty = false; @@ -4542,31 +4613,33 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { dev.check(.x86_64_backend); const Register = @import("../arch/x86_64/bits.zig").Register; for (dwarf.debug_frame.section.units.items) |*unit| { - header.clearRetainingCapacity(); - try header.ensureTotalCapacity(unit.header_len); + try header.resize(gpa, unit.header_len); + header_bw.initFixed(header.items); const unit_len = unit.header_len - dwarf.unitLengthBytes(); switch (dwarf.format) { - .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian), + .@"32" => header_bw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, .@"64" => { - std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian); - std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian); + header_bw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable; + header_bw.writeInt(u64, unit_len, dwarf.endian) catch unreachable; }, } - header.appendNTimesAssumeCapacity(0, 4); - header.appendAssumeCapacity(1); - header.appendSliceAssumeCapacity("zR\x00"); - uleb128(header.fixedWriter(), dwarf.debug_frame.header.code_alignment_factor) catch unreachable; - sleb128(header.fixedWriter(), dwarf.debug_frame.header.data_alignment_factor) catch unreachable; - uleb128(header.fixedWriter(), dwarf.debug_frame.header.return_address_register) catch unreachable; - uleb128(header.fixedWriter(), 1) catch unreachable; - header.appendAssumeCapacity(DW.EH.PE.pcrel | DW.EH.PE.sdata4); - header.appendAssumeCapacity(DW.CFA.def_cfa_sf); - uleb128(header.fixedWriter(), Register.rsp.dwarfNum()) catch unreachable; - sleb128(header.fixedWriter(), -1) catch unreachable; - header.appendAssumeCapacity(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum()); - uleb128(header.fixedWriter(), 1) catch unreachable; - header.appendNTimesAssumeCapacity(DW.CFA.nop, unit.header_len - header.items.len); - try unit.replaceHeader(&dwarf.debug_frame.section, dwarf, header.items); + header_bw.splatByteAll(0, 4) catch unreachable; + header_bw.writeByte(1) catch unreachable; + header_bw.writeAll("zR\x00") catch unreachable; + header_bw.writeLeb128(dwarf.debug_frame.header.code_alignment_factor) catch unreachable; + header_bw.writeLeb128(dwarf.debug_frame.header.data_alignment_factor) catch unreachable; + header_bw.writeLeb128(dwarf.debug_frame.header.return_address_register) catch unreachable; + header_bw.writeUleb128(1) catch unreachable; + header_bw.writeByte(DW.EH.PE.pcrel | DW.EH.PE.sdata4) catch unreachable; + header_bw.writeByte(DW.CFA.def_cfa_sf) catch unreachable; + header_bw.writeUleb128(1) catch unreachable; + header_bw.writeLeb128(Register.rsp.dwarfNum()) catch unreachable; + header_bw.writeSleb128(-1) catch unreachable; + header_bw.writeByte(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum()) catch unreachable; + header_bw.writeUleb128(1) catch unreachable; + header_bw.splatByteAll(DW.CFA.nop, unit.header_len - header_bw.end) catch unreachable; + assert(header_bw.end == header_bw.buffer.len); + try unit.replaceHeader(&dwarf.debug_frame.section, dwarf, header_bw.buffer); try unit.writeTrailer(&dwarf.debug_frame.section, dwarf); } }, @@ -4579,83 +4652,84 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| { const unit: Unit.Index = @enumFromInt(unit_index); unit_ptr.clear(); - try unit_ptr.cross_unit_relocs.ensureTotalCapacity(dwarf.gpa, 1); - try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 7); - header.clearRetainingCapacity(); - try header.ensureTotalCapacity(unit_ptr.header_len); + try unit_ptr.cross_unit_relocs.ensureTotalCapacity(gpa, 1); + try unit_ptr.cross_section_relocs.ensureTotalCapacity(gpa, 7); + try header.resize(gpa, unit_ptr.header_len); + header_bw.initFixed(header.items); const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| dwarf.debug_info.section.getUnit(next_unit).off else dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes(); switch (dwarf.format) { - .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian), + .@"32" => header_bw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, .@"64" => { - std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian); - std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian); + header_bw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable; + header_bw.writeInt(u64, unit_len, dwarf.endian) catch unreachable; }, } - std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 5, dwarf.endian); - header.appendSliceAssumeCapacity(&.{ DW.UT.compile, @intFromEnum(dwarf.address_size) }); + header_bw.writeInt(u16, 5, dwarf.endian) catch unreachable; + header_bw.writeAll(&.{ DW.UT.compile, @intFromEnum(dwarf.address_size) }) catch unreachable; unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_sec = .debug_abbrev, .target_unit = DebugAbbrev.unit, }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); - const compile_unit_off: u32 = @intCast(header.items.len); - uleb128(header.fixedWriter(), try dwarf.refAbbrevCode(.compile_unit)) catch unreachable; - header.appendAssumeCapacity(DW.LANG.Zig); + header_bw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; + const compile_unit_off: u32 = @intCast(header_bw.end); + header_bw.writeLeb128(try dwarf.refAbbrevCode(.compile_unit)) catch unreachable; + header_bw.writeByte(DW.LANG.Zig) catch unreachable; unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_sec = .debug_line_str, .target_unit = StringSection.unit, .target_entry = (try dwarf.debug_line_str.addString(dwarf, "zig " ++ @import("build_options").version)).toOptional(), }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); + header_bw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_sec = .debug_line_str, .target_unit = StringSection.unit, .target_entry = mod_info.root_dir_path.toOptional(), }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); + header_bw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_sec = .debug_line_str, .target_unit = StringSection.unit, .target_entry = (try dwarf.debug_line_str.addString(dwarf, mod.root_src_path)).toOptional(), }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); + header_bw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; unit_ptr.cross_unit_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_unit = .main, .target_off = compile_unit_off, }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); + header_bw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_sec = .debug_line, .target_unit = unit, }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); + header_bw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_sec = .debug_rnglists, .target_unit = unit, .target_off = DebugRngLists.baseOffset(dwarf), }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); - uleb128(header.fixedWriter(), 0) catch unreachable; - uleb128(header.fixedWriter(), try dwarf.refAbbrevCode(.module)) catch unreachable; + header_bw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; + header_bw.writeUleb128(0) catch unreachable; + header_bw.writeLeb128(try dwarf.refAbbrevCode(.module)) catch unreachable; unit_ptr.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_sec = .debug_str, .target_unit = StringSection.unit, .target_entry = (try dwarf.debug_str.addString(dwarf, mod.fully_qualified_name)).toOptional(), }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); - uleb128(header.fixedWriter(), 0) catch unreachable; - try unit_ptr.replaceHeader(&dwarf.debug_info.section, dwarf, header.items); + header_bw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; + header_bw.writeUleb128(0) catch unreachable; + assert(header_bw.end == header_bw.buffer.len); + try unit_ptr.replaceHeader(&dwarf.debug_info.section, dwarf, header_bw.buffer); try unit_ptr.writeTrailer(&dwarf.debug_info.section, dwarf); } dwarf.debug_info.section.dirty = false; @@ -4679,33 +4753,37 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { ); for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| { unit.clear(); - try unit.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, mod_info.dirs.count() + 2 * (mod_info.files.count())); - header.clearRetainingCapacity(); - try header.ensureTotalCapacity(unit.header_len); + try unit.cross_section_relocs.ensureTotalCapacity(gpa, mod_info.dirs.count() + 2 * (mod_info.files.count())); + try header.resize(gpa, unit.header_len); + header_bw.initFixed(header.items); const unit_len = (if (unit.next.unwrap()) |next_unit| dwarf.debug_line.section.getUnit(next_unit).off else dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes(); switch (dwarf.format) { - .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian), + .@"32" => header_bw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, .@"64" => { - std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian); - std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian); + header_bw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable; + header_bw.writeInt(u64, unit_len, dwarf.endian) catch unreachable; }, } - std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 5, dwarf.endian); - header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 }); - dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), unit.header_len - header.items.len); + header_bw.writeInt(u16, 5, dwarf.endian) catch unreachable; + header_bw.writeAll(&.{ @intFromEnum(dwarf.address_size), 0 }) catch unreachable; + dwarf.writeIntTo( + &header_bw, + dwarf.sectionOffsetBytes(), + unit.header_len - header_bw.end, + ) catch unreachable; const StandardOpcode = DeclValEnum(DW.LNS); - header.appendSliceAssumeCapacity(&[_]u8{ + header_bw.writeAll(&.{ dwarf.debug_line.header.minimum_instruction_length, dwarf.debug_line.header.maximum_operations_per_instruction, @intFromBool(dwarf.debug_line.header.default_is_stmt), @bitCast(dwarf.debug_line.header.line_base), dwarf.debug_line.header.line_range, dwarf.debug_line.header.opcode_base, - }); - header.appendSliceAssumeCapacity(std.enums.EnumArray(StandardOpcode, u8).init(.{ + }) catch unreachable; + header_bw.writeAll(std.enums.EnumArray(StandardOpcode, u8).init(.{ .extended_op = undefined, .copy = 0, .advance_pc = 1, @@ -4719,44 +4797,45 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { .set_prologue_end = 0, .set_epilogue_begin = 0, .set_isa = 1, - }).values[1..dwarf.debug_line.header.opcode_base]); - header.appendAssumeCapacity(1); - uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable; - uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable; - uleb128(header.fixedWriter(), mod_info.dirs.count()) catch unreachable; + }).values[1..dwarf.debug_line.header.opcode_base]) catch unreachable; + header_bw.writeByte(1) catch unreachable; + header_bw.writeLeb128(@as(u14, DW.LNCT.path)) catch unreachable; + header_bw.writeLeb128(@as(u13, DW.FORM.line_strp)) catch unreachable; + header_bw.writeLeb128(mod_info.dirs.count()) catch unreachable; for (mod_info.dirs.keys()) |dir_unit| { unit.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_sec = .debug_line_str, .target_unit = StringSection.unit, .target_entry = dwarf.getModInfo(dir_unit).root_dir_path.toOptional(), }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); + header_bw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; } const dir_index_info = DebugLine.dirIndexInfo(@intCast(mod_info.dirs.count())); - header.appendAssumeCapacity(3); - uleb128(header.fixedWriter(), DW.LNCT.path) catch unreachable; - uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable; - uleb128(header.fixedWriter(), DW.LNCT.directory_index) catch unreachable; - uleb128(header.fixedWriter(), @intFromEnum(dir_index_info.form)) catch unreachable; - uleb128(header.fixedWriter(), DW.LNCT.LLVM_source) catch unreachable; - uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable; - uleb128(header.fixedWriter(), mod_info.files.count()) catch unreachable; + header_bw.writeByte(3) catch unreachable; + header_bw.writeLeb128(@as(u14, DW.LNCT.path)) catch unreachable; + header_bw.writeLeb128(@as(u13, DW.FORM.line_strp)) catch unreachable; + header_bw.writeLeb128(@as(u14, DW.LNCT.directory_index)) catch unreachable; + header_bw.writeLeb128(@intFromEnum(dir_index_info.form)) catch unreachable; + header_bw.writeLeb128(@as(u14, DW.LNCT.LLVM_source)) catch unreachable; + header_bw.writeLeb128(@as(u13, DW.FORM.line_strp)) catch unreachable; + header_bw.writeLeb128(mod_info.files.count()) catch unreachable; for (mod_info.files.keys()) |file_index| { const file = zcu.fileByIndex(file_index); unit.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_sec = .debug_line_str, .target_unit = StringSection.unit, .target_entry = (try dwarf.debug_line_str.addString(dwarf, file.sub_file_path)).toOptional(), }); header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); - dwarf.writeInt( - header.addManyAsSliceAssumeCapacity(dir_index_info.bytes), + dwarf.writeIntTo( + &header_bw, + dir_index_info.bytes, mod_info.dirs.getIndex(dwarf.getUnitIfExists(file.mod.?).?) orelse 0, ); unit.cross_section_relocs.appendAssumeCapacity(.{ - .source_off = @intCast(header.items.len), + .source_off = @intCast(header_bw.end), .target_sec = .debug_line_str, .target_unit = StringSection.unit, .target_entry = (try dwarf.debug_line_str.addString( @@ -4764,9 +4843,10 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { if (file.is_builtin) file.source.? else "", )).toOptional(), }); - header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes()); + header_bw.splatByteAll(0, dwarf.sectionOffsetBytes()) catch unreachable; } - try unit.replaceHeader(&dwarf.debug_line.section, dwarf, header.items); + assert(header_bw.end == header_bw.buffer.len); + try unit.replaceHeader(&dwarf.debug_line.section, dwarf, header_bw.buffer); try unit.writeTrailer(&dwarf.debug_line.section, dwarf); } dwarf.debug_line.section.dirty = false; @@ -4782,24 +4862,25 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { } if (dwarf.debug_rnglists.section.dirty) { for (dwarf.debug_rnglists.section.units.items) |*unit| { - header.clearRetainingCapacity(); - try header.ensureTotalCapacity(unit.header_len); + try header.resize(gpa, unit.header_len); + header_bw.initFixed(header.items); const unit_len = (if (unit.next.unwrap()) |next_unit| dwarf.debug_rnglists.section.getUnit(next_unit).off else dwarf.debug_rnglists.section.len) - unit.off - dwarf.unitLengthBytes(); switch (dwarf.format) { - .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian), + .@"32" => header_bw.writeInt(u32, @intCast(unit_len), dwarf.endian) catch unreachable, .@"64" => { - std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian); - std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian); + header_bw.writeInt(u32, std.math.maxInt(u32), dwarf.endian) catch unreachable; + header_bw.writeInt(u64, unit_len, dwarf.endian) catch unreachable; }, } - std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 5, dwarf.endian); - header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 }); - std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), 1, dwarf.endian); - dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), dwarf.sectionOffsetBytes() * 1); - try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header.items); + header_bw.writeInt(u16, 5, dwarf.endian) catch unreachable; + header_bw.writeAll(&.{ @intFromEnum(dwarf.address_size), 0 }) catch unreachable; + header_bw.writeInt(u32, 1, dwarf.endian) catch unreachable; + dwarf.writeIntTo(&header_bw, dwarf.sectionOffsetBytes(), dwarf.sectionOffsetBytes() * 1) catch unreachable; + assert(header_bw.end == header_bw.buffer.len); + try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header_bw.buffer); try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf); } dwarf.debug_rnglists.section.dirty = false; @@ -4815,6 +4896,9 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { assert(!dwarf.debug_str.section.dirty); } +const sleb128 = {}; +const uleb128 = {}; + pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void { for ([_]*Section{ &dwarf.debug_abbrev.section, @@ -5979,7 +6063,7 @@ fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index { return entry; } -fn freeCommonEntry(dwarf: *Dwarf, unit: Unit.Index, entry: Entry.Index) UpdateError!void { +fn freeCommonEntry(dwarf: *Dwarf, unit: Unit.Index, entry: Entry.Index) anyerror!void { try dwarf.debug_aranges.section.freeEntry(unit, entry, dwarf); try dwarf.debug_frame.section.freeEntry(unit, entry, dwarf); try dwarf.debug_info.section.freeEntry(unit, entry, dwarf); @@ -5998,6 +6082,11 @@ fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void { } } +fn writeIntTo(dwarf: *Dwarf, bw: *std.io.BufferedWriter, len: usize, int: u64) anyerror!void { + dwarf.writeInt((try bw.writableSlice(len))[0..len], int); + bw.advance(len); +} + fn resolveReloc(dwarf: *Dwarf, source: u64, target: u64, size: u32) RelocError!void { var buf: [8]u8 = undefined; dwarf.writeInt(buf[0..size], target); @@ -6019,21 +6108,34 @@ fn sectionOffsetBytes(dwarf: *Dwarf) u32 { } fn uleb128Bytes(value: anytype) u32 { - var buffer: [std.atomic.cache_line]u8 = undefined; - var bw: std.io.BufferedWriter = .{ - .unbuffered_writer = .null, - .buffer = .initBuffer(&buffer), - }; - return try std.leb.writeUleb128Count(&bw, value); + return leb128Bytes(switch (@typeInfo(@TypeOf(value))) { + .comptime_int => @as(std.math.IntFittingRange(0, @abs(value)), value), + .int => |value_info| switch (value_info.signedness) { + .signed => @as(@Type(.{ .int = .{ .signedness = .unsigned, .bits = value_info.bits -| 1 } }), @intCast(value)), + .unsigned => value, + }, + else => comptime unreachable, + }); } - fn sleb128Bytes(value: anytype) u32 { - var buffer: [std.atomic.cache_line]u8 = undefined; - var bw: std.io.BufferedWriter = .{ - .unbuffered_writer = .null, - .buffer = .initBuffer(&buffer), - }; - return try std.leb.writeIleb128Count(&bw, value); + return leb128Bytes(switch (@typeInfo(@TypeOf(value))) { + .comptime_int => @as(std.math.IntFittingRange(@min(value, -1), @max(0, value)), value), + .int => |value_info| switch (value_info.signedness) { + .signed => value, + .unsigned => @as(@Type(.{ .int = .{ .signedness = .signed, .bits = value_info.bits + 1 } }), value), + }, + else => comptime unreachable, + }); +} +fn leb128Bytes(value: anytype) u32 { + const value_info = @typeInfo(@TypeOf(value)).int; + var buffer: [ + std.math.divCeil(u16, @intFromBool(value_info.signedness == .signed) + value_info.bits, 7) catch unreachable + ]u8 = undefined; + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(&buffer); + bw.writeLeb128(value) catch unreachable; + return @intCast(bw.end); } /// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional @@ -6055,7 +6157,5 @@ const codegen = @import("../codegen.zig"); const dev = @import("../dev.zig"); const link = @import("../link.zig"); const log = std.log.scoped(.dwarf); -const sleb128 = std.leb.writeIleb128; const std = @import("std"); const target_info = @import("../target.zig"); -const uleb128 = std.leb.writeUleb128; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index dc27e0bdd7..a510a30dba 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -702,7 +702,7 @@ pub fn allocateChunk(self: *Elf, args: struct { shdr.sh_addr + res.value, shdr.sh_offset + res.value, }); - log.debug(" placement {}, {s}", .{ + log.debug(" placement {f}, {s}", .{ res.placement, if (self.atom(res.placement)) |atom_ptr| atom_ptr.name(self) else "", }); @@ -869,7 +869,7 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void { // Dump the state for easy debugging. // State can be dumped via `--debug-log link_state`. if (build_options.enable_logging) { - state_log.debug("{}", .{self.dumpState()}); + state_log.debug("{f}", .{self.dumpState()}); } // Beyond this point, everything has been allocated a virtual address and we can resolve @@ -1849,7 +1849,7 @@ pub fn updateMergeSectionSizes(self: *Elf) !void { pub fn writeMergeSections(self: *Elf) !void { const gpa = self.base.comp.gpa; - var buffer = std.ArrayList(u8).init(gpa); + var buffer: std.ArrayList(u8) = .init(gpa); defer buffer.deinit(); for (self.merge_sections.items) |*msec| { @@ -2996,7 +2996,7 @@ fn allocateSpecialPhdrs(self: *Elf) void { } } -fn writeAtoms(self: *Elf) !void { +fn writeAtoms(self: *Elf) anyerror!void { const gpa = self.base.comp.gpa; var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa); @@ -3005,7 +3005,7 @@ fn writeAtoms(self: *Elf) !void { undefs.deinit(); } - var buffer = std.ArrayList(u8).init(gpa); + var buffer: std.ArrayList(u8) = .init(gpa); defer buffer.deinit(); const slice = self.sections.slice(); @@ -3028,14 +3028,14 @@ fn writeAtoms(self: *Elf) !void { if (self.requiresThunks()) { for (self.thunks.items) |th| { - const thunk_size = th.size(self); - try buffer.ensureUnusedCapacity(thunk_size); + try buffer.resize(th.size(self)); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(buffer.items); const shdr = slice.items(.shdr)[th.output_section_index]; const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset; - try th.write(self, buffer.writer()); - assert(buffer.items.len == thunk_size); - try self.pwriteAll(buffer.items, offset); - buffer.clearRetainingCapacity(); + try th.write(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, offset); } } } @@ -3130,32 +3130,36 @@ pub fn updateSymtabSize(self: *Elf) !void { strtab.sh_size = strsize + 1; } -fn writeSyntheticSections(self: *Elf) !void { +fn writeSyntheticSections(self: *Elf) anyerror!void { const gpa = self.base.comp.gpa; const slice = self.sections.slice(); + var buffer: std.ArrayListUnmanaged(u8) = .empty; + defer buffer.deinit(gpa); + var bw: std.io.BufferedWriter = undefined; + if (self.section_indexes.interp) |shndx| { - var buffer: [256]u8 = undefined; - const interp = self.getTarget().dynamic_linker.get().?; - @memcpy(buffer[0..interp.len], interp); - buffer[interp.len] = 0; - const contents = buffer[0 .. interp.len + 1]; const shdr = slice.items(.shdr)[shndx]; - assert(shdr.sh_size == contents.len); - try self.pwriteAll(contents, shdr.sh_offset); + const interp = self.getTarget().dynamic_linker.get().?; + assert(shdr.sh_size == interp.len + 1); + try buffer.resize(gpa, shdr.sh_size); + @memcpy(buffer.items[0..interp.len], interp); + buffer.items[interp.len] = 0; + try self.pwriteAll(buffer.items, shdr.sh_offset); } if (self.section_indexes.hash) |shndx| { const shdr = slice.items(.shdr)[shndx]; - try self.pwriteAll(self.hash.buffer.items, shdr.sh_offset); + try self.pwriteAll(@ptrCast(self.hash.buffer), shdr.sh_offset); } if (self.section_indexes.gnu_hash) |shndx| { const shdr = slice.items(.shdr)[shndx]; - var buffer = try std.ArrayList(u8).initCapacity(gpa, self.gnu_hash.size()); - defer buffer.deinit(); - try self.gnu_hash.write(self, buffer.writer()); - try self.pwriteAll(buffer.items, shdr.sh_offset); + try buffer.resize(gpa, self.gnu_hash.size()); + bw.initFixed(buffer.items); + try self.gnu_hash.write(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, shdr.sh_offset); } if (self.section_indexes.versym) |shndx| { @@ -3165,26 +3169,29 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.verneed) |shndx| { const shdr = slice.items(.shdr)[shndx]; - var buffer = try std.ArrayList(u8).initCapacity(gpa, self.verneed.size()); - defer buffer.deinit(); - try self.verneed.write(buffer.writer()); - try self.pwriteAll(buffer.items, shdr.sh_offset); + try buffer.resize(gpa, self.verneed.size()); + bw.initFixed(buffer.items); + try self.verneed.write(&bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, shdr.sh_offset); } if (self.section_indexes.dynamic) |shndx| { const shdr = slice.items(.shdr)[shndx]; - var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynamic.size(self)); - defer buffer.deinit(); - try self.dynamic.write(self, buffer.writer()); - try self.pwriteAll(buffer.items, shdr.sh_offset); + try buffer.resize(gpa, self.dynamic.size(self)); + bw.initFixed(buffer.items); + try self.dynamic.write(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, shdr.sh_offset); } if (self.section_indexes.dynsymtab) |shndx| { const shdr = slice.items(.shdr)[shndx]; - var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynsym.size()); - defer buffer.deinit(); - try self.dynsym.write(self, buffer.writer()); - try self.pwriteAll(buffer.items, shdr.sh_offset); + try buffer.resize(gpa, self.dynsym.size()); + bw.initFixed(buffer.items); + try self.dynsym.write(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, shdr.sh_offset); } if (self.section_indexes.dynstrtab) |shndx| { @@ -3200,28 +3207,30 @@ fn writeSyntheticSections(self: *Elf) !void { }; const shdr = slice.items(.shdr)[shndx]; const sh_size = try self.cast(usize, shdr.sh_size); - var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size)); - defer buffer.deinit(); - try eh_frame.writeEhFrame(self, buffer.writer()); - assert(buffer.items.len == sh_size - existing_size); - try self.pwriteAll(buffer.items, shdr.sh_offset + existing_size); + try buffer.resize(gpa, @intCast(sh_size - existing_size)); + bw.initFixed(buffer.items); + try eh_frame.writeEhFrame(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, shdr.sh_offset + existing_size); } if (self.section_indexes.eh_frame_hdr) |shndx| { const shdr = slice.items(.shdr)[shndx]; const sh_size = try self.cast(usize, shdr.sh_size); - var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); - defer buffer.deinit(); - try eh_frame.writeEhFrameHdr(self, buffer.writer()); - try self.pwriteAll(buffer.items, shdr.sh_offset); + try buffer.resize(gpa, sh_size); + bw.initFixed(buffer.items); + try eh_frame.writeEhFrameHdr(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, shdr.sh_offset); } if (self.section_indexes.got) |index| { const shdr = slice.items(.shdr)[index]; - var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got.size(self)); - defer buffer.deinit(); - try self.got.write(self, buffer.writer()); - try self.pwriteAll(buffer.items, shdr.sh_offset); + try buffer.resize(gpa, self.got.size(self)); + bw.initFixed(buffer.items); + try self.got.write(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, shdr.sh_offset); } if (self.section_indexes.rela_dyn) |shndx| { @@ -3234,26 +3243,29 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.section_indexes.plt) |shndx| { const shdr = slice.items(.shdr)[shndx]; - var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt.size(self)); - defer buffer.deinit(); - try self.plt.write(self, buffer.writer()); - try self.pwriteAll(buffer.items, shdr.sh_offset); + try buffer.resize(gpa, self.plt.size(self)); + bw.initFixed(buffer.items); + try self.plt.write(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, shdr.sh_offset); } if (self.section_indexes.got_plt) |shndx| { const shdr = slice.items(.shdr)[shndx]; - var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got_plt.size(self)); - defer buffer.deinit(); - try self.got_plt.write(self, buffer.writer()); - try self.pwriteAll(buffer.items, shdr.sh_offset); + try buffer.resize(gpa, self.got_plt.size(self)); + bw.initFixed(buffer.items); + try self.got_plt.write(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, shdr.sh_offset); } if (self.section_indexes.plt_got) |shndx| { const shdr = slice.items(.shdr)[shndx]; - var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt_got.size(self)); - defer buffer.deinit(); - try self.plt_got.write(self, buffer.writer()); - try self.pwriteAll(buffer.items, shdr.sh_offset); + try buffer.resize(gpa, self.plt_got.size(self)); + bw.initFixed(buffer.items); + try self.plt_got.write(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, shdr.sh_offset); } if (self.section_indexes.rela_plt) |shndx| { @@ -3544,7 +3556,7 @@ pub fn addRelaDyn(self: *Elf, opts: RelaDyn) !void { } pub fn addRelaDynAssumeCapacity(self: *Elf, opts: RelaDyn) void { - relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{ + relocs_log.debug(" {f}: [{x} => {d}({s})] + {x}", .{ relocation.fmtRelocType(opts.type, self.getTarget().cpu.arch), opts.offset, opts.sym, @@ -3754,9 +3766,8 @@ fn shString( pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 { const gpa = self.base.comp.gpa; - const off = @as(u32, @intCast(self.shstrtab.items.len)); - try self.shstrtab.ensureUnusedCapacity(gpa, name.len + 1); - self.shstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable; + const off: u32 = @intCast(self.shstrtab.items.len); + try self.shstrtab.print(gpa, "{s}\x00", .{name}); return off; } @@ -3769,7 +3780,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 { const gpa = self.base.comp.gpa; const off = @as(u32, @intCast(self.dynstrtab.items.len)); try self.dynstrtab.ensureUnusedCapacity(gpa, name.len + 1); - self.dynstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable; + self.dynstrtab.print(gpa, "{s}\x00", .{name}) catch unreachable; return off; } @@ -3791,7 +3802,7 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { for (refs.items[0..nrefs]) |ref| { const atom_ptr = self.atom(ref).?; const file_ptr = atom_ptr.file(self).?; - err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) }); + err.addNote("referenced by {f}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) }); } if (refs.items.len > max_notes) { @@ -3813,12 +3824,12 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor var err = try diags.addErrorWithNotes(nnotes + 1); try err.addMsg("duplicate symbol definition: {s}", .{sym.name(self)}); - err.addNote("defined by {}", .{sym.file(self).?.fmtPath()}); + err.addNote("defined by {f}", .{sym.file(self).?.fmtPath()}); var inote: usize = 0; while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { const file_ptr = self.file(notes.items[inote]).?; - err.addNote("defined by {}", .{file_ptr.fmtPath()}); + err.addNote("defined by {f}", .{file_ptr.fmtPath()}); } if (notes.items.len > max_notes) { @@ -3847,7 +3858,7 @@ pub fn addFileError( const diags = &self.base.comp.link_diags; var err = try diags.addErrorWithNotes(1); try err.addMsg(format, args); - err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()}); + err.addNote("while parsing {f}", .{self.file(file_index).?.fmtPath()}); } pub fn failFile( @@ -3872,16 +3883,10 @@ fn fmtShdr(self: *Elf, shdr: elf.Elf64_Shdr) std.fmt.Formatter(formatShdr) { } }; } -fn formatShdr( - ctx: FormatShdrCtx, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn formatShdr(ctx: FormatShdrCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const shdr = ctx.shdr; - try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : entsize({x}) : flags({})", .{ + try bw.print("{s} : @{x} ({x}) : align({x}) : size({x}) : entsize({x}) : flags({f})", .{ ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset, shdr.sh_addr, shdr.sh_addralign, shdr.sh_size, shdr.sh_entsize, @@ -3893,55 +3898,49 @@ pub fn fmtShdrFlags(sh_flags: u64) std.fmt.Formatter(formatShdrFlags) { return .{ .data = sh_flags }; } -fn formatShdrFlags( - sh_flags: u64, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatShdrFlags(sh_flags: u64, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) !void { _ = unused_fmt_string; - _ = options; if (elf.SHF_WRITE & sh_flags != 0) { - try writer.writeAll("W"); + try bw.writeByte('W'); } if (elf.SHF_ALLOC & sh_flags != 0) { - try writer.writeAll("A"); + try bw.writeByte('A'); } if (elf.SHF_EXECINSTR & sh_flags != 0) { - try writer.writeAll("X"); + try bw.writeByte('X'); } if (elf.SHF_MERGE & sh_flags != 0) { - try writer.writeAll("M"); + try bw.writeByte('M'); } if (elf.SHF_STRINGS & sh_flags != 0) { - try writer.writeAll("S"); + try bw.writeByte('S'); } if (elf.SHF_INFO_LINK & sh_flags != 0) { - try writer.writeAll("I"); + try bw.writeByte('I'); } if (elf.SHF_LINK_ORDER & sh_flags != 0) { - try writer.writeAll("L"); + try bw.writeByte('L'); } if (elf.SHF_EXCLUDE & sh_flags != 0) { - try writer.writeAll("E"); + try bw.writeByte('E'); } if (elf.SHF_COMPRESSED & sh_flags != 0) { - try writer.writeAll("C"); + try bw.writeByte('C'); } if (elf.SHF_GROUP & sh_flags != 0) { - try writer.writeAll("G"); + try bw.writeByte('G'); } if (elf.SHF_OS_NONCONFORMING & sh_flags != 0) { - try writer.writeAll("O"); + try bw.writeByte('O'); } if (elf.SHF_TLS & sh_flags != 0) { - try writer.writeAll("T"); + try bw.writeByte('T'); } if (elf.SHF_X86_64_LARGE & sh_flags != 0) { - try writer.writeAll("l"); + try bw.writeByte('l'); } if (elf.SHF_MIPS_ADDR & sh_flags != 0 or elf.SHF_ARM_PURECODE & sh_flags != 0) { - try writer.writeAll("p"); + try bw.writeByte('p'); } } @@ -3959,11 +3958,9 @@ fn fmtPhdr(self: *Elf, phdr: elf.Elf64_Phdr) std.fmt.Formatter(formatPhdr) { fn formatPhdr( ctx: FormatPhdrCtx, + bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, ) !void { - _ = options; _ = unused_fmt_string; const phdr = ctx.phdr; const write = phdr.p_flags & elf.PF_W != 0; @@ -3985,7 +3982,7 @@ fn formatPhdr( elf.PT_NOTE => "NOTE", else => "UNKNOWN", }; - try writer.print("{s} : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})", .{ + try bw.print("{s} : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})", .{ p_type, flags, phdr.p_offset, phdr.p_vaddr, phdr.p_align, phdr.p_filesz, phdr.p_memsz, }); @@ -3997,30 +3994,28 @@ pub fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) { fn fmtDumpState( self: *Elf, + bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, ) !void { _ = unused_fmt_string; - _ = options; const shared_objects = self.shared_objects.values(); if (self.zigObjectPtr()) |zig_object| { - try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.basename }); - try writer.print("{}{}", .{ + try bw.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.basename }); + try bw.print("{f}{f}", .{ zig_object.fmtAtoms(self), zig_object.fmtSymtab(self), }); - try writer.writeByte('\n'); + try bw.writeByte('\n'); } for (self.objects.items) |index| { const object = self.file(index).?.object; - try writer.print("object({d}) : {}", .{ index, object.fmtPath() }); - if (!object.alive) try writer.writeAll(" : [*]"); - try writer.writeByte('\n'); - try writer.print("{}{}{}{}{}\n", .{ + try bw.print("object({d}) : {f}", .{ index, object.fmtPath() }); + if (!object.alive) try bw.writeAll(" : [*]"); + try bw.writeByte('\n'); + try bw.print("{f}{f}{f}{f}{f}\n", .{ object.fmtAtoms(self), object.fmtCies(self), object.fmtFdes(self), @@ -4031,59 +4026,59 @@ fn fmtDumpState( for (shared_objects) |index| { const shared_object = self.file(index).?.shared_object; - try writer.print("shared_object({d}) : {} : needed({})", .{ + try bw.print("shared_object({d}) : {f} : needed({})", .{ index, shared_object.path, shared_object.needed, }); - if (!shared_object.alive) try writer.writeAll(" : [*]"); - try writer.writeByte('\n'); - try writer.print("{}\n", .{shared_object.fmtSymtab(self)}); + if (!shared_object.alive) try bw.writeAll(" : [*]"); + try bw.writeByte('\n'); + try bw.print("{f}\n", .{shared_object.fmtSymtab(self)}); } if (self.linker_defined_index) |index| { const linker_defined = self.file(index).?.linker_defined; - try writer.print("linker_defined({d}) : (linker defined)\n", .{index}); - try writer.print("{}\n", .{linker_defined.fmtSymtab(self)}); + try bw.print("linker_defined({d}) : (linker defined)\n", .{index}); + try bw.print("{f}\n", .{linker_defined.fmtSymtab(self)}); } const slice = self.sections.slice(); { - try writer.writeAll("atom lists\n"); + try bw.writeAll("atom lists\n"); for (slice.items(.shdr), slice.items(.atom_list_2), 0..) |shdr, atom_list, shndx| { - try writer.print("shdr({d}) : {s} : {}\n", .{ shndx, self.getShString(shdr.sh_name), atom_list.fmt(self) }); + try bw.print("shdr({d}) : {s} : {f}\n", .{ shndx, self.getShString(shdr.sh_name), atom_list.fmt(self) }); } } if (self.requiresThunks()) { - try writer.writeAll("thunks\n"); + try bw.writeAll("thunks\n"); for (self.thunks.items, 0..) |th, index| { - try writer.print("thunk({d}) : {}\n", .{ index, th.fmt(self) }); + try bw.print("thunk({d}) : {f}\n", .{ index, th.fmt(self) }); } } - try writer.print("{}\n", .{self.got.fmt(self)}); - try writer.print("{}\n", .{self.plt.fmt(self)}); + try bw.print("{f}\n", .{self.got.fmt(self)}); + try bw.print("{f}\n", .{self.plt.fmt(self)}); - try writer.writeAll("Output groups\n"); + try bw.writeAll("Output groups\n"); for (self.group_sections.items) |cg| { - try writer.print(" shdr({d}) : GROUP({})\n", .{ cg.shndx, cg.cg_ref }); + try bw.print(" shdr({d}) : GROUP({f})\n", .{ cg.shndx, cg.cg_ref }); } - try writer.writeAll("\nOutput merge sections\n"); + try bw.writeAll("\nOutput merge sections\n"); for (self.merge_sections.items) |msec| { - try writer.print(" shdr({d}) : {}\n", .{ msec.output_section_index, msec.fmt(self) }); + try bw.print(" shdr({d}) : {f}\n", .{ msec.output_section_index, msec.fmt(self) }); } - try writer.writeAll("\nOutput shdrs\n"); + try bw.writeAll("\nOutput shdrs\n"); for (slice.items(.shdr), slice.items(.phndx), 0..) |shdr, phndx, shndx| { - try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{ + try bw.print(" shdr({d}) : phdr({?d}) : {f}\n", .{ shndx, phndx, self.fmtShdr(shdr), }); } - try writer.writeAll("\nOutput phdrs\n"); + try bw.writeAll("\nOutput phdrs\n"); for (self.phdrs.items, 0..) |phdr, phndx| { - try writer.print(" phdr({d}) : {}\n", .{ phndx, self.fmtPhdr(phdr) }); + try bw.print(" phdr({d}) : {f}\n", .{ phndx, self.fmtPhdr(phdr) }); } } @@ -4221,15 +4216,9 @@ pub const Ref = struct { return ref.index == other.index and ref.file == other.file; } - pub fn format( - ref: Ref, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(ref: Ref, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; - try writer.print("ref({},{})", .{ ref.index, ref.file }); + try bw.print("ref({},{})", .{ ref.index, ref.file }); } }; @@ -4424,7 +4413,7 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void { for (atom_list.atoms.keys()[start..i]) |ref| { const atom_ptr = elf_file.atom(ref).?; const file_ptr = atom_ptr.file(elf_file).?; - log.debug("atom({}) {s}", .{ ref, atom_ptr.name(elf_file) }); + log.debug("atom({f}) {s}", .{ ref, atom_ptr.name(elf_file) }); for (atom_ptr.relocs(elf_file)) |rel| { const is_reachable = switch (cpu_arch) { .aarch64 => r: { @@ -4453,7 +4442,7 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void { thunk_ptr.value = try advance(atom_list, thunk_ptr.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2)); - log.debug("thunk({d}) : {}", .{ thunk_index, thunk_ptr.fmt(elf_file) }); + log.debug("thunk({d}) : {f}", .{ thunk_index, thunk_ptr.fmt(elf_file) }); } } diff --git a/src/link/Elf/Archive.zig b/src/link/Elf/Archive.zig index 0d177bc21a..930bf26774 100644 --- a/src/link/Elf/Archive.zig +++ b/src/link/Elf/Archive.zig @@ -44,7 +44,7 @@ pub fn parse( pos += @sizeOf(elf.ar_hdr); if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) { - return diags.failParse(path, "invalid archive header delimiter: {s}", .{ + return diags.failParse(path, "invalid archive header delimiter: {f}", .{ std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), }); } @@ -83,8 +83,8 @@ pub fn parse( .alive = false, }; - log.debug("extracting object '{}' from archive '{}'", .{ - @as(Path, object.path), @as(Path, path), + log.debug("extracting object '{f}' from archive '{f}'", .{ + object.path, path, }); try objects.append(gpa, object); @@ -110,33 +110,16 @@ pub fn setArHdr(opts: struct { }, size: usize, }) elf.ar_hdr { - var hdr: elf.ar_hdr = .{ - .ar_name = undefined, - .ar_date = undefined, - .ar_uid = undefined, - .ar_gid = undefined, - .ar_mode = undefined, - .ar_size = undefined, - .ar_fmag = undefined, - }; - @memset(mem.asBytes(&hdr), 0x20); + var hdr: elf.ar_hdr = undefined; + @memset(mem.asBytes(&hdr), ' '); @memcpy(&hdr.ar_fmag, elf.ARFMAG); - - { - var stream = std.io.fixedBufferStream(&hdr.ar_name); - const writer = stream.writer(); - switch (opts.name) { - .symtab => writer.print("{s}", .{elf.SYM64NAME}) catch unreachable, - .strtab => writer.print("//", .{}) catch unreachable, - .name => |x| writer.print("{s}/", .{x}) catch unreachable, - .name_off => |x| writer.print("/{d}", .{x}) catch unreachable, - } + switch (opts.name) { + .symtab => _ = std.fmt.bufPrint(&hdr.ar_name, "{s}", .{elf.SYM64NAME}) catch unreachable, + .strtab => _ = std.fmt.bufPrint(&hdr.ar_name, "//", .{}) catch unreachable, + .name => |x| _ = std.fmt.bufPrint(&hdr.ar_name, "{s}/", .{x}) catch unreachable, + .name_off => |x| _ = std.fmt.bufPrint(&hdr.ar_name, "/{d}", .{x}) catch unreachable, } - { - var stream = std.io.fixedBufferStream(&hdr.ar_size); - stream.writer().print("{d}", .{opts.size}) catch unreachable; - } - + _ = std.fmt.bufPrint(&hdr.ar_size, "{d}", .{opts.size}) catch unreachable; return hdr; } @@ -201,16 +184,10 @@ pub const ArSymtab = struct { } } - pub fn format( - ar: ArSymtab, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(ar: ArSymtab, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = ar; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format ar symtab directly; use fmt instead"); } @@ -226,20 +203,14 @@ pub const ArSymtab = struct { } }; } - fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const ar = ctx.ar; const elf_file = ctx.elf_file; for (ar.symtab.items, 0..) |entry, i| { const name = ar.strtab.getAssumeExists(entry.off); const file = elf_file.file(entry.file_index).?; - try writer.print(" {d}: {s} in file({d})({})\n", .{ i, name, entry.file_index, file.fmtPath() }); + try bw.print(" {d}: {s} in file({d})({f})\n", .{ i, name, entry.file_index, file.fmtPath() }); } } @@ -264,9 +235,9 @@ pub const ArStrtab = struct { ar.buffer.deinit(allocator); } - pub fn insert(ar: *ArStrtab, allocator: Allocator, name: []const u8) error{OutOfMemory}!u32 { - const off = @as(u32, @intCast(ar.buffer.items.len)); - try ar.buffer.writer(allocator).print("{s}/{c}", .{ name, strtab_delimiter }); + pub fn insert(ar: *ArStrtab, gpa: Allocator, name: []const u8) error{OutOfMemory}!u32 { + const off: u32 = @intCast(ar.buffer.items.len); + try ar.buffer.print(gpa, "{s}/{c}", .{ name, strtab_delimiter }); return off; } @@ -280,15 +251,9 @@ pub const ArStrtab = struct { try writer.writeAll(ar.buffer.items); } - pub fn format( - ar: ArStrtab, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(ar: ArStrtab, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; - try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ar.buffer.items)}); + try bw.print("{f}", .{std.fmt.fmtSliceEscapeLower(ar.buffer.items)}); } }; diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 0869d6582e..8ed6171dfd 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -142,7 +142,7 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool { } pub fn free(self: *Atom, elf_file: *Elf) void { - log.debug("freeAtom atom({}) ({s})", .{ self.ref(), self.name(elf_file) }); + log.debug("freeAtom atom({f}) ({s})", .{ self.ref(), self.name(elf_file) }); const comp = elf_file.base.comp; const gpa = comp.gpa; @@ -243,7 +243,7 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El }, } - relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{ + relocs_log.debug(" {f}: [{x} => {d}({s})] + {x}", .{ relocation.fmtRelocType(rel.r_type(), cpu_arch), r_offset, r_sym, @@ -316,7 +316,7 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype }; // Violation of One Definition Rule for COMDATs. // TODO convert into an error - log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ + log.debug("{f}: {s}: {s} refers to a discarded COMDAT section", .{ file_ptr.fmtPath(), self.name(elf_file), sym_name, @@ -519,11 +519,11 @@ fn dataType(symbol: *const Symbol, elf_file: *Elf) u2 { fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) RelocError!void { const diags = &elf_file.base.comp.link_diags; var err = try diags.addErrorWithNotes(1); - try err.addMsg("fatal linker error: unhandled relocation type {} at offset 0x{x}", .{ + try err.addMsg("fatal linker error: unhandled relocation type {f} at offset 0x{x}", .{ relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch), rel.r_offset, }); - err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); + err.addNote("in {f}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); return error.RelocFailure; } @@ -539,7 +539,7 @@ fn reportTextRelocError( rel.r_offset, symbol.name(elf_file), }); - err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); + err.addNote("in {f}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); return error.RelocFailure; } @@ -555,7 +555,7 @@ fn reportPicError( rel.r_offset, symbol.name(elf_file), }); - err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); + err.addNote("in {f}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); err.addNote("recompile with -fPIC", .{}); return error.RelocFailure; } @@ -572,7 +572,7 @@ fn reportNoPicError( rel.r_offset, symbol.name(elf_file), }); - err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); + err.addNote("in {f}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) }); err.addNote("recompile with -fno-PIC", .{}); return error.RelocFailure; } @@ -621,7 +621,9 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi const cpu_arch = elf_file.getTarget().cpu.arch; const file_ptr = self.file(elf_file).?; - var stream = std.io.fixedBufferStream(code); + + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(code); const rels = self.relocs(elf_file); var it = RelocsIterator{ .relocs = rels }; @@ -652,7 +654,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi // Address of the dynamic thread pointer. const DTP = elf_file.dtpAddress(); - relocs_log.debug(" {s}: {x}: [{x} => {x}] GOT({x}) ({s})", .{ + relocs_log.debug(" {f}: {x}: [{x} => {x}] GOT({x}) ({s})", .{ relocation.fmtRelocType(rel.r_type(), cpu_arch), r_offset, P, @@ -661,32 +663,32 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi target.name(elf_file), }); - try stream.seekTo(r_offset); - const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP }; + bw.end = r_offset; + bw.count = 0; switch (cpu_arch) { - .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) { + .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, &bw) catch |err| switch (err) { error.RelocFailure, error.RelaxFailure, error.InvalidInstruction, error.CannotEncode, => has_reloc_errors = true, - else => |e| return e, + else => |e| return @errorCast(e), }, - .aarch64 => aarch64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) { + .aarch64 => aarch64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, &bw) catch |err| switch (err) { error.RelocFailure, error.RelaxFailure, error.UnexpectedRemainder, error.DivisionByZero, => has_reloc_errors = true, - else => |e| return e, + else => |e| return @errorCast(e), }, - .riscv64 => riscv.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) { + .riscv64 => riscv.resolveRelocAlloc(self, elf_file, rel, target, args, &it, &bw) catch |err| switch (err) { error.RelocFailure, error.RelaxFailure, => has_reloc_errors = true, - else => |e| return e, + else => |e| return @errorCast(e), }, else => return error.UnsupportedCpuArch, } @@ -804,7 +806,9 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any const cpu_arch = elf_file.getTarget().cpu.arch; const file_ptr = self.file(elf_file).?; - var stream = std.io.fixedBufferStream(code); + + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(code); const rels = self.relocs(elf_file); var has_reloc_errors = false; @@ -823,7 +827,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any }; // Violation of One Definition Rule for COMDATs. // TODO convert into an error - log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ + log.debug("{f}: {s}: {s} refers to a discarded COMDAT section", .{ file_ptr.fmtPath(), self.name(elf_file), sym_name, @@ -855,7 +859,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP }; - relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{ + relocs_log.debug(" {f}: {x}: [{x} => {x}] ({s})", .{ relocation.fmtRelocType(rel.r_type(), cpu_arch), rel.r_offset, P, @@ -863,18 +867,18 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any target.name(elf_file), }); - try stream.seekTo(r_offset); - + bw.end = r_offset; + bw.count = 0; switch (cpu_arch) { - .x86_64 => x86_64.resolveRelocNonAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) { + .x86_64 => x86_64.resolveRelocNonAlloc(self, elf_file, rel, target, args, &bw) catch |err| switch (err) { error.RelocFailure => has_reloc_errors = true, else => |e| return e, }, - .aarch64 => aarch64.resolveRelocNonAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) { + .aarch64 => aarch64.resolveRelocNonAlloc(self, elf_file, rel, target, args, &bw) catch |err| switch (err) { error.RelocFailure => has_reloc_errors = true, else => |e| return e, }, - .riscv64 => riscv.resolveRelocNonAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) { + .riscv64 => riscv.resolveRelocNonAlloc(self, elf_file, rel, target, args, &bw) catch |err| switch (err) { error.RelocFailure => has_reloc_errors = true, else => |e| return e, }, @@ -904,16 +908,10 @@ pub fn setExtra(atom: Atom, extras: Extra, elf_file: *Elf) void { atom.file(elf_file).?.setAtomExtra(atom.extra_index, extras); } -pub fn format( - atom: Atom, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +pub fn format(atom: Atom, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = atom; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format Atom directly"); } @@ -929,17 +927,11 @@ const FormatContext = struct { elf_file: *Elf, }; -fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const atom = ctx.atom; const elf_file = ctx.elf_file; - try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x}) : prev({}) : next({})", .{ + try bw.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x}) : prev({f}) : next({f})", .{ atom.atom_index, atom.name(elf_file), atom.address(elf_file), atom.output_section_index, atom.alignment.toByteUnits() orelse 0, atom.size, atom.prev_atom_ref, atom.next_atom_ref, @@ -947,20 +939,20 @@ fn format2( if (atom.file(elf_file)) |atom_file| switch (atom_file) { .object => |object| { if (atom.fdes(object).len > 0) { - try writer.writeAll(" : fdes{ "); + try bw.writeAll(" : fdes{ "); const extras = atom.extra(elf_file); for (atom.fdes(object), extras.fde_start..) |fde, i| { - try writer.print("{d}", .{i}); - if (!fde.alive) try writer.writeAll("([*])"); - if (i - extras.fde_start < extras.fde_count - 1) try writer.writeAll(", "); + try bw.print("{d}", .{i}); + if (!fde.alive) try bw.writeAll("([*])"); + if (i - extras.fde_start < extras.fde_count - 1) try bw.writeAll(", "); } - try writer.writeAll(" }"); + try bw.writeAll(" }"); } }, else => {}, }; if (!atom.alive) { - try writer.writeAll(" : [*]"); + try bw.writeAll(" : [*]"); } } @@ -1087,16 +1079,12 @@ const x86_64 = struct { target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, - code: []u8, - stream: anytype, - ) (error{ InvalidInstruction, CannotEncode } || RelocError)!void { + bw: *std.io.BufferedWriter, + ) anyerror!void { dev.check(.x86_64_backend); const t = &elf_file.base.comp.root_mod.resolved_target.result; const diags = &elf_file.base.comp.link_diags; const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); - const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; - - const cwriter = stream.writer(); const P, const A, const S, const GOT, const G, const TP, const DTP = args; @@ -1109,58 +1097,54 @@ const x86_64 = struct { rel, dynAbsRelocAction(target, elf_file), elf_file, - cwriter, + bw, ); }, - .PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), - .PC32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), + .PLT32 => try bw.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), + .PC32 => try bw.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), - .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little), - .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little), - .GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little), + .GOTPCREL => try bw.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little), + .GOTPC32 => try bw.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little), + .GOTPC64 => try bw.writeInt(i64, GOT + A - P, .little), - .GOTPCRELX => { - if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { - x86_64.relaxGotpcrelx(code[r_offset - 2 ..], t) catch break :blk; - try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); - return; - } - try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); + .GOTPCRELX => if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { + x86_64.relaxGotpcrelx(bw.buffer[bw.end - 2 ..], t) catch break :blk; + try bw.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); + } else { + try bw.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); }, - .REX_GOTPCRELX => { - if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { - x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..], t) catch break :blk; - try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); - return; - } - try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); + .REX_GOTPCRELX => if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { + x86_64.relaxRexGotpcrelx(bw.buffer[bw.end - 3 ..], t) catch break :blk; + try bw.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); + } else { + try bw.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); }, - .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little), - .@"32S" => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little), + .@"32" => try bw.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little), + .@"32S" => try bw.writeInt(i32, @as(i32, @truncate(S + A)), .little), - .TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little), - .TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little), + .TPOFF32 => try bw.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little), + .TPOFF64 => try bw.writeInt(i64, S + A - TP, .little), - .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little), - .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little), + .DTPOFF32 => try bw.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little), + .DTPOFF64 => try bw.writeInt(i64, S + A - DTP, .little), .TLSGD => { if (target.flags.has_tlsgd) { const S_ = target.tlsGdAddress(elf_file); - try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); + try bw.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); } else if (target.flags.has_gottp) { const S_ = target.gotTpAddress(elf_file); - try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, stream); + try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, bw); } else { try x86_64.relaxTlsGdToLe( atom, &.{ rel, it.next().? }, @as(i32, @intCast(S - TP)), elf_file, - stream, + bw, ); } }, @@ -1169,14 +1153,14 @@ const x86_64 = struct { if (elf_file.got.tlsld_index) |entry_index| { const tlsld_entry = elf_file.got.entries.items[entry_index]; const S_ = tlsld_entry.address(elf_file); - try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); + try bw.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); } else { try x86_64.relaxTlsLdToLe( atom, &.{ rel, it.next().? }, @as(i32, @intCast(TP - elf_file.tlsAddress())), elf_file, - stream, + bw, ); } }, @@ -1184,38 +1168,38 @@ const x86_64 = struct { .GOTPC32_TLSDESC => { if (target.flags.has_tlsdesc) { const S_ = target.tlsDescAddress(elf_file); - try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); + try bw.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); } else { - x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..], t) catch { + x86_64.relaxGotPcTlsDesc(bw.buffer[bw.end - 3 ..], t) catch { var err = try diags.addErrorWithNotes(1); try err.addMsg("could not relax {s}", .{@tagName(r_type)}); - err.addNote("in {}:{s} at offset 0x{x}", .{ + err.addNote("in {f}:{s} at offset 0x{x}", .{ atom.file(elf_file).?.fmtPath(), atom.name(elf_file), rel.r_offset, }); return error.RelaxFailure; }; - try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little); + try bw.writeInt(i32, @as(i32, @intCast(S - TP)), .little); } }, .TLSDESC_CALL => if (!target.flags.has_tlsdesc) { // call -> nop - try cwriter.writeAll(&.{ 0x66, 0x90 }); + try bw.writeAll(&.{ 0x66, 0x90 }); }, .GOTTPOFF => { if (target.flags.has_gottp) { const S_ = target.gotTpAddress(elf_file); - try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); + try bw.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); } else { - x86_64.relaxGotTpOff(code[r_offset - 3 ..], t); - try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little); + x86_64.relaxGotTpOff(bw.buffer[bw.end - 3 ..], t); + try bw.writeInt(i32, @as(i32, @intCast(S - TP)), .little); } }, - .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + A)), .little), + .GOT32 => try bw.writeInt(i32, @as(i32, @intCast(G + A)), .little), else => try atom.reportUnhandledRelocError(rel, elf_file), } @@ -1227,45 +1211,40 @@ const x86_64 = struct { rel: elf.Elf64_Rela, target: *const Symbol, args: ResolveArgs, - it: *RelocsIterator, - code: []u8, - stream: anytype, - ) !void { + bw: *std.io.BufferedWriter, + ) anyerror!void { dev.check(.x86_64_backend); - _ = code; - _ = it; - const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); - const cwriter = stream.writer(); + const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); _, const A, const S, const GOT, _, _, const DTP = args; switch (r_type) { .NONE => unreachable, - .@"8" => try cwriter.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little), - .@"16" => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little), - .@"32" => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little), - .@"32S" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), + .@"8" => try bw.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little), + .@"16" => try bw.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little), + .@"32" => try bw.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little), + .@"32S" => try bw.writeInt(i32, @as(i32, @intCast(S + A)), .little), .@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value| - try cwriter.writeInt(u64, value, .little) + try bw.writeInt(u64, value, .little) else - try cwriter.writeInt(i64, S + A, .little), + try bw.writeInt(i64, S + A, .little), .DTPOFF32 => if (atom.debugTombstoneValue(target.*, elf_file)) |value| - try cwriter.writeInt(u64, value, .little) + try bw.writeInt(u64, value, .little) else - try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little), + try bw.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little), .DTPOFF64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value| - try cwriter.writeInt(u64, value, .little) + try bw.writeInt(u64, value, .little) else - try cwriter.writeInt(i64, S + A - DTP, .little), - .GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little), - .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little), + try bw.writeInt(i64, S + A - DTP, .little), + .GOTOFF64 => try bw.writeInt(i64, S + A - GOT, .little), + .GOTPC64 => try bw.writeInt(i64, GOT + A, .little), .SIZE32 => { const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); - try cwriter.writeInt(u32, @bitCast(@as(i32, @intCast(size + A))), .little); + try bw.writeInt(u32, @bitCast(@as(i32, @intCast(size + A))), .little); }, .SIZE64 => { const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); - try cwriter.writeInt(i64, @intCast(size + A), .little); + try bw.writeInt(i64, @intCast(size + A), .little); }, else => try atom.reportUnhandledRelocError(rel, elf_file), } @@ -1285,7 +1264,7 @@ const x86_64 = struct { }, t), else => return error.RelaxFailure, }; - relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding }); + relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding }); const nop: Instruction = try .new(.none, .nop, &.{}, t); try encode(&.{ nop, inst }, code); } @@ -1296,7 +1275,7 @@ const x86_64 = struct { switch (old_inst.encoding.mnemonic) { .mov => { const inst: Instruction = try .new(old_inst.prefix, .lea, &old_inst.ops, t); - relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding }); + relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding }); try encode(&.{inst}, code); }, else => return error.RelaxFailure, @@ -1308,12 +1287,11 @@ const x86_64 = struct { rels: []const elf.Elf64_Rela, value: i32, elf_file: *Elf, - stream: anytype, + bw: *std.io.BufferedWriter, ) !void { dev.check(.x86_64_backend); assert(rels.len == 2); const diags = &elf_file.base.comp.link_diags; - const writer = stream.writer(); const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type()); switch (rel) { .PC32, @@ -1324,17 +1302,17 @@ const x86_64 = struct { 0x48, 0x03, 0x05, 0, 0, 0, 0, // add foo@gottpoff(%rip), %rax }; std.mem.writeInt(i32, insts[12..][0..4], value - 12, .little); - try stream.seekBy(-4); - try writer.writeAll(&insts); + bw.end -= 4; + try bw.writeAll(&insts); }, else => { var err = try diags.addErrorWithNotes(1); - try err.addMsg("TODO: rewrite {} when followed by {}", .{ + try err.addMsg("TODO: rewrite {f} when followed by {f}", .{ relocation.fmtRelocType(rels[0].r_type(), .x86_64), relocation.fmtRelocType(rels[1].r_type(), .x86_64), }); - err.addNote("in {}:{s} at offset 0x{x}", .{ + err.addNote("in {f}:{s} at offset 0x{x}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file), rels[0].r_offset, @@ -1349,12 +1327,11 @@ const x86_64 = struct { rels: []const elf.Elf64_Rela, value: i32, elf_file: *Elf, - stream: anytype, + bw: *std.io.BufferedWriter, ) !void { dev.check(.x86_64_backend); assert(rels.len == 2); const diags = &elf_file.base.comp.link_diags; - const writer = stream.writer(); const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type()); switch (rel) { .PC32, @@ -1366,8 +1343,8 @@ const x86_64 = struct { 0x48, 0x2d, 0, 0, 0, 0, // sub $tls_size, %rax }; std.mem.writeInt(i32, insts[8..][0..4], value, .little); - try stream.seekBy(-3); - try writer.writeAll(&insts); + bw.end -= 3; + try bw.writeAll(&insts); }, .GOTPCREL, @@ -1380,17 +1357,17 @@ const x86_64 = struct { 0x90, // nop }; std.mem.writeInt(i32, insts[8..][0..4], value, .little); - try stream.seekBy(-3); - try writer.writeAll(&insts); + bw.end -= 3; + try bw.writeAll(&insts); }, else => { var err = try diags.addErrorWithNotes(1); - try err.addMsg("TODO: rewrite {} when followed by {}", .{ + try err.addMsg("TODO: rewrite {f} when followed by {f}", .{ relocation.fmtRelocType(rels[0].r_type(), .x86_64), relocation.fmtRelocType(rels[1].r_type(), .x86_64), }); - err.addNote("in {}:{s} at offset 0x{x}", .{ + err.addNote("in {f}:{s} at offset 0x{x}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file), rels[0].r_offset, @@ -1410,7 +1387,12 @@ const x86_64 = struct { // TODO: hack to force imm32s in the assembler .{ .imm = .s(-129) }, }, t) catch return false; - inst.encode(std.io.null_writer, .{}) catch return false; + var buf: [std.atomic.cache_line]u8 = undefined; + var bw: std.io.BufferedWriter = .{ + .unbuffered_writer = .null, + .buffer = &buf, + }; + inst.encode(&bw, .{}) catch return false; return true; }, else => return false, @@ -1427,7 +1409,7 @@ const x86_64 = struct { // TODO: hack to force imm32s in the assembler .{ .imm = .s(-129) }, }, t) catch unreachable; - relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding }); + relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding }); encode(&.{inst}, code) catch unreachable; }, else => unreachable, @@ -1444,7 +1426,7 @@ const x86_64 = struct { // TODO: hack to force imm32s in the assembler .{ .imm = .s(-129) }, }, target); - relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding }); + relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding }); try encode(&.{inst}, code); }, else => return error.RelaxFailure, @@ -1456,12 +1438,11 @@ const x86_64 = struct { rels: []const elf.Elf64_Rela, value: i32, elf_file: *Elf, - stream: anytype, + bw: *std.io.BufferedWriter, ) !void { dev.check(.x86_64_backend); assert(rels.len == 2); const diags = &elf_file.base.comp.link_diags; - const writer = stream.writer(); const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type()); switch (rel) { .PC32, @@ -1474,9 +1455,9 @@ const x86_64 = struct { 0x48, 0x81, 0xc0, 0, 0, 0, 0, // add $tp_offset, %rax }; std.mem.writeInt(i32, insts[12..][0..4], value, .little); - try stream.seekBy(-4); - try writer.writeAll(&insts); - relocs_log.debug(" relaxing {} and {}", .{ + bw.end -= 4; + try bw.writeAll(&insts); + relocs_log.debug(" relaxing {f} and {f}", .{ relocation.fmtRelocType(rels[0].r_type(), .x86_64), relocation.fmtRelocType(rels[1].r_type(), .x86_64), }); @@ -1484,11 +1465,11 @@ const x86_64 = struct { else => { var err = try diags.addErrorWithNotes(1); - try err.addMsg("fatal linker error: rewrite {} when followed by {}", .{ + try err.addMsg("fatal linker error: rewrite {f} when followed by {f}", .{ relocation.fmtRelocType(rels[0].r_type(), .x86_64), relocation.fmtRelocType(rels[1].r_type(), .x86_64), }); - err.addNote("in {}:{s} at offset 0x{x}", .{ + err.addNote("in {f}:{s} at offset 0x{x}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file), rels[0].r_offset, @@ -1505,11 +1486,9 @@ const x86_64 = struct { } fn encode(insts: []const Instruction, code: []u8) !void { - var stream = std.io.fixedBufferStream(code); - const writer = stream.writer(); - for (insts) |inst| { - try inst.encode(writer, .{}); - } + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(code); + for (insts) |inst| try inst.encode(&bw, .{}); } const bits = @import("../../arch/x86_64/bits.zig"); @@ -1613,16 +1592,14 @@ const aarch64 = struct { target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, - code_buffer: []u8, - stream: anytype, - ) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void { + bw: *std.io.BufferedWriter, + ) anyerror!void { _ = it; const diags = &elf_file.base.comp.link_diags; const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; - const cwriter = stream.writer(); - const code = code_buffer[r_offset..][0..4]; + const code = (try bw.writableSlice(4))[0..4]; const file_ptr = atom.file(elf_file).?; const P, const A, const S, const GOT, const G, const TP, const DTP = args; @@ -1636,7 +1613,7 @@ const aarch64 = struct { rel, dynAbsRelocAction(target, elf_file), elf_file, - cwriter, + bw, ); }, @@ -1649,17 +1626,17 @@ const aarch64 = struct { const S_ = th.targetAddress(target_index, elf_file); break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; }; - aarch64_util.writeBranchImm(disp, code); + aarch64_util.writeBranchImm(disp, (try bw.writableSlice(4))[0..4]); }, .PREL32 => { const value = math.cast(i32, S + A - P) orelse return error.Overflow; - mem.writeInt(u32, code, @bitCast(value), .little); + try bw.writeInt(u32, @bitCast(value), .little); }, .PREL64 => { const value = S + A - P; - mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little); + try bw.writeInt(u64, @bitCast(value), .little); }, .ADR_PREL_PG_HI21 => { @@ -1675,7 +1652,7 @@ const aarch64 = struct { // TODO: relax var err = try diags.addErrorWithNotes(1); try err.addMsg("TODO: relax ADR_GOT_PAGE", .{}); - err.addNote("in {}:{s} at offset 0x{x}", .{ + err.addNote("in {f}:{s} at offset 0x{x}", .{ atom.file(elf_file).?.fmtPath(), atom.name(elf_file), r_offset, @@ -1818,25 +1795,18 @@ const aarch64 = struct { rel: elf.Elf64_Rela, target: *const Symbol, args: ResolveArgs, - it: *RelocsIterator, - code: []u8, - stream: anytype, + bw: *std.io.BufferedWriter, ) !void { - _ = it; - _ = code; - const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); - const cwriter = stream.writer(); - _, const A, const S, _, _, _, _ = args; switch (r_type) { .NONE => unreachable, - .ABS32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), + .ABS32 => try bw.writeInt(i32, @as(i32, @intCast(S + A)), .little), .ABS64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value| - try cwriter.writeInt(u64, value, .little) + try bw.writeInt(u64, value, .little) else - try cwriter.writeInt(i64, S + A, .little), + try bw.writeInt(i64, S + A, .little), else => try atom.reportUnhandledRelocError(rel, elf_file), } } @@ -1898,13 +1868,10 @@ const riscv = struct { target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, - code: []u8, - stream: anytype, + bw: *std.io.BufferedWriter, ) !void { const diags = &elf_file.base.comp.link_diags; const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); - const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; - const cwriter = stream.writer(); const P, const A, const S, const GOT, const G, const TP, const DTP = args; _ = TP; @@ -1913,7 +1880,7 @@ const riscv = struct { switch (r_type) { .NONE => unreachable, - .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little), + .@"32" => try bw.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little), .@"64" => { try atom.resolveDynAbsReloc( @@ -1921,34 +1888,35 @@ const riscv = struct { rel, dynAbsRelocAction(target, elf_file), elf_file, - cwriter, + bw, ); }, - .ADD32 => riscv_util.writeAddend(i32, .add, code[r_offset..][0..4], S + A), - .SUB32 => riscv_util.writeAddend(i32, .sub, code[r_offset..][0..4], S + A), + .ADD32 => try riscv_util.writeAddend(i32, .add, S + A, bw), + .SUB32 => try riscv_util.writeAddend(i32, .sub, S + A, bw), .HI20 => { const value: u32 = @bitCast(math.cast(i32, S + A) orelse return error.Overflow); - riscv_util.writeInstU(code[r_offset..][0..4], value); + riscv_util.writeInstU((try bw.writableSlice(4))[0..4], value); }, .GOT_HI20 => { assert(target.flags.has_got); const disp: u32 = @bitCast(math.cast(i32, G + GOT + A - P) orelse return error.Overflow); - riscv_util.writeInstU(code[r_offset..][0..4], disp); + riscv_util.writeInstU((try bw.writableSlice(4))[0..4], disp); }, .CALL_PLT => { // TODO: relax const disp: u32 = @bitCast(math.cast(i32, S + A - P) orelse return error.Overflow); - riscv_util.writeInstU(code[r_offset..][0..4], disp); // auipc - riscv_util.writeInstI(code[r_offset + 4 ..][0..4], disp); // jalr + const code = (try bw.writableSlice(8))[0..8]; + riscv_util.writeInstU(code[0..4], disp); // auipc + riscv_util.writeInstI(code[4..8], disp); // jalr }, .PCREL_HI20 => { const disp: u32 = @bitCast(math.cast(i32, S + A - P) orelse return error.Overflow); - riscv_util.writeInstU(code[r_offset..][0..4], disp); + riscv_util.writeInstU((try bw.writableSlice(4))[0..4], disp); }, .PCREL_LO12_I, @@ -1965,7 +1933,7 @@ const riscv = struct { // TODO: implement searching forward var err = try diags.addErrorWithNotes(1); try err.addMsg("TODO: find HI20 paired reloc scanning forward", .{}); - err.addNote("in {}:{s} at offset 0x{x}", .{ + err.addNote("in {f}:{s} at offset 0x{x}", .{ atom.file(elf_file).?.fmtPath(), atom.name(elf_file), rel.r_offset, @@ -1986,8 +1954,8 @@ const riscv = struct { }; relocs_log.debug(" [{x} => {x}]", .{ P_, disp + P_ }); switch (r_type) { - .PCREL_LO12_I => riscv_util.writeInstI(code[r_offset..][0..4], @bitCast(disp)), - .PCREL_LO12_S => riscv_util.writeInstS(code[r_offset..][0..4], @bitCast(disp)), + .PCREL_LO12_I => riscv_util.writeInstI((try bw.writableSlice(4))[0..4], @bitCast(disp)), + .PCREL_LO12_S => riscv_util.writeInstS((try bw.writableSlice(4))[0..4], @bitCast(disp)), else => unreachable, } }, @@ -1997,8 +1965,8 @@ const riscv = struct { => { const disp: u32 = @bitCast(math.cast(i32, S + A) orelse return error.Overflow); switch (r_type) { - .LO12_I => riscv_util.writeInstI(code[r_offset..][0..4], disp), - .LO12_S => riscv_util.writeInstS(code[r_offset..][0..4], disp), + .LO12_I => riscv_util.writeInstI((try bw.writableSlice(4))[0..4], disp), + .LO12_S => riscv_util.writeInstS((try bw.writableSlice(4))[0..4], disp), else => unreachable, } }, @@ -2006,7 +1974,7 @@ const riscv = struct { .TPREL_HI20 => { const target_addr: u32 = @intCast(target.address(.{}, elf_file)); const val: i32 = @intCast(S + A - target_addr); - riscv_util.writeInstU(code[r_offset..][0..4], @bitCast(val)); + riscv_util.writeInstU((try bw.writableSlice(4))[0..4], @bitCast(val)); }, .TPREL_LO12_I, @@ -2015,8 +1983,8 @@ const riscv = struct { const target_addr: u32 = @intCast(target.address(.{}, elf_file)); const val: i32 = @intCast(S + A - target_addr); switch (r_type) { - .TPREL_LO12_I => riscv_util.writeInstI(code[r_offset..][0..4], @bitCast(val)), - .TPREL_LO12_S => riscv_util.writeInstS(code[r_offset..][0..4], @bitCast(val)), + .TPREL_LO12_I => riscv_util.writeInstI((try bw.writableSlice(4))[0..4], @bitCast(val)), + .TPREL_LO12_S => riscv_util.writeInstS((try bw.writableSlice(4))[0..4], @bitCast(val)), else => unreachable, } }, @@ -2035,15 +2003,9 @@ const riscv = struct { rel: elf.Elf64_Rela, target: *const Symbol, args: ResolveArgs, - it: *RelocsIterator, - code: []u8, - stream: anytype, - ) !void { - _ = it; - + bw: *std.io.BufferedWriter, + ) anyerror!void { const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); - const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; - const cwriter = stream.writer(); _, const A, const S, const GOT, _, _, const DTP = args; _ = GOT; @@ -2052,30 +2014,30 @@ const riscv = struct { switch (r_type) { .NONE => unreachable, - .@"32" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), + .@"32" => try bw.writeInt(i32, @as(i32, @intCast(S + A)), .little), .@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value| - try cwriter.writeInt(u64, value, .little) + try bw.writeInt(u64, value, .little) else - try cwriter.writeInt(i64, S + A, .little), + try bw.writeInt(i64, S + A, .little), - .ADD8 => riscv_util.writeAddend(i8, .add, code[r_offset..][0..1], S + A), - .SUB8 => riscv_util.writeAddend(i8, .sub, code[r_offset..][0..1], S + A), - .ADD16 => riscv_util.writeAddend(i16, .add, code[r_offset..][0..2], S + A), - .SUB16 => riscv_util.writeAddend(i16, .sub, code[r_offset..][0..2], S + A), - .ADD32 => riscv_util.writeAddend(i32, .add, code[r_offset..][0..4], S + A), - .SUB32 => riscv_util.writeAddend(i32, .sub, code[r_offset..][0..4], S + A), - .ADD64 => riscv_util.writeAddend(i64, .add, code[r_offset..][0..8], S + A), - .SUB64 => riscv_util.writeAddend(i64, .sub, code[r_offset..][0..8], S + A), + .ADD8 => try riscv_util.writeAddend(i8, .add, S + A, bw), + .SUB8 => try riscv_util.writeAddend(i8, .sub, S + A, bw), + .ADD16 => try riscv_util.writeAddend(i16, .add, S + A, bw), + .SUB16 => try riscv_util.writeAddend(i16, .sub, S + A, bw), + .ADD32 => try riscv_util.writeAddend(i32, .add, S + A, bw), + .SUB32 => try riscv_util.writeAddend(i32, .sub, S + A, bw), + .ADD64 => try riscv_util.writeAddend(i64, .add, S + A, bw), + .SUB64 => try riscv_util.writeAddend(i64, .sub, S + A, bw), - .SET8 => mem.writeInt(i8, code[r_offset..][0..1], @as(i8, @truncate(S + A)), .little), - .SET16 => mem.writeInt(i16, code[r_offset..][0..2], @as(i16, @truncate(S + A)), .little), - .SET32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @truncate(S + A)), .little), + .SET8 => try bw.writeInt(i8, @truncate(S + A), .little), + .SET16 => try bw.writeInt(i16, @truncate(S + A), .little), + .SET32 => try bw.writeInt(i32, @truncate(S + A), .little), - .SET6 => riscv_util.writeSetSub6(.set, code[r_offset..][0..1], S + A), - .SUB6 => riscv_util.writeSetSub6(.sub, code[r_offset..][0..1], S + A), + .SET6 => try riscv_util.writeSetSub6(.set, S + A, bw), + .SUB6 => try riscv_util.writeSetSub6(.sub, S + A, bw), - .SET_ULEB128 => try riscv_util.writeSetSubUleb(.set, stream, S + A), - .SUB_ULEB128 => try riscv_util.writeSetSubUleb(.sub, stream, S - A), + .SET_ULEB128 => try riscv_util.writeSetSubUleb(.set, S + A, bw), + .SUB_ULEB128 => try riscv_util.writeSetSubUleb(.sub, S - A, bw), else => try atom.reportUnhandledRelocError(rel, elf_file), } diff --git a/src/link/Elf/AtomList.zig b/src/link/Elf/AtomList.zig index f8d57d04a1..2f70a29f27 100644 --- a/src/link/Elf/AtomList.zig +++ b/src/link/Elf/AtomList.zig @@ -108,7 +108,7 @@ pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_fi const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow; const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; - log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off }); + log.debug(" atom({f}) at 0x{x}", .{ ref, list.offset(elf_file) + off }); const object = atom_ptr.file(elf_file).?.object; const code = try object.codeDecompressAlloc(elf_file, ref.index); @@ -144,7 +144,7 @@ pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *E const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow; const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; - log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off }); + log.debug(" atom({f}) at 0x{x}", .{ ref, list.offset(elf_file) + off }); const object = atom_ptr.file(elf_file).?.object; const code = try object.codeDecompressAlloc(elf_file, ref.index); @@ -167,16 +167,10 @@ pub fn lastAtom(list: AtomList, elf_file: *Elf) *Atom { return elf_file.atom(list.atoms.keys()[list.atoms.keys().len - 1]).?; } -pub fn format( - list: AtomList, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +pub fn format(list: AtomList, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = list; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format AtomList directly"); } @@ -186,25 +180,19 @@ pub fn fmt(list: AtomList, elf_file: *Elf) std.fmt.Formatter(format2) { return .{ .data = .{ list, elf_file } }; } -fn format2( - ctx: FormatCtx, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn format2(ctx: FormatCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const list, const elf_file = ctx; - try writer.print("list : @{x} : shdr({d}) : align({x}) : size({x})", .{ + try bw.print("list : @{x} : shdr({d}) : align({x}) : size({x})", .{ list.address(elf_file), list.output_section_index, list.alignment.toByteUnits() orelse 0, list.size, }); - try writer.writeAll(" : atoms{ "); + try bw.writeAll(" : atoms{ "); for (list.atoms.keys(), 0..) |ref, i| { - try writer.print("{}", .{ref}); - if (i < list.atoms.keys().len - 1) try writer.writeAll(", "); + try bw.print("{f}", .{ref}); + if (i < list.atoms.keys().len - 1) try bw.writeAll(", "); } - try writer.writeAll(" }"); + try bw.writeAll(" }"); } const assert = std.debug.assert; diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig index ad02d8d5d9..80d599ca2c 100644 --- a/src/link/Elf/LinkerDefined.zig +++ b/src/link/Elf/LinkerDefined.zig @@ -449,23 +449,17 @@ const FormatContext = struct { elf_file: *Elf, }; -fn formatSymtab( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const self = ctx.self; const elf_file = ctx.elf_file; - try writer.writeAll(" globals\n"); + try bw.writeAll(" globals\n"); for (self.symbols.items, 0..) |sym, i| { const ref = self.resolveSymbol(@intCast(i), elf_file); if (elf_file.symbol(ref)) |ref_sym| { - try writer.print(" {}\n", .{ref_sym.fmt(elf_file)}); + try bw.print(" {f}\n", .{ref_sym.fmt(elf_file)}); } else { - try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)}); + try bw.print(" {s} : unclaimed\n", .{sym.name(elf_file)}); } } } diff --git a/src/link/Elf/Merge.zig b/src/link/Elf/Merge.zig index 33e4f9c5b2..be01985682 100644 --- a/src/link/Elf/Merge.zig +++ b/src/link/Elf/Merge.zig @@ -157,16 +157,10 @@ pub const Section = struct { } }; - pub fn format( - msec: Section, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(msec: Section, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = msec; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format directly"); } @@ -182,17 +176,11 @@ pub const Section = struct { elf_file: *Elf, }; - pub fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = options; + pub fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const msec = ctx.msec; const elf_file = ctx.elf_file; - try writer.print("{s} : @{x} : size({x}) : align({x}) : entsize({x}) : type({x}) : flags({x})\n", .{ + try bw.print("{s} : @{x} : size({x}) : align({x}) : entsize({x}) : type({x}) : flags({x})\n", .{ msec.name(elf_file), msec.address(elf_file), msec.size, @@ -202,7 +190,7 @@ pub const Section = struct { msec.flags, }); for (msec.subsections.items) |msub| { - try writer.print(" {}\n", .{msub.fmt(elf_file)}); + try bw.print(" {f}\n", .{msub.fmt(elf_file)}); } } @@ -231,16 +219,10 @@ pub const Subsection = struct { return msec.bytes.items[msub.string_index..][0..msub.size]; } - pub fn format( - msub: Subsection, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(msub: Subsection, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = msub; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format directly"); } @@ -256,22 +238,16 @@ pub const Subsection = struct { elf_file: *Elf, }; - pub fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = options; + pub fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const msub = ctx.msub; const elf_file = ctx.elf_file; - try writer.print("@{x} : align({x}) : size({x})", .{ + try bw.print("@{x} : align({x}) : size({x})", .{ msub.address(elf_file), msub.alignment, msub.size, }); - if (!msub.alive) try writer.writeAll(" : [*]"); + if (!msub.alive) try bw.writeAll(" : [*]"); } pub const Index = u32; diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 4d5b5378c4..7cb17f01f6 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -281,7 +281,7 @@ fn initAtoms( elf.SHT_GROUP => { if (shdr.sh_info >= self.symtab.items.len) { // TODO convert into an error - log.debug("{}: invalid symbol index in sh_info", .{self.fmtPath()}); + log.debug("{f}: invalid symbol index in sh_info", .{self.fmtPath()}); continue; } const group_info_sym = self.symtab.items[shdr.sh_info]; @@ -448,7 +448,8 @@ fn parseEhFrame( const fdes_start = self.fdes.items.len; const cies_start = self.cies.items.len; - var it = eh_frame.Iterator{ .data = raw }; + var it: eh_frame.Iterator = undefined; + it.br.initFixed(raw); while (try it.next()) |rec| { const rel_range = filterRelocs(self.relocs.items[rel_start..][0..relocs.len], rec.offset, rec.size + 4); switch (rec.tag) { @@ -488,7 +489,7 @@ fn parseEhFrame( if (cie.offset == cie_ptr) break @as(u32, @intCast(cie_index)); } else { // TODO convert into an error - log.debug("{s}: no matching CIE found for FDE at offset {x}", .{ + log.debug("{f}: no matching CIE found for FDE at offset {x}", .{ self.fmtPath(), fde.offset, }); @@ -582,7 +583,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { if (sym.flags.import) { if (sym.type(elf_file) != elf.STT_FUNC) // TODO convert into an error - log.debug("{s}: {s}: CIE referencing external data reference", .{ + log.debug("{fs}: {s}: CIE referencing external data reference", .{ self.fmtPath(), sym.name(elf_file), }); sym.flags.needs_plt = true; @@ -796,7 +797,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void { if (!isNull(data[end .. end + sh_entsize])) { var err = try diags.addErrorWithNotes(1); try err.addMsg("string not null terminated", .{}); - err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); + err.addNote("in {f}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); return error.LinkFailure; } end += sh_entsize; @@ -811,7 +812,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void { if (shdr.sh_size % sh_entsize != 0) { var err = try diags.addErrorWithNotes(1); try err.addMsg("size not a multiple of sh_entsize", .{}); - err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); + err.addNote("in {f}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); return error.LinkFailure; } @@ -889,7 +890,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{ var err = try diags.addErrorWithNotes(2); try err.addMsg("invalid symbol value: {x}", .{esym.st_value}); err.addNote("for symbol {s}", .{sym.name(elf_file)}); - err.addNote("in {}", .{self.fmtPath()}); + err.addNote("in {f}", .{self.fmtPath()}); return error.LinkFailure; }; @@ -914,7 +915,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{ const res = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse { var err = try diags.addErrorWithNotes(1); try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset}); - err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); + err.addNote("in {f}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); return error.LinkFailure; }; @@ -952,7 +953,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { const is_tls = sym.type(elf_file) == elf.STT_TLS; const name = if (is_tls) ".tls_common" else ".common"; const name_offset = @as(u32, @intCast(self.strtab.items.len)); - try self.strtab.writer(gpa).print("{s}\x00", .{name}); + try self.strtab.print(gpa, "{s}\x00", .{name}); var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE; if (is_tls) sh_flags |= elf.SHF_TLS; @@ -1191,28 +1192,26 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index const atom_ptr = self.atom(atom_index).?; const shdr = atom_ptr.inputShdr(elf_file); const handle = elf_file.fileHandle(self.file_handle); - const data = try self.preadShdrContentsAlloc(gpa, handle, atom_ptr.input_section_index); - defer if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) gpa.free(data); + var br: std.io.BufferedReader = undefined; + br.initFixed(try self.preadShdrContentsAlloc(gpa, handle, atom_ptr.input_section_index)); + defer if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) gpa.free(br.storageBuffer()); if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) { - const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; + const chdr = (try br.takeStruct(elf.Elf64_Chdr)).*; switch (chdr.ch_type) { .ZLIB => { - var stream = std.io.fixedBufferStream(data[@sizeOf(elf.Elf64_Chdr)..]); - var zlib_stream = std.compress.zlib.decompressor(stream.reader()); - const size = std.math.cast(usize, chdr.ch_size) orelse return error.Overflow; - const decomp = try gpa.alloc(u8, size); - const nread = zlib_stream.reader().readAll(decomp) catch return error.InputOutput; - if (nread != decomp.len) { - return error.InputOutput; - } - return decomp; + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, std.math.cast(usize, chdr.ch_size) orelse return error.Overflow)); + errdefer gpa.free(bw.buffer); + try std.compress.zlib.decompress(&br, &bw); + if (bw.end != bw.buffer.len) return error.InputOutput; + return bw.buffer; }, else => @panic("TODO unhandled compression scheme"), } } - return data; + return br.storageBuffer(); } fn locals(self: *Object) []Symbol { @@ -1432,16 +1431,10 @@ pub fn group(self: *Object, index: Elf.Group.Index) *Elf.Group { return &self.groups.items[index]; } -pub fn format( - self: *Object, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +pub fn format(self: *Object, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = self; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format objects directly"); } @@ -1457,28 +1450,22 @@ const FormatContext = struct { elf_file: *Elf, }; -fn formatSymtab( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const object = ctx.object; const elf_file = ctx.elf_file; - try writer.writeAll(" locals\n"); + try bw.writeAll(" locals\n"); for (object.locals()) |sym| { - try writer.print(" {}\n", .{sym.fmt(elf_file)}); + try bw.print(" {f}\n", .{sym.fmt(elf_file)}); } - try writer.writeAll(" globals\n"); + try bw.writeAll(" globals\n"); for (object.globals(), 0..) |sym, i| { const first_global = object.first_global.?; const ref = object.resolveSymbol(@intCast(i + first_global), elf_file); if (elf_file.symbol(ref)) |ref_sym| { - try writer.print(" {}\n", .{ref_sym.fmt(elf_file)}); + try bw.print(" {f}\n", .{ref_sym.fmt(elf_file)}); } else { - try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)}); + try bw.print(" {s} : unclaimed\n", .{sym.name(elf_file)}); } } } @@ -1490,19 +1477,13 @@ pub fn fmtAtoms(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatAtoms) { } }; } -fn formatAtoms( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatAtoms(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const object = ctx.object; - try writer.writeAll(" atoms\n"); + try bw.writeAll(" atoms\n"); for (object.atoms_indexes.items) |atom_index| { const atom_ptr = object.atom(atom_index) orelse continue; - try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)}); + try bw.print(" {f}\n", .{atom_ptr.fmt(ctx.elf_file)}); } } @@ -1513,18 +1494,12 @@ pub fn fmtCies(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatCies) { } }; } -fn formatCies( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatCies(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const object = ctx.object; - try writer.writeAll(" cies\n"); + try bw.writeAll(" cies\n"); for (object.cies.items, 0..) |cie, i| { - try writer.print(" cie({d}) : {}\n", .{ i, cie.fmt(ctx.elf_file) }); + try bw.print(" cie({d}) : {f}\n", .{ i, cie.fmt(ctx.elf_file) }); } } @@ -1535,18 +1510,12 @@ pub fn fmtFdes(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatFdes) { } }; } -fn formatFdes( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatFdes(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const object = ctx.object; - try writer.writeAll(" fdes\n"); + try bw.writeAll(" fdes\n"); for (object.fdes.items, 0..) |fde, i| { - try writer.print(" fde({d}) : {}\n", .{ i, fde.fmt(ctx.elf_file) }); + try bw.print(" fde({d}) : {f}\n", .{ i, fde.fmt(ctx.elf_file) }); } } @@ -1557,26 +1526,20 @@ pub fn fmtGroups(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatGroups) } }; } -fn formatGroups( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatGroups(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const object = ctx.object; const elf_file = ctx.elf_file; - try writer.writeAll(" groups\n"); + try bw.writeAll(" groups\n"); for (object.groups.items, 0..) |g, g_index| { - try writer.print(" {s}({d})", .{ if (g.is_comdat) "COMDAT" else "GROUP", g_index }); - if (!g.alive) try writer.writeAll(" : [*]"); - try writer.writeByte('\n'); + try bw.print(" {s}({d})", .{ if (g.is_comdat) "COMDAT" else "GROUP", g_index }); + if (!g.alive) try bw.writeAll(" : [*]"); + try bw.writeByte('\n'); const g_members = g.members(elf_file); for (g_members) |shndx| { const atom_index = object.atoms_indexes.items[shndx]; const atom_ptr = object.atom(atom_index) orelse continue; - try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom_ptr.name(elf_file) }); + try bw.print(" atom({d}) : {s}\n", .{ atom_index, atom_ptr.name(elf_file) }); } } } @@ -1585,18 +1548,12 @@ pub fn fmtPath(self: Object) std.fmt.Formatter(formatPath) { return .{ .data = self }; } -fn formatPath( - object: Object, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatPath(object: Object, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; if (object.archive) |ar| { - try writer.print("{}({})", .{ ar.path, object.path }); + try bw.print("{f}({f})", .{ ar.path, object.path }); } else { - try writer.print("{}", .{object.path}); + try bw.print("{f}", .{object.path}); } } diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index 30def4429b..298670c839 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -509,16 +509,10 @@ pub fn setSymbolExtra(self: *SharedObject, index: u32, extra: Symbol.Extra) void } } -pub fn format( - self: SharedObject, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +pub fn format(self: SharedObject, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = self; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("unreachable"); } @@ -534,23 +528,17 @@ const FormatContext = struct { elf_file: *Elf, }; -fn formatSymtab( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const shared = ctx.shared; const elf_file = ctx.elf_file; - try writer.writeAll(" globals\n"); + try bw.writeAll(" globals\n"); for (shared.symbols.items, 0..) |sym, i| { const ref = shared.resolveSymbol(@intCast(i), elf_file); if (elf_file.symbol(ref)) |ref_sym| { - try writer.print(" {}\n", .{ref_sym.fmt(elf_file)}); + try bw.print(" {f}\n", .{ref_sym.fmt(elf_file)}); } else { - try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)}); + try bw.print(" {s} : unclaimed\n", .{sym.name(elf_file)}); } } } diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 843c23dca4..6c5e0c55e6 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -316,16 +316,10 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { out.st_size = esym.st_size; } -pub fn format( - symbol: Symbol, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +pub fn format(symbol: Symbol, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = symbol; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format Symbol directly"); } @@ -341,24 +335,18 @@ pub fn fmtName(symbol: Symbol, elf_file: *Elf) std.fmt.Formatter(formatName) { } }; } -fn formatName( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn formatName(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const elf_file = ctx.elf_file; const symbol = ctx.symbol; - try writer.writeAll(symbol.name(elf_file)); + try bw.writeAll(symbol.name(elf_file)); switch (symbol.version_index.VERSION) { @intFromEnum(elf.VER_NDX.LOCAL), @intFromEnum(elf.VER_NDX.GLOBAL) => {}, else => { const file_ptr = symbol.file(elf_file).?; assert(file_ptr == .shared_object); const shared_object = file_ptr.shared_object; - try writer.print("@{s}", .{shared_object.versionString(symbol.version_index)}); + try bw.print("@{s}", .{shared_object.versionString(symbol.version_index)}); }, } } @@ -370,17 +358,11 @@ pub fn fmt(symbol: Symbol, elf_file: *Elf) std.fmt.Formatter(format2) { } }; } -fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const symbol = ctx.symbol; const elf_file = ctx.elf_file; - try writer.print("%{d} : {s} : @{x}", .{ + try bw.print("%{d} : {f} : @{x}", .{ symbol.esym_index, symbol.fmtName(elf_file), symbol.address(.{ .plt = false, .trampoline = false }, elf_file), @@ -388,25 +370,25 @@ fn format2( if (symbol.file(elf_file)) |file_ptr| { if (symbol.isAbs(elf_file)) { if (symbol.elfSym(elf_file).st_shndx == elf.SHN_UNDEF) { - try writer.writeAll(" : undef"); + try bw.writeAll(" : undef"); } else { - try writer.writeAll(" : absolute"); + try bw.writeAll(" : absolute"); } } else if (symbol.outputShndx(elf_file)) |shndx| { - try writer.print(" : shdr({d})", .{shndx}); + try bw.print(" : shdr({d})", .{shndx}); } if (symbol.atom(elf_file)) |atom_ptr| { - try writer.print(" : atom({d})", .{atom_ptr.atom_index}); + try bw.print(" : atom({d})", .{atom_ptr.atom_index}); } var buf: [2]u8 = .{'_'} ** 2; if (symbol.flags.@"export") buf[0] = 'E'; if (symbol.flags.import) buf[1] = 'I'; - try writer.print(" : {s}", .{&buf}); - if (symbol.flags.weak) try writer.writeAll(" : weak"); + try bw.print(" : {s}", .{&buf}); + if (symbol.flags.weak) try bw.writeAll(" : weak"); switch (file_ptr) { - inline else => |x| try writer.print(" : {s}({d})", .{ @tagName(file_ptr), x.index }), + inline else => |x| try bw.print(" : {s}({d})", .{ @tagName(file_ptr), x.index }), } - } else try writer.writeAll(" : unresolved"); + } else try bw.writeAll(" : unresolved"); } pub const Flags = packed struct { diff --git a/src/link/Elf/Thunk.zig b/src/link/Elf/Thunk.zig index 23dc2f3b0b..c5ddce7542 100644 --- a/src/link/Elf/Thunk.zig +++ b/src/link/Elf/Thunk.zig @@ -65,16 +65,10 @@ fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) usize { }; } -pub fn format( - thunk: Thunk, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +pub fn format(thunk: Thunk, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = thunk; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format Thunk directly"); } @@ -90,20 +84,14 @@ const FormatContext = struct { elf_file: *Elf, }; -fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const thunk = ctx.thunk; const elf_file = ctx.elf_file; - try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) }); + try bw.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) }); for (thunk.symbols.keys()) |ref| { const sym = elf_file.symbol(ref).?; - try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value }); + try bw.print(" {f} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value }); } } diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index f4b340a549..7bf293f144 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -35,9 +35,6 @@ lazy_syms: LazySymbolTable = .{}, /// Table of tracked `Nav`s. navs: NavTable = .{}, -/// TLS variables indexed by Atom.Index. -tls_variables: TlsTable = .{}, - /// Table of tracked `Uav`s. uavs: UavTable = .{}, @@ -257,7 +254,6 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { meta.exports.deinit(allocator); } self.uavs.deinit(allocator); - self.tls_variables.deinit(allocator); if (self.dwarf) |*dwarf| { dwarf.deinit(); @@ -925,7 +921,7 @@ pub fn getNavVAddr( const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index }); + log.debug("getNavVAddr {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); const this_sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol( elf_file, nav.name.toSlice(ip), @@ -1268,7 +1264,7 @@ fn updateNavCode( const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - log.debug("updateNavCode {}({d})", .{ nav.fqn.fmt(ip), nav_index }); + log.debug("updateNavCode {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; const required_alignment = switch (pt.navAlignment(nav_index)) { @@ -1302,7 +1298,7 @@ fn updateNavCode( self.allocateAtom(atom_ptr, true, elf_file) catch |err| return elf_file.base.cgFail(nav_index, "failed to allocate atom: {s}", .{@errorName(err)}); - log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value }); + log.debug("growing {f} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value }); if (old_vaddr != atom_ptr.value) { sym.value = 0; esym.st_value = 0; @@ -1347,7 +1343,7 @@ fn updateNavCode( const file_offset = atom_ptr.offset(elf_file); elf_file.base.file.?.pwriteAll(code, file_offset) catch |err| return elf_file.base.cgFail(nav_index, "failed to write to output file: {s}", .{@errorName(err)}); - log.debug("writing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len }); + log.debug("writing {f} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len }); } } @@ -1365,7 +1361,7 @@ fn updateTlv( const gpa = zcu.gpa; const nav = ip.getNav(nav_index); - log.debug("updateTlv {}({d})", .{ nav.fqn.fmt(ip), nav_index }); + log.debug("updateTlv {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); const required_alignment = pt.navAlignment(nav_index); @@ -1386,9 +1382,6 @@ fn updateTlv( atom_ptr.alignment = required_alignment; atom_ptr.size = code.len; - const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index); - assert(!gop.found_existing); // TODO incremental updates - self.allocateAtom(atom_ptr, true, elf_file) catch |err| return elf_file.base.cgFail(nav_index, "failed to allocate atom: {s}", .{@errorName(err)}); sym.value = 0; @@ -1424,7 +1417,7 @@ pub fn updateFunc( const gpa = elf_file.base.comp.gpa; const func = zcu.funcInfo(func_index); - log.debug("updateFunc {}({d})", .{ ip.getNav(func.owner_nav).fqn.fmt(ip), func.owner_nav }); + log.debug("updateFunc {f}({d})", .{ ip.getNav(func.owner_nav).fqn.fmt(ip), func.owner_nav }); const sym_index = try self.getOrCreateMetadataForNav(zcu, func.owner_nav); self.atom(self.symbol(sym_index).ref.index).?.freeRelocs(self); @@ -1447,7 +1440,7 @@ pub fn updateFunc( const code = code_buffer.items; const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, sym_index, code); - log.debug("setting shdr({x},{s}) for {}", .{ + log.debug("setting shdr({x},{s}) for {f}", .{ shndx, elf_file.getShString(elf_file.sections.items(.shdr)[shndx].sh_name), ip.getNav(func.owner_nav).fqn.fmt(ip), @@ -1529,7 +1522,7 @@ pub fn updateNav( const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index }); + log.debug("updateNav {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) { .func => .none, @@ -1546,7 +1539,6 @@ pub fn updateNav( defer debug_wip_nav.deinit(); dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, - error.Overflow => return error.Overflow, else => |e| return elf_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}), }; } @@ -1576,7 +1568,7 @@ pub fn updateNav( const code = code_buffer.items; const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code); - log.debug("setting shdr({x},{s}) for {}", .{ + log.debug("setting shdr({x},{s}) for {f}", .{ shndx, elf_file.getShString(elf_file.sections.items(.shdr)[shndx].sh_name), nav.fqn.fmt(ip), @@ -1588,7 +1580,6 @@ pub fn updateNav( if (debug_wip_nav) |*wip_nav| self.dwarf.?.finishWipNav(pt, nav_index, wip_nav) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, - error.Overflow => return error.Overflow, else => |e| return elf_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}), }; } else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index); @@ -1622,7 +1613,7 @@ fn updateLazySymbol( defer code_buffer.deinit(gpa); const name_str_index = blk: { - const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{ + const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ @tagName(sym.kind), Type.fromInterned(sym.ty).fmt(pt), }); @@ -2207,25 +2198,19 @@ const FormatContext = struct { elf_file: *Elf, }; -fn formatSymtab( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const self = ctx.self; const elf_file = ctx.elf_file; - try writer.writeAll(" locals\n"); + try bw.writeAll(" locals\n"); for (self.local_symbols.items) |index| { const local = self.symbols.items[index]; - try writer.print(" {}\n", .{local.fmt(elf_file)}); + try bw.print(" {f}\n", .{local.fmt(elf_file)}); } - try writer.writeAll(" globals\n"); + try bw.writeAll(" globals\n"); for (ctx.self.global_symbols.items) |index| { const global = self.symbols.items[index]; - try writer.print(" {}\n", .{global.fmt(elf_file)}); + try bw.print(" {f}\n", .{global.fmt(elf_file)}); } } @@ -2236,18 +2221,12 @@ pub fn fmtAtoms(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatAtoms) } }; } -fn formatAtoms( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatAtoms(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; - try writer.writeAll(" atoms\n"); + try bw.writeAll(" atoms\n"); for (ctx.self.atoms_indexes.items) |atom_index| { const atom_ptr = ctx.self.atom(atom_index) orelse continue; - try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)}); + try bw.print(" {f}\n", .{atom_ptr.fmt(ctx.elf_file)}); } } @@ -2285,7 +2264,7 @@ fn checkNavAllocated(pt: Zcu.PerThread, index: InternPool.Nav.Index, meta: AvMet const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(index); - log.err("NAV {}({d}) assigned symbol {d} but not allocated!", .{ + log.err("NAV {f}({d}) assigned symbol {d} but not allocated!", .{ nav.fqn.fmt(ip), index, meta.symbol_index, @@ -2298,7 +2277,7 @@ fn checkUavAllocated(pt: Zcu.PerThread, index: InternPool.Index, meta: AvMetadat const zcu = pt.zcu; const uav = Value.fromInterned(index); const ty = uav.typeOf(zcu); - log.err("UAV {}({d}) assigned symbol {d} but not allocated!", .{ + log.err("UAV {f}({d}) assigned symbol {d} but not allocated!", .{ ty.fmt(pt), index, meta.symbol_index, diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index a8492a1689..60a7741f78 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -49,14 +49,12 @@ pub const Fde = struct { pub fn format( fde: Fde, + bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: *std.io.BufferedWriter, ) !void { _ = fde; _ = unused_fmt_string; - _ = options; - _ = writer; + _ = bw; @compileError("do not format FDEs directly"); } @@ -74,24 +72,22 @@ pub const Fde = struct { fn format2( ctx: FdeFormatContext, + bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: *std.io.BufferedWriter, ) !void { _ = unused_fmt_string; - _ = options; const fde = ctx.fde; const elf_file = ctx.elf_file; const base_addr = fde.address(elf_file); const object = elf_file.file(fde.file_index).?.object; const atom_name = fde.atom(object).name(elf_file); - try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{ + try bw.print("@{x} : size({x}) : cie({d}) : {s}", .{ base_addr + fde.out_offset, fde.calcSize(), fde.cie_index, atom_name, }); - if (!fde.alive) try writer.writeAll(" : [*]"); + if (!fde.alive) try bw.writeAll(" : [*]"); } }; @@ -152,14 +148,12 @@ pub const Cie = struct { pub fn format( cie: Cie, + bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: *std.io.BufferedWriter, ) !void { _ = cie; _ = unused_fmt_string; - _ = options; - _ = writer; + _ = bw; @compileError("do not format CIEs directly"); } @@ -177,26 +171,23 @@ pub const Cie = struct { fn format2( ctx: CieFormatContext, + bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: *std.io.BufferedWriter, ) !void { _ = unused_fmt_string; - _ = options; const cie = ctx.cie; const elf_file = ctx.elf_file; const base_addr = cie.address(elf_file); - try writer.print("@{x} : size({x})", .{ + try bw.print("@{x} : size({x})", .{ base_addr + cie.out_offset, cie.calcSize(), }); - if (!cie.alive) try writer.writeAll(" : [*]"); + if (!cie.alive) try bw.writeAll(" : [*]"); } }; pub const Iterator = struct { - data: []const u8, - pos: usize = 0, + br: std.io.BufferedReader, pub const Record = struct { tag: enum { fde, cie }, @@ -205,22 +196,18 @@ pub const Iterator = struct { }; pub fn next(it: *Iterator) !?Record { - if (it.pos >= it.data.len) return null; + if (it.br.seek >= it.br.storageBuffer().len) return null; - var stream = std.io.fixedBufferStream(it.data[it.pos..]); - const reader = stream.reader(); + const size = try it.br.takeInt(u32, .little); + if (size == 0xFFFFFFFF) @panic("DWARF CFI is 32bit on macOS"); - const size = try reader.readInt(u32, .little); - if (size == 0) return null; - if (size == 0xFFFFFFFF) @panic("TODO"); - - const id = try reader.readInt(u32, .little); - const record = Record{ + const id = try it.br.takeInt(u32, .little); + const record: Record = .{ .tag = if (id == 0) .cie else .fde, - .offset = it.pos, + .offset = it.br.seek, .size = size, }; - it.pos += size + 4; + try it.br.discard(size); return record; } @@ -316,7 +303,7 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: const S = math.cast(i64, sym.address(.{}, elf_file)) orelse return error.Overflow; const A = rel.r_addend; - relocs_log.debug(" {s}: {x}: [{x} => {x}] ({s})", .{ + relocs_log.debug(" {f}: {x}: [{x} => {x}] ({s})", .{ relocation.fmtRelocType(rel.r_type(), cpu_arch), offset, P, @@ -332,7 +319,7 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: } } -pub fn writeEhFrame(elf_file: *Elf, writer: *std.io.BufferedWriter) !void { +pub fn writeEhFrame(elf_file: *Elf, bw: *std.io.BufferedWriter) !void { relocs_log.debug("{x}: .eh_frame", .{ elf_file.sections.items(.shdr)[elf_file.section_indexes.eh_frame.?].sh_addr, }); @@ -356,7 +343,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: *std.io.BufferedWriter) !void { }; } - try writer.writeAll(contents); + try bw.writeAll(contents); } } @@ -384,22 +371,22 @@ pub fn writeEhFrame(elf_file: *Elf, writer: *std.io.BufferedWriter) !void { }; } - try writer.writeAll(contents); + try bw.writeAll(contents); } } - try writer.writeInt(u32, 0, .little); + try bw.writeInt(u32, 0, .little); if (has_reloc_errors) return error.RelocFailure; } -pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: *std.io.BufferedWriter) !void { +pub fn writeEhFrameRelocatable(elf_file: *Elf, bw: *std.io.BufferedWriter) !void { for (elf_file.objects.items) |index| { const object = elf_file.file(index).?.object; for (object.cies.items) |cie| { if (!cie.alive) continue; - try writer.writeAll(cie.data(elf_file)); + try bw.writeAll(cie.data(elf_file)); } } @@ -418,7 +405,7 @@ pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: *std.io.BufferedWriter) ! .little, ); - try writer.writeAll(contents); + try bw.writeAll(contents); } } } @@ -438,7 +425,7 @@ fn emitReloc(elf_file: *Elf, r_offset: u64, sym: *const Symbol, rel: elf.Elf64_R }, } - relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{ + relocs_log.debug(" {f}: [{x} => {d}({s})] + {x}", .{ relocation.fmtRelocType(r_type, cpu_arch), r_offset, r_sym, @@ -495,14 +482,14 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, relocs: *std.ArrayList(elf.Elf64_Rela) } } -pub fn writeEhFrameHdr(elf_file: *Elf, writer: *std.io.BufferedWriter) !void { +pub fn writeEhFrameHdr(elf_file: *Elf, bw: *std.io.BufferedWriter) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; - try writer.writeByte(1); // version - try writer.writeByte(DW_EH_PE.pcrel | DW_EH_PE.sdata4); - try writer.writeByte(DW_EH_PE.udata4); - try writer.writeByte(DW_EH_PE.datarel | DW_EH_PE.sdata4); + try bw.writeByte(1); // version + try bw.writeByte(DW_EH_PE.pcrel | DW_EH_PE.sdata4); + try bw.writeByte(DW_EH_PE.udata4); + try bw.writeByte(DW_EH_PE.datarel | DW_EH_PE.sdata4); const shdrs = elf_file.sections.items(.shdr); const eh_frame_shdr = shdrs[elf_file.section_indexes.eh_frame.?]; @@ -513,7 +500,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: *std.io.BufferedWriter) !void { const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0); break :existing_size sym.atom(elf_file).?.size; }; - try writer.writeInt( + try bw.writeInt( u32, @as(u32, @bitCast(@as( i32, @@ -521,7 +508,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: *std.io.BufferedWriter) !void { ))), .little, ); - try writer.writeInt(u32, num_fdes, .little); + try bw.writeInt(u32, num_fdes, .little); const Entry = struct { init_addr: u32, @@ -561,7 +548,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: *std.io.BufferedWriter) !void { } std.mem.sort(Entry, entries.items, {}, Entry.lessThan); - try writer.writeAll(std.mem.sliceAsBytes(entries.items)); + try bw.writeAll(std.mem.sliceAsBytes(entries.items)); } const eh_frame_hdr_header_size: usize = 12; @@ -607,11 +594,11 @@ const riscv = struct { fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void { const diags = &elf_file.base.comp.link_diags; var err = try diags.addErrorWithNotes(1); - try err.addMsg("invalid relocation type {} at offset 0x{x}", .{ + try err.addMsg("invalid relocation type {f} at offset 0x{x}", .{ relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch), rel.r_offset, }); - err.addNote("in {}:.eh_frame", .{elf_file.file(rec.file_index).?.fmtPath()}); + err.addNote("in {f}:.eh_frame", .{elf_file.file(rec.file_index).?.fmtPath()}); return error.RelocFailure; } diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index 7292f8ca5d..c6c9aea6b3 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -14,19 +14,13 @@ pub const File = union(enum) { return .{ .data = file }; } - fn formatPath( - file: File, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + fn formatPath(file: File, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; switch (file) { - .zig_object => |zo| try writer.writeAll(zo.basename), - .linker_defined => try writer.writeAll("(linker defined)"), - .object => |x| try writer.print("{}", .{x.fmtPath()}), - .shared_object => |x| try writer.print("{}", .{@as(Path, x.path)}), + .zig_object => |zo| try bw.writeAll(zo.basename), + .linker_defined => try bw.writeAll("(linker defined)"), + .object => |x| try bw.print("{f}", .{x.fmtPath()}), + .shared_object => |x| try bw.print("{f}", .{x.path}), } } diff --git a/src/link/Elf/gc.zig b/src/link/Elf/gc.zig index 43b0ca843f..3a702e53a4 100644 --- a/src/link/Elf/gc.zig +++ b/src/link/Elf/gc.zig @@ -111,7 +111,7 @@ fn markLive(atom: *Atom, elf_file: *Elf) void { const target_sym = elf_file.symbol(ref) orelse continue; const target_atom = target_sym.atom(elf_file) orelse continue; target_atom.alive = true; - gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index }); + gc_track_live_log.debug("{f}marking live atom({d})", .{ track_live_level, target_atom.atom_index }); if (markAtom(target_atom)) markLive(target_atom, elf_file); } } @@ -128,7 +128,7 @@ fn markLive(atom: *Atom, elf_file: *Elf) void { } const target_atom = target_sym.atom(elf_file) orelse continue; target_atom.alive = true; - gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index }); + gc_track_live_log.debug("{f}marking live atom({d})", .{ track_live_level, target_atom.atom_index }); if (markAtom(target_atom)) markLive(target_atom, elf_file); } } @@ -170,7 +170,7 @@ pub fn dumpPrunedAtoms(elf_file: *Elf) !void { for (file.atoms()) |atom_index| { const atom = file.atom(atom_index) orelse continue; if (!atom.alive) - try stderr.print("link: removing unused section '{s}' in file '{}'\n", .{ + try stderr.print("link: removing unused section '{s}' in file '{f}'\n", .{ atom.name(elf_file), atom.file(elf_file).?.fmtPath(), }); @@ -185,15 +185,9 @@ const Level = struct { self.value += 1; } - pub fn format( - self: *const @This(), - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(self: *const @This(), bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; - try writer.writeByteNTimes(' ', self.value); + try bw.splatByteAll(' ', self.value); } }; diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index cd7a403ab1..bd35b51dbf 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -31,7 +31,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void { try elf_file.allocateNonAllocSections(); if (build_options.enable_logging) { - state_log.debug("{}", .{elf_file.dumpState()}); + state_log.debug("{f}", .{elf_file.dumpState()}); } try elf_file.writeMergeSections(); @@ -96,36 +96,35 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void { }; if (build_options.enable_logging) { - state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(elf_file)}); - state_log.debug("ar_strtab\n{}\n", .{ar_strtab}); + state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)}); + state_log.debug("ar_strtab\n{f}\n", .{ar_strtab}); } - var buffer = std.ArrayList(u8).init(gpa); - defer buffer.deinit(); - try buffer.ensureTotalCapacityPrecise(total_size); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, total_size)); + defer gpa.free(bw.buffer); // Write magic - try buffer.writer().writeAll(elf.ARMAG); + try bw.writeAll(elf.ARMAG); // Write symtab - try ar_symtab.write(.p64, elf_file, buffer.writer()); + try ar_symtab.write(.p64, elf_file, &bw); // Write strtab if (ar_strtab.size() > 0) { - if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); - try ar_strtab.write(buffer.writer()); + if (!mem.isAligned(bw.count, 2)) try bw.writeByte(0); + try ar_strtab.write(&bw); } // Write object files for (files.items) |index| { - if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); - try elf_file.file(index).?.writeAr(elf_file, buffer.writer()); + if (!mem.isAligned(bw.count, 2)) try bw.writeByte(0); + try elf_file.file(index).?.writeAr(elf_file, &bw); } - assert(buffer.items.len == total_size); - + assert(bw.end == bw.buffer.len); try elf_file.base.file.?.setEndPos(total_size); - try elf_file.base.file.?.pwriteAll(buffer.items, 0); + try elf_file.base.file.?.pwriteAll(bw.buffer, 0); if (diags.hasErrors()) return error.LinkFailure; } @@ -170,7 +169,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void { try elf_file.allocateNonAllocSections(); if (build_options.enable_logging) { - state_log.debug("{}", .{elf_file.dumpState()}); + state_log.debug("{f}", .{elf_file.dumpState()}); } try writeAtoms(elf_file); @@ -407,17 +406,16 @@ fn writeSyntheticSections(elf_file: *Elf) !void { }; const shdr = slice.items(.shdr)[shndx]; const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; - var buffer: std.io.AllocatingWriter = undefined; - const bw = buffer.init(gpa); - defer buffer.deinit(); - try buffer.ensureTotalCapacity(gpa, sh_size - existing_size); - try eh_frame.writeEhFrameRelocatable(elf_file, bw); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, sh_size - existing_size)); + defer gpa.free(bw.buffer); + try eh_frame.writeEhFrameRelocatable(elf_file, &bw); log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{ shdr.sh_offset + existing_size, shdr.sh_offset + sh_size, }); - assert(buffer.getWritten().len == sh_size - existing_size); - try elf_file.base.file.?.pwriteAll(buffer.getWritten(), shdr.sh_offset + existing_size); + assert(bw.end == bw.buffer.len); + try elf_file.base.file.?.pwriteAll(bw.buffer, shdr.sh_offset + existing_size); } if (elf_file.section_indexes.eh_frame_rela) |shndx| { const shdr = slice.items(.shdr)[shndx]; diff --git a/src/link/Elf/relocation.zig b/src/link/Elf/relocation.zig index 047312cd68..70214373d2 100644 --- a/src/link/Elf/relocation.zig +++ b/src/link/Elf/relocation.zig @@ -148,19 +148,13 @@ pub fn fmtRelocType(r_type: u32, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatte } }; } -fn formatRelocType( - ctx: FormatRelocTypeCtx, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatRelocType(ctx: FormatRelocTypeCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const r_type = ctx.r_type; switch (ctx.cpu_arch) { - .x86_64 => try writer.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}), - .aarch64 => try writer.print("R_AARCH64_{s}", .{@tagName(@as(elf.R_AARCH64, @enumFromInt(r_type)))}), - .riscv64 => try writer.print("R_RISCV_{s}", .{@tagName(@as(elf.R_RISCV, @enumFromInt(r_type)))}), + .x86_64 => try bw.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}), + .aarch64 => try bw.print("R_AARCH64_{s}", .{@tagName(@as(elf.R_AARCH64, @enumFromInt(r_type)))}), + .riscv64 => try bw.print("R_RISCV_{s}", .{@tagName(@as(elf.R_RISCV, @enumFromInt(r_type)))}), else => unreachable, } } diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index aca0c17d0c..8de6ecbe56 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -94,115 +94,115 @@ pub const DynamicSection = struct { return nentries * @sizeOf(elf.Elf64_Dyn); } - pub fn write(dt: DynamicSection, elf_file: *Elf, writer: anytype) !void { + pub fn write(dt: DynamicSection, elf_file: *Elf, bw: *std.io.BufferedWriter) anyerror!void { const shdrs = elf_file.sections.items(.shdr); // NEEDED for (dt.needed.items) |off| { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NEEDED, .d_val = off }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NEEDED, .d_val = off }); } if (dt.soname) |off| { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SONAME, .d_val = off }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SONAME, .d_val = off }); } // RUNPATH // TODO add option in Options to revert to old RPATH tag if (dt.rpath > 0) { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RUNPATH, .d_val = dt.rpath }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RUNPATH, .d_val = dt.rpath }); } // INIT if (elf_file.sectionByName(".init")) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT, .d_val = addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT, .d_val = addr }); } // FINI if (elf_file.sectionByName(".fini")) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI, .d_val = addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI, .d_val = addr }); } // INIT_ARRAY if (elf_file.sectionByName(".init_array")) |shndx| { const shdr = shdrs[shndx]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAY, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAYSZ, .d_val = shdr.sh_size }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAY, .d_val = shdr.sh_addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAYSZ, .d_val = shdr.sh_size }); } // FINI_ARRAY if (elf_file.sectionByName(".fini_array")) |shndx| { const shdr = shdrs[shndx]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAY, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAYSZ, .d_val = shdr.sh_size }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAY, .d_val = shdr.sh_addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAYSZ, .d_val = shdr.sh_size }); } // RELA if (elf_file.section_indexes.rela_dyn) |shndx| { const shdr = shdrs[shndx]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELA, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELASZ, .d_val = shdr.sh_size }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELAENT, .d_val = shdr.sh_entsize }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELA, .d_val = shdr.sh_addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELASZ, .d_val = shdr.sh_size }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELAENT, .d_val = shdr.sh_entsize }); } // JMPREL if (elf_file.section_indexes.rela_plt) |shndx| { const shdr = shdrs[shndx]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_JMPREL, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTRELSZ, .d_val = shdr.sh_size }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTREL, .d_val = elf.DT_RELA }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_JMPREL, .d_val = shdr.sh_addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTRELSZ, .d_val = shdr.sh_size }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTREL, .d_val = elf.DT_RELA }); } // PLTGOT if (elf_file.section_indexes.got_plt) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTGOT, .d_val = addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTGOT, .d_val = addr }); } { assert(elf_file.section_indexes.hash != null); const addr = shdrs[elf_file.section_indexes.hash.?].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_HASH, .d_val = addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_HASH, .d_val = addr }); } if (elf_file.section_indexes.gnu_hash) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_GNU_HASH, .d_val = addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_GNU_HASH, .d_val = addr }); } // TEXTREL if (elf_file.has_text_reloc) { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_TEXTREL, .d_val = 0 }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_TEXTREL, .d_val = 0 }); } // SYMTAB + SYMENT { assert(elf_file.section_indexes.dynsymtab != null); const shdr = shdrs[elf_file.section_indexes.dynsymtab.?]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMTAB, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMENT, .d_val = shdr.sh_entsize }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMTAB, .d_val = shdr.sh_addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMENT, .d_val = shdr.sh_entsize }); } // STRTAB + STRSZ { assert(elf_file.section_indexes.dynstrtab != null); const shdr = shdrs[elf_file.section_indexes.dynstrtab.?]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRTAB, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRSZ, .d_val = shdr.sh_size }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRTAB, .d_val = shdr.sh_addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRSZ, .d_val = shdr.sh_size }); } // VERSYM if (elf_file.section_indexes.versym) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERSYM, .d_val = addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERSYM, .d_val = addr }); } // VERNEED + VERNEEDNUM if (elf_file.section_indexes.verneed) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERNEED, .d_val = addr }); - try writer.writeStruct(elf.Elf64_Dyn{ + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERNEED, .d_val = addr }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERNEEDNUM, .d_val = elf_file.verneed.verneed.items.len, }); @@ -210,18 +210,18 @@ pub const DynamicSection = struct { // FLAGS if (dt.getFlags(elf_file)) |flags| { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS, .d_val = flags }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS, .d_val = flags }); } // FLAGS_1 if (dt.getFlags1(elf_file)) |flags_1| { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS_1, .d_val = flags_1 }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS_1, .d_val = flags_1 }); } // DEBUG - if (!elf_file.isEffectivelyDynLib()) try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_DEBUG, .d_val = 0 }); + if (!elf_file.isEffectivelyDynLib()) try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_DEBUG, .d_val = 0 }); // NULL - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NULL, .d_val = 0 }); + try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NULL, .d_val = 0 }); } }; @@ -360,7 +360,7 @@ pub const GotSection = struct { return s; } - pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void { + pub fn write(got: GotSection, elf_file: *Elf, bw: *std.io.BufferedWriter) anyerror!void { const comp = elf_file.base.comp; const is_dyn_lib = elf_file.isEffectivelyDynLib(); const apply_relocs = true; // TODO add user option for this @@ -381,47 +381,47 @@ pub const GotSection = struct { } break :blk value; }; - try writeInt(value, elf_file, writer); + try writeInt(value, elf_file, bw); }, .tlsld => { - try writeInt(if (is_dyn_lib) @as(u64, 0) else 1, elf_file, writer); - try writeInt(0, elf_file, writer); + try writeInt(if (is_dyn_lib) @as(u64, 0) else 1, elf_file, bw); + try writeInt(0, elf_file, bw); }, .tlsgd => { if (symbol.?.flags.import) { - try writeInt(0, elf_file, writer); - try writeInt(0, elf_file, writer); + try writeInt(0, elf_file, bw); + try writeInt(0, elf_file, bw); } else { - try writeInt(if (is_dyn_lib) @as(u64, 0) else 1, elf_file, writer); + try writeInt(if (is_dyn_lib) @as(u64, 0) else 1, elf_file, bw); const offset = symbol.?.address(.{}, elf_file) - elf_file.dtpAddress(); - try writeInt(offset, elf_file, writer); + try writeInt(offset, elf_file, bw); } }, .gottp => { if (symbol.?.flags.import) { - try writeInt(0, elf_file, writer); + try writeInt(0, elf_file, bw); } else if (is_dyn_lib) { const offset = if (apply_relocs) symbol.?.address(.{}, elf_file) - elf_file.tlsAddress() else 0; - try writeInt(offset, elf_file, writer); + try writeInt(offset, elf_file, bw); } else { const offset = symbol.?.address(.{}, elf_file) - elf_file.tpAddress(); - try writeInt(offset, elf_file, writer); + try writeInt(offset, elf_file, bw); } }, .tlsdesc => { if (symbol.?.flags.import) { - try writeInt(0, elf_file, writer); - try writeInt(0, elf_file, writer); + try writeInt(0, elf_file, bw); + try writeInt(0, elf_file, bw); } else { - try writeInt(0, elf_file, writer); + try writeInt(0, elf_file, bw); const offset = if (apply_relocs) symbol.?.address(.{}, elf_file) - elf_file.tlsAddress() else 0; - try writeInt(offset, elf_file, writer); + try writeInt(offset, elf_file, bw); } }, } @@ -615,20 +615,14 @@ pub const GotSection = struct { return .{ .data = .{ .got = got, .elf_file = elf_file } }; } - pub fn format2( - ctx: FormatCtx, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = options; + pub fn format2(ctx: FormatCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const got = ctx.got; const elf_file = ctx.elf_file; - try writer.writeAll("GOT\n"); + try bw.writeAll("GOT\n"); for (got.entries.items) |entry| { const symbol = elf_file.symbol(entry.ref).?; - try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{ + try bw.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{ entry.cell_index, entry.address(elf_file), entry.ref, @@ -678,11 +672,11 @@ pub const PltSection = struct { }; } - pub fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { + pub fn write(plt: PltSection, elf_file: *Elf, bw: *std.io.BufferedWriter) anyerror!void { const cpu_arch = elf_file.getTarget().cpu.arch; switch (cpu_arch) { - .x86_64 => try x86_64.write(plt, elf_file, writer), - .aarch64 => try aarch64.write(plt, elf_file, writer), + .x86_64 => try x86_64.write(plt, elf_file, bw), + .aarch64 => try aarch64.write(plt, elf_file, bw), else => return error.UnsupportedCpuArch, } } @@ -703,7 +697,7 @@ pub const PltSection = struct { const r_sym: u64 = extra.dynamic; const r_type = relocation.encode(.jump_slot, cpu_arch); - relocs_log.debug(" {s}: [{x} => {d}({s})] + 0", .{ + relocs_log.debug(" {f}: [{x} => {d}({s})] + 0", .{ relocation.fmtRelocType(r_type, cpu_arch), r_offset, r_sym, @@ -758,20 +752,14 @@ pub const PltSection = struct { return .{ .data = .{ .plt = plt, .elf_file = elf_file } }; } - pub fn format2( - ctx: FormatCtx, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = options; + pub fn format2(ctx: FormatCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const plt = ctx.plt; const elf_file = ctx.elf_file; - try writer.writeAll("PLT\n"); + try bw.writeAll("PLT\n"); for (plt.symbols.items, 0..) |ref, i| { const symbol = elf_file.symbol(ref).?; - try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{ + try bw.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{ i, symbol.pltAddress(elf_file), ref, @@ -782,7 +770,7 @@ pub const PltSection = struct { } const x86_64 = struct { - fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { + fn write(plt: PltSection, elf_file: *Elf, bw: *std.io.BufferedWriter) anyerror!void { const shdrs = elf_file.sections.items(.shdr); const plt_addr = shdrs[elf_file.section_indexes.plt.?].sh_addr; const got_plt_addr = shdrs[elf_file.section_indexes.got_plt.?].sh_addr; @@ -796,8 +784,8 @@ pub const PltSection = struct { mem.writeInt(i32, preamble[8..][0..4], @as(i32, @intCast(disp)), .little); disp = @as(i64, @intCast(got_plt_addr + 16)) - @as(i64, @intCast(plt_addr + 14)) - 4; mem.writeInt(i32, preamble[14..][0..4], @as(i32, @intCast(disp)), .little); - try writer.writeAll(&preamble); - try writer.writeByteNTimes(0xcc, preambleSize(.x86_64) - preamble.len); + try bw.writeAll(&preamble); + try bw.splatByteAll(0xcc, preambleSize(.x86_64) - preamble.len); for (plt.symbols.items, 0..) |ref, i| { const sym = elf_file.symbol(ref).?; @@ -811,13 +799,13 @@ pub const PltSection = struct { }; mem.writeInt(i32, entry[6..][0..4], @as(i32, @intCast(i)), .little); mem.writeInt(i32, entry[12..][0..4], @as(i32, @intCast(disp)), .little); - try writer.writeAll(&entry); + try bw.writeAll(&entry); } } }; const aarch64 = struct { - fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { + fn write(plt: PltSection, elf_file: *Elf, bw: *std.io.BufferedWriter) anyerror!void { { const shdrs = elf_file.sections.items(.shdr); const plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.plt.?].sh_addr); @@ -845,7 +833,7 @@ pub const PltSection = struct { }; comptime assert(preamble.len == 8); for (preamble) |inst| { - try writer.writeInt(u32, inst.toU32(), .little); + try bw.writeInt(u32, inst.toU32(), .little); } } @@ -864,7 +852,7 @@ pub const PltSection = struct { }; comptime assert(insts.len == 4); for (insts) |inst| { - try writer.writeInt(u32, inst.toU32(), .little); + try bw.writeInt(u32, inst.toU32(), .little); } } } @@ -883,22 +871,22 @@ pub const GotPltSection = struct { return preamble_size + elf_file.plt.symbols.items.len * 8; } - pub fn write(got_plt: GotPltSection, elf_file: *Elf, writer: anytype) !void { + pub fn write(got_plt: GotPltSection, elf_file: *Elf, bw: *std.io.BufferedWriter) anyerror!void { _ = got_plt; { // [0]: _DYNAMIC const symbol = elf_file.linkerDefinedPtr().?.dynamicSymbol(elf_file).?; - try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little); + try bw.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little); } // [1]: 0x0 // [2]: 0x0 - try writer.writeInt(u64, 0x0, .little); - try writer.writeInt(u64, 0x0, .little); + try bw.writeInt(u64, 0x0, .little); + try bw.writeInt(u64, 0x0, .little); if (elf_file.section_indexes.plt) |shndx| { const plt_addr = elf_file.sections.items(.shdr)[shndx].sh_addr; for (0..elf_file.plt.symbols.items.len) |_| { // [N]: .plt - try writer.writeInt(u64, plt_addr, .little); + try bw.writeInt(u64, plt_addr, .little); } } } @@ -934,11 +922,11 @@ pub const PltGotSection = struct { }; } - pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void { + pub fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *std.io.BufferedWriter) anyerror!void { const cpu_arch = elf_file.getTarget().cpu.arch; switch (cpu_arch) { - .x86_64 => try x86_64.write(plt_got, elf_file, writer), - .aarch64 => try aarch64.write(plt_got, elf_file, writer), + .x86_64 => try x86_64.write(plt_got, elf_file, bw), + .aarch64 => try aarch64.write(plt_got, elf_file, bw), else => return error.UnsupportedCpuArch, } } @@ -970,7 +958,7 @@ pub const PltGotSection = struct { } const x86_64 = struct { - pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void { + pub fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *std.io.BufferedWriter) anyerror!void { for (plt_got.symbols.items) |ref| { const sym = elf_file.symbol(ref).?; const target_addr = sym.gotAddress(elf_file); @@ -982,13 +970,13 @@ pub const PltGotSection = struct { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, }; mem.writeInt(i32, entry[6..][0..4], @as(i32, @intCast(disp)), .little); - try writer.writeAll(&entry); + try bw.writeAll(&entry); } } }; const aarch64 = struct { - fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void { + fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *std.io.BufferedWriter) anyerror!void { for (plt_got.symbols.items) |ref| { const sym = elf_file.symbol(ref).?; const target_addr = sym.gotAddress(elf_file); @@ -1003,7 +991,7 @@ pub const PltGotSection = struct { }; comptime assert(insts.len == 4); for (insts) |inst| { - try writer.writeInt(u32, inst.toU32(), .little); + try bw.writeInt(u32, inst.toU32(), .little); } } } @@ -1167,23 +1155,23 @@ pub const DynsymSection = struct { return @as(u32, @intCast(dynsym.entries.items.len + 1)); } - pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: anytype) !void { - try writer.writeStruct(Elf.null_sym); + pub fn write(dynsym: DynsymSection, elf_file: *Elf, bw: *std.io.BufferedWriter) anyerror!void { + try bw.writeStruct(Elf.null_sym); for (dynsym.entries.items) |entry| { const sym = elf_file.symbol(entry.ref).?; var out_sym: elf.Elf64_Sym = Elf.null_sym; sym.setOutputSym(elf_file, &out_sym); out_sym.st_name = entry.off; - try writer.writeStruct(out_sym); + try bw.writeStruct(out_sym); } } }; pub const HashSection = struct { - buffer: std.ArrayListUnmanaged(u8) = .empty, + buffer: []u32 = &.{}, - pub fn deinit(hs: *HashSection, allocator: Allocator) void { - hs.buffer.deinit(allocator); + pub fn deinit(hs: *HashSection, gpa: Allocator) void { + gpa.free(hs.buffer); } pub fn generate(hs: *HashSection, elf_file: *Elf) !void { @@ -1193,30 +1181,25 @@ pub const HashSection = struct { const gpa = comp.gpa; const nsyms = elf_file.dynsym.count(); - var buckets = try gpa.alloc(u32, nsyms); - defer gpa.free(buckets); - @memset(buckets, 0); + assert(hs.buffer.len == 0); + hs.buffer = try gpa.alloc(u32, 2 * (1 + nsyms)); - var chains = try gpa.alloc(u32, nsyms); - defer gpa.free(chains); + @memset(hs.buffer[0..2], std.mem.nativeToLittle(u32, @intCast(nsyms))); + const buckets = hs.buffer[2..][0..nsyms]; + @memset(buckets, 0); + const chains = hs.buffer[2 + nsyms ..][0..nsyms]; @memset(chains, 0); for (elf_file.dynsym.entries.items, 1..) |entry, i| { const name = elf_file.getDynString(entry.off); - const hash = hasher(name) % buckets.len; - chains[@as(u32, @intCast(i))] = buckets[hash]; - buckets[hash] = @as(u32, @intCast(i)); + const hash = hasher(name) % nsyms; + chains[i] = buckets[hash]; + buckets[hash] = std.mem.nativeToLittle(u32, @intCast(i)); } - - try hs.buffer.ensureTotalCapacityPrecise(gpa, (2 + nsyms * 2) * 4); - hs.buffer.writer(gpa).writeInt(u32, @as(u32, @intCast(nsyms)), .little) catch unreachable; - hs.buffer.writer(gpa).writeInt(u32, @as(u32, @intCast(nsyms)), .little) catch unreachable; - hs.buffer.writer(gpa).writeAll(mem.sliceAsBytes(buckets)) catch unreachable; - hs.buffer.writer(gpa).writeAll(mem.sliceAsBytes(chains)) catch unreachable; } pub inline fn size(hs: HashSection) usize { - return hs.buffer.items.len; + return @sizeOf(u32) * hs.buffer.len; } pub fn hasher(name: [:0]const u8) u32 { @@ -1266,17 +1249,14 @@ pub const GnuHashSection = struct { return header_size + hash.num_bloom * 8 + hash.num_buckets * 4 + hash.num_exports * 4; } - pub fn write(hash: GnuHashSection, elf_file: *Elf, writer: anytype) !void { + pub fn write(hash: GnuHashSection, elf_file: *Elf, br: *std.io.BufferedWriter) !void { const exports = getExports(elf_file); const export_off = elf_file.dynsym.count() - hash.num_exports; - var counting = std.io.countingWriter(writer); - const cwriter = counting.writer(); - - try cwriter.writeInt(u32, hash.num_buckets, .little); - try cwriter.writeInt(u32, export_off, .little); - try cwriter.writeInt(u32, hash.num_bloom, .little); - try cwriter.writeInt(u32, bloom_shift, .little); + try br.writeInt(u32, hash.num_buckets, .little); + try br.writeInt(u32, export_off, .little); + try br.writeInt(u32, hash.num_bloom, .little); + try br.writeInt(u32, bloom_shift, .little); const comp = elf_file.base.comp; const gpa = comp.gpa; @@ -1300,7 +1280,7 @@ pub const GnuHashSection = struct { bloom[idx] |= @as(u64, 1) << @as(u6, @intCast((h >> bloom_shift) % 64)); } - try cwriter.writeAll(mem.sliceAsBytes(bloom)); + try br.writeAll(mem.sliceAsBytes(bloom)); // Fill in the hash bucket indices const buckets = try gpa.alloc(u32, hash.num_buckets); @@ -1313,7 +1293,7 @@ pub const GnuHashSection = struct { } } - try cwriter.writeAll(mem.sliceAsBytes(buckets)); + try br.writeAll(mem.sliceAsBytes(buckets)); // Finally, write the hash table const table = try gpa.alloc(u32, hash.num_exports); @@ -1329,9 +1309,9 @@ pub const GnuHashSection = struct { } } - try cwriter.writeAll(mem.sliceAsBytes(table)); + try br.writeAll(mem.sliceAsBytes(table)); - assert(counting.bytes_written == hash.size()); + assert(br.count == hash.size()); } pub fn hasher(name: [:0]const u8) u32 { @@ -1478,9 +1458,9 @@ pub const VerneedSection = struct { return vern.verneed.items.len * @sizeOf(elf.Elf64_Verneed) + vern.vernaux.items.len * @sizeOf(elf.Vernaux); } - pub fn write(vern: VerneedSection, writer: anytype) !void { - try writer.writeAll(mem.sliceAsBytes(vern.verneed.items)); - try writer.writeAll(mem.sliceAsBytes(vern.vernaux.items)); + pub fn write(vern: VerneedSection, bw: *std.io.BufferedWriter) anyerror!void { + try bw.writeAll(mem.sliceAsBytes(vern.verneed.items)); + try bw.writeAll(mem.sliceAsBytes(vern.vernaux.items)); } }; @@ -1506,11 +1486,11 @@ pub const GroupSection = struct { return (members.len + 1) * @sizeOf(u32); } - pub fn write(cgs: GroupSection, elf_file: *Elf, writer: anytype) !void { + pub fn write(cgs: GroupSection, elf_file: *Elf, bw: *std.io.BufferedWriter) !void { const cg = cgs.group(elf_file); const object = cg.file(elf_file).object; const members = cg.members(elf_file); - try writer.writeInt(u32, if (cg.is_comdat) elf.GRP_COMDAT else 0, .little); + try bw.writeInt(u32, if (cg.is_comdat) elf.GRP_COMDAT else 0, .little); for (members) |shndx| { const shdr = object.shdrs.items[shndx]; switch (shdr.sh_type) { @@ -1522,26 +1502,26 @@ pub const GroupSection = struct { atom.output_section_index == rela_shdr.sh_info) break rela_shndx; } else unreachable; - try writer.writeInt(u32, @intCast(rela_shndx), .little); + try bw.writeInt(u32, @intCast(rela_shndx), .little); }, else => { const atom_index = object.atoms_indexes.items[shndx]; const atom = object.atom(atom_index).?; - try writer.writeInt(u32, atom.output_section_index, .little); + try bw.writeInt(u32, atom.output_section_index, .little); }, } } } }; -fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void { +fn writeInt(value: anytype, elf_file: *Elf, bw: *std.io.BufferedWriter) anyerror!void { const entry_size = elf_file.archPtrWidthBytes(); const target = elf_file.getTarget(); const endian = target.cpu.arch.endian(); switch (entry_size) { - 2 => try writer.writeInt(u16, @intCast(value), endian), - 4 => try writer.writeInt(u32, @intCast(value), endian), - 8 => try writer.writeInt(u64, @intCast(value), endian), + 2 => try bw.writeInt(u16, @intCast(value), endian), + 4 => try bw.writeInt(u32, @intCast(value), endian), + 8 => try bw.writeInt(u64, @intCast(value), endian), else => unreachable, } } diff --git a/src/link/LdScript.zig b/src/link/LdScript.zig index ed5dbc4681..eadde7ce6c 100644 --- a/src/link/LdScript.zig +++ b/src/link/LdScript.zig @@ -41,7 +41,7 @@ pub fn parse( try line_col.append(gpa, .{ .line = line, .column = column }); switch (tok.id) { .invalid => { - return diags.failParse(path, "invalid token in LD script: '{s}' ({d}:{d})", .{ + return diags.failParse(path, "invalid token in LD script: '{f}' ({d}:{d})", .{ std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column, }); }, diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 7443435264..57d7019e22 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -41,9 +41,9 @@ data_in_code_cmd: macho.linkedit_data_command = .{ .cmd = .DATA_IN_CODE }, uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 }, codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE }, -pagezero_seg_index: ?u8 = null, -text_seg_index: ?u8 = null, -linkedit_seg_index: ?u8 = null, +pagezero_seg_index: ?u4 = null, +text_seg_index: ?u4 = null, +linkedit_seg_index: ?u4 = null, text_sect_index: ?u8 = null, data_sect_index: ?u8 = null, got_sect_index: ?u8 = null, @@ -76,10 +76,10 @@ unwind_info: UnwindInfo = .{}, data_in_code: DataInCode = .{}, /// Tracked loadable segments during incremental linking. -zig_text_seg_index: ?u8 = null, -zig_const_seg_index: ?u8 = null, -zig_data_seg_index: ?u8 = null, -zig_bss_seg_index: ?u8 = null, +zig_text_seg_index: ?u4 = null, +zig_const_seg_index: ?u4 = null, +zig_data_seg_index: ?u4 = null, +zig_bss_seg_index: ?u4 = null, /// Tracked section headers with incremental updates to Zig object. zig_text_sect_index: ?u8 = null, @@ -543,7 +543,7 @@ pub fn flush( self.allocateSyntheticSymbols(); if (build_options.enable_logging) { - state_log.debug("{}", .{self.dumpState()}); + state_log.debug("{f}", .{self.dumpState()}); } // Beyond this point, everything has been allocated a virtual address and we can resolve @@ -591,6 +591,7 @@ pub fn flush( error.NoSpaceLeft => unreachable, error.OutOfMemory => return error.OutOfMemory, error.LinkFailure => return error.LinkFailure, + else => unreachable, }; try self.writeHeader(ncmds, sizeofcmds); self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) { @@ -677,12 +678,12 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { try argv.append("-platform_version"); try argv.append(@tagName(self.platform.os_tag)); - try argv.append(try std.fmt.allocPrint(arena, "{}", .{self.platform.version})); + try argv.append(try std.fmt.allocPrint(arena, "{f}", .{self.platform.version})); if (self.sdk_version) |ver| { try argv.append(try std.fmt.allocPrint(arena, "{d}.{d}", .{ ver.major, ver.minor })); } else { - try argv.append(try std.fmt.allocPrint(arena, "{}", .{self.platform.version})); + try argv.append(try std.fmt.allocPrint(arena, "{f}", .{self.platform.version})); } if (comp.sysroot) |syslibroot| { @@ -863,7 +864,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void { const path, const file = input.pathAndFile().?; // TODO don't classify now, it's too late. The input file has already been classified - log.debug("classifying input file {}", .{path}); + log.debug("classifying input file {f}", .{path}); const fh = try self.addFileHandle(file); var buffer: [Archive.SARMAG]u8 = undefined; @@ -1074,7 +1075,7 @@ fn accessLibPath( for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { test_path.clearRetainingCapacity(); - try test_path.writer().print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext }); + try test_path.print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext }); try checked_paths.append(try arena.dupe(u8, test_path.items)); fs.cwd().access(test_path.items, .{}) catch |err| switch (err) { error.FileNotFound => continue, @@ -1097,7 +1098,7 @@ fn accessFrameworkPath( for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { test_path.clearRetainingCapacity(); - try test_path.writer().print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{ + try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{ search_dir, name, name, @@ -1178,9 +1179,9 @@ fn parseDependentDylibs(self: *MachO) !void { for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { test_path.clearRetainingCapacity(); if (self.base.comp.sysroot) |root| { - try test_path.writer().print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext }); + try test_path.print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext }); } else { - try test_path.writer().print("{s}{s}", .{ path, ext }); + try test_path.print("{s}{s}", .{ path, ext }); } try checked_paths.append(try arena.dupe(u8, test_path.items)); fs.cwd().access(test_path.items, .{}) catch |err| switch (err) { @@ -1591,7 +1592,7 @@ fn reportUndefs(self: *MachO) !void { const ref = refs.items[inote]; const file = self.getFile(ref.file).?; const atom = ref.getAtom(self).?; - err.addNote("referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) }); + err.addNote("referenced by {f}:{s}", .{ file.fmtPath(), atom.getName(self) }); } if (refs.items.len > max_notes) { @@ -2131,7 +2132,7 @@ fn initSegments(self: *MachO) !void { mem.sort(Entry, entries.items, self, Entry.lessThan); - const backlinks = try gpa.alloc(u8, entries.items.len); + const backlinks = try gpa.alloc(u4, entries.items.len); defer gpa.free(backlinks); for (entries.items, 0..) |entry, i| { backlinks[entry.index] = @intCast(i); @@ -2145,7 +2146,7 @@ fn initSegments(self: *MachO) !void { self.segments.appendAssumeCapacity(segments[sorted.index]); } - for (&[_]*?u8{ + for (&[_]*?u4{ &self.pagezero_seg_index, &self.text_seg_index, &self.linkedit_seg_index, @@ -2163,7 +2164,7 @@ fn initSegments(self: *MachO) !void { for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| { const segname = header.segName(); const segment_id = self.getSegmentByName(segname) orelse blk: { - const segment_id = @as(u8, @intCast(self.segments.items.len)); + const segment_id: u4 = @intCast(self.segments.items.len); const protection = getSegmentProt(segname); try self.segments.append(gpa, .{ .cmdsize = @sizeOf(macho.segment_command_64), @@ -2526,10 +2527,9 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void { const doWork = struct { fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void { - const off = try macho_file.cast(usize, th.value); - const size = th.size(); - var stream = std.io.fixedBufferStream(buffer[off..][0..size]); - try th.write(macho_file, stream.writer()); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(buffer[try macho_file.cast(usize, th.value)..][0..th.size()]); + try th.write(macho_file, &bw); } }.doWork; const out = self.sections.items(.out)[thunk.out_n_sect].items; @@ -2556,15 +2556,16 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void { const doWork = struct { fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void { - var stream = std.io.fixedBufferStream(buffer); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(buffer); switch (tag) { .eh_frame => eh_frame.write(macho_file, buffer), - .unwind_info => try macho_file.unwind_info.write(macho_file, buffer), - .got => try macho_file.got.write(macho_file, stream.writer()), - .stubs => try macho_file.stubs.write(macho_file, stream.writer()), - .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, stream.writer()), - .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, stream.writer()), - .objc_stubs => try macho_file.objc_stubs.write(macho_file, stream.writer()), + .unwind_info => try macho_file.unwind_info.write(macho_file, &bw), + .got => try macho_file.got.write(macho_file, &bw), + .stubs => try macho_file.stubs.write(macho_file, &bw), + .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, &bw), + .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, &bw), + .objc_stubs => try macho_file.objc_stubs.write(macho_file, &bw), } } }.doWork; @@ -2605,8 +2606,9 @@ fn updateLazyBindSizeWorker(self: *MachO) void { try macho_file.lazy_bind_section.updateSize(macho_file); const sect_id = macho_file.stubs_helper_sect_index.?; const out = &macho_file.sections.items(.out)[sect_id]; - var stream = std.io.fixedBufferStream(out.items); - try macho_file.stubs_helper.write(macho_file, stream.writer()); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(out.items); + try macho_file.stubs_helper.write(macho_file, &bw); } }.doWork; doWork(self) catch |err| @@ -2665,23 +2667,21 @@ fn writeDyldInfo(self: *MachO) !void { needed_size += cmd.lazy_bind_size; needed_size += cmd.export_size; - const buffer = try gpa.alloc(u8, needed_size); - defer gpa.free(buffer); - @memset(buffer, 0); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, needed_size)); + defer gpa.free(bw.buffer); + @memset(bw.buffer, 0); - var stream = std.io.fixedBufferStream(buffer); - const writer = stream.writer(); - - try self.rebase_section.write(writer); - try stream.seekTo(cmd.bind_off - base_off); - try self.bind_section.write(writer); - try stream.seekTo(cmd.weak_bind_off - base_off); - try self.weak_bind_section.write(writer); - try stream.seekTo(cmd.lazy_bind_off - base_off); - try self.lazy_bind_section.write(writer); - try stream.seekTo(cmd.export_off - base_off); - try self.export_trie.write(writer); - try self.pwriteAll(buffer, cmd.rebase_off); + try self.rebase_section.write(&bw); + bw.end = cmd.bind_off - base_off; + try self.bind_section.write(&bw); + bw.end = cmd.weak_bind_off - base_off; + try self.weak_bind_section.write(&bw); + bw.end = cmd.lazy_bind_off - base_off; + try self.lazy_bind_section.write(&bw); + bw.end = cmd.export_off - base_off; + try self.export_trie.write(&bw); + try self.pwriteAll(bw.buffer, cmd.rebase_off); } pub fn writeDataInCode(self: *MachO) !void { @@ -2689,22 +2689,30 @@ pub fn writeDataInCode(self: *MachO) !void { defer tracy.end(); const gpa = self.base.comp.gpa; const cmd = self.data_in_code_cmd; - var buffer = try std.ArrayList(u8).initCapacity(gpa, self.data_in_code.size()); - defer buffer.deinit(); - try self.data_in_code.write(self, buffer.writer()); - try self.pwriteAll(buffer.items, cmd.dataoff); + + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, self.data_in_code.size())); + defer gpa.free(bw.buffer); + + try self.data_in_code.write(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, cmd.dataoff); } fn writeIndsymtab(self: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); + const gpa = self.base.comp.gpa; const cmd = self.dysymtab_cmd; - const needed_size = cmd.nindirectsyms * @sizeOf(u32); - var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size); - defer buffer.deinit(); - try self.indsymtab.write(self, buffer.writer()); - try self.pwriteAll(buffer.items, cmd.indirectsymoff); + + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, @sizeOf(u32) * cmd.nindirectsyms)); + defer gpa.free(bw.buffer); + + try self.indsymtab.write(self, &bw); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, cmd.indirectsymoff); } pub fn writeSymtabToFile(self: *MachO) !void { @@ -2814,15 +2822,13 @@ fn calcSymtabSize(self: *MachO) !void { } } -fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { +fn writeLoadCommands(self: *MachO) anyerror!struct { usize, usize, u64 } { const comp = self.base.comp; const gpa = comp.gpa; - const needed_size = try load_commands.calcLoadCommandsSize(self, false); - const buffer = try gpa.alloc(u8, needed_size); - defer gpa.free(buffer); - var stream = std.io.fixedBufferStream(buffer); - const writer = stream.writer(); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, try load_commands.calcLoadCommandsSize(self, false))); + defer gpa.free(bw.buffer); var ncmds: usize = 0; @@ -2831,26 +2837,26 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { const slice = self.sections.slice(); var sect_id: usize = 0; for (self.segments.items) |seg| { - try writer.writeStruct(seg); + try bw.writeStruct(seg); for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| { - try writer.writeStruct(header); + try bw.writeStruct(header); } sect_id += seg.nsects; } ncmds += self.segments.items.len; } - try writer.writeStruct(self.dyld_info_cmd); + try bw.writeStruct(self.dyld_info_cmd); ncmds += 1; - try writer.writeStruct(self.function_starts_cmd); + try bw.writeStruct(self.function_starts_cmd); ncmds += 1; - try writer.writeStruct(self.data_in_code_cmd); + try bw.writeStruct(self.data_in_code_cmd); ncmds += 1; - try writer.writeStruct(self.symtab_cmd); + try bw.writeStruct(self.symtab_cmd); ncmds += 1; - try writer.writeStruct(self.dysymtab_cmd); + try bw.writeStruct(self.dysymtab_cmd); ncmds += 1; - try load_commands.writeDylinkerLC(writer); + try load_commands.writeDylinkerLC(&bw); ncmds += 1; if (self.getInternalObject()) |obj| { @@ -2861,7 +2867,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { 0 else @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr)); - try writer.writeStruct(macho.entry_point_command{ + try bw.writeStruct(macho.entry_point_command{ .entryoff = entryoff, .stacksize = self.base.stack_size, }); @@ -2870,35 +2876,35 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { } if (self.base.isDynLib()) { - try load_commands.writeDylibIdLC(self, writer); + try load_commands.writeDylibIdLC(self, &bw); ncmds += 1; } for (self.rpath_list) |rpath| { - try load_commands.writeRpathLC(rpath, writer); + try load_commands.writeRpathLC(&bw, rpath); ncmds += 1; } if (comp.config.any_sanitize_thread) { const path = try comp.tsan_lib.?.full_object_path.toString(gpa); defer gpa.free(path); const rpath = std.fs.path.dirname(path) orelse "."; - try load_commands.writeRpathLC(rpath, writer); + try load_commands.writeRpathLC(&bw, rpath); ncmds += 1; } - try writer.writeStruct(macho.source_version_command{ .version = 0 }); + try bw.writeStruct(macho.source_version_command{ .version = 0 }); ncmds += 1; if (self.platform.isBuildVersionCompatible()) { - try load_commands.writeBuildVersionLC(self.platform, self.sdk_version, writer); + try load_commands.writeBuildVersionLC(&bw, self.platform, self.sdk_version); ncmds += 1; } else { - try load_commands.writeVersionMinLC(self.platform, self.sdk_version, writer); + try load_commands.writeVersionMinLC(&bw, self.platform, self.sdk_version); ncmds += 1; } - const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + stream.pos; - try writer.writeStruct(self.uuid_cmd); + const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + bw.count; + try bw.writeStruct(self.uuid_cmd); ncmds += 1; for (self.dylibs.items) |index| { @@ -2916,20 +2922,19 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { .timestamp = dylib_id.timestamp, .current_version = dylib_id.current_version, .compatibility_version = dylib_id.compatibility_version, - }, writer); + }, &bw); ncmds += 1; } if (self.requiresCodeSig()) { - try writer.writeStruct(self.codesig_cmd); + try bw.writeStruct(self.codesig_cmd); ncmds += 1; } - assert(stream.pos == needed_size); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64)); - try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); - - return .{ ncmds, buffer.len, uuid_cmd_offset }; + return .{ ncmds, bw.end, uuid_cmd_offset }; } fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void { @@ -3012,27 +3017,28 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void { } pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void { + const gpa = self.base.comp.gpa; const seg = self.getTextSegment(); const offset = self.codesig_cmd.dataoff; - var buffer = std.ArrayList(u8).init(self.base.comp.gpa); - defer buffer.deinit(); - try buffer.ensureTotalCapacityPrecise(code_sig.size()); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, code_sig.size())); + defer gpa.free(bw.buffer); try code_sig.writeAdhocSignature(self, .{ .file = self.base.file.?, .exec_seg_base = seg.fileoff, .exec_seg_limit = seg.filesize, .file_size = offset, .dylib = self.base.isDynLib(), - }, buffer.writer()); - assert(buffer.items.len == code_sig.size()); + }, &bw); log.debug("writing code signature from 0x{x} to 0x{x}", .{ offset, - offset + buffer.items.len, + offset + bw.end, }); - try self.pwriteAll(buffer.items, offset); + assert(bw.end == bw.buffer.len); + try self.pwriteAll(bw.buffer, offset); } pub fn updateFunc( @@ -3341,7 +3347,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { } const appendSect = struct { - fn appendSect(macho_file: *MachO, sect_id: u8, seg_id: u8) void { + fn appendSect(macho_file: *MachO, sect_id: u8, seg_id: u4) void { const sect = &macho_file.sections.items(.header)[sect_id]; const seg = macho_file.segments.items[seg_id]; sect.addr = seg.vmaddr; @@ -3600,7 +3606,7 @@ inline fn requiresThunks(self: MachO) bool { } pub fn isZigSegment(self: MachO, seg_id: u8) bool { - inline for (&[_]?u8{ + inline for (&[_]?u4{ self.zig_text_seg_index, self.zig_const_seg_index, self.zig_data_seg_index, @@ -3648,9 +3654,9 @@ pub fn addSegment(self: *MachO, name: []const u8, opts: struct { fileoff: u64 = 0, filesize: u64 = 0, prot: macho.vm_prot_t = macho.PROT.NONE, -}) error{OutOfMemory}!u8 { +}) error{OutOfMemory}!u4 { const gpa = self.base.comp.gpa; - const index = @as(u8, @intCast(self.segments.items.len)); + const index: u4 = @intCast(self.segments.items.len); try self.segments.append(gpa, .{ .segname = makeStaticString(name), .vmaddr = opts.vmaddr, @@ -3700,9 +3706,9 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 { return buf; } -pub fn getSegmentByName(self: MachO, segname: []const u8) ?u8 { +pub fn getSegmentByName(self: MachO, segname: []const u8) ?u4 { for (self.segments.items, 0..) |seg, i| { - if (mem.eql(u8, segname, seg.segName())) return @as(u8, @intCast(i)); + if (mem.eql(u8, segname, seg.segName())) return @intCast(i); } else return null; } @@ -3791,7 +3797,7 @@ pub fn reportParseError2( const diags = &self.base.comp.link_diags; var err = try diags.addErrorWithNotes(1); try err.addMsg(format, args); - err.addNote("while parsing {}", .{self.getFile(file_index).?.fmtPath()}); + err.addNote("while parsing {f}", .{self.getFile(file_index).?.fmtPath()}); } fn reportMissingDependencyError( @@ -3806,7 +3812,7 @@ fn reportMissingDependencyError( var err = try diags.addErrorWithNotes(2 + checked_paths.len); try err.addMsg(format, args); err.addNote("while resolving {s}", .{path}); - err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()}); + err.addNote("a dependency of {f}", .{self.getFile(parent).?.fmtPath()}); for (checked_paths) |p| { err.addNote("tried {s}", .{p}); } @@ -3823,7 +3829,7 @@ fn reportDependencyError( var err = try diags.addErrorWithNotes(2); try err.addMsg(format, args); err.addNote("while parsing {s}", .{path}); - err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()}); + err.addNote("a dependency of {f}", .{self.getFile(parent).?.fmtPath()}); } fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void { @@ -3853,12 +3859,12 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void { var err = try diags.addErrorWithNotes(nnotes + 1); try err.addMsg("duplicate symbol definition: {s}", .{sym.getName(self)}); - err.addNote("defined by {}", .{sym.getFile(self).?.fmtPath()}); + err.addNote("defined by {f}", .{sym.getFile(self).?.fmtPath()}); var inote: usize = 0; while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { const file = self.getFile(notes.items[inote]).?; - err.addNote("defined by {}", .{file.fmtPath()}); + err.addNote("defined by {f}", .{file.fmtPath()}); } if (notes.items.len > max_notes) { @@ -3904,31 +3910,25 @@ pub fn dumpState(self: *MachO) std.fmt.Formatter(fmtDumpState) { return .{ .data = self }; } -fn fmtDumpState( - self: *MachO, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn fmtDumpState(self: *MachO, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; if (self.getZigObject()) |zo| { - try writer.print("zig_object({d}) : {s}\n", .{ zo.index, zo.basename }); - try writer.print("{}{}\n", .{ + try bw.print("zig_object({d}) : {s}\n", .{ zo.index, zo.basename }); + try bw.print("{f}{f}\n", .{ zo.fmtAtoms(self), zo.fmtSymtab(self), }); } for (self.objects.items) |index| { const object = self.getFile(index).?.object; - try writer.print("object({d}) : {} : has_debug({})", .{ + try bw.print("object({d}) : {f} : has_debug({})", .{ index, object.fmtPath(), object.hasDebugInfo(), }); - if (!object.alive) try writer.writeAll(" : ([*])"); - try writer.writeByte('\n'); - try writer.print("{}{}{}{}{}\n", .{ + if (!object.alive) try bw.writeAll(" : ([*])"); + try bw.writeByte('\n'); + try bw.print("{f}{f}{f}{f}{f}\n", .{ object.fmtAtoms(self), object.fmtCies(self), object.fmtFdes(self), @@ -3938,48 +3938,42 @@ fn fmtDumpState( } for (self.dylibs.items) |index| { const dylib = self.getFile(index).?.dylib; - try writer.print("dylib({d}) : {} : needed({}) : weak({})", .{ + try bw.print("dylib({d}) : {f} : needed({}) : weak({})", .{ index, @as(Path, dylib.path), dylib.needed, dylib.weak, }); - if (!dylib.isAlive(self)) try writer.writeAll(" : ([*])"); - try writer.writeByte('\n'); - try writer.print("{}\n", .{dylib.fmtSymtab(self)}); + if (!dylib.isAlive(self)) try bw.writeAll(" : ([*])"); + try bw.writeByte('\n'); + try bw.print("{f}\n", .{dylib.fmtSymtab(self)}); } if (self.getInternalObject()) |internal| { - try writer.print("internal({d}) : internal\n", .{internal.index}); - try writer.print("{}{}\n", .{ internal.fmtAtoms(self), internal.fmtSymtab(self) }); + try bw.print("internal({d}) : internal\n", .{internal.index}); + try bw.print("{f}{f}\n", .{ internal.fmtAtoms(self), internal.fmtSymtab(self) }); } - try writer.writeAll("thunks\n"); + try bw.writeAll("thunks\n"); for (self.thunks.items, 0..) |thunk, index| { - try writer.print("thunk({d}) : {}\n", .{ index, thunk.fmt(self) }); + try bw.print("thunk({d}) : {f}\n", .{ index, thunk.fmt(self) }); } - try writer.print("stubs\n{}\n", .{self.stubs.fmt(self)}); - try writer.print("objc_stubs\n{}\n", .{self.objc_stubs.fmt(self)}); - try writer.print("got\n{}\n", .{self.got.fmt(self)}); - try writer.print("tlv_ptr\n{}\n", .{self.tlv_ptr.fmt(self)}); - try writer.writeByte('\n'); - try writer.print("sections\n{}\n", .{self.fmtSections()}); - try writer.print("segments\n{}\n", .{self.fmtSegments()}); + try bw.print("stubs\n{f}\n", .{self.stubs.fmt(self)}); + try bw.print("objc_stubs\n{f}\n", .{self.objc_stubs.fmt(self)}); + try bw.print("got\n{f}\n", .{self.got.fmt(self)}); + try bw.print("tlv_ptr\n{f}\n", .{self.tlv_ptr.fmt(self)}); + try bw.writeByte('\n'); + try bw.print("sections\n{f}\n", .{self.fmtSections()}); + try bw.print("segments\n{f}\n", .{self.fmtSegments()}); } fn fmtSections(self: *MachO) std.fmt.Formatter(formatSections) { return .{ .data = self }; } -fn formatSections( - self: *MachO, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn formatSections(self: *MachO, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const slice = self.sections.slice(); for (slice.items(.header), slice.items(.segment_id), 0..) |header, seg_id, i| { - try writer.print( + try bw.print( "sect({d}) : seg({d}) : {s},{s} : @{x} ({x}) : align({x}) : size({x}) : relocs({x};{d})\n", .{ i, seg_id, header.segName(), header.sectName(), header.addr, header.offset, @@ -3993,16 +3987,10 @@ fn fmtSegments(self: *MachO) std.fmt.Formatter(formatSegments) { return .{ .data = self }; } -fn formatSegments( - self: *MachO, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn formatSegments(self: *MachO, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; for (self.segments.items, 0..) |seg, i| { - try writer.print("seg({d}) : {s} : @{x}-{x} ({x}-{x})\n", .{ + try bw.print("seg({d}) : {s} : @{x}-{x} ({x}-{x})\n", .{ i, seg.segName(), seg.vmaddr, seg.vmaddr + seg.vmsize, seg.fileoff, seg.fileoff + seg.filesize, }); @@ -4013,13 +4001,7 @@ pub fn fmtSectType(tt: u8) std.fmt.Formatter(formatSectType) { return .{ .data = tt }; } -fn formatSectType( - tt: u8, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn formatSectType(tt: u8, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const name = switch (tt) { macho.S_REGULAR => "REGULAR", @@ -4044,9 +4026,9 @@ fn formatSectType( macho.S_THREAD_LOCAL_VARIABLE_POINTERS => "THREAD_LOCAL_VARIABLE_POINTERS", macho.S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => "THREAD_LOCAL_INIT_FUNCTION_POINTERS", macho.S_INIT_FUNC_OFFSETS => "INIT_FUNC_OFFSETS", - else => |x| return writer.print("UNKNOWN({x})", .{x}), + else => |x| return bw.print("UNKNOWN({x})", .{x}), }; - try writer.print("{s}", .{name}); + try bw.print("{s}", .{name}); } const is_hot_update_compatible = switch (builtin.target.os.tag) { @@ -4058,7 +4040,7 @@ const default_entry_symbol_name = "_main"; const Section = struct { header: macho.section_64, - segment_id: u8, + segment_id: u4, atoms: std.ArrayListUnmanaged(Ref) = .empty, free_list: std.ArrayListUnmanaged(Atom.Index) = .empty, last_atom_index: Atom.Index = 0, @@ -4288,17 +4270,11 @@ pub const Platform = struct { cpu_arch: std.Target.Cpu.Arch, }; - pub fn formatTarget( - ctx: FmtCtx, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn formatTarget(ctx: FmtCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; - try writer.print("{s}-{s}", .{ @tagName(ctx.cpu_arch), @tagName(ctx.platform.os_tag) }); + try bw.print("{s}-{s}", .{ @tagName(ctx.cpu_arch), @tagName(ctx.platform.os_tag) }); if (ctx.platform.abi != .none) { - try writer.print("-{s}", .{@tagName(ctx.platform.abi)}); + try bw.print("-{s}", .{@tagName(ctx.platform.abi)}); } } @@ -4390,7 +4366,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi // The file/property is also available with vendored libc. fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 { const sdk_path = try fs.path.join(arena, &.{ dir, "SDKSettings.json" }); - const contents = try fs.cwd().readFileAlloc(arena, sdk_path, std.math.maxInt(u16)); + const contents = try fs.cwd().readFileAlloc(sdk_path, arena, .limited(std.math.maxInt(u16))); const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{}); if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string; return error.SdkVersionFailure; @@ -4406,7 +4382,7 @@ fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion { }; const parseNext = struct { - fn parseNext(it: anytype) ?u16 { + fn parseNext(it: *std.mem.SplitIterator(u8, .any)) ?u16 { const nn = it.next() orelse return null; return std.fmt.parseInt(u16, nn, 10) catch null; } @@ -4507,15 +4483,9 @@ pub const Ref = struct { }; } - pub fn format( - ref: Ref, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(ref: Ref, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; - try writer.print("%{d} in file({d})", .{ ref.index, ref.file }); + try bw.print("%{d} in file({d})", .{ ref.index, ref.file }); } }; @@ -5315,7 +5285,7 @@ fn createThunks(macho_file: *MachO, sect_id: u8) !void { try scanThunkRelocs(thunk_index, gpa, atoms[start..i], macho_file); thunk.value = advanceSection(header, thunk.size(), .@"4"); - log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) }); + log.debug("thunk({d}) : {f}", .{ thunk_index, thunk.fmt(macho_file) }); } } diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig index 82818aa697..0ab3a33885 100644 --- a/src/link/MachO/Archive.zig +++ b/src/link/MachO/Archive.zig @@ -29,7 +29,7 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File pos += @sizeOf(ar_hdr); if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) { - return diags.failParse(path, "invalid header delimiter: expected '{s}', found '{s}'", .{ + return diags.failParse(path, "invalid header delimiter: expected '{f}', found '{f}'", .{ std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), }); } @@ -71,53 +71,29 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File .mtime = hdr.date() catch 0, }; - log.debug("extracting object '{}' from archive '{}'", .{ object.path, path }); + log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path }); try self.objects.append(gpa, object); } } pub fn writeHeader( + bw: *std.io.BufferedWriter, object_name: []const u8, object_size: usize, format: Format, - writer: anytype, -) !void { - var hdr: ar_hdr = .{ - .ar_name = undefined, - .ar_date = undefined, - .ar_uid = undefined, - .ar_gid = undefined, - .ar_mode = undefined, - .ar_size = undefined, - .ar_fmag = undefined, - }; - @memset(mem.asBytes(&hdr), 0x20); - inline for (@typeInfo(ar_hdr).@"struct".fields) |field| { - var stream = std.io.fixedBufferStream(&@field(hdr, field.name)); - stream.writer().print("0", .{}) catch unreachable; - } +) anyerror!void { + var hdr: ar_hdr = undefined; + @memset(mem.asBytes(&hdr), ' '); + inline for (@typeInfo(ar_hdr).@"struct".fields) |field| @field(hdr, field.name)[0] = '0'; @memcpy(&hdr.ar_fmag, ARFMAG); - const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format)); + _ = std.fmt.bufPrint(&hdr.ar_name, "#1/{d}", .{object_name_len}) catch unreachable; const total_object_size = object_size + object_name_len; - - { - var stream = std.io.fixedBufferStream(&hdr.ar_name); - stream.writer().print("#1/{d}", .{object_name_len}) catch unreachable; - } - { - var stream = std.io.fixedBufferStream(&hdr.ar_size); - stream.writer().print("{d}", .{total_object_size}) catch unreachable; - } - - try writer.writeAll(mem.asBytes(&hdr)); - try writer.print("{s}\x00", .{object_name}); - - const padding = object_name_len - object_name.len - 1; - if (padding > 0) { - try writer.writeByteNTimes(0, padding); - } + _ = std.fmt.bufPrint(&hdr.ar_size, "{d}", .{total_object_size}) catch unreachable; + try bw.writeStruct(hdr); + try bw.writeAll(object_name); + try bw.splatByteAll(0, object_name_len - object_name.len); } // Archive files start with the ARMAG identifying string. Then follows a @@ -201,12 +177,12 @@ pub const ArSymtab = struct { return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width); } - pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: anytype) !void { + pub fn write(ar: ArSymtab, bw: *std.io.BufferedWriter, format: Format, macho_file: *MachO) anyerror!void { const ptr_width = ptrWidth(format); // Header - try writeHeader(SYMDEF, ar.size(format), format, writer); + try writeHeader(bw, SYMDEF, ar.size(format), format); // Symtab size - try writeInt(format, ar.entries.items.len * 2 * ptr_width, writer); + try writeInt(bw, format, ar.entries.items.len * 2 * ptr_width); // Symtab entries for (ar.entries.items) |entry| { const file_off = switch (macho_file.getFile(entry.file).?) { @@ -215,19 +191,16 @@ pub const ArSymtab = struct { else => unreachable, }; // Name offset - try writeInt(format, entry.off, writer); + try writeInt(bw, format, entry.off); // File offset - try writeInt(format, file_off, writer); + try writeInt(bw, format, file_off); } // Strtab size const strtab_size = mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width); - const padding = strtab_size - ar.strtab.buffer.items.len; - try writeInt(format, strtab_size, writer); + try writeInt(bw, format, strtab_size); // Strtab - try writer.writeAll(ar.strtab.buffer.items); - if (padding > 0) { - try writer.writeByteNTimes(0, padding); - } + try bw.writeAll(ar.strtab.buffer.items); + try bw.splatByteAll(0, strtab_size - ar.strtab.buffer.items.len); } const FormatContext = struct { @@ -239,20 +212,14 @@ pub const ArSymtab = struct { return .{ .data = .{ .ar = ar, .macho_file = macho_file } }; } - fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const ar = ctx.ar; const macho_file = ctx.macho_file; for (ar.entries.items, 0..) |entry, i| { const name = ar.strtab.getAssumeExists(entry.off); const file = macho_file.getFile(entry.file).?; - try writer.print(" {d}: {s} in file({d})({})\n", .{ i, name, entry.file, file.fmtPath() }); + try bw.print(" {d}: {s} in file({d})({f})\n", .{ i, name, entry.file, file.fmtPath() }); } } @@ -282,10 +249,10 @@ pub fn ptrWidth(format: Format) usize { }; } -pub fn writeInt(format: Format, value: u64, writer: anytype) !void { +pub fn writeInt(bw: *std.io.BufferedWriter, format: Format, value: u64) anyerror!void { switch (format) { - .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little), - .p64 => try writer.writeInt(u64, value, .little), + .p32 => try bw.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little), + .p64 => try bw.writeInt(u64, value, .little), } } diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index baa9e6172c..f2af52090f 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -580,8 +580,10 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { relocs_log.debug("{x}: {s}", .{ self.value, name }); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(buffer); + var has_error = false; - var stream = std.io.fixedBufferStream(buffer); var i: usize = 0; while (i < relocs.len) : (i += 1) { const rel = relocs[i]; @@ -592,30 +594,28 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue; } - try stream.seekTo(rel_offset); - self.resolveRelocInner(rel, subtractor, buffer, macho_file, stream.writer()) catch |err| { - switch (err) { - error.RelaxFail => { - const target = switch (rel.tag) { - .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file), - .local => rel.getTargetAtom(self, macho_file).getName(macho_file), - }; - try macho_file.reportParseError2( - file.getIndex(), - "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {}, target {s}", - .{ - name, - self.getAddress(macho_file), - rel.offset, - rel.fmtPretty(macho_file.getTarget().cpu.arch), - target, - }, - ); - has_error = true; - }, - error.RelaxFailUnexpectedInstruction => has_error = true, - else => |e| return e, - } + bw.end = std.math.cast(usize, rel_offset) orelse return error.Overflow; + self.resolveRelocInner(rel, subtractor, buffer, macho_file, &bw) catch |err| switch (@as(ResolveError, @errorCast(err))) { + error.RelaxFail => { + const target = switch (rel.tag) { + .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file), + .local => rel.getTargetAtom(self, macho_file).getName(macho_file), + }; + try macho_file.reportParseError2( + file.getIndex(), + "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {f}, target {s}", + .{ + name, + self.getAddress(macho_file), + rel.offset, + rel.fmtPretty(macho_file.getTarget().cpu.arch), + target, + }, + ); + has_error = true; + }, + error.RelaxFailUnexpectedInstruction => has_error = true, + else => |e| return e, }; } @@ -638,8 +638,8 @@ fn resolveRelocInner( subtractor: ?Relocation, code: []u8, macho_file: *MachO, - writer: anytype, -) ResolveError!void { + bw: *std.io.BufferedWriter, +) anyerror!void { const t = &macho_file.base.comp.root_mod.resolved_target.result; const cpu_arch = t.cpu.arch; const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow; @@ -653,7 +653,7 @@ fn resolveRelocInner( const divExact = struct { fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 { return math.divExact(u12, num, den) catch { - try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {s} at offset 0x{x}", .{ + try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {f} at offset 0x{x}", .{ atom.getName(ctx), r.fmtPretty(ctx.getTarget().cpu.arch), r.offset, @@ -664,14 +664,14 @@ fn resolveRelocInner( }.divExact; switch (rel.tag) { - .local => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] atom({d})", .{ + .local => relocs_log.debug(" {x}<+{d}>: {f}: [=> {x}] atom({d})", .{ P, rel_offset, rel.fmtPretty(cpu_arch), S + A - SUB, rel.getTargetAtom(self, macho_file).atom_index, }), - .@"extern" => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] G({x}) ({s})", .{ + .@"extern" => relocs_log.debug(" {x}<+{d}>: {f}: [=> {x}] G({x}) ({s})", .{ P, rel_offset, rel.fmtPretty(cpu_arch), @@ -690,14 +690,14 @@ fn resolveRelocInner( if (rel.tag == .@"extern") { const sym = rel.getTargetSymbol(self, macho_file); if (sym.isTlvInit(macho_file)) { - try writer.writeInt(u64, @intCast(S - TLS), .little); + try bw.writeInt(u64, @intCast(S - TLS), .little); return; } if (sym.flags.import) return; } - try writer.writeInt(u64, @bitCast(S + A - SUB), .little); + try bw.writeInt(u64, @bitCast(S + A - SUB), .little); } else if (rel.meta.length == 2) { - try writer.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little); + try bw.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little); } else unreachable; }, @@ -705,7 +705,7 @@ fn resolveRelocInner( assert(rel.tag == .@"extern"); assert(rel.meta.length == 2); assert(rel.meta.pcrel); - try writer.writeInt(i32, @intCast(G + A - P), .little); + try bw.writeInt(i32, @intCast(G + A - P), .little); }, .branch => { @@ -714,7 +714,7 @@ fn resolveRelocInner( assert(rel.tag == .@"extern"); switch (cpu_arch) { - .x86_64 => try writer.writeInt(i32, @intCast(S + A - P), .little), + .x86_64 => try bw.writeInt(i32, @intCast(S + A - P), .little), .aarch64 => { const disp: i28 = math.cast(i28, S + A - P) orelse blk: { const thunk = self.getThunk(macho_file); @@ -732,10 +732,10 @@ fn resolveRelocInner( assert(rel.meta.length == 2); assert(rel.meta.pcrel); if (rel.getTargetSymbol(self, macho_file).getSectionFlags().has_got) { - try writer.writeInt(i32, @intCast(G + A - P), .little); + try bw.writeInt(i32, @intCast(G + A - P), .little); } else { try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file); - try writer.writeInt(i32, @intCast(S + A - P), .little); + try bw.writeInt(i32, @intCast(S + A - P), .little); } }, @@ -746,17 +746,17 @@ fn resolveRelocInner( const sym = rel.getTargetSymbol(self, macho_file); if (sym.getSectionFlags().tlv_ptr) { const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); - try writer.writeInt(i32, @intCast(S_ + A - P), .little); + try bw.writeInt(i32, @intCast(S_ + A - P), .little); } else { try x86_64.relaxTlv(code[rel_offset - 3 ..], t); - try writer.writeInt(i32, @intCast(S + A - P), .little); + try bw.writeInt(i32, @intCast(S + A - P), .little); } }, .signed, .signed1, .signed2, .signed4 => { assert(rel.meta.length == 2); assert(rel.meta.pcrel); - try writer.writeInt(i32, @intCast(S + A - P), .little); + try bw.writeInt(i32, @intCast(S + A - P), .little); }, .page, @@ -808,7 +808,7 @@ fn resolveRelocInner( 2 => try divExact(self, rel, @truncate(target), 4, macho_file), 3 => try divExact(self, rel, @truncate(target), 8, macho_file), }; - try writer.writeInt(u32, inst.toU32(), .little); + try bw.writeInt(u32, inst.toU32(), .little); } }, @@ -886,7 +886,7 @@ fn resolveRelocInner( .sf = @as(u1, @truncate(reg_info.size)), }, }; - try writer.writeInt(u32, inst.toU32(), .little); + try bw.writeInt(u32, inst.toU32(), .little); }, } } @@ -900,19 +900,19 @@ const x86_64 = struct { switch (old_inst.encoding.mnemonic) { .mov => { const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops, t) catch return error.RelaxFail; - relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding }); + relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding }); encode(&.{inst}, code) catch return error.RelaxFail; }, else => |x| { var err = try diags.addErrorWithNotes(2); - try err.addMsg("{s}: 0x{x}: 0x{x}: failed to relax relocation of type {}", .{ + try err.addMsg("{s}: 0x{x}: 0x{x}: failed to relax relocation of type {f}", .{ self.getName(macho_file), self.getAddress(macho_file), rel.offset, rel.fmtPretty(.x86_64), }); err.addNote("expected .mov instruction but found .{s}", .{@tagName(x)}); - err.addNote("while parsing {}", .{self.getFile(macho_file).fmtPath()}); + err.addNote("while parsing {f}", .{self.getFile(macho_file).fmtPath()}); return error.RelaxFailUnexpectedInstruction; }, } @@ -924,7 +924,7 @@ const x86_64 = struct { switch (old_inst.encoding.mnemonic) { .mov => { const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops, t) catch return error.RelaxFail; - relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding }); + relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding }); encode(&.{inst}, code) catch return error.RelaxFail; }, else => return error.RelaxFail, @@ -938,11 +938,9 @@ const x86_64 = struct { } fn encode(insts: []const Instruction, code: []u8) !void { - var stream = std.io.fixedBufferStream(code); - const writer = stream.writer(); - for (insts) |inst| { - try inst.encode(writer, .{}); - } + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(code); + for (insts) |inst| try inst.encode(&bw, .{}); } const bits = @import("../../arch/x86_64/bits.zig"); @@ -1003,7 +1001,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r } switch (rel.tag) { - .local => relocs_log.debug(" {}: [{x} => {d}({s},{s})] + {x}", .{ + .local => relocs_log.debug(" {f}: [{x} => {d}({s},{s})] + {x}", .{ rel.fmtPretty(cpu_arch), r_address, r_symbolnum, @@ -1011,7 +1009,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r macho_file.sections.items(.header)[r_symbolnum - 1].sectName(), addend, }), - .@"extern" => relocs_log.debug(" {}: [{x} => {d}({s})] + {x}", .{ + .@"extern" => relocs_log.debug(" {f}: [{x} => {d}({s})] + {x}", .{ rel.fmtPretty(cpu_arch), r_address, r_symbolnum, @@ -1142,33 +1140,27 @@ const FormatContext = struct { macho_file: *MachO, }; -fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const atom = ctx.atom; const macho_file = ctx.macho_file; const file = atom.getFile(macho_file); - try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{ + try bw.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{ atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), atom.out_n_sect, atom.alignment, atom.size, atom.getRelocs(macho_file).len, atom.getExtra(macho_file).thunk, }); - if (!atom.isAlive()) try writer.writeAll(" : [*]"); + if (!atom.isAlive()) try bw.writeAll(" : [*]"); if (atom.getUnwindRecords(macho_file).len > 0) { - try writer.writeAll(" : unwind{ "); + try bw.writeAll(" : unwind{ "); const extra = atom.getExtra(macho_file); for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| { const rec = file.object.getUnwindRecord(index); - try writer.print("{d}", .{index}); - if (!rec.alive) try writer.writeAll("([*])"); - if (i < extra.unwind_index + extra.unwind_count - 1) try writer.writeAll(", "); + try bw.print("{d}", .{index}); + if (!rec.alive) try bw.writeAll("([*])"); + if (i < extra.unwind_index + extra.unwind_count - 1) try bw.writeAll(", "); } - try writer.writeAll(" }"); + try bw.writeAll(" }"); } } diff --git a/src/link/MachO/CodeSignature.zig b/src/link/MachO/CodeSignature.zig index c8a092eab6..11b5abcde4 100644 --- a/src/link/MachO/CodeSignature.zig +++ b/src/link/MachO/CodeSignature.zig @@ -247,7 +247,7 @@ pub fn deinit(self: *CodeSignature, allocator: Allocator) void { pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void { const file = try fs.cwd().openFile(path, .{}); defer file.close(); - const inner = try file.readToEndAlloc(allocator, std.math.maxInt(u32)); + const inner = try file.readToEndAlloc(allocator, .unlimited); self.entitlements = .{ .inner = inner }; } @@ -304,10 +304,12 @@ pub fn writeAdhocSignature( var hash: [hash_size]u8 = undefined; if (self.requirements) |*req| { - var buf = std.ArrayList(u8).init(allocator); - defer buf.deinit(); - try req.write(buf.writer()); - Sha256.hash(buf.items, &hash, .{}); + var aw: std.io.AllocatingWriter = undefined; + aw.init(allocator); + defer aw.deinit(); + + try req.write(&aw.buffered_writer); + Sha256.hash(aw.getWritten(), &hash, .{}); self.code_directory.addSpecialHash(req.slotType(), hash); try blobs.append(.{ .requirements = req }); @@ -316,10 +318,12 @@ pub fn writeAdhocSignature( } if (self.entitlements) |*ents| { - var buf = std.ArrayList(u8).init(allocator); - defer buf.deinit(); - try ents.write(buf.writer()); - Sha256.hash(buf.items, &hash, .{}); + var aw: std.io.AllocatingWriter = undefined; + aw.init(allocator); + defer aw.deinit(); + + try ents.write(&aw.buffered_writer); + Sha256.hash(aw.getWritten(), &hash, .{}); self.code_directory.addSpecialHash(ents.slotType(), hash); try blobs.append(.{ .entitlements = ents }); diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index eef3492b48..76cd8e42aa 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -269,18 +269,15 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void { fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } { const gpa = self.allocator; - const needed_size = load_commands.calcLoadCommandsSizeDsym(macho_file, self); - const buffer = try gpa.alloc(u8, needed_size); - defer gpa.free(buffer); - - var stream = std.io.fixedBufferStream(buffer); - const writer = stream.writer(); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeDsym(macho_file, self))); + defer gpa.free(bw.buffer); var ncmds: usize = 0; // UUID comes first presumably to speed up lookup by the consumer like lldb. @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid); - try writer.writeStruct(self.uuid_cmd); + try bw.writeStruct(self.uuid_cmd); ncmds += 1; // Segment and section load commands @@ -293,11 +290,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u var out_seg = seg; out_seg.fileoff = 0; out_seg.filesize = 0; - try writer.writeStruct(out_seg); + try bw.writeStruct(out_seg); for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| { var out_header = header; out_header.offset = 0; - try writer.writeStruct(out_header); + try bw.writeStruct(out_header); } sect_id += seg.nsects; } @@ -306,23 +303,22 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u // Next, commit DSYM's __LINKEDIT and __DWARF segments headers. sect_id = 0; for (self.segments.items) |seg| { - try writer.writeStruct(seg); + try bw.writeStruct(seg); for (self.sections.items[sect_id..][0..seg.nsects]) |header| { - try writer.writeStruct(header); + try bw.writeStruct(header); } sect_id += seg.nsects; } ncmds += self.segments.items.len; } - try writer.writeStruct(self.symtab_cmd); + try bw.writeStruct(self.symtab_cmd); ncmds += 1; - assert(stream.pos == needed_size); + assert(bw.end == bw.buffer.len); + try self.file.?.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64)); - try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); - - return .{ ncmds, buffer.len }; + return .{ ncmds, bw.end }; } fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { diff --git a/src/link/MachO/Dwarf.zig b/src/link/MachO/Dwarf.zig index fdc3f33bbc..5ec20dec47 100644 --- a/src/link/MachO/Dwarf.zig +++ b/src/link/MachO/Dwarf.zig @@ -81,7 +81,7 @@ pub const InfoReader = struct { .dwarf64 => 12, } + cuh_length; while (p.pos < end_pos) { - const di_code = try p.readUleb128(u64); + const di_code = try p.readLeb128(u64); if (di_code == 0) return error.UnexpectedEndOfFile; if (di_code == code) return; @@ -174,14 +174,14 @@ pub const InfoReader = struct { dw.FORM.block1 => try p.readByte(), dw.FORM.block2 => try p.readInt(u16), dw.FORM.block4 => try p.readInt(u32), - dw.FORM.block => try p.readUleb128(u64), + dw.FORM.block => try p.readLeb128(u64), else => unreachable, }; return p.readNBytes(len); } pub fn readExprLoc(p: *InfoReader) ![]const u8 { - const len: u64 = try p.readUleb128(u64); + const len: u64 = try p.readLeb128(u64); return p.readNBytes(len); } @@ -191,8 +191,8 @@ pub const InfoReader = struct { dw.FORM.data2, dw.FORM.ref2 => try p.readInt(u16), dw.FORM.data4, dw.FORM.ref4 => try p.readInt(u32), dw.FORM.data8, dw.FORM.ref8, dw.FORM.ref_sig8 => try p.readInt(u64), - dw.FORM.udata, dw.FORM.ref_udata => try p.readUleb128(u64), - dw.FORM.sdata => @bitCast(try p.readIleb128(i64)), + dw.FORM.udata, dw.FORM.ref_udata => try p.readLeb128(u64), + dw.FORM.sdata => @bitCast(try p.readLeb128(i64)), else => return error.UnhandledConstantForm, }; } @@ -203,7 +203,7 @@ pub const InfoReader = struct { dw.FORM.strx2, dw.FORM.addrx2 => try p.readInt(u16), dw.FORM.strx3, dw.FORM.addrx3 => error.UnhandledForm, dw.FORM.strx4, dw.FORM.addrx4 => try p.readInt(u32), - dw.FORM.strx, dw.FORM.addrx => try p.readUleb128(u64), + dw.FORM.strx, dw.FORM.addrx => try p.readLeb128(u64), else => return error.UnhandledIndexForm, }; } @@ -272,20 +272,11 @@ pub const InfoReader = struct { }; } - pub fn readUleb128(p: *InfoReader, comptime Type: type) !Type { - var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]); - var creader = std.io.countingReader(stream.reader()); - const value: Type = try leb.readUleb128(Type, creader.reader()); - p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow; - return value; - } - - pub fn readIleb128(p: *InfoReader, comptime Type: type) !Type { - var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]); - var creader = std.io.countingReader(stream.reader()); - const value: Type = try leb.readIleb128(Type, creader.reader()); - p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow; - return value; + pub fn readLeb128(p: *InfoReader, comptime Type: type) !Type { + var br: std.io.BufferedReader = undefined; + br.initFixed(p.bytes()[p.pos..]); + defer p.pos += br.seek; + return br.takeLeb128(Type); } pub fn seekTo(p: *InfoReader, off: u64) !void { @@ -307,10 +298,10 @@ pub const AbbrevReader = struct { pub fn readDecl(p: *AbbrevReader) !?AbbrevDecl { const pos = p.pos; - const code = try p.readUleb128(Code); + const code = try p.readLeb128(Code); if (code == 0) return null; - const tag = try p.readUleb128(Tag); + const tag = try p.readLeb128(Tag); const has_children = (try p.readByte()) > 0; return .{ .code = code, @@ -323,8 +314,8 @@ pub const AbbrevReader = struct { pub fn readAttr(p: *AbbrevReader) !?AbbrevAttr { const pos = p.pos; - const at = try p.readUleb128(At); - const form = try p.readUleb128(Form); + const at = try p.readLeb128(At); + const form = try p.readLeb128(Form); return if (at == 0 and form == 0) null else .{ .at = at, .form = form, @@ -339,12 +330,11 @@ pub const AbbrevReader = struct { return p.bytes()[p.pos]; } - pub fn readUleb128(p: *AbbrevReader, comptime Type: type) !Type { - var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]); - var creader = std.io.countingReader(stream.reader()); - const value: Type = try leb.readUleb128(Type, creader.reader()); - p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow; - return value; + pub fn readLeb128(p: *AbbrevReader, comptime Type: type) !Type { + var br: std.io.BufferedReader = undefined; + br.initFixed(p.bytes()[p.pos..]); + defer p.pos += br.seek; + return br.takeLeb128(Type); } pub fn seekTo(p: *AbbrevReader, off: u64) !void { diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig index 01dd25fa8c..4b2e4c725e 100644 --- a/src/link/MachO/Dylib.zig +++ b/src/link/MachO/Dylib.zig @@ -61,7 +61,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void { const file = macho_file.getFileHandle(self.file_handle); const offset = self.offset; - log.debug("parsing dylib from binary: {}", .{@as(Path, self.path)}); + log.debug("parsing dylib from binary: {f}", .{@as(Path, self.path)}); var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; { @@ -140,7 +140,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void { if (self.platform) |platform| { if (!macho_file.platform.eqlTarget(platform)) { - try macho_file.reportParseError2(self.index, "invalid platform: {}", .{ + try macho_file.reportParseError2(self.index, "invalid platform: {f}", .{ platform.fmtTarget(macho_file.getTarget().cpu.arch), }); return error.InvalidTarget; @@ -148,7 +148,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void { // TODO: this can cause the CI to fail so I'm commenting this check out so that // I can work out the rest of the changes first // if (macho_file.platform.version.order(platform.version) == .lt) { - // try macho_file.reportParseError2(self.index, "object file built for newer platform: {}: {} < {}", .{ + // try macho_file.reportParseError2(self.index, "object file built for newer platform: {f}: {f} < {f}", .{ // macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch), // macho_file.platform.version, // platform.version, @@ -158,46 +158,6 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void { } } -const TrieIterator = struct { - data: []const u8, - pos: usize = 0, - - fn getStream(it: *TrieIterator) std.io.FixedBufferStream([]const u8) { - return std.io.fixedBufferStream(it.data[it.pos..]); - } - - fn readUleb128(it: *TrieIterator) !u64 { - var stream = it.getStream(); - var creader = std.io.countingReader(stream.reader()); - const reader = creader.reader(); - const value = try std.leb.readUleb128(u64, reader); - it.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow; - return value; - } - - fn readString(it: *TrieIterator) ![:0]const u8 { - var stream = it.getStream(); - const reader = stream.reader(); - - var count: usize = 0; - while (true) : (count += 1) { - const byte = try reader.readByte(); - if (byte == 0) break; - } - - const str = @as([*:0]const u8, @ptrCast(it.data.ptr + it.pos))[0..count :0]; - it.pos += count + 1; - return str; - } - - fn readByte(it: *TrieIterator) !u8 { - var stream = it.getStream(); - const value = try stream.reader().readByte(); - it.pos += 1; - return value; - } -}; - pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void { try self.exports.append(allocator, .{ .name = try self.addString(allocator, name), @@ -207,16 +167,16 @@ pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Ex fn parseTrieNode( self: *Dylib, - it: *TrieIterator, + br: *std.io.BufferedReader, allocator: Allocator, arena: Allocator, prefix: []const u8, ) !void { const tracy = trace(@src()); defer tracy.end(); - const size = try it.readUleb128(); + const size = try br.takeLeb128(u64); if (size > 0) { - const flags = try it.readUleb128(); + const flags = try br.takeLeb128(u8); const kind = flags & macho.EXPORT_SYMBOL_FLAGS_KIND_MASK; const out_flags = Export.Flags{ .abs = kind == macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE, @@ -224,29 +184,28 @@ fn parseTrieNode( .weak = flags & macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION != 0, }; if (flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT != 0) { - _ = try it.readUleb128(); // dylib ordinal - const name = try it.readString(); + _ = try br.takeLeb128(u64); // dylib ordinal + const name = try br.takeSentinel(0); try self.addExport(allocator, if (name.len > 0) name else prefix, out_flags); } else if (flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER != 0) { - _ = try it.readUleb128(); // stub offset - _ = try it.readUleb128(); // resolver offset + _ = try br.takeLeb128(u64); // stub offset + _ = try br.takeLeb128(u64); // resolver offset try self.addExport(allocator, prefix, out_flags); } else { - _ = try it.readUleb128(); // VM offset + _ = try br.takeLeb128(u64); // VM offset try self.addExport(allocator, prefix, out_flags); } } - const nedges = try it.readByte(); - + const nedges = try br.takeByte(); for (0..nedges) |_| { - const label = try it.readString(); - const off = try it.readUleb128(); + const label = try br.takeSentinel(0); + const off = try br.takeLeb128(usize); const prefix_label = try std.fmt.allocPrint(arena, "{s}{s}", .{ prefix, label }); - const curr = it.pos; - it.pos = math.cast(usize, off) orelse return error.Overflow; - try self.parseTrieNode(it, allocator, arena, prefix_label); - it.pos = curr; + const seek = br.seek; + br.seek = off; + try self.parseTrieNode(br, allocator, arena, prefix_label); + br.seek = seek; } } @@ -257,8 +216,9 @@ fn parseTrie(self: *Dylib, data: []const u8, macho_file: *MachO) !void { var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); - var it: TrieIterator = .{ .data = data }; - try self.parseTrieNode(&it, gpa, arena.allocator(), ""); + var br: std.io.BufferedReader = undefined; + br.initFixed(data); + try self.parseTrieNode(&br, gpa, arena.allocator(), ""); } fn parseTbd(self: *Dylib, macho_file: *MachO) !void { @@ -267,7 +227,7 @@ fn parseTbd(self: *Dylib, macho_file: *MachO) !void { const gpa = macho_file.base.comp.gpa; - log.debug("parsing dylib from stub: {}", .{self.path}); + log.debug("parsing dylib from stub: {f}", .{self.path}); const file = macho_file.getFileHandle(self.file_handle); var lib_stub = LibStub.loadFromFile(gpa, file) catch |err| { @@ -716,24 +676,18 @@ const FormatContext = struct { macho_file: *MachO, }; -fn formatSymtab( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const dylib = ctx.dylib; const macho_file = ctx.macho_file; - try writer.writeAll(" globals\n"); + try bw.writeAll(" globals\n"); for (dylib.symbols.items, 0..) |sym, i| { const ref = dylib.getSymbolRef(@intCast(i), macho_file); if (ref.getFile(macho_file) == null) { // TODO any better way of handling this? - try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); + try bw.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); } else { - try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); + try bw.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); } } } diff --git a/src/link/MachO/InternalObject.zig b/src/link/MachO/InternalObject.zig index 0218f0c1bb..7182efb823 100644 --- a/src/link/MachO/InternalObject.zig +++ b/src/link/MachO/InternalObject.zig @@ -261,7 +261,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil sect.offset = @intCast(self.objc_methnames.items.len); try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1); - self.objc_methnames.writer(gpa).print("{s}\x00", .{methname}) catch unreachable; + self.objc_methnames.print(gpa, "{s}\x00", .{methname}) catch unreachable; const name_str = try self.addString(gpa, "ltmp"); const sym_index = try self.addSymbol(gpa); @@ -848,18 +848,12 @@ pub fn fmtAtoms(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(for } }; } -fn formatAtoms( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatAtoms(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; - try writer.writeAll(" atoms\n"); + try bw.writeAll(" atoms\n"); for (ctx.self.getAtoms()) |atom_index| { const atom = ctx.self.getAtom(atom_index) orelse continue; - try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)}); + try bw.print(" {f}\n", .{atom.fmt(ctx.macho_file)}); } } @@ -870,24 +864,18 @@ pub fn fmtSymtab(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(fo } }; } -fn formatSymtab( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const macho_file = ctx.macho_file; const self = ctx.self; - try writer.writeAll(" symbols\n"); + try bw.writeAll(" symbols\n"); for (self.symbols.items, 0..) |sym, i| { const ref = self.getSymbolRef(@intCast(i), macho_file); if (ref.getFile(macho_file) == null) { // TODO any better way of handling this? - try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); + try bw.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); } else { - try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); + try bw.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); } } } diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index ec9d07aabc..e6a4d587fe 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -72,7 +72,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); - log.debug("parsing {}", .{self.fmtPath()}); + log.debug("parsing {f}", .{self.fmtPath()}); const gpa = macho_file.base.comp.gpa; const handle = macho_file.getFileHandle(self.file_handle); @@ -239,7 +239,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { if (self.platform) |platform| { if (!macho_file.platform.eqlTarget(platform)) { - try macho_file.reportParseError2(self.index, "invalid platform: {}", .{ + try macho_file.reportParseError2(self.index, "invalid platform: {f}", .{ platform.fmtTarget(cpu_arch), }); return error.InvalidTarget; @@ -247,7 +247,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { // TODO: this causes the CI to fail so I'm commenting this check out so that // I can work out the rest of the changes first // if (macho_file.platform.version.order(platform.version) == .lt) { - // try macho_file.reportParseError2(self.index, "object file built for newer platform: {}: {} < {}", .{ + // try macho_file.reportParseError2(self.index, "object file built for newer platform: {f}: {f} < {f}", .{ // macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch), // macho_file.platform.version, // platform.version, @@ -1065,7 +1065,8 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi } } - var it = eh_frame.Iterator{ .data = self.eh_frame_data.items }; + var it: eh_frame.Iterator = undefined; + it.br.initFixed(self.eh_frame_data.items); while (try it.next()) |rec| { switch (rec.tag) { .cie => try self.cies.append(allocator, .{ @@ -1694,11 +1695,11 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { }; } -pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { +pub fn writeAr(self: Object, bw: *std.io.BufferedWriter, ar_format: Archive.Format, macho_file: *MachO) !void { // Header const size = try macho_file.cast(usize, self.output_ar_state.size); const basename = std.fs.path.basename(self.path.sub_path); - try Archive.writeHeader(basename, size, ar_format, writer); + try Archive.writeHeader(bw, basename, size, ar_format); // Data const file = macho_file.getFileHandle(self.file_handle); // TODO try using copyRangeAll @@ -1707,7 +1708,7 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ defer gpa.free(data); const amt = try file.preadAll(data, self.offset); if (amt != size) return error.InputOutput; - try writer.writeAll(data); + try bw.writeAll(data); } pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void { @@ -1861,7 +1862,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void { } gpa.free(sections_data); } - @memset(sections_data, &[0]u8{}); + @memset(sections_data, &.{}); const file = macho_file.getFileHandle(self.file_handle); for (headers, 0..) |header, n_sect| { @@ -2512,16 +2513,10 @@ pub fn readSectionData(self: Object, allocator: Allocator, file: File.Handle, n_ return data; } -pub fn format( - self: *Object, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +pub fn format(self: *Object, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = self; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format objects directly"); } @@ -2537,20 +2532,14 @@ pub fn fmtAtoms(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatAtoms } }; } -fn formatAtoms( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatAtoms(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const object = ctx.object; const macho_file = ctx.macho_file; - try writer.writeAll(" atoms\n"); + try bw.writeAll(" atoms\n"); for (object.getAtoms()) |atom_index| { const atom = object.getAtom(atom_index) orelse continue; - try writer.print(" {}\n", .{atom.fmt(macho_file)}); + try bw.print(" {f}\n", .{atom.fmt(macho_file)}); } } @@ -2561,18 +2550,12 @@ pub fn fmtCies(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatCies) } }; } -fn formatCies( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatCies(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const object = ctx.object; - try writer.writeAll(" cies\n"); + try bw.writeAll(" cies\n"); for (object.cies.items, 0..) |cie, i| { - try writer.print(" cie({d}) : {}\n", .{ i, cie.fmt(ctx.macho_file) }); + try bw.print(" cie({d}) : {f}\n", .{ i, cie.fmt(ctx.macho_file) }); } } @@ -2583,18 +2566,12 @@ pub fn fmtFdes(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatFdes) } }; } -fn formatFdes( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatFdes(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const object = ctx.object; - try writer.writeAll(" fdes\n"); + try bw.writeAll(" fdes\n"); for (object.fdes.items, 0..) |fde, i| { - try writer.print(" fde({d}) : {}\n", .{ i, fde.fmt(ctx.macho_file) }); + try bw.print(" fde({d}) : {f}\n", .{ i, fde.fmt(ctx.macho_file) }); } } @@ -2605,19 +2582,13 @@ pub fn fmtUnwindRecords(self: *Object, macho_file: *MachO) std.fmt.Formatter(for } }; } -fn formatUnwindRecords( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatUnwindRecords(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const object = ctx.object; const macho_file = ctx.macho_file; - try writer.writeAll(" unwind records\n"); + try bw.writeAll(" unwind records\n"); for (object.unwind_records_indexes.items) |rec| { - try writer.print(" rec({d}) : {}\n", .{ rec, object.getUnwindRecord(rec).fmt(macho_file) }); + try bw.print(" rec({d}) : {f}\n", .{ rec, object.getUnwindRecord(rec).fmt(macho_file) }); } } @@ -2628,34 +2599,28 @@ pub fn fmtSymtab(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatSymt } }; } -fn formatSymtab( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const object = ctx.object; const macho_file = ctx.macho_file; - try writer.writeAll(" symbols\n"); + try bw.writeAll(" symbols\n"); for (object.symbols.items, 0..) |sym, i| { const ref = object.getSymbolRef(@intCast(i), macho_file); if (ref.getFile(macho_file) == null) { // TODO any better way of handling this? - try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); + try bw.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); } else { - try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); + try bw.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); } } for (object.stab_files.items) |sf| { - try writer.print(" stabs({s},{s},{s})\n", .{ + try bw.print(" stabs({s},{s},{s})\n", .{ sf.getCompDir(object.*), sf.getTuName(object.*), sf.getOsoPath(object.*), }); for (sf.stabs.items) |stab| { - try writer.print(" {}", .{stab.fmt(object.*)}); + try bw.print(" {f}", .{stab.fmt(object.*)}); } } } @@ -2664,20 +2629,14 @@ pub fn fmtPath(self: Object) std.fmt.Formatter(formatPath) { return .{ .data = self }; } -fn formatPath( - object: Object, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatPath(object: Object, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; if (object.in_archive) |ar| { - try writer.print("{}({s})", .{ - @as(Path, ar.path), object.path.basename(), + try bw.print("{f}({s})", .{ + ar.path, object.path.basename(), }); } else { - try writer.print("{}", .{@as(Path, object.path)}); + try bw.print("{f}", .{object.path}); } } @@ -2731,16 +2690,10 @@ const StabFile = struct { return object.symbols.items[index]; } - pub fn format( - stab: Stab, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(stab: Stab, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = stab; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format stabs directly"); } @@ -2750,22 +2703,16 @@ const StabFile = struct { return .{ .data = .{ stab, object } }; } - fn format2( - ctx: StabFormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + fn format2(ctx: StabFormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const stab, const object = ctx; const sym = stab.getSymbol(object).?; if (stab.is_func) { - try writer.print("func({d})", .{stab.index.?}); + try bw.print("func({d})", .{stab.index.?}); } else if (sym.visibility == .global) { - try writer.print("gsym({d})", .{stab.index.?}); + try bw.print("gsym({d})", .{stab.index.?}); } else { - try writer.print("stsym({d})", .{stab.index.?}); + try bw.print("stsym({d})", .{stab.index.?}); } } }; diff --git a/src/link/MachO/Relocation.zig b/src/link/MachO/Relocation.zig index c732dc3a89..968e7ca0be 100644 --- a/src/link/MachO/Relocation.zig +++ b/src/link/MachO/Relocation.zig @@ -76,16 +76,10 @@ pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatt return .{ .data = .{ rel, cpu_arch } }; } -fn formatPretty( - ctx: FormatCtx, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn formatPretty(ctx: FormatCtx, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const rel, const cpu_arch = ctx; - const str = switch (rel.type) { + try bw.writeAll(switch (rel.type) { .signed => "X86_64_RELOC_SIGNED", .signed1 => "X86_64_RELOC_SIGNED_1", .signed2 => "X86_64_RELOC_SIGNED_2", @@ -118,8 +112,7 @@ fn formatPretty( .aarch64 => "ARM64_RELOC_UNSIGNED", else => unreachable, }, - }; - try writer.writeAll(str); + }); } pub const Type = enum { diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index be126b0963..f8f8eb7915 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -286,16 +286,10 @@ pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) vo } } -pub fn format( - symbol: Symbol, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +pub fn format(symbol: Symbol, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = symbol; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format symbols directly"); } @@ -311,26 +305,20 @@ pub fn fmt(symbol: Symbol, macho_file: *MachO) std.fmt.Formatter(format2) { } }; } -fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const symbol = ctx.symbol; - try writer.print("%{d} : {s} : @{x}", .{ + try bw.print("%{d} : {s} : @{x}", .{ symbol.nlist_idx, symbol.getName(ctx.macho_file), symbol.getAddress(.{}, ctx.macho_file), }); if (symbol.getFile(ctx.macho_file)) |file| { if (symbol.getOutputSectionIndex(ctx.macho_file) != 0) { - try writer.print(" : sect({d})", .{symbol.getOutputSectionIndex(ctx.macho_file)}); + try bw.print(" : sect({d})", .{symbol.getOutputSectionIndex(ctx.macho_file)}); } if (symbol.getAtom(ctx.macho_file)) |atom| { - try writer.print(" : atom({d})", .{atom.atom_index}); + try bw.print(" : atom({d})", .{atom.atom_index}); } var buf: [3]u8 = .{'_'} ** 3; if (symbol.flags.@"export") buf[0] = 'E'; @@ -340,16 +328,16 @@ fn format2( .hidden => buf[2] = 'H', .global => buf[2] = 'G', } - try writer.print(" : {s}", .{&buf}); - if (symbol.flags.weak) try writer.writeAll(" : weak"); - if (symbol.isSymbolStab(ctx.macho_file)) try writer.writeAll(" : stab"); + try bw.print(" : {s}", .{&buf}); + if (symbol.flags.weak) try bw.writeAll(" : weak"); + if (symbol.isSymbolStab(ctx.macho_file)) try bw.writeAll(" : stab"); switch (file) { - .zig_object => |x| try writer.print(" : zig_object({d})", .{x.index}), - .internal => |x| try writer.print(" : internal({d})", .{x.index}), - .object => |x| try writer.print(" : object({d})", .{x.index}), - .dylib => |x| try writer.print(" : dylib({d})", .{x.index}), + .zig_object => |x| try bw.print(" : zig_object({d})", .{x.index}), + .internal => |x| try bw.print(" : internal({d})", .{x.index}), + .object => |x| try bw.print(" : object({d})", .{x.index}), + .dylib => |x| try bw.print(" : dylib({d})", .{x.index}), } - } else try writer.writeAll(" : unresolved"); + } else try bw.writeAll(" : unresolved"); } pub const Flags = packed struct { diff --git a/src/link/MachO/Thunk.zig b/src/link/MachO/Thunk.zig index d720d4fd25..4fec423d63 100644 --- a/src/link/MachO/Thunk.zig +++ b/src/link/MachO/Thunk.zig @@ -20,16 +20,16 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 { return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size; } -pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { +pub fn write(thunk: Thunk, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { for (thunk.symbols.keys(), 0..) |ref, i| { const sym = ref.getSymbol(macho_file).?; const saddr = thunk.getAddress(macho_file) + i * trampoline_size; const taddr = sym.getAddress(.{}, macho_file); const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); const off: u12 = @truncate(taddr); - try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little); - try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); } } @@ -61,16 +61,10 @@ pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void { } } -pub fn format( - thunk: Thunk, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +pub fn format(thunk: Thunk, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = thunk; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format Thunk directly"); } @@ -86,20 +80,14 @@ const FormatContext = struct { macho_file: *MachO, }; -fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; const thunk = ctx.thunk; const macho_file = ctx.macho_file; - try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() }); + try bw.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() }); for (thunk.symbols.keys()) |ref| { const sym = ref.getSymbol(macho_file).?; - try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value }); + try bw.print(" {f} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value }); } } diff --git a/src/link/MachO/UnwindInfo.zig b/src/link/MachO/UnwindInfo.zig index ffeeaddb23..5e62e1080f 100644 --- a/src/link/MachO/UnwindInfo.zig +++ b/src/link/MachO/UnwindInfo.zig @@ -133,7 +133,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { for (info.records.items) |ref| { const rec = ref.getUnwindRecord(macho_file); const atom = rec.getAtom(macho_file); - log.debug("@{x}-{x} : {s} : rec({d}) : object({d}) : {}", .{ + log.debug("@{x}-{x} : {s} : rec({d}) : object({d}) : {f}", .{ rec.getAtomAddress(macho_file), rec.getAtomAddress(macho_file) + rec.length, atom.getName(macho_file), @@ -202,7 +202,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { if (i >= max_common_encodings) break; if (slice[i].count < 2) continue; info.appendCommonEncoding(slice[i].enc); - log.debug("adding common encoding: {d} => {}", .{ i, slice[i].enc }); + log.debug("adding common encoding: {d} => {f}", .{ i, slice[i].enc }); } } @@ -255,7 +255,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { page.kind = .compressed; } - log.debug("{}", .{page.fmt(info.*)}); + log.debug("{f}", .{page.fmt(info.*)}); try info.pages.append(gpa, page); } @@ -289,13 +289,10 @@ pub fn calcSize(info: UnwindInfo) usize { return total_size; } -pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { +pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *std.io.BufferedWriter) anyerror!void { const seg = macho_file.getTextSegment(); const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?]; - var stream = std.io.fixedBufferStream(buffer); - const writer = stream.writer(); - const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header); const common_encodings_count: u32 = info.common_encodings_count; const personalities_offset: u32 = common_encodings_offset + common_encodings_count * @sizeOf(u32); @@ -303,7 +300,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32); const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1)); - try writer.writeStruct(macho.unwind_info_section_header{ + try bw.writeStruct(macho.unwind_info_section_header{ .commonEncodingsArraySectionOffset = common_encodings_offset, .commonEncodingsArrayCount = common_encodings_count, .personalityArraySectionOffset = personalities_offset, @@ -312,11 +309,11 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { .indexCount = indexes_count, }); - try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count])); + try bw.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count])); for (info.personalities[0..info.personalities_count]) |ref| { const sym = ref.getSymbol(macho_file).?; - try writer.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little); + try bw.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little); } const pages_base_offset = @as(u32, @intCast(header.size - (info.pages.items.len * second_level_page_bytes))); @@ -325,7 +322,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { for (info.pages.items, 0..) |page, i| { assert(page.count > 0); const rec = info.records.items[page.start].getUnwindRecord(macho_file); - try writer.writeStruct(macho.unwind_info_section_header_index_entry{ + try bw.writeStruct(macho.unwind_info_section_header_index_entry{ .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)), .lsdaIndexArraySectionOffset = lsda_base_offset + @@ -335,7 +332,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file); const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr)); - try writer.writeStruct(macho.unwind_info_section_header_index_entry{ + try bw.writeStruct(macho.unwind_info_section_header_index_entry{ .functionOffset = sentinel_address, .secondLevelPagesSectionOffset = 0, .lsdaIndexArraySectionOffset = lsda_base_offset + @@ -344,23 +341,20 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { for (info.lsdas.items) |index| { const rec = info.records.items[index].getUnwindRecord(macho_file); - try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{ + try bw.writeStruct(macho.unwind_info_section_header_lsda_index_entry{ .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)), }); } for (info.pages.items) |page| { - const start = stream.pos; - try page.write(info, macho_file, writer); - const nwritten = stream.pos - start; - if (nwritten < second_level_page_bytes) { - const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow; - try writer.writeByteNTimes(0, padding); - } + const start = bw.count; + try page.write(info, macho_file, bw); + const nwritten = bw.count - start; + try bw.splatByteAll(0, math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow); } - @memset(buffer[stream.pos..], 0); + @memset(bw.unusedCapacitySlice(), 0); } fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 { @@ -455,15 +449,9 @@ pub const Encoding = extern struct { return enc.enc == other.enc; } - pub fn format( - enc: Encoding, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(enc: Encoding, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; - try writer.print("0x{x:0>8}", .{enc.enc}); + try bw.print("0x{x:0>8}", .{enc.enc}); } }; @@ -517,16 +505,10 @@ pub const Record = struct { return lsda.getAddress(macho_file) + rec.lsda_offset; } - pub fn format( - rec: Record, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(rec: Record, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = rec; + _ = bw; _ = unused_fmt_string; - _ = options; - _ = writer; @compileError("do not format UnwindInfo.Records directly"); } @@ -542,22 +524,16 @@ pub const Record = struct { macho_file: *MachO, }; - fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const rec = ctx.rec; const macho_file = ctx.macho_file; - try writer.print("{x} : len({x})", .{ + try bw.print("{x} : len({x})", .{ rec.enc.enc, rec.length, }); - if (rec.enc.isDwarf(macho_file)) try writer.print(" : fde({d})", .{rec.fde}); - try writer.print(" : {s}", .{rec.getAtom(macho_file).getName(macho_file)}); - if (!rec.alive) try writer.writeAll(" : [*]"); + if (rec.enc.isDwarf(macho_file)) try bw.print(" : fde({d})", .{rec.fde}); + try bw.print(" : {s}", .{rec.getAtom(macho_file).getName(macho_file)}); + if (!rec.alive) try bw.writeAll(" : [*]"); } pub const Index = u32; @@ -613,16 +589,10 @@ const Page = struct { return null; } - fn format( - page: *const Page, - comptime unused_format_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + fn format(page: *const Page, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) anyerror!void { _ = page; + _ = bw; _ = unused_format_string; - _ = options; - _ = writer; @compileError("do not format Page directly; use page.fmt()"); } @@ -631,23 +601,17 @@ const Page = struct { info: UnwindInfo, }; - fn format2( - ctx: FormatPageContext, - comptime unused_format_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - _ = options; + fn format2(ctx: FormatPageContext, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) anyerror!void { _ = unused_format_string; - try writer.writeAll("Page:\n"); - try writer.print(" kind: {s}\n", .{@tagName(ctx.page.kind)}); - try writer.print(" entries: {d} - {d}\n", .{ + try bw.writeAll("Page:\n"); + try bw.print(" kind: {s}\n", .{@tagName(ctx.page.kind)}); + try bw.print(" entries: {d} - {d}\n", .{ ctx.page.start, ctx.page.start + ctx.page.count, }); - try writer.print(" encodings (count = {d})\n", .{ctx.page.page_encodings_count}); + try bw.print(" encodings (count = {d})\n", .{ctx.page.page_encodings_count}); for (ctx.page.page_encodings[0..ctx.page.page_encodings_count], 0..) |enc, i| { - try writer.print(" {d}: {}\n", .{ ctx.info.common_encodings_count + i, enc }); + try bw.print(" {d}: {f}\n", .{ ctx.info.common_encodings_count + i, enc }); } } diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 97c1a0ad54..ef716f953c 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -317,12 +317,12 @@ pub fn updateArSize(self: *ZigObject) void { self.output_ar_state.size = self.data.items.len; } -pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !void { +pub fn writeAr(self: ZigObject, bw: *std.io.BufferedWriter, ar_format: Archive.Format) anyerror!void { // Header const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; - try Archive.writeHeader(self.basename, size, ar_format, writer); + try Archive.writeHeader(bw, self.basename, size, ar_format); // Data - try writer.writeAll(self.data.items); + try bw.writeAll(self.data.items); } pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void { @@ -618,7 +618,7 @@ pub fn getNavVAddr( const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index }); + log.debug("getNavVAddr {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); const sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol( macho_file, nav.name.toSlice(ip), @@ -884,7 +884,6 @@ pub fn updateNav( defer debug_wip_nav.deinit(); dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, - error.Overflow => return error.Overflow, else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}), }; } @@ -921,7 +920,6 @@ pub fn updateNav( if (debug_wip_nav) |*wip_nav| self.dwarf.?.finishWipNav(pt, nav_index, wip_nav) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, - error.Overflow => return error.Overflow, else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}), }; } else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index); @@ -943,7 +941,7 @@ fn updateNavCode( const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - log.debug("updateNavCode {} 0x{x}", .{ nav.fqn.fmt(ip), nav_index }); + log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index }); const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; const required_alignment = switch (pt.navAlignment(nav_index)) { @@ -981,7 +979,7 @@ fn updateNavCode( if (need_realloc) { atom.grow(macho_file) catch |err| return macho_file.base.cgFail(nav_index, "failed to grow atom: {s}", .{@errorName(err)}); - log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom.value }); + log.debug("growing {f} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom.value }); if (old_vaddr != atom.value) { sym.value = 0; nlist.n_value = 0; @@ -1023,7 +1021,7 @@ fn updateTlv( const ip = &pt.zcu.intern_pool; const nav = ip.getNav(nav_index); - log.debug("updateTlv {} (0x{x})", .{ nav.fqn.fmt(ip), nav_index }); + log.debug("updateTlv {f} (0x{x})", .{ nav.fqn.fmt(ip), nav_index }); // 1. Lower TLV initializer const init_sym_index = try self.createTlvInitializer( @@ -1351,7 +1349,7 @@ fn updateLazySymbol( defer code_buffer.deinit(gpa); const name_str = blk: { - const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{ + const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt), }); @@ -1430,7 +1428,7 @@ pub fn deleteExport( } orelse return; const nlist_index = metadata.@"export"(self, name.toSlice(&zcu.intern_pool)) orelse return; - log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)}); + log.debug("deleting export '{f}'", .{name.fmt(&zcu.intern_pool)}); const nlist = &self.symtab.items(.nlist)[nlist_index.*]; self.symtab.items(.size)[nlist_index.*] = 0; @@ -1690,24 +1688,18 @@ const FormatContext = struct { macho_file: *MachO, }; -fn formatSymtab( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatSymtab(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; - try writer.writeAll(" symbols\n"); + try bw.writeAll(" symbols\n"); const self = ctx.self; const macho_file = ctx.macho_file; for (self.symbols.items, 0..) |sym, i| { const ref = self.getSymbolRef(@intCast(i), macho_file); if (ref.getFile(macho_file) == null) { // TODO any better way of handling this? - try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); + try bw.print(" {s} : unclaimed\n", .{sym.getName(macho_file)}); } else { - try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); + try bw.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)}); } } } @@ -1719,20 +1711,14 @@ pub fn fmtAtoms(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(formatAt } }; } -fn formatAtoms( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { +fn formatAtoms(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const self = ctx.self; const macho_file = ctx.macho_file; - try writer.writeAll(" atoms\n"); + try bw.writeAll(" atoms\n"); for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - try writer.print(" {}\n", .{atom.fmt(macho_file)}); + try bw.print(" {f}\n", .{atom.fmt(macho_file)}); } } diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig index 24d7e18d1a..8397f11d42 100644 --- a/src/link/MachO/dead_strip.zig +++ b/src/link/MachO/dead_strip.zig @@ -117,7 +117,7 @@ fn mark(roots: []*Atom, objects: []const File.Index, macho_file: *MachO) void { fn markLive(atom: *Atom, macho_file: *MachO) void { assert(atom.visited.load(.seq_cst)); atom.setAlive(true); - track_live_log.debug("{}marking live atom({d},{s})", .{ + track_live_log.debug("{f}marking live atom({d},{s})", .{ track_live_level, atom.atom_index, atom.getName(macho_file), @@ -196,15 +196,9 @@ const Level = struct { self.value += 1; } - pub fn format( - self: *const @This(), - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(self: *const @This(), bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; - try writer.writeByteNTimes(' ', self.value); + try bw.splatByteAll(' ', self.value); } }; diff --git a/src/link/MachO/dyld_info/Rebase.zig b/src/link/MachO/dyld_info/Rebase.zig index dc4fcbcc1d..52c57ff161 100644 --- a/src/link/MachO/dyld_info/Rebase.zig +++ b/src/link/MachO/dyld_info/Rebase.zig @@ -3,7 +3,7 @@ buffer: std.ArrayListUnmanaged(u8) = .empty, pub const Entry = struct { offset: u64, - segment_id: u8, + segment_id: u4, pub fn lessThan(ctx: void, entry: Entry, other: Entry) bool { _ = ctx; @@ -110,33 +110,35 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void { fn finalize(rebase: *Rebase, gpa: Allocator) !void { if (rebase.entries.items.len == 0) return; - const writer = rebase.buffer.writer(gpa); + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.fromArrayList(gpa, &rebase.buffer); + defer rebase.buffer = aw.toArrayList(); log.debug("rebase opcodes", .{}); std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan); - try setTypePointer(writer); + try setTypePointer(bw); var start: usize = 0; var seg_id: ?u8 = null; for (rebase.entries.items, 0..) |entry, i| { if (seg_id != null and seg_id.? == entry.segment_id) continue; - try finalizeSegment(rebase.entries.items[start..i], writer); + try finalizeSegment(rebase.entries.items[start..i], bw); seg_id = entry.segment_id; start = i; } - try finalizeSegment(rebase.entries.items[start..], writer); - try done(writer); + try finalizeSegment(rebase.entries.items[start..], bw); + try done(bw); } -fn finalizeSegment(entries: []const Entry, writer: anytype) !void { +fn finalizeSegment(entries: []const Entry, bw: *std.io.BufferedWriter) anyerror!void { if (entries.len == 0) return; const segment_id = entries[0].segment_id; var offset = entries[0].offset; - try setSegmentOffset(segment_id, offset, writer); + try setSegmentOffset(segment_id, offset, bw); var count: usize = 0; var skip: u64 = 0; @@ -155,7 +157,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void { .start => { if (offset < current_offset) { const delta = current_offset - offset; - try addAddr(delta, writer); + try addAddr(delta, bw); offset += delta; } state = .times; @@ -175,7 +177,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void { offset += skip; i -= 1; } else { - try rebaseTimes(count, writer); + try rebaseTimes(count, bw); state = .start; i -= 1; } @@ -184,9 +186,9 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void { if (current_offset < offset) { count -= 1; if (count == 1) { - try rebaseAddAddr(skip, writer); + try rebaseAddAddr(skip, bw); } else { - try rebaseTimesSkip(count, skip, writer); + try rebaseTimesSkip(count, skip, bw); } state = .start; offset = offset - (@sizeOf(u64) + skip); @@ -199,7 +201,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void { count += 1; offset += @sizeOf(u64) + skip; } else { - try rebaseTimesSkip(count, skip, writer); + try rebaseTimesSkip(count, skip, bw); state = .start; i -= 1; } @@ -210,68 +212,66 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void { switch (state) { .start => unreachable, .times => { - try rebaseTimes(count, writer); + try rebaseTimes(count, bw); }, .times_skip => { - try rebaseTimesSkip(count, skip, writer); + try rebaseTimesSkip(count, skip, bw); }, } } -fn setTypePointer(writer: anytype) !void { +fn setTypePointer(bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> set type: {d}", .{macho.REBASE_TYPE_POINTER}); - try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.REBASE_TYPE_POINTER))); + try bw.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.REBASE_TYPE_POINTER))); } -fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void { +fn setSegmentOffset(segment_id: u4, offset: u64, bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset }); - try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id))); - try std.leb.writeUleb128(writer, offset); + try bw.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id))); + try bw.writeLeb128(offset); } -fn rebaseAddAddr(addr: u64, writer: anytype) !void { +fn rebaseAddAddr(addr: u64, bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> rebase with add: {x}", .{addr}); - try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB); - try std.leb.writeUleb128(writer, addr); + try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB); + try bw.writeLeb128(addr); } -fn rebaseTimes(count: usize, writer: anytype) !void { +fn rebaseTimes(count: usize, bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> rebase with count: {d}", .{count}); if (count <= 0xf) { - try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count))); + try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count))); } else { - try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES); - try std.leb.writeUleb128(writer, count); + try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES); + try bw.writeLeb128(count); } } -fn rebaseTimesSkip(count: usize, skip: u64, writer: anytype) !void { +fn rebaseTimesSkip(count: usize, skip: u64, bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, skip }); - try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB); - try std.leb.writeUleb128(writer, count); - try std.leb.writeUleb128(writer, skip); + try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB); + try bw.writeLeb128(count); + try bw.writeLeb128(skip); } -fn addAddr(addr: u64, writer: anytype) !void { +fn addAddr(addr: u64, bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> add: {x}", .{addr}); - if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) { - const imm = @divExact(addr, @sizeOf(u64)); - if (imm <= 0xf) { - try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm))); - return; - } - } - try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB); - try std.leb.writeUleb128(writer, addr); + if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| { + if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte( + macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | imm_scaled, + ); + } else |_| {} + try bw.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB); + try bw.writeLeb128(addr); } -fn done(writer: anytype) !void { +fn done(bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> done", .{}); - try writer.writeByte(macho.REBASE_OPCODE_DONE); + try bw.writeByte(macho.REBASE_OPCODE_DONE); } -pub fn write(rebase: Rebase, writer: anytype) !void { - try writer.writeAll(rebase.buffer.items); +pub fn write(rebase: Rebase, bw: *std.io.BufferedWriter) anyerror!void { + try bw.writeAll(rebase.buffer.items); } test "rebase - no entries" { diff --git a/src/link/MachO/dyld_info/Trie.zig b/src/link/MachO/dyld_info/Trie.zig index 8224dc8424..d39f1aad52 100644 --- a/src/link/MachO/dyld_info/Trie.zig +++ b/src/link/MachO/dyld_info/Trie.zig @@ -31,7 +31,7 @@ /// The root node of the trie. root: ?Node.Index = null, -buffer: std.ArrayListUnmanaged(u8) = .empty, +buffer: []u8 = &.{}, nodes: std.MultiArrayList(Node) = .{}, edges: std.ArrayListUnmanaged(Edge) = .empty, @@ -123,7 +123,7 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void { try self.finalize(gpa); - macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); + macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.len), @alignOf(u64)); } /// Finalizes this trie for writing to a byte stream. @@ -164,9 +164,12 @@ fn finalize(self: *Trie, allocator: Allocator) !void { } } - try self.buffer.ensureTotalCapacityPrecise(allocator, size); + assert(self.buffer.len == 0); + self.buffer = try allocator.alloc(u8, size); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(self.buffer); for (ordered_nodes.items) |node_index| { - try self.writeNode(node_index, self.buffer.writer(allocator)); + try self.writeNode(node_index, &bw); } } @@ -181,17 +184,20 @@ const FinalizeNodeResult = struct { /// Updates offset of this node in the output byte stream. fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult { - var stream = std.io.countingWriter(std.io.null_writer); - const writer = stream.writer(); + var buf: [1024]u8 = undefined; + var bw: std.io.BufferedWriter = .{ + .unbuffered_writer = .null, + .buffer = &buf, + }; const slice = self.nodes.slice(); var node_size: u32 = 0; if (slice.items(.is_terminal)[node_index]) { const export_flags = slice.items(.export_flags)[node_index]; const vmaddr_offset = slice.items(.vmaddr_offset)[node_index]; - try leb.writeULEB128(writer, export_flags); - try leb.writeULEB128(writer, vmaddr_offset); - try leb.writeULEB128(writer, stream.bytes_written); + try bw.writeLeb128(export_flags); + try bw.writeLeb128(vmaddr_offset); + try bw.writeLeb128(bw.count); } else { node_size += 1; // 0x0 for non-terminal nodes } @@ -201,13 +207,13 @@ fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !Final const edge = &self.edges.items[edge_index]; const next_node_offset = slice.items(.trie_offset)[edge.node]; node_size += @intCast(edge.label.len + 1); - try leb.writeULEB128(writer, next_node_offset); + try bw.writeLeb128(next_node_offset); } const trie_offset = slice.items(.trie_offset)[node_index]; const updated = offset_in_trie != trie_offset; slice.items(.trie_offset)[node_index] = offset_in_trie; - node_size += @intCast(stream.bytes_written); + node_size += @intCast(bw.count); return .{ .node_size = node_size, .updated = updated }; } @@ -223,12 +229,11 @@ pub fn deinit(self: *Trie, allocator: Allocator) void { } self.nodes.deinit(allocator); self.edges.deinit(allocator); - self.buffer.deinit(allocator); + allocator.free(self.buffer); } -pub fn write(self: Trie, writer: anytype) !void { - if (self.buffer.items.len == 0) return; - try writer.writeAll(self.buffer.items); +pub fn write(self: Trie, bw: *std.io.BufferedWriter) anyerror!void { + try bw.writeAll(self.buffer); } /// Writes this node to a byte stream. @@ -237,7 +242,7 @@ pub fn write(self: Trie, writer: anytype) !void { /// iterate over `Trie.ordered_nodes` and call this method on each node. /// This is one of the requirements of the MachO. /// Panics if `finalize` was not called before calling this method. -fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void { +fn writeNode(self: *Trie, node_index: Node.Index, bw: *std.io.BufferedWriter) !void { const slice = self.nodes.slice(); const edges = slice.items(.edges)[node_index]; const is_terminal = slice.items(.is_terminal)[node_index]; @@ -245,36 +250,28 @@ fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void { const vmaddr_offset = slice.items(.vmaddr_offset)[node_index]; if (is_terminal) { - // Terminal node info: encode export flags and vmaddr offset of this symbol. - var info_buf: [@sizeOf(u64) * 2]u8 = undefined; - var info_stream = std.io.fixedBufferStream(&info_buf); + const start = bw.count; // TODO Implement for special flags. assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0); - try leb.writeULEB128(info_stream.writer(), export_flags); - try leb.writeULEB128(info_stream.writer(), vmaddr_offset); - + // Terminal node info: encode export flags and vmaddr offset of this symbol. + try bw.writeLeb128(export_flags); + try bw.writeLeb128(vmaddr_offset); // Encode the size of the terminal node info. - var size_buf: [@sizeOf(u64)]u8 = undefined; - var size_stream = std.io.fixedBufferStream(&size_buf); - try leb.writeULEB128(size_stream.writer(), info_stream.pos); - - // Now, write them to the output stream. - try writer.writeAll(size_buf[0..size_stream.pos]); - try writer.writeAll(info_buf[0..info_stream.pos]); + try bw.writeLeb128(bw.count - start); } else { // Non-terminal node is delimited by 0 byte. - try writer.writeByte(0); + try bw.writeByte(0); } - // Write number of edges (max legal number of edges is 256). - try writer.writeByte(@as(u8, @intCast(edges.items.len))); + // Write number of edges (max legal number of edges is 255). + try bw.writeByte(@intCast(edges.items.len)); for (edges.items) |edge_index| { const edge = self.edges.items[edge_index]; // Write edge label and offset to next node in trie. - try writer.writeAll(edge.label); - try writer.writeByte(0); - try leb.writeULEB128(writer, slice.items(.trie_offset)[edge.node]); + try bw.writeAll(edge.label); + try bw.writeByte(0); + try bw.writeLeb128(slice.items(.trie_offset)[edge.node]); } } diff --git a/src/link/MachO/dyld_info/bind.zig b/src/link/MachO/dyld_info/bind.zig index 328d6a402c..1b546b1fcc 100644 --- a/src/link/MachO/dyld_info/bind.zig +++ b/src/link/MachO/dyld_info/bind.zig @@ -1,7 +1,7 @@ pub const Entry = struct { target: MachO.Ref, offset: u64, - segment_id: u8, + segment_id: u4, addend: i64, pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool { @@ -20,14 +20,12 @@ pub const Bind = struct { entries: std.ArrayListUnmanaged(Entry) = .empty, buffer: std.ArrayListUnmanaged(u8) = .empty, - const Self = @This(); - - pub fn deinit(self: *Self, gpa: Allocator) void { - self.entries.deinit(gpa); - self.buffer.deinit(gpa); + pub fn deinit(bind: *Bind, gpa: Allocator) void { + bind.entries.deinit(gpa); + bind.buffer.deinit(gpa); } - pub fn updateSize(self: *Self, macho_file: *MachO) !void { + pub fn updateSize(bind: *Bind, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); @@ -56,15 +54,12 @@ pub const Bind = struct { const addend = rel.addend + rel.getRelocAddend(cpu_arch); const sym = rel.getTargetSymbol(atom.*, macho_file); if (sym.isTlvInit(macho_file)) continue; - const entry = Entry{ + if (sym.flags.import or (!(sym.flags.@"export" and sym.flags.weak) and sym.flags.interposable)) (try bind.entries.addOne(gpa)).* = .{ .target = rel.getTargetSymbolRef(atom.*, macho_file), .offset = atom_addr + rel_offset - seg.vmaddr, .segment_id = seg_id, .addend = addend, }; - if (sym.flags.import or (!(sym.flags.@"export" and sym.flags.weak) and sym.flags.interposable)) { - try self.entries.append(gpa, entry); - } } } } @@ -75,15 +70,12 @@ pub const Bind = struct { for (macho_file.got.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = macho_file.got.getAddress(@intCast(idx), macho_file); - const entry = Entry{ + if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) { - try self.entries.append(gpa, entry); - } } } @@ -94,15 +86,12 @@ pub const Bind = struct { for (macho_file.stubs.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = sect.addr + idx * @sizeOf(u64); - const bind_entry = Entry{ + if (sym.flags.import and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.import and sym.flags.weak) { - try self.entries.append(gpa, bind_entry); - } } } @@ -113,49 +102,48 @@ pub const Bind = struct { for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file); - const entry = Entry{ + if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) { - try self.entries.append(gpa, entry); - } } } - try self.finalize(gpa, macho_file); - macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); + try bind.finalize(gpa, macho_file); + macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64)); } - fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { - if (self.entries.items.len == 0) return; + fn finalize(bind: *Bind, gpa: Allocator, ctx: *MachO) !void { + if (bind.entries.items.len == 0) return; - const writer = self.buffer.writer(gpa); + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.fromArrayList(gpa, &bind.buffer); + defer bind.buffer = aw.toArrayList(); log.debug("bind opcodes", .{}); - std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan); + std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan); var start: usize = 0; var seg_id: ?u8 = null; - for (self.entries.items, 0..) |entry, i| { + for (bind.entries.items, 0..) |entry, i| { if (seg_id != null and seg_id.? == entry.segment_id) continue; - try finalizeSegment(self.entries.items[start..i], ctx, writer); + try finalizeSegment(bind.entries.items[start..i], ctx, bw); seg_id = entry.segment_id; start = i; } - try finalizeSegment(self.entries.items[start..], ctx, writer); - try done(writer); + try finalizeSegment(bind.entries.items[start..], ctx, bw); + try done(bw); } - fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void { + fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *std.io.BufferedWriter) anyerror!void { if (entries.len == 0) return; const seg_id = entries[0].segment_id; - try setSegmentOffset(seg_id, 0, writer); + try setSegmentOffset(seg_id, 0, bw); var offset: u64 = 0; var addend: i64 = 0; @@ -175,15 +163,15 @@ pub const Bind = struct { if (target == null or !target.?.eql(current.target)) { switch (state) { .start => {}, - .bind_single => try doBind(writer), - .bind_times_skip => try doBindTimesSkip(count, skip, writer), + .bind_single => try doBind(bw), + .bind_times_skip => try doBindTimesSkip(count, skip, bw), } state = .start; target = current.target; const sym = current.target.getSymbol(ctx).?; const name = sym.getName(ctx); - const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; + const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; const ordinal: i16 = ord: { if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP; if (sym.flags.import) { @@ -195,13 +183,13 @@ pub const Bind = struct { break :ord macho.BIND_SPECIAL_DYLIB_SELF; }; - try setSymbol(name, flags, writer); - try setTypePointer(writer); - try setDylibOrdinal(ordinal, writer); + try setSymbol(name, flags, bw); + try setTypePointer(bw); + try setDylibOrdinal(ordinal, bw); if (current.addend != addend) { addend = current.addend; - try setAddend(addend, writer); + try setAddend(addend, bw); } } @@ -210,11 +198,11 @@ pub const Bind = struct { switch (state) { .start => { if (current.offset < offset) { - try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), writer); + try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), bw); offset = offset - (offset - current.offset); } else if (current.offset > offset) { const delta = current.offset - offset; - try addAddr(delta, writer); + try addAddr(delta, bw); offset += delta; } state = .bind_single; @@ -223,7 +211,7 @@ pub const Bind = struct { }, .bind_single => { if (current.offset == offset) { - try doBind(writer); + try doBind(bw); state = .start; } else if (current.offset > offset) { const delta = current.offset - offset; @@ -237,9 +225,9 @@ pub const Bind = struct { if (current.offset < offset) { count -= 1; if (count == 1) { - try doBindAddAddr(skip, writer); + try doBindAddAddr(skip, bw); } else { - try doBindTimesSkip(count, skip, writer); + try doBindTimesSkip(count, skip, bw); } state = .start; offset = offset - (@sizeOf(u64) + skip); @@ -248,7 +236,7 @@ pub const Bind = struct { count += 1; offset += @sizeOf(u64) + skip; } else { - try doBindTimesSkip(count, skip, writer); + try doBindTimesSkip(count, skip, bw); state = .start; i -= 1; } @@ -258,13 +246,13 @@ pub const Bind = struct { switch (state) { .start => unreachable, - .bind_single => try doBind(writer), - .bind_times_skip => try doBindTimesSkip(count, skip, writer), + .bind_single => try doBind(bw), + .bind_times_skip => try doBindTimesSkip(count, skip, bw), } } - pub fn write(self: Self, writer: anytype) !void { - try writer.writeAll(self.buffer.items); + pub fn write(bind: Bind, bw: *std.io.BufferedWriter) anyerror!void { + try bw.writeAll(bind.buffer.items); } }; @@ -272,14 +260,12 @@ pub const WeakBind = struct { entries: std.ArrayListUnmanaged(Entry) = .empty, buffer: std.ArrayListUnmanaged(u8) = .empty, - const Self = @This(); - - pub fn deinit(self: *Self, gpa: Allocator) void { - self.entries.deinit(gpa); - self.buffer.deinit(gpa); + pub fn deinit(bind: *WeakBind, gpa: Allocator) void { + bind.entries.deinit(gpa); + bind.buffer.deinit(gpa); } - pub fn updateSize(self: *Self, macho_file: *MachO) !void { + pub fn updateSize(bind: *WeakBind, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); @@ -308,15 +294,12 @@ pub const WeakBind = struct { const addend = rel.addend + rel.getRelocAddend(cpu_arch); const sym = rel.getTargetSymbol(atom.*, macho_file); if (sym.isTlvInit(macho_file)) continue; - const entry = Entry{ + if (!sym.isLocal() and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{ .target = rel.getTargetSymbolRef(atom.*, macho_file), .offset = atom_addr + rel_offset - seg.vmaddr, .segment_id = seg_id, .addend = addend, }; - if (!sym.isLocal() and sym.flags.weak) { - try self.entries.append(gpa, entry); - } } } } @@ -327,15 +310,12 @@ pub const WeakBind = struct { for (macho_file.got.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = macho_file.got.getAddress(@intCast(idx), macho_file); - const entry = Entry{ + if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.weak) { - try self.entries.append(gpa, entry); - } } } @@ -347,15 +327,12 @@ pub const WeakBind = struct { for (macho_file.stubs.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = sect.addr + idx * @sizeOf(u64); - const bind_entry = Entry{ + if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.weak) { - try self.entries.append(gpa, bind_entry); - } } } @@ -366,49 +343,48 @@ pub const WeakBind = struct { for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file); - const entry = Entry{ + if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if (sym.flags.weak) { - try self.entries.append(gpa, entry); - } } } - try self.finalize(gpa, macho_file); - macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); + try bind.finalize(gpa, macho_file); + macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64)); } - fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { - if (self.entries.items.len == 0) return; + fn finalize(bind: *WeakBind, gpa: Allocator, ctx: *MachO) !void { + if (bind.entries.items.len == 0) return; - const writer = self.buffer.writer(gpa); + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.fromArrayList(gpa, &bind.buffer); + defer bind.buffer = aw.toArrayList(); log.debug("weak bind opcodes", .{}); - std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan); + std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan); var start: usize = 0; var seg_id: ?u8 = null; - for (self.entries.items, 0..) |entry, i| { + for (bind.entries.items, 0..) |entry, i| { if (seg_id != null and seg_id.? == entry.segment_id) continue; - try finalizeSegment(self.entries.items[start..i], ctx, writer); + try finalizeSegment(bind.entries.items[start..i], ctx, bw); seg_id = entry.segment_id; start = i; } - try finalizeSegment(self.entries.items[start..], ctx, writer); - try done(writer); + try finalizeSegment(bind.entries.items[start..], ctx, bw); + try done(bw); } - fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void { + fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *std.io.BufferedWriter) anyerror!void { if (entries.len == 0) return; const seg_id = entries[0].segment_id; - try setSegmentOffset(seg_id, 0, writer); + try setSegmentOffset(seg_id, 0, bw); var offset: u64 = 0; var addend: i64 = 0; @@ -428,8 +404,8 @@ pub const WeakBind = struct { if (target == null or !target.?.eql(current.target)) { switch (state) { .start => {}, - .bind_single => try doBind(writer), - .bind_times_skip => try doBindTimesSkip(count, skip, writer), + .bind_single => try doBind(bw), + .bind_times_skip => try doBindTimesSkip(count, skip, bw), } state = .start; target = current.target; @@ -438,12 +414,12 @@ pub const WeakBind = struct { const name = sym.getName(ctx); const flags: u8 = 0; // TODO NON_WEAK_DEFINITION - try setSymbol(name, flags, writer); - try setTypePointer(writer); + try setSymbol(name, flags, bw); + try setTypePointer(bw); if (current.addend != addend) { addend = current.addend; - try setAddend(addend, writer); + try setAddend(addend, bw); } } @@ -452,11 +428,11 @@ pub const WeakBind = struct { switch (state) { .start => { if (current.offset < offset) { - try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), writer); + try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), bw); offset = offset - (offset - current.offset); } else if (current.offset > offset) { const delta = current.offset - offset; - try addAddr(delta, writer); + try addAddr(delta, bw); offset += delta; } state = .bind_single; @@ -465,7 +441,7 @@ pub const WeakBind = struct { }, .bind_single => { if (current.offset == offset) { - try doBind(writer); + try doBind(bw); state = .start; } else if (current.offset > offset) { const delta = current.offset - offset; @@ -479,9 +455,9 @@ pub const WeakBind = struct { if (current.offset < offset) { count -= 1; if (count == 1) { - try doBindAddAddr(skip, writer); + try doBindAddAddr(skip, bw); } else { - try doBindTimesSkip(count, skip, writer); + try doBindTimesSkip(count, skip, bw); } state = .start; offset = offset - (@sizeOf(u64) + skip); @@ -490,7 +466,7 @@ pub const WeakBind = struct { count += 1; offset += @sizeOf(u64) + skip; } else { - try doBindTimesSkip(count, skip, writer); + try doBindTimesSkip(count, skip, bw); state = .start; i -= 1; } @@ -500,13 +476,13 @@ pub const WeakBind = struct { switch (state) { .start => unreachable, - .bind_single => try doBind(writer), - .bind_times_skip => try doBindTimesSkip(count, skip, writer), + .bind_single => try doBind(bw), + .bind_times_skip => try doBindTimesSkip(count, skip, bw), } } - pub fn write(self: Self, writer: anytype) !void { - try writer.writeAll(self.buffer.items); + pub fn write(bind: WeakBind, bw: *std.io.BufferedWriter) anyerror!void { + try bw.writeAll(bind.buffer.items); } }; @@ -515,15 +491,13 @@ pub const LazyBind = struct { buffer: std.ArrayListUnmanaged(u8) = .empty, offsets: std.ArrayListUnmanaged(u32) = .empty, - const Self = @This(); - - pub fn deinit(self: *Self, gpa: Allocator) void { - self.entries.deinit(gpa); - self.buffer.deinit(gpa); - self.offsets.deinit(gpa); + pub fn deinit(bind: *LazyBind, gpa: Allocator) void { + bind.entries.deinit(gpa); + bind.buffer.deinit(gpa); + bind.offsets.deinit(gpa); } - pub fn updateSize(self: *Self, macho_file: *MachO) !void { + pub fn updateSize(bind: *LazyBind, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); @@ -537,36 +511,35 @@ pub const LazyBind = struct { for (macho_file.stubs.symbols.items, 0..) |ref, idx| { const sym = ref.getSymbol(macho_file).?; const addr = sect.addr + idx * @sizeOf(u64); - const bind_entry = Entry{ + if ((sym.flags.import and !sym.flags.weak) or (sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{ .target = ref, .offset = addr - seg.vmaddr, .segment_id = seg_id, .addend = 0, }; - if ((sym.flags.import and !sym.flags.weak) or (sym.flags.interposable and !sym.flags.weak)) { - try self.entries.append(gpa, bind_entry); - } } - try self.finalize(gpa, macho_file); - macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64)); + try bind.finalize(gpa, macho_file); + macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64)); } - fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void { - try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len); + fn finalize(bind: *LazyBind, gpa: Allocator, ctx: *MachO) !void { + try bind.offsets.ensureTotalCapacityPrecise(gpa, bind.entries.items.len); - const writer = self.buffer.writer(gpa); + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.fromArrayList(gpa, &bind.buffer); + defer bind.buffer = aw.toArrayList(); log.debug("lazy bind opcodes", .{}); var addend: i64 = 0; - for (self.entries.items) |entry| { - self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len)); + for (bind.entries.items) |entry| { + bind.offsets.appendAssumeCapacity(@intCast(bind.buffer.items.len)); const sym = entry.target.getSymbol(ctx).?; const name = sym.getName(ctx); - const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; + const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0; const ordinal: i16 = ord: { if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP; if (sym.flags.import) { @@ -578,109 +551,103 @@ pub const LazyBind = struct { break :ord macho.BIND_SPECIAL_DYLIB_SELF; }; - try setSegmentOffset(entry.segment_id, entry.offset, writer); - try setSymbol(name, flags, writer); - try setDylibOrdinal(ordinal, writer); + try setSegmentOffset(entry.segment_id, entry.offset, bw); + try setSymbol(name, flags, bw); + try setDylibOrdinal(ordinal, bw); if (entry.addend != addend) { - try setAddend(entry.addend, writer); + try setAddend(entry.addend, bw); addend = entry.addend; } - try doBind(writer); - try done(writer); + try doBind(bw); + try done(bw); } } - pub fn write(self: Self, writer: anytype) !void { - try writer.writeAll(self.buffer.items); + pub fn write(bind: LazyBind, bw: *std.io.BufferedWriter) anyerror!void { + try bw.writeAll(bind.buffer.items); } }; -fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void { +fn setSegmentOffset(segment_id: u4, offset: u64, bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset }); - try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id))); - try std.leb.writeUleb128(writer, offset); + try bw.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segment_id); + try bw.writeLeb128(offset); } -fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void { +fn setSymbol(name: []const u8, flags: u4, bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags }); - try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | @as(u4, @truncate(flags))); - try writer.writeAll(name); - try writer.writeByte(0); + try bw.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags); + try bw.writeAll(name); + try bw.writeByte(0); } -fn setTypePointer(writer: anytype) !void { +fn setTypePointer(bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER}); - try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.BIND_TYPE_POINTER))); + try bw.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.BIND_TYPE_POINTER))); } -fn setDylibOrdinal(ordinal: i16, writer: anytype) !void { - if (ordinal <= 0) { - switch (ordinal) { - macho.BIND_SPECIAL_DYLIB_SELF, - macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE, - macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP, - => {}, - else => unreachable, // Invalid dylib special binding - } - log.debug(">>> set dylib special: {d}", .{ordinal}); - const cast = @as(u16, @bitCast(ordinal)); - try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @truncate(cast))); - } else { - const cast = @as(u16, @bitCast(ordinal)); - log.debug(">>> set dylib ordinal: {d}", .{ordinal}); - if (cast <= 0xf) { - try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @as(u4, @truncate(cast))); - } else { - try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB); - try std.leb.writeUleb128(writer, cast); - } +fn setDylibOrdinal(ordinal: i16, bw: *std.io.BufferedWriter) anyerror!void { + switch (ordinal) { + else => unreachable, // Invalid dylib special binding + macho.BIND_SPECIAL_DYLIB_SELF, + macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE, + macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP, + => { + log.debug(">>> set dylib special: {d}", .{ordinal}); + try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @bitCast(@as(i4, @intCast(ordinal))))); + }, + 1...std.math.maxInt(i16) => { + log.debug(">>> set dylib ordinal: {d}", .{ordinal}); + if (std.math.cast(u4, ordinal)) |imm| { + try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | imm); + } else { + try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB); + try bw.writeUleb128(ordinal); + } + }, } } -fn setAddend(addend: i64, writer: anytype) !void { +fn setAddend(addend: i64, bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> set addend: {x}", .{addend}); - try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB); - try std.leb.writeIleb128(writer, addend); + try bw.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB); + try bw.writeLeb128(addend); } -fn doBind(writer: anytype) !void { +fn doBind(bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> bind", .{}); - try writer.writeByte(macho.BIND_OPCODE_DO_BIND); + try bw.writeByte(macho.BIND_OPCODE_DO_BIND); } -fn doBindAddAddr(addr: u64, writer: anytype) !void { +fn doBindAddAddr(addr: u64, bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> bind with add: {x}", .{addr}); - if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) { - const imm = @divExact(addr, @sizeOf(u64)); - if (imm <= 0xf) { - try writer.writeByte( - macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm)), - ); - return; - } - } - try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB); - try std.leb.writeUleb128(writer, addr); + if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| { + if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte( + macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | imm_scaled, + ); + } else |_| {} + try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB); + try bw.writeLeb128(addr); } -fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void { +fn doBindTimesSkip(count: usize, skip: u64, bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip }); - try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB); - try std.leb.writeUleb128(writer, count); - try std.leb.writeUleb128(writer, skip); + try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB); + try bw.writeLeb128(count); + try bw.writeLeb128(skip); } -fn addAddr(addr: u64, writer: anytype) !void { +fn addAddr(addr: u64, bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> add: {x}", .{addr}); - try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB); - try std.leb.writeUleb128(writer, addr); + try bw.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB); + try bw.writeLeb128(addr); } -fn done(writer: anytype) !void { +fn done(bw: *std.io.BufferedWriter) anyerror!void { log.debug(">>> done", .{}); - try writer.writeByte(macho.BIND_OPCODE_DONE); + try bw.writeByte(macho.BIND_OPCODE_DONE); } const assert = std.debug.assert; diff --git a/src/link/MachO/eh_frame.zig b/src/link/MachO/eh_frame.zig index ccabffb1dc..3371ec7d02 100644 --- a/src/link/MachO/eh_frame.zig +++ b/src/link/MachO/eh_frame.zig @@ -12,36 +12,34 @@ pub const Cie = struct { const tracy = trace(@src()); defer tracy.end(); - const data = cie.getData(macho_file); - const aug = std.mem.sliceTo(@as([*:0]const u8, @ptrCast(data.ptr + 9)), 0); + var br: std.io.BufferedReader = undefined; + br.initFixed(cie.getData(macho_file)); + try br.discard(9); + const aug = try br.takeSentinel(0); if (aug[0] != 'z') return; // TODO should we error out? - var stream = std.io.fixedBufferStream(data[9 + aug.len + 1 ..]); - var creader = std.io.countingReader(stream.reader()); - const reader = creader.reader(); - - _ = try leb.readUleb128(u64, reader); // code alignment factor - _ = try leb.readUleb128(u64, reader); // data alignment factor - _ = try leb.readUleb128(u64, reader); // return address register - _ = try leb.readUleb128(u64, reader); // augmentation data length + _ = try br.takeLeb128(u64); // code alignment factor + _ = try br.takeLeb128(u64); // data alignment factor + _ = try br.takeLeb128(u64); // return address register + _ = try br.takeLeb128(u64); // augmentation data length for (aug[1..]) |ch| switch (ch) { 'R' => { - const enc = try reader.readByte(); + const enc = try br.takeByte(); if (enc != DW_EH_PE.pcrel | DW_EH_PE.absptr) { @panic("unexpected pointer encoding"); // TODO error } }, 'P' => { - const enc = try reader.readByte(); + const enc = try br.takeByte(); if (enc != DW_EH_PE.pcrel | DW_EH_PE.indirect | DW_EH_PE.sdata4) { @panic("unexpected personality pointer encoding"); // TODO error } - _ = try reader.readInt(u32, .little); // personality pointer + _ = try br.takeInt(u32, .little); // personality pointer }, 'L' => { - const enc = try reader.readByte(); + const enc = try br.takeByte(); switch (enc & DW_EH_PE.type_mask) { DW_EH_PE.sdata4 => cie.lsda_size = .p32, DW_EH_PE.absptr => cie.lsda_size = .p64, @@ -106,20 +104,14 @@ pub const Cie = struct { macho_file: *MachO, }; - fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const cie = ctx.cie; - try writer.print("@{x} : size({x})", .{ + try bw.print("@{x} : size({x})", .{ cie.offset, cie.getSize(), }); - if (!cie.alive) try writer.writeAll(" : [*]"); + if (!cie.alive) try bw.writeAll(" : [*]"); } pub const Index = u32; @@ -148,12 +140,17 @@ pub const Fde = struct { const tracy = trace(@src()); defer tracy.end(); - const data = fde.getData(macho_file); const object = fde.getObject(macho_file); const sect = object.sections.items(.header)[object.eh_frame_sect_index.?]; + var br: std.io.BufferedReader = undefined; + br.initFixed(fde.getData(macho_file)); + + try br.discard(4); + const cie_ptr = try br.takeInt(u32, .little); + const pc_begin = try br.takeInt(i64, .little); + // Parse target atom index - const pc_begin = std.mem.readInt(i64, data[8..][0..8], .little); const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin); fde.atom = object.findAtom(taddr) orelse { try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{ @@ -165,7 +162,6 @@ pub const Fde = struct { fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file)); // Associate with a CIE - const cie_ptr = std.mem.readInt(u32, data[4..8], .little); const cie_offset = fde.offset + 4 - cie_ptr; const cie_index = for (object.cies.items, 0..) |cie, cie_index| { if (cie.offset == cie_offset) break @as(Cie.Index, @intCast(cie_index)); @@ -183,14 +179,12 @@ pub const Fde = struct { // Parse LSDA atom index if any if (cie.lsda_size) |lsda_size| { - var stream = std.io.fixedBufferStream(data[24..]); - var creader = std.io.countingReader(stream.reader()); - const reader = creader.reader(); - _ = try leb.readUleb128(u64, reader); // augmentation length - fde.lsda_ptr_offset = @intCast(creader.bytes_read + 24); + try br.discard(8); + _ = try br.takeLeb128(u64); // augmentation length + fde.lsda_ptr_offset = @intCast(br.seek); const lsda_ptr = switch (lsda_size) { - .p32 => try reader.readInt(i32, .little), - .p64 => try reader.readInt(i64, .little), + .p32 => try br.takeInt(i32, .little), + .p64 => try br.takeInt(i64, .little), }; const lsda_addr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + fde.lsda_ptr_offset)) + lsda_ptr); fde.lsda = object.findAtom(lsda_addr) orelse { @@ -256,31 +250,24 @@ pub const Fde = struct { macho_file: *MachO, }; - fn format2( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + fn format2(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; const fde = ctx.fde; const macho_file = ctx.macho_file; - try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{ + try bw.print("@{x} : size({x}) : cie({d}) : {s}", .{ fde.offset, fde.getSize(), fde.cie, fde.getAtom(macho_file).getName(macho_file), }); - if (!fde.alive) try writer.writeAll(" : [*]"); + if (!fde.alive) try bw.writeAll(" : [*]"); } pub const Index = u32; }; pub const Iterator = struct { - data: []const u8, - pos: u32 = 0, + br: std.io.BufferedReader, pub const Record = struct { tag: enum { fde, cie }, @@ -289,21 +276,18 @@ pub const Iterator = struct { }; pub fn next(it: *Iterator) !?Record { - if (it.pos >= it.data.len) return null; + if (it.br.seek >= it.br.storageBuffer().len) return null; - var stream = std.io.fixedBufferStream(it.data[it.pos..]); - const reader = stream.reader(); - - const size = try reader.readInt(u32, .little); + const size = try it.br.takeInt(u32, .little); if (size == 0xFFFFFFFF) @panic("DWARF CFI is 32bit on macOS"); - const id = try reader.readInt(u32, .little); - const record = Record{ + const id = try it.br.takeInt(u32, .little); + const record: Record = .{ .tag = if (id == 0) .cie else .fde, - .offset = it.pos, + .offset = @intCast(it.br.seek), .size = size, }; - it.pos += size + 4; + try it.br.discard(size); return record; } diff --git a/src/link/MachO/file.zig b/src/link/MachO/file.zig index 6d90dde4a9..9d438920ab 100644 --- a/src/link/MachO/file.zig +++ b/src/link/MachO/file.zig @@ -14,19 +14,13 @@ pub const File = union(enum) { return .{ .data = file }; } - fn formatPath( - file: File, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + fn formatPath(file: File, bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8) anyerror!void { _ = unused_fmt_string; - _ = options; switch (file) { - .zig_object => |zo| try writer.writeAll(zo.basename), - .internal => try writer.writeAll("internal"), - .object => |x| try writer.print("{}", .{x.fmtPath()}), - .dylib => |dl| try writer.print("{}", .{@as(Path, dl.path)}), + .zig_object => |zo| try bw.writeAll(zo.basename), + .internal => try bw.writeAll("internal"), + .object => |x| try bw.print("{f}", .{x.fmtPath()}), + .dylib => |dl| try bw.print("{f}", .{@as(Path, dl.path)}), } } @@ -328,11 +322,11 @@ pub const File = union(enum) { }; } - pub fn writeAr(file: File, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { + pub fn writeAr(file: File, bw: *std.io.BufferedWriter, ar_format: Archive.Format, macho_file: *MachO) anyerror!void { return switch (file) { .dylib, .internal => unreachable, - .zig_object => |x| x.writeAr(ar_format, writer), - .object => |x| x.writeAr(ar_format, macho_file, writer), + .zig_object => |x| x.writeAr(bw, ar_format), + .object => |x| x.writeAr(bw, ar_format, macho_file), }; } diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 08ab11e3f9..77c6a1ce53 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -180,23 +180,20 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 { return offset; } -pub fn writeDylinkerLC(writer: anytype) !void { +pub fn writeDylinkerLC(bw: *std.io.BufferedWriter) anyerror!void { const name_len = mem.sliceTo(default_dyld_path, 0).len; const cmdsize = @as(u32, @intCast(mem.alignForward( u64, @sizeOf(macho.dylinker_command) + name_len, @sizeOf(u64), ))); - try writer.writeStruct(macho.dylinker_command{ + try bw.writeStruct(macho.dylinker_command{ .cmd = .LOAD_DYLINKER, .cmdsize = cmdsize, .name = @sizeOf(macho.dylinker_command), }); - try writer.writeAll(mem.sliceTo(default_dyld_path, 0)); - const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len; - if (padding > 0) { - try writer.writeByteNTimes(0, padding); - } + try bw.writeAll(mem.sliceTo(default_dyld_path, 0)); + try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylinker_command) - name_len); } const WriteDylibLCCtx = struct { @@ -207,14 +204,14 @@ const WriteDylibLCCtx = struct { compatibility_version: u32 = 0x10000, }; -pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void { +pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *std.io.BufferedWriter) !void { const name_len = ctx.name.len + 1; - const cmdsize = @as(u32, @intCast(mem.alignForward( + const cmdsize: u32 = @intCast(mem.alignForward( u64, @sizeOf(macho.dylib_command) + name_len, @sizeOf(u64), - ))); - try writer.writeStruct(macho.dylib_command{ + )); + try bw.writeStruct(macho.dylib_command{ .cmd = ctx.cmd, .cmdsize = cmdsize, .dylib = .{ @@ -224,12 +221,9 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void { .compatibility_version = ctx.compatibility_version, }, }); - try writer.writeAll(ctx.name); - try writer.writeByte(0); - const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len; - if (padding > 0) { - try writer.writeByteNTimes(0, padding); - } + try bw.writeAll(ctx.name); + try bw.writeByte(0); + try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylib_command) - name_len); } pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void { @@ -258,26 +252,23 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void { }, writer); } -pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void { +pub fn writeRpathLC(bw: *std.io.BufferedWriter, rpath: []const u8) !void { const rpath_len = rpath.len + 1; const cmdsize = @as(u32, @intCast(mem.alignForward( u64, @sizeOf(macho.rpath_command) + rpath_len, @sizeOf(u64), ))); - try writer.writeStruct(macho.rpath_command{ + try bw.writeStruct(macho.rpath_command{ .cmdsize = cmdsize, .path = @sizeOf(macho.rpath_command), }); - try writer.writeAll(rpath); - try writer.writeByte(0); - const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len; - if (padding > 0) { - try writer.writeByteNTimes(0, padding); - } + try bw.writeAll(rpath); + try bw.writeByte(0); + try bw.splatByteAll(0, cmdsize - @sizeOf(macho.rpath_command) - rpath_len); } -pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void { +pub fn writeVersionMinLC(bw: *std.io.BufferedWriter, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) anyerror!void { const cmd: macho.LC = switch (platform.os_tag) { .macos => .VERSION_MIN_MACOSX, .ios => .VERSION_MIN_IPHONEOS, @@ -285,7 +276,7 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer .watchos => .VERSION_MIN_WATCHOS, else => unreachable, }; - try writer.writeAll(mem.asBytes(&macho.version_min_command{ + try bw.writeAll(mem.asBytes(&macho.version_min_command{ .cmd = cmd, .version = platform.toAppleVersion(), .sdk = if (sdk_version) |ver| @@ -295,9 +286,9 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer })); } -pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void { +pub fn writeBuildVersionLC(bw: *std.io.BufferedWriter, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) anyerror!void { const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version); - try writer.writeStruct(macho.build_version_command{ + try bw.writeStruct(macho.build_version_command{ .cmdsize = cmdsize, .platform = platform.toApplePlatform(), .minos = platform.toAppleVersion(), @@ -307,7 +298,7 @@ pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticV platform.toAppleVersion(), .ntools = 1, }); - try writer.writeAll(mem.asBytes(&macho.build_tool_version{ + try bw.writeAll(mem.asBytes(&macho.build_tool_version{ .tool = .ZIG, .version = 0x0, })); diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index 4edf6e043d..7d9df227cf 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -20,13 +20,13 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat // the *only* input file over. const path = positionals.items[0].path().?; const in_file = path.root_dir.handle.openFile(path.sub_path, .{}) catch |err| - return diags.fail("failed to open {}: {s}", .{ path, @errorName(err) }); + return diags.fail("failed to open {f}: {s}", .{ path, @errorName(err) }); const stat = in_file.stat() catch |err| - return diags.fail("failed to stat {}: {s}", .{ path, @errorName(err) }); + return diags.fail("failed to stat {f}: {s}", .{ path, @errorName(err) }); const amt = in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size) catch |err| - return diags.fail("failed to copy range of file {}: {s}", .{ path, @errorName(err) }); + return diags.fail("failed to copy range of file {f}: {s}", .{ path, @errorName(err) }); if (amt != stat.size) - return diags.fail("unexpected short write in copy range of file {}", .{path}); + return diags.fail("unexpected short write in copy range of file {f}", .{path}); return; } @@ -62,12 +62,12 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat allocateSegment(macho_file); if (build_options.enable_logging) { - state_log.debug("{}", .{macho_file.dumpState()}); + state_log.debug("{f}", .{macho_file.dumpState()}); } try writeSections(macho_file); sortRelocs(macho_file); - try writeSectionsToFile(macho_file); + writeSectionsToFile(macho_file) catch |err| return @errorCast(err); // In order to please Apple ld (and possibly other MachO linkers in the wild), // we will now sanitize segment names of Zig-specific segments. @@ -126,12 +126,12 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? allocateSegment(macho_file); if (build_options.enable_logging) { - state_log.debug("{}", .{macho_file.dumpState()}); + state_log.debug("{f}", .{macho_file.dumpState()}); } try writeSections(macho_file); sortRelocs(macho_file); - try writeSectionsToFile(macho_file); + writeSectionsToFile(macho_file) catch |err| return @errorCast(err); // In order to please Apple ld (and possibly other MachO linkers in the wild), // we will now sanitize segment names of Zig-specific segments. @@ -202,38 +202,32 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? }; if (build_options.enable_logging) { - state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(macho_file)}); + state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)}); } - var buffer = std.ArrayList(u8).init(gpa); - defer buffer.deinit(); - try buffer.ensureTotalCapacityPrecise(total_size); - const writer = buffer.writer(); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, total_size)); + defer gpa.free(bw.buffer); // Write magic - try writer.writeAll(Archive.ARMAG); + bw.writeAll(Archive.ARMAG) catch unreachable; // Write symtab - ar_symtab.write(format, macho_file, writer) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, + ar_symtab.write(&bw, format, macho_file) catch |err| switch (err) { + error.OutOfMemory => unreachable, else => |e| return diags.fail("failed to write archive symbol table: {s}", .{@errorName(e)}), }; // Write object files for (files.items) |index| { - const aligned = mem.alignForward(usize, buffer.items.len, 2); - const padding = aligned - buffer.items.len; - if (padding > 0) { - try writer.writeByteNTimes(0, padding); - } - macho_file.getFile(index).?.writeAr(format, macho_file, writer) catch |err| + bw.splatByteAll(0, mem.alignForward(usize, bw.end, 2) - bw.end) catch unreachable; + macho_file.getFile(index).?.writeAr(&bw, format, macho_file) catch |err| return diags.fail("failed to write archive: {s}", .{@errorName(err)}); } - assert(buffer.items.len == total_size); - - try macho_file.setEndPos(total_size); - try macho_file.pwriteAll(buffer.items, 0); + assert(bw.end == bw.buffer.len); + try macho_file.setEndPos(bw.end); + try macho_file.pwriteAll(bw.buffer, 0); if (diags.hasErrors()) return error.LinkFailure; } @@ -689,12 +683,9 @@ fn writeSectionsToFile(macho_file: *MachO) !void { fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } { const gpa = macho_file.base.comp.gpa; - const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file); - const buffer = try gpa.alloc(u8, needed_size); - defer gpa.free(buffer); - - var stream = std.io.fixedBufferStream(buffer); - const writer = stream.writer(); + var bw: std.io.BufferedWriter = undefined; + bw.initFixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeObject(macho_file))); + defer gpa.free(bw.buffer); var ncmds: usize = 0; @@ -702,47 +693,31 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc { assert(macho_file.segments.items.len == 1); const seg = macho_file.segments.items[0]; - writer.writeStruct(seg) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; + bw.writeStruct(seg) catch unreachable; for (macho_file.sections.items(.header)) |header| { - writer.writeStruct(header) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; + bw.writeStruct(header) catch unreachable; } ncmds += 1; } - writer.writeStruct(macho_file.data_in_code_cmd) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; + bw.writeStruct(macho_file.data_in_code_cmd) catch unreachable; ncmds += 1; - writer.writeStruct(macho_file.symtab_cmd) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; + bw.writeStruct(macho_file.symtab_cmd) catch unreachable; ncmds += 1; - writer.writeStruct(macho_file.dysymtab_cmd) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; + bw.writeStruct(macho_file.dysymtab_cmd) catch unreachable; ncmds += 1; if (macho_file.platform.isBuildVersionCompatible()) { - load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; + load_commands.writeBuildVersionLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable; ncmds += 1; } else { - load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; + load_commands.writeVersionMinLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable; ncmds += 1; } - assert(stream.pos == needed_size); - - try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); - - return .{ ncmds, buffer.len }; + assert(bw.end == bw.buffer.len); + try macho_file.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64)); + return .{ ncmds, bw.end }; } fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { diff --git a/src/link/MachO/synthetic.zig b/src/link/MachO/synthetic.zig index 6042fe628d..387225ae71 100644 --- a/src/link/MachO/synthetic.zig +++ b/src/link/MachO/synthetic.zig @@ -27,13 +27,13 @@ pub const GotSection = struct { return got.symbols.items.len * @sizeOf(u64); } - pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void { + pub fn write(got: GotSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { const tracy = trace(@src()); defer tracy.end(); for (got.symbols.items) |ref| { const sym = ref.getSymbol(macho_file).?; const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file); - try writer.writeInt(u64, value, .little); + try bw.writeInt(u64, value, .little); } } @@ -48,15 +48,13 @@ pub const GotSection = struct { pub fn format2( ctx: FormatCtx, + bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, ) !void { - _ = options; _ = unused_fmt_string; for (ctx.got.symbols.items, 0..) |ref, i| { const symbol = ref.getSymbol(ctx.macho_file).?; - try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ + try bw.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{ i, symbol.getGotAddress(ctx.macho_file), ref, @@ -96,7 +94,7 @@ pub const StubsSection = struct { return stubs.symbols.items.len * header.reserved2; } - pub fn write(stubs: StubsSection, macho_file: *MachO, writer: anytype) !void { + pub fn write(stubs: StubsSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { const tracy = trace(@src()); defer tracy.end(); const cpu_arch = macho_file.getTarget().cpu.arch; @@ -108,20 +106,20 @@ pub const StubsSection = struct { const target = laptr_sect.addr + idx * @sizeOf(u64); switch (cpu_arch) { .x86_64 => { - try writer.writeAll(&.{ 0xff, 0x25 }); - try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little); + try bw.writeAll(&.{ 0xff, 0x25 }); + try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little); }, .aarch64 => { // TODO relax if possible const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); const off = try math.divExact(u12, @truncate(target), 8); - try writer.writeInt( + try bw.writeInt( u32, aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), .little, ); - try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); }, else => unreachable, } @@ -139,15 +137,13 @@ pub const StubsSection = struct { pub fn format2( ctx: FormatCtx, + bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, ) !void { - _ = options; _ = unused_fmt_string; for (ctx.stubs.symbols.items, 0..) |ref, i| { const symbol = ref.getSymbol(ctx.macho_file).?; - try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ + try bw.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{ i, symbol.getStubsAddress(ctx.macho_file), ref, @@ -189,11 +185,11 @@ pub const StubsHelperSection = struct { return s; } - pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void { + pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { const tracy = trace(@src()); defer tracy.end(); - try stubs_helper.writePreamble(macho_file, writer); + try stubs_helper.writePreamble(macho_file, bw); const cpu_arch = macho_file.getTarget().cpu.arch; const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?]; @@ -209,24 +205,24 @@ pub const StubsHelperSection = struct { const target: i64 = @intCast(sect.addr); switch (cpu_arch) { .x86_64 => { - try writer.writeByte(0x68); - try writer.writeInt(u32, offset, .little); - try writer.writeByte(0xe9); - try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little); + try bw.writeByte(0x68); + try bw.writeInt(u32, offset, .little); + try bw.writeByte(0xe9); + try bw.writeInt(i32, @intCast(target - source - 6 - 4), .little); }, .aarch64 => { const literal = blk: { const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4); break :blk std.math.cast(u18, div_res) orelse return error.Overflow; }; - try writer.writeInt(u32, aarch64.Instruction.ldrLiteral( + try bw.writeInt(u32, aarch64.Instruction.ldrLiteral( .w16, literal, ).toU32(), .little); const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse return error.Overflow; - try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little); - try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 }); + try bw.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little); + try bw.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 }); }, else => unreachable, } @@ -234,7 +230,7 @@ pub const StubsHelperSection = struct { } } - fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void { + fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { _ = stubs_helper; const obj = macho_file.getInternalObject().?; const cpu_arch = macho_file.getTarget().cpu.arch; @@ -249,21 +245,21 @@ pub const StubsHelperSection = struct { }; switch (cpu_arch) { .x86_64 => { - try writer.writeAll(&.{ 0x4c, 0x8d, 0x1d }); - try writer.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little); - try writer.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 }); - try writer.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little); - try writer.writeByte(0x90); + try bw.writeAll(&.{ 0x4c, 0x8d, 0x1d }); + try bw.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little); + try bw.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 }); + try bw.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little); + try bw.writeByte(0x90); }, .aarch64 => { { // TODO relax if possible const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little); const off: u12 = @truncate(dyld_private_addr); - try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little); } - try writer.writeInt(u32, aarch64.Instruction.stp( + try bw.writeInt(u32, aarch64.Instruction.stp( .x16, .x17, aarch64.Register.sp, @@ -272,15 +268,15 @@ pub const StubsHelperSection = struct { { // TODO relax if possible const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8); - try writer.writeInt(u32, aarch64.Instruction.ldr( + try bw.writeInt(u32, aarch64.Instruction.ldr( .x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off), ).toU32(), .little); } - try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); }, else => unreachable, } @@ -293,7 +289,7 @@ pub const LaSymbolPtrSection = struct { return macho_file.stubs.symbols.items.len * @sizeOf(u64); } - pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: anytype) !void { + pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { const tracy = trace(@src()); defer tracy.end(); _ = laptr; @@ -304,12 +300,12 @@ pub const LaSymbolPtrSection = struct { const sym = ref.getSymbol(macho_file).?; if (sym.flags.weak) { const value = sym.getAddress(.{ .stubs = false }, macho_file); - try writer.writeInt(u64, @intCast(value), .little); + try bw.writeInt(u64, @intCast(value), .little); } else { const value = sect.addr + StubsHelperSection.preambleSize(cpu_arch) + StubsHelperSection.entrySize(cpu_arch) * stub_helper_idx; stub_helper_idx += 1; - try writer.writeInt(u64, @intCast(value), .little); + try bw.writeInt(u64, @intCast(value), .little); } } } @@ -343,16 +339,16 @@ pub const TlvPtrSection = struct { return tlv.symbols.items.len * @sizeOf(u64); } - pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: anytype) !void { + pub fn write(tlv: TlvPtrSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { const tracy = trace(@src()); defer tracy.end(); for (tlv.symbols.items) |ref| { const sym = ref.getSymbol(macho_file).?; if (sym.flags.import) { - try writer.writeInt(u64, 0, .little); + try bw.writeInt(u64, 0, .little); } else { - try writer.writeInt(u64, sym.getAddress(.{}, macho_file), .little); + try bw.writeInt(u64, sym.getAddress(.{}, macho_file), .little); } } } @@ -368,15 +364,13 @@ pub const TlvPtrSection = struct { pub fn format2( ctx: FormatCtx, + bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, ) !void { - _ = options; _ = unused_fmt_string; for (ctx.tlv.symbols.items, 0..) |ref, i| { const symbol = ref.getSymbol(ctx.macho_file).?; - try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ + try bw.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{ i, symbol.getTlvPtrAddress(ctx.macho_file), ref, @@ -421,7 +415,7 @@ pub const ObjcStubsSection = struct { return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch); } - pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: anytype) !void { + pub fn write(objc: ObjcStubsSection, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { const tracy = trace(@src()); defer tracy.end(); @@ -432,18 +426,18 @@ pub const ObjcStubsSection = struct { const addr = objc.getAddress(@intCast(idx), macho_file); switch (macho_file.getTarget().cpu.arch) { .x86_64 => { - try writer.writeAll(&.{ 0x48, 0x8b, 0x35 }); + try bw.writeAll(&.{ 0x48, 0x8b, 0x35 }); { const target = sym.getObjcSelrefsAddress(macho_file); const source = addr; - try writer.writeInt(i32, @intCast(target - source - 3 - 4), .little); + try bw.writeInt(i32, @intCast(target - source - 3 - 4), .little); } - try writer.writeAll(&.{ 0xff, 0x25 }); + try bw.writeAll(&.{ 0xff, 0x25 }); { const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?; const target = target_sym.getGotAddress(macho_file); const source = addr + 7; - try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little); + try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little); } }, .aarch64 => { @@ -451,9 +445,9 @@ pub const ObjcStubsSection = struct { const target = sym.getObjcSelrefsAddress(macho_file); const source = addr; const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little); const off = try math.divExact(u12, @truncate(target), 8); - try writer.writeInt( + try bw.writeInt( u32, aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), .little, @@ -464,18 +458,18 @@ pub const ObjcStubsSection = struct { const target = target_sym.getGotAddress(macho_file); const source = addr + 2 * @sizeOf(u32); const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); const off = try math.divExact(u12, @truncate(target), 8); - try writer.writeInt( + try bw.writeInt( u32, aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), .little, ); } - try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); - try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); - try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); - try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); + try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); }, else => unreachable, } @@ -493,15 +487,13 @@ pub const ObjcStubsSection = struct { pub fn format2( ctx: FormatCtx, + bw: *std.io.BufferedWriter, comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, ) !void { - _ = options; _ = unused_fmt_string; for (ctx.objc.symbols.items, 0..) |ref, i| { const symbol = ref.getSymbol(ctx.macho_file).?; - try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ + try bw.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{ i, symbol.getObjcStubsAddress(ctx.macho_file), ref, @@ -524,7 +516,7 @@ pub const Indsymtab = struct { macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file); } - pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void { + pub fn write(ind: Indsymtab, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { const tracy = trace(@src()); defer tracy.end(); @@ -533,21 +525,21 @@ pub const Indsymtab = struct { for (macho_file.stubs.symbols.items) |ref| { const sym = ref.getSymbol(macho_file).?; if (sym.getOutputSymtabIndex(macho_file)) |idx| { - try writer.writeInt(u32, idx, .little); + try bw.writeInt(u32, idx, .little); } } for (macho_file.got.symbols.items) |ref| { const sym = ref.getSymbol(macho_file).?; if (sym.getOutputSymtabIndex(macho_file)) |idx| { - try writer.writeInt(u32, idx, .little); + try bw.writeInt(u32, idx, .little); } } for (macho_file.stubs.symbols.items) |ref| { const sym = ref.getSymbol(macho_file).?; if (sym.getOutputSymtabIndex(macho_file)) |idx| { - try writer.writeInt(u32, idx, .little); + try bw.writeInt(u32, idx, .little); } } } @@ -601,7 +593,7 @@ pub const DataInCode = struct { macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow; } - pub fn write(dice: DataInCode, macho_file: *MachO, writer: anytype) !void { + pub fn write(dice: DataInCode, macho_file: *MachO, bw: *std.io.BufferedWriter) !void { const base_address = if (!macho_file.base.isRelocatable()) macho_file.getTextSegment().vmaddr else @@ -609,7 +601,7 @@ pub const DataInCode = struct { for (dice.entries.items) |entry| { const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file); const offset = atom_address + entry.offset - base_address; - try writer.writeStruct(macho.data_in_code_entry{ + try bw.writeStruct(macho.data_in_code_entry{ .offset = @intCast(offset), .length = entry.length, .kind = entry.kind, diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 9658495bce..bde706fd5f 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -202,7 +202,7 @@ pub const Atom = struct { /// after every opcode, add the quanta of the instruction size to the pc pub const DebugInfoOutput = struct { /// the actual opcodes - dbg_line: std.ArrayList(u8), + dbg_line: std.ArrayListUnmanaged(u8), /// what line the debuginfo starts on /// this helps because the linker might have to insert some opcodes to make sure that the line count starts at the right amount for the next decl start_line: ?u32, @@ -336,23 +336,26 @@ fn putFn(self: *Plan9, nav_index: InternPool.Nav.Index, out: FnNavOutput) !void }; try fn_map_res.value_ptr.functions.put(gpa, nav_index, out); - var a = std.ArrayList(u8).init(arena); - errdefer a.deinit(); + var aw: std.io.AllocatingWriter = undefined; + aw.init(arena); + defer aw.deinit(); + const bw = &aw.buffered_writer; + // every 'z' starts with 0 - try a.append(0); + try bw.writeByte(0); // path component value of '/' - try a.writer().writeInt(u16, 1, .big); + try bw.writeInt(u16, 1, .big); // getting the full file path { const full_path = try file.path.toAbsolute(comp.dirs, gpa); defer gpa.free(full_path); - try self.addPathComponents(full_path, &a); + try self.addPathComponents(full_path, bw); } // null terminate - try a.append(0); - const final = try a.toOwnedSlice(); + try bw.writeByte(0); + const final = try aw.toOwnedSlice(); self.syms.items[fn_map_res.value_ptr.sym_index - 1] = .{ .type = .z, .value = 1, @@ -367,17 +370,17 @@ fn putFn(self: *Plan9, nav_index: InternPool.Nav.Index, out: FnNavOutput) !void } } -fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !void { +fn addPathComponents(self: *Plan9, path: []const u8, bw: *std.io.BufferedWriter) !void { const gpa = self.base.comp.gpa; const sep = std.fs.path.sep; var it = std.mem.tokenizeScalar(u8, path, sep); while (it.next()) |component| { if (self.file_segments.get(component)) |num| { - try a.writer().writeInt(u16, num, .big); + try bw.writeInt(u16, num, .big); } else { self.file_segments_i += 1; try self.file_segments.put(gpa, component, self.file_segments_i); - try a.writer().writeInt(u16, self.file_segments_i, .big); + try bw.writeInt(u16, self.file_segments_i, .big); } } } @@ -402,14 +405,14 @@ pub fn updateFunc( var code_buffer: std.ArrayListUnmanaged(u8) = .empty; defer code_buffer.deinit(gpa); var dbg_info_output: DebugInfoOutput = .{ - .dbg_line = std.ArrayList(u8).init(gpa), + .dbg_line = .empty, .start_line = null, .end_line = undefined, .pcop_change_index = null, // we have already checked the target in the linker to make sure it is compatable .pc_quanta = aout.getPCQuant(target.cpu.arch) catch unreachable, }; - defer dbg_info_output.dbg_line.deinit(); + defer dbg_info_output.dbg_line.deinit(gpa); try codegen.emitFunction( &self.base, @@ -427,7 +430,7 @@ pub fn updateFunc( }; const out: FnNavOutput = .{ .code = code, - .lineinfo = try dbg_info_output.dbg_line.toOwnedSlice(), + .lineinfo = try dbg_info_output.dbg_line.toOwnedSlice(gpa), .start_line = dbg_info_output.start_line.?, .end_line = dbg_info_output.end_line, }; @@ -445,7 +448,7 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde .func => return, .variable => |variable| Value.fromInterned(variable.init), .@"extern" => { - log.debug("found extern decl: {}", .{nav.name.fmt(ip)}); + log.debug("found extern decl: {f}", .{nav.name.fmt(ip)}); return; }, else => nav_val, @@ -524,16 +527,14 @@ fn allocateGotIndex(self: *Plan9) usize { } } -pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void { +pub fn changeLine(bw: *std.io.Writer, delta_line: i32) !void { if (delta_line > 0 and delta_line < 65) { - const toappend = @as(u8, @intCast(delta_line)); - try l.append(toappend); + try bw.writeByte(@intCast(delta_line)); } else if (delta_line < 0 and delta_line > -65) { - const toadd: u8 = @as(u8, @intCast(-delta_line + 64)); - try l.append(toadd); + try bw.writeByte(@intCast(-delta_line + 64)); } else if (delta_line != 0) { - try l.append(0); - try l.writer().writeInt(i32, delta_line, .big); + try bw.writeByte(0); + try bw.writeInt(i32, delta_line, .big); } } @@ -645,10 +646,12 @@ pub fn flush( var iovecs_i: usize = 1; var text_i: u64 = 0; - var linecountinfo = std.ArrayList(u8).init(gpa); - defer linecountinfo.deinit(); + var linecountinfo_aw: std.io.AllocatingWriter = undefined; + linecountinfo_aw.init(gpa); + defer linecountinfo_aw.deinit(); // text { + const linecountinfo_bw = &linecountinfo_aw.buffered_writer; var linecount: i64 = -1; var it_file = self.fn_nav_table.iterator(); while (it_file.next()) |fentry| { @@ -662,11 +665,11 @@ pub fn flush( // connect the previous decl to the next const delta_line = @as(i32, @intCast(out.start_line)) - @as(i32, @intCast(linecount)); - try changeLine(&linecountinfo, delta_line); + changeLine(linecountinfo_bw, delta_line) catch |err| return @errorCast(err); // TODO change the pc too (maybe?) // write out the actual info that was generated in codegen now - try linecountinfo.appendSlice(out.lineinfo); + linecountinfo_bw.writeAll(out.lineinfo) catch |err| return @errorCast(err); linecount = out.end_line; } foff += out.code.len; @@ -675,7 +678,7 @@ pub fn flush( const off = self.getAddr(text_i, .t); text_i += out.code.len; atom.offset = off; - log.debug("write text nav 0x{x} ({}), lines {d} to {d}.;__GOT+0x{x} vaddr: 0x{x}", .{ nav_index, nav.name.fmt(&pt.zcu.intern_pool), out.start_line + 1, out.end_line, atom.got_index.? * 8, off }); + log.debug("write text nav 0x{x} ({f}), lines {d} to {d}.;__GOT+0x{x} vaddr: 0x{x}", .{ nav_index, nav.name.fmt(&pt.zcu.intern_pool), out.start_line + 1, out.end_line, atom.got_index.? * 8, off }); if (!self.sixtyfour_bit) { mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @intCast(off), target.cpu.arch.endian()); } else { @@ -687,11 +690,12 @@ pub fn flush( } } } - if (linecountinfo.items.len & 1 == 1) { + if (linecountinfo_aw.getWritten().len & 1 == 1) { // just a nop to make it even, the plan9 linker does this - try linecountinfo.append(129); + linecountinfo_bw.writeByte(129) catch |err| return @errorCast(err); } } + const linecountinfo = linecountinfo_aw.getWritten(); // the text lazy symbols { var it = self.lazy_syms.iterator(); @@ -815,25 +819,26 @@ pub fn flush( } } } - var sym_buf = std.ArrayList(u8).init(gpa); - try self.writeSyms(&sym_buf); - const syms = try sym_buf.toOwnedSlice(); - defer gpa.free(syms); + var syms_aw: std.io.AllocatingWriter = undefined; + syms_aw.init(gpa); + defer syms_aw.deinit(); + self.writeSyms(&syms_aw.buffered_writer) catch |err| return @errorCast(err); + const syms = syms_aw.getWritten(); assert(2 + self.atomCount() - self.externCount() == iovecs_i); // we didn't write all the decls iovecs[iovecs_i] = .{ .base = syms.ptr, .len = syms.len }; iovecs_i += 1; - iovecs[iovecs_i] = .{ .base = linecountinfo.items.ptr, .len = linecountinfo.items.len }; + iovecs[iovecs_i] = .{ .base = linecountinfo.ptr, .len = linecountinfo.len }; iovecs_i += 1; // generate the header self.hdr = .{ .magic = self.magic, - .text = @as(u32, @intCast(text_i)), - .data = @as(u32, @intCast(data_i)), - .syms = @as(u32, @intCast(syms.len)), + .text = @intCast(text_i), + .data = @intCast(data_i), + .syms = @intCast(syms.len), .bss = 0, .spsz = 0, - .pcsz = @as(u32, @intCast(linecountinfo.items.len)), - .entry = @as(u32, @intCast(self.entry_val.?)), + .pcsz = @intCast(linecountinfo.len), + .entry = @intCast(self.entry_val.?), }; @memcpy(hdr_slice, self.hdr.toU8s()[0..hdr_size]); // write the fat header for 64 bit entry points @@ -974,11 +979,11 @@ pub fn seeNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) self.etext_edata_end_atom_indices[2] = atom_idx; } try self.updateFinish(pt, nav_index); - log.debug("seeNav(extern) for {} (got_addr=0x{x})", .{ + log.debug("seeNav(extern) for {f} (got_addr=0x{x})", .{ nav.name.fmt(ip), self.getAtom(atom_idx).getOffsetTableAddress(self), }); - } else log.debug("seeNav for {}", .{nav.name.fmt(ip)}); + } else log.debug("seeNav for {f}", .{nav.name.fmt(ip)}); return atom_idx; } @@ -1043,7 +1048,7 @@ fn updateLazySymbolAtom( defer code_buffer.deinit(gpa); // create the symbol for the name - const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{ + const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ @tagName(sym.kind), Type.fromInterned(sym.ty).fmt(pt), }); @@ -1200,17 +1205,16 @@ pub fn writeSym(self: *Plan9, w: anytype, sym: aout.Sym) !void { try w.writeByte(0); } -pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { +pub fn writeSyms(self: *Plan9, bw: *std.io.BufferedWriter) !void { const zcu = self.base.comp.zcu.?; const ip = &zcu.intern_pool; - const writer = buf.writer(); // write __GOT - try self.writeSym(writer, self.syms.items[0]); + try self.writeSym(bw, self.syms.items[0]); // write the f symbols { var it = self.file_segments.iterator(); while (it.next()) |entry| { - try self.writeSym(writer, .{ + try self.writeSym(bw, .{ .type = .f, .value = entry.value_ptr.*, .name = entry.key_ptr.*, @@ -1226,12 +1230,12 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { const nav_metadata = self.navs.get(nav_index).?; const atom = self.getAtom(nav_metadata.index); const sym = self.syms.items[atom.sym_index.?]; - try self.writeSym(writer, sym); + try self.writeSym(bw, sym); if (self.nav_exports.get(nav_index)) |export_indices| { for (export_indices) |export_idx| { const exp = export_idx.ptr(zcu); if (nav_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| { - try self.writeSym(writer, self.syms.items[exp_i]); + try self.writeSym(bw, self.syms.items[exp_i]); } } } @@ -1244,7 +1248,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { const meta = kv.value_ptr; const data_atom = if (meta.rodata_state != .unused) self.getAtomPtr(meta.rodata_atom) else continue; const sym = self.syms.items[data_atom.sym_index.?]; - try self.writeSym(writer, sym); + try self.writeSym(bw, sym); } } // text symbols are the hardest: @@ -1255,8 +1259,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { while (it_file.next()) |fentry| { var symidx_and_submap = fentry.value_ptr; // write the z symbols - try self.writeSym(writer, self.syms.items[symidx_and_submap.sym_index - 1]); - try self.writeSym(writer, self.syms.items[symidx_and_submap.sym_index]); + try self.writeSym(bw, self.syms.items[symidx_and_submap.sym_index - 1]); + try self.writeSym(bw, self.syms.items[symidx_and_submap.sym_index]); // write all the decls come from the file of the z symbol var submap_it = symidx_and_submap.functions.iterator(); @@ -1265,7 +1269,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { const nav_metadata = self.navs.get(nav_index).?; const atom = self.getAtom(nav_metadata.index); const sym = self.syms.items[atom.sym_index.?]; - try self.writeSym(writer, sym); + try self.writeSym(bw, sym); if (self.nav_exports.get(nav_index)) |export_indices| { for (export_indices) |export_idx| { const exp = export_idx.ptr(zcu); @@ -1273,7 +1277,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { const s = self.syms.items[exp_i]; if (mem.eql(u8, s.name, "_start")) self.entry_val = s.value; - try self.writeSym(writer, s); + try self.writeSym(bw, s); } } } @@ -1286,7 +1290,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { const meta = kv.value_ptr; const text_atom = if (meta.text_state != .unused) self.getAtomPtr(meta.text_atom) else continue; const sym = self.syms.items[text_atom.sym_index.?]; - try self.writeSym(writer, sym); + try self.writeSym(bw, sym); } } } @@ -1295,7 +1299,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { if (idx) |atom_idx| { const atom = self.getAtom(atom_idx); const sym = self.syms.items[atom.sym_index.?]; - try self.writeSym(writer, sym); + try self.writeSym(bw, sym); } } } @@ -1314,7 +1318,7 @@ pub fn getNavVAddr( ) !u64 { const ip = &pt.zcu.intern_pool; const nav = ip.getNav(nav_index); - log.debug("getDeclVAddr for {}", .{nav.name.fmt(ip)}); + log.debug("getDeclVAddr for {f}", .{nav.name.fmt(ip)}); if (nav.getExtern(ip) != null) { if (nav.name.eqlSlice("etext", ip)) { try self.addReloc(reloc_info.parent.atom_index, .{ diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 7b908d56ed..9745009c17 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -117,7 +117,7 @@ pub fn updateNav(self: *SpirV, pt: Zcu.PerThread, nav: InternPool.Nav.Index) lin } const ip = &pt.zcu.intern_pool; - log.debug("lowering nav {}({d})", .{ ip.getNav(nav).fqn.fmt(ip), nav }); + log.debug("lowering nav {f}({d})", .{ ip.getNav(nav).fqn.fmt(ip), nav }); try self.object.updateNav(pt, nav); } @@ -203,10 +203,11 @@ pub fn flush( // We need to export the list of error names somewhere so that we can pretty-print them in the // executor. This is not really an important thing though, so we can just dump it in any old // nonsemantic instruction. For now, just put it in OpSourceExtension with a special name. - var error_info = std.ArrayList(u8).init(self.object.gpa); + var error_info: std.io.AllocatingWriter = undefined; + error_info.init(self.object.gpa); defer error_info.deinit(); - try error_info.appendSlice("zig_errors:"); + error_info.buffered_writer.writeAll("zig_errors:") catch |err| return @errorCast(err); const ip = &self.base.comp.zcu.?.intern_pool; for (ip.global_error_set.getNamesFromMainThread()) |name| { // Errors can contain pretty much any character - to encode them in a string we must escape @@ -214,9 +215,9 @@ pub fn flush( // name if it contains no strange characters is nice for debugging. URI encoding fits the bill. // We're using : as separator, which is a reserved character. - try error_info.append(':'); - try std.Uri.Component.percentEncode( - error_info.writer(), + error_info.buffered_writer.writeByte(':') catch |err| return @errorCast(err); + std.Uri.Component.percentEncode( + &error_info.buffered_writer, name.toSlice(ip), struct { fn isValidChar(c: u8) bool { @@ -226,10 +227,10 @@ pub fn flush( }; } }.isValidChar, - ); + ) catch |err| return @errorCast(err); } try spv.sections.debug_strings.emit(gpa, .OpSourceExtension, .{ - .extension = error_info.items, + .extension = error_info.getWritten(), }); const module = try spv.finalize(arena); diff --git a/src/link/SpirV/deduplicate.zig b/src/link/SpirV/deduplicate.zig index 2526900938..46b9642458 100644 --- a/src/link/SpirV/deduplicate.zig +++ b/src/link/SpirV/deduplicate.zig @@ -110,7 +110,7 @@ const ModuleInfo = struct { .TypeDeclaration, .ConstantCreation => { const entry = try entities.getOrPut(result_id); if (entry.found_existing) { - log.err("type or constant {} has duplicate definition", .{result_id}); + log.err("type or constant {f} has duplicate definition", .{result_id}); return error.DuplicateId; } entry.value_ptr.* = entity; diff --git a/src/link/SpirV/lower_invocation_globals.zig b/src/link/SpirV/lower_invocation_globals.zig index 9d91a142e4..5a64f38a35 100644 --- a/src/link/SpirV/lower_invocation_globals.zig +++ b/src/link/SpirV/lower_invocation_globals.zig @@ -92,7 +92,7 @@ const ModuleInfo = struct { const entry_point: ResultId = @enumFromInt(inst.operands[1]); const entry = try entry_points.getOrPut(entry_point); if (entry.found_existing) { - log.err("Entry point type {} has duplicate definition", .{entry_point}); + log.err("Entry point type {f} has duplicate definition", .{entry_point}); return error.DuplicateId; } }, @@ -103,7 +103,7 @@ const ModuleInfo = struct { const entry = try fn_types.getOrPut(fn_type); if (entry.found_existing) { - log.err("Function type {} has duplicate definition", .{fn_type}); + log.err("Function type {f} has duplicate definition", .{fn_type}); return error.DuplicateId; } @@ -135,7 +135,7 @@ const ModuleInfo = struct { }, .OpFunction => { if (maybe_current_function) |current_function| { - log.err("OpFunction {} does not have an OpFunctionEnd", .{current_function}); + log.err("OpFunction {f} does not have an OpFunctionEnd", .{current_function}); return error.InvalidPhysicalFormat; } @@ -154,7 +154,7 @@ const ModuleInfo = struct { }; const entry = try functions.getOrPut(current_function); if (entry.found_existing) { - log.err("Function {} has duplicate definition", .{current_function}); + log.err("Function {f} has duplicate definition", .{current_function}); return error.DuplicateId; } @@ -162,7 +162,7 @@ const ModuleInfo = struct { try callee_store.appendSlice(calls.keys()); const fn_type = fn_types.get(fn_ty_id) orelse { - log.err("Function {} has invalid OpFunction type", .{current_function}); + log.err("Function {f} has invalid OpFunction type", .{current_function}); return error.InvalidId; }; @@ -187,7 +187,7 @@ const ModuleInfo = struct { } if (maybe_current_function) |current_function| { - log.err("OpFunction {} does not have an OpFunctionEnd", .{current_function}); + log.err("OpFunction {f} does not have an OpFunctionEnd", .{current_function}); return error.InvalidPhysicalFormat; } @@ -222,7 +222,7 @@ const ModuleInfo = struct { seen: *std.DynamicBitSetUnmanaged, ) !void { const index = self.functions.getIndex(id) orelse { - log.err("function calls invalid function {}", .{id}); + log.err("function calls invalid function {f}", .{id}); return error.InvalidId; }; @@ -261,7 +261,7 @@ const ModuleInfo = struct { seen: *std.DynamicBitSetUnmanaged, ) !void { const index = self.invocation_globals.getIndex(id) orelse { - log.err("invalid invocation global {}", .{id}); + log.err("invalid invocation global {f}", .{id}); return error.InvalidId; }; @@ -276,7 +276,7 @@ const ModuleInfo = struct { } const initializer = self.functions.get(info.initializer) orelse { - log.err("invocation global {} has invalid initializer {}", .{ id, info.initializer }); + log.err("invocation global {f} has invalid initializer {f}", .{ id, info.initializer }); return error.InvalidId; }; diff --git a/src/link/SpirV/prune_unused.zig b/src/link/SpirV/prune_unused.zig index 51903f9424..275458564e 100644 --- a/src/link/SpirV/prune_unused.zig +++ b/src/link/SpirV/prune_unused.zig @@ -128,7 +128,7 @@ const ModuleInfo = struct { switch (inst.opcode) { .OpFunction => { if (maybe_current_function) |current_function| { - log.err("OpFunction {} does not have an OpFunctionEnd", .{current_function}); + log.err("OpFunction {f} does not have an OpFunctionEnd", .{current_function}); return error.InvalidPhysicalFormat; } @@ -145,7 +145,7 @@ const ModuleInfo = struct { }; const entry = try functions.getOrPut(current_function); if (entry.found_existing) { - log.err("Function {} has duplicate definition", .{current_function}); + log.err("Function {f} has duplicate definition", .{current_function}); return error.DuplicateId; } @@ -163,7 +163,7 @@ const ModuleInfo = struct { } if (maybe_current_function) |current_function| { - log.err("OpFunction {} does not have an OpFunctionEnd", .{current_function}); + log.err("OpFunction {f} does not have an OpFunctionEnd", .{current_function}); return error.InvalidPhysicalFormat; } @@ -184,7 +184,7 @@ const AliveMarker = struct { fn markAlive(self: *AliveMarker, result_id: ResultId) BinaryModule.ParseError!void { const index = self.info.result_id_to_code_offset.getIndex(result_id) orelse { - log.err("undefined result-id {}", .{result_id}); + log.err("undefined result-id {f}", .{result_id}); return error.InvalidId; }; diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 5f98771dcf..bf102b45c5 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -547,7 +547,7 @@ pub const SourceLocation = enum(u32) { switch (sl.unpack(wasm)) { .none => unreachable, .zig_object_nofile => diags.addError("zig compilation unit: " ++ f, args), - .object_index => |i| diags.addError("{}: " ++ f, .{i.ptr(wasm).path} ++ args), + .object_index => |i| diags.addError("{f}: " ++ f, .{i.ptr(wasm).path} ++ args), .source_location_index => @panic("TODO"), } } @@ -579,9 +579,9 @@ pub const SourceLocation = enum(u32) { .object_index => |i| { const obj = i.ptr(wasm); return if (obj.archive_member_name.slice(wasm)) |obj_name| - try bundle.printString("{} ({s}): {s}", .{ obj.path, std.fs.path.basename(obj_name), msg }) + try bundle.printString("{f} ({s}): {s}", .{ obj.path, std.fs.path.basename(obj_name), msg }) else - try bundle.printString("{}: {s}", .{ obj.path, msg }); + try bundle.printString("{f}: {s}", .{ obj.path, msg }); }, .source_location_index => @panic("TODO"), }; @@ -2087,11 +2087,10 @@ pub const Expr = enum(u32) { pub const end = @intFromEnum(std.wasm.Opcode.end); pub fn slice(index: Expr, wasm: *const Wasm) [:end]const u8 { - const start_slice = wasm.string_bytes.items[@intFromEnum(index)..]; - const end_pos = Object.exprEndPos(start_slice, 0) catch |err| switch (err) { - error.InvalidInitOpcode => unreachable, - }; - return start_slice[0..end_pos :end]; + var br: std.io.BufferedReader = undefined; + br.initFixed(wasm.string_bytes.items[@intFromEnum(index)..]); + Object.skipInit(&br) catch unreachable; + return br.storageBuffer()[0 .. br.seek - 1 :end]; } }; @@ -2126,32 +2125,26 @@ pub const FunctionType = extern struct { wasm: *const Wasm, ft: FunctionType, - pub fn format( - self: Formatter, - comptime format_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(self: Formatter, bw: *std.io.BufferedWriter, comptime format_string: []const u8) anyerror!void { if (format_string.len != 0) std.fmt.invalidFmtError(format_string, self); - _ = options; const params = self.ft.params.slice(self.wasm); const returns = self.ft.returns.slice(self.wasm); - try writer.writeByte('('); + try bw.writeByte('('); for (params, 0..) |param, i| { - try writer.print("{s}", .{@tagName(param)}); + try bw.print("{s}", .{@tagName(param)}); if (i + 1 != params.len) { - try writer.writeAll(", "); + try bw.writeAll(", "); } } - try writer.writeAll(") -> "); + try bw.writeAll(") -> "); if (returns.len == 0) { - try writer.writeAll("nil"); + try bw.writeAll("nil"); } else { for (returns, 0..) |return_ty, i| { - try writer.print("{s}", .{@tagName(return_ty)}); + try bw.print("{s}", .{@tagName(return_ty)}); if (i + 1 != returns.len) { - try writer.writeAll(", "); + try bw.writeAll(", "); } } } @@ -2912,10 +2905,9 @@ pub const Feature = packed struct(u8) { @"=", }; - pub fn format(feature: Feature, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void { - _ = opt; + pub fn format(feature: Feature, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { _ = fmt; - try writer.print("{s} {s}", .{ @tagName(feature.prefix), @tagName(feature.tag) }); + try bw.print("{s} {s}", .{ @tagName(feature.prefix), @tagName(feature.tag) }); } pub fn lessThan(_: void, a: Feature, b: Feature) bool { @@ -3036,7 +3028,7 @@ fn openParseObjectReportingFailure(wasm: *Wasm, path: Path) void { } fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void { - log.debug("parseObject {}", .{obj.path}); + log.debug("parseObject {f}", .{obj.path}); const gpa = wasm.base.comp.gpa; const gc_sections = wasm.base.gc_sections; @@ -3046,21 +3038,22 @@ fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void { const stat = try obj.file.stat(); const size = std.math.cast(usize, stat.size) orelse return error.FileTooBig; - const file_contents = try gpa.alloc(u8, size); - defer gpa.free(file_contents); + var br: std.io.BufferedReader = undefined; + br.initFixed(try gpa.alloc(u8, size)); + defer gpa.free(br.storageBuffer()); - const n = try obj.file.preadAll(file_contents, 0); - if (n != file_contents.len) return error.UnexpectedEndOfFile; + const n = try obj.file.preadAll(br.storageBuffer(), 0); + if (n != br.storageBuffer().len) return error.UnexpectedEndOfFile; var ss: Object.ScratchSpace = .{}; defer ss.deinit(gpa); - const object = try Object.parse(wasm, file_contents, obj.path, null, wasm.object_host_name, &ss, obj.must_link, gc_sections); + const object = try Object.parse(wasm, &br, obj.path, null, wasm.object_host_name, &ss, obj.must_link, gc_sections); wasm.objects.appendAssumeCapacity(object); } fn parseArchive(wasm: *Wasm, obj: link.Input.Object) !void { - log.debug("parseArchive {}", .{obj.path}); + log.debug("parseArchive {f}", .{obj.path}); const gpa = wasm.base.comp.gpa; const gc_sections = wasm.base.gc_sections; @@ -3196,7 +3189,7 @@ pub fn updateFunc( const is_obj = zcu.comp.config.output_mode == .Obj; const target = &zcu.comp.root_mod.resolved_target.result; const owner_nav = zcu.funcInfo(func_index).owner_nav; - log.debug("updateFunc {}", .{ip.getNav(owner_nav).fqn.fmt(ip)}); + log.debug("updateFunc {f}", .{ip.getNav(owner_nav).fqn.fmt(ip)}); // For Wasm, we do not lower the MIR to code just yet. That lowering happens during `flush`, // after garbage collection, which can affect function and global indexes, which affects the @@ -4347,7 +4340,7 @@ fn resolveFunctionSynthetic( }); if (import.type != correct_func_type) { const diags = &wasm.base.comp.link_diags; - return import.source_location.fail(diags, "synthetic function {s} {} imported with incorrect signature {}", .{ + return import.source_location.fail(diags, "synthetic function {s} {f} imported with incorrect signature {f}", .{ @tagName(res), correct_func_type.fmt(wasm), import.type.fmt(wasm), }); } diff --git a/src/link/Wasm/Archive.zig b/src/link/Wasm/Archive.zig index 2ad1b38579..c1877bd166 100644 --- a/src/link/Wasm/Archive.zig +++ b/src/link/Wasm/Archive.zig @@ -167,9 +167,10 @@ pub fn parseObject( }; const object_file_size = try header.parsedSize(); - const contents = file_contents[object_offset + @sizeOf(Header) ..][0..object_file_size]; + var br: std.io.BufferedReader = undefined; + br.initFixed(file_contents[object_offset + @sizeOf(Header) ..][0..object_file_size]); - return Object.parse(wasm, contents, path, object_name, host_name, scratch_space, must_link, gc_sections); + return Object.parse(wasm, &br, path, object_name, host_name, scratch_space, must_link, gc_sections); } const Archive = @This(); diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index 7bd9f89a42..8e8fdab948 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -16,7 +16,6 @@ const build_options = @import("build_options"); const std = @import("std"); const Allocator = std.mem.Allocator; const mem = std.mem; -const leb = std.leb; const log = std.log.scoped(.link); const assert = std.debug.assert; @@ -557,13 +556,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Index of the data section. Used to tell relocation table where the section lives. var data_section_index: ?u32 = null; - const binary_bytes = &f.binary_bytes; - assert(binary_bytes.items.len == 0); + assert(f.binary_bytes.items.len == 0); + var aw: std.io.AllocatingWriter = undefined; + const bw = aw.fromArrayList(gpa, &f.binary_bytes); + defer f.binary_bytes = aw.toArrayList(); - try binary_bytes.appendSlice(gpa, &std.wasm.magic ++ &std.wasm.version); - assert(binary_bytes.items.len == 8); - - const binary_writer = binary_bytes.writer(gpa); + try bw.writeAll(&std.wasm.magic ++ &std.wasm.version); // Type section. for (f.function_imports.values()) |id| { @@ -573,22 +571,18 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { try f.func_types.put(gpa, function.typeIndex(wasm), {}); } if (f.func_types.entries.len != 0) { - const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); + const header_offset = try reserveVecSectionHeader(bw); for (f.func_types.keys()) |func_type_index| { const func_type = func_type_index.ptr(wasm); - try leb.writeUleb128(binary_writer, std.wasm.function_type); + try bw.writeLeb128(std.wasm.function_type); const params = func_type.params.slice(wasm); - try leb.writeUleb128(binary_writer, @as(u32, @intCast(params.len))); - for (params) |param_ty| { - try leb.writeUleb128(binary_writer, @intFromEnum(param_ty)); - } + try bw.writeLeb128(params.len); + for (params) |param_ty| try bw.writeLeb128(@intFromEnum(param_ty)); const returns = func_type.returns.slice(wasm); - try leb.writeUleb128(binary_writer, @as(u32, @intCast(returns.len))); - for (returns) |ret_ty| { - try leb.writeUleb128(binary_writer, @intFromEnum(ret_ty)); - } + try bw.writeLeb128(returns.len); + for (returns) |ret_ty| try bw.writeLeb128(@intFromEnum(ret_ty)); } - replaceVecSectionHeader(binary_bytes, header_offset, .type, @intCast(f.func_types.entries.len)); + replaceVecSectionHeader(&aw, header_offset, .type, @intCast(f.func_types.entries.len)); section_index += 1; } @@ -601,42 +595,42 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Import section { var total_imports: usize = 0; - const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); + const header_offset = try reserveVecSectionHeader(bw); for (f.function_imports.values()) |id| { const module_name = id.moduleName(wasm).slice(wasm).?; - try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len))); - try binary_writer.writeAll(module_name); + try bw.writeLeb128(module_name.len); + try bw.writeAll(module_name); const name = id.importName(wasm).slice(wasm); - try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); - try binary_writer.writeAll(name); + try bw.writeLeb128(name.len); + try bw.writeAll(name); - try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.function)); + try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.function)); const type_index: FuncTypeIndex = .fromTypeIndex(id.functionType(wasm), f); - try leb.writeUleb128(binary_writer, @intFromEnum(type_index)); + try bw.writeLeb128(@intFromEnum(type_index)); } total_imports += f.function_imports.entries.len; for (wasm.table_imports.values()) |id| { const table_import = id.value(wasm); const module_name = table_import.module_name.slice(wasm); - try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len))); - try binary_writer.writeAll(module_name); + try bw.writeLeb128(module_name.len); + try bw.writeAll(module_name); const name = table_import.name.slice(wasm); - try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); - try binary_writer.writeAll(name); + try bw.writeLeb128(name.len); + try bw.writeAll(name); - try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.table)); - try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to()))); - try emitLimits(gpa, binary_bytes, table_import.limits()); + try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.table)); + try bw.writeLeb128(@intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to()))); + try emitLimits(bw, table_import.limits()); } total_imports += wasm.table_imports.entries.len; if (import_memory) { const name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory; - try emitMemoryImport(wasm, binary_bytes, name, &.{ + try emitMemoryImport(wasm, bw, name, &.{ // TODO the import_memory option needs to specify from which module .module_name = wasm.object_host_name.unwrap().?, .limits_min = wasm.memories.limits.min, @@ -650,215 +644,209 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { for (f.global_imports.values()) |id| { const module_name = id.moduleName(wasm).slice(wasm).?; - try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len))); - try binary_writer.writeAll(module_name); + try bw.writeLeb128(module_name.len); + try bw.writeAll(module_name); const name = id.importName(wasm).slice(wasm); - try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); - try binary_writer.writeAll(name); + try bw.writeLeb128(name.len); + try bw.writeAll(name); - try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.global)); + try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.global)); const global_type = id.globalType(wasm); - try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.Valtype, global_type.valtype))); - try binary_writer.writeByte(@intFromBool(global_type.mutable)); + try bw.writeLeb128(@intFromEnum(global_type.valtype)); + try bw.writeByte(@intFromBool(global_type.mutable)); } total_imports += f.global_imports.entries.len; if (total_imports > 0) { - replaceVecSectionHeader(binary_bytes, header_offset, .import, @intCast(total_imports)); + replaceVecSectionHeader(&aw, header_offset, .import, @intCast(total_imports)); section_index += 1; } else { - binary_bytes.shrinkRetainingCapacity(header_offset); + aw.shrinkRetainingCapacity(header_offset); } } // Function section if (wasm.functions.count() != 0) { - const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); + const header_offset = try reserveVecSectionHeader(bw); for (wasm.functions.keys()) |function| { const index: FuncTypeIndex = .fromTypeIndex(function.typeIndex(wasm), f); - try leb.writeUleb128(binary_writer, @intFromEnum(index)); + try bw.writeLeb128(@intFromEnum(index)); } - replaceVecSectionHeader(binary_bytes, header_offset, .function, @intCast(wasm.functions.count())); + replaceVecSectionHeader(&aw, header_offset, .function, @intCast(wasm.functions.count())); section_index += 1; } // Table section if (wasm.tables.entries.len > 0) { - const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); + const header_offset = try reserveVecSectionHeader(bw); for (wasm.tables.keys()) |table| { - try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table.refType(wasm)))); - try emitLimits(gpa, binary_bytes, table.limits(wasm)); + try bw.writeLeb128(@intFromEnum(table.refType(wasm))); + try emitLimits(bw, table.limits(wasm)); } - replaceVecSectionHeader(binary_bytes, header_offset, .table, @intCast(wasm.tables.entries.len)); + replaceVecSectionHeader(&aw, header_offset, .table, @intCast(wasm.tables.entries.len)); section_index += 1; } // Memory section. wasm currently only supports 1 linear memory segment. if (!import_memory) { - const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); - try emitLimits(gpa, binary_bytes, wasm.memories.limits); - replaceVecSectionHeader(binary_bytes, header_offset, .memory, 1); + const header_offset = try reserveVecSectionHeader(bw); + try emitLimits(bw, wasm.memories.limits); + replaceVecSectionHeader(&aw, header_offset, .memory, 1); section_index += 1; } // Global section. const globals_len: u32 = @intCast(wasm.globals.entries.len); if (globals_len > 0) { - const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); + const header_offset = try reserveVecSectionHeader(bw); for (wasm.globals.keys()) |global_resolution| { switch (global_resolution.unpack(wasm)) { .unresolved => unreachable, - .__heap_base => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_base), - .__heap_end => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_end), - .__stack_pointer => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.stack_pointer), - .__tls_align => try appendGlobal(gpa, binary_bytes, 0, @intCast(virtual_addrs.tls_align.toByteUnits().?)), - .__tls_base => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.tls_base.?), - .__tls_size => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.tls_size.?), + .__heap_base => try appendGlobal(bw, false, virtual_addrs.heap_base), + .__heap_end => try appendGlobal(bw, false, virtual_addrs.heap_end), + .__stack_pointer => try appendGlobal(bw, true, virtual_addrs.stack_pointer), + .__tls_align => try appendGlobal(bw, false, @intCast(virtual_addrs.tls_align.toByteUnits().?)), + .__tls_base => try appendGlobal(bw, true, virtual_addrs.tls_base.?), + .__tls_size => try appendGlobal(bw, false, virtual_addrs.tls_size.?), .object_global => |i| { const global = i.ptr(wasm); - try binary_bytes.appendSlice(gpa, &.{ + try bw.writeAll(&.{ @intFromEnum(@as(std.wasm.Valtype, global.flags.global_type.valtype.to())), @intFromBool(global.flags.global_type.mutable), }); - try emitExpr(wasm, binary_bytes, global.expr); + try emitExpr(wasm, bw, global.expr); }, .nav_exe => unreachable, // Zig source code currently cannot represent this. .nav_obj => unreachable, // Zig source code currently cannot represent this. } } - replaceVecSectionHeader(binary_bytes, header_offset, .global, globals_len); + replaceVecSectionHeader(&aw, header_offset, .global, globals_len); section_index += 1; } // Export section { - const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); + const header_offset = try reserveVecSectionHeader(bw); var exports_len: usize = 0; for (wasm.function_exports.keys(), wasm.function_exports.values()) |exp_name, function_index| { const name = exp_name.slice(wasm); - try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); - try binary_bytes.appendSlice(gpa, name); - try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function)); + try bw.writeLeb128(name.len); + try bw.writeAll(name); + try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.function)); const func_index = Wasm.OutputFunctionIndex.fromFunctionIndex(wasm, function_index); - try leb.writeUleb128(binary_writer, @intFromEnum(func_index)); + try bw.writeLeb128(@intFromEnum(func_index)); } exports_len += wasm.function_exports.entries.len; if (wasm.export_table and f.indirect_function_table.entries.len > 0) { const name = "__indirect_function_table"; const index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?); - try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); - try binary_bytes.appendSlice(gpa, name); - try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.table)); - try leb.writeUleb128(binary_writer, index); + try bw.writeLeb128(name.len); + try bw.writeAll(name); + try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.table)); + try bw.writeLeb128(index); exports_len += 1; } if (export_memory) { const name = "memory"; - try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); - try binary_bytes.appendSlice(gpa, name); - try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory)); - try leb.writeUleb128(binary_writer, @as(u32, 0)); + try bw.writeLeb128(name.len); + try bw.writeAll(name); + try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.memory)); + try bw.writeUleb128(0); exports_len += 1; } for (wasm.global_exports.items) |exp| { const name = exp.name.slice(wasm); - try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); - try binary_bytes.appendSlice(gpa, name); - try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.global)); - try leb.writeUleb128(binary_writer, @intFromEnum(exp.global_index)); + try bw.writeLeb128(name.len); + try bw.writeAll(name); + try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.global)); + try bw.writeLeb128(@intFromEnum(exp.global_index)); } exports_len += wasm.global_exports.items.len; if (exports_len > 0) { - replaceVecSectionHeader(binary_bytes, header_offset, .@"export", @intCast(exports_len)); + replaceVecSectionHeader(&aw, header_offset, .@"export", @intCast(exports_len)); section_index += 1; } else { - binary_bytes.shrinkRetainingCapacity(header_offset); + aw.shrinkRetainingCapacity(header_offset); } } // start section if (wasm.functions.getIndex(.__wasm_init_memory)) |func_index| { - try emitStartSection(gpa, binary_bytes, .fromFunctionIndex(wasm, @enumFromInt(func_index))); + try emitStartSection(&aw, .fromFunctionIndex(wasm, @enumFromInt(func_index))); } else if (Wasm.OutputFunctionIndex.fromResolution(wasm, wasm.entry_resolution)) |func_index| { - try emitStartSection(gpa, binary_bytes, func_index); + try emitStartSection(&aw, func_index); } // element section if (f.indirect_function_table.entries.len > 0) { - const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); + const header_offset = try reserveVecSectionHeader(bw); // indirect function table elements const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?); // passive with implicit 0-index table or set table index manually const flags: u32 = if (table_index == 0) 0x0 else 0x02; - try leb.writeUleb128(binary_writer, flags); - if (flags == 0x02) { - try leb.writeUleb128(binary_writer, table_index); - } + try bw.writeLeb128(flags); + if (flags == 0x02) try bw.writeLeb128(table_index); // We start at index 1, so unresolved function pointers are invalid - try emitInit(binary_writer, .{ .i32_const = 1 }); - if (flags == 0x02) { - try leb.writeUleb128(binary_writer, @as(u8, 0)); // represents funcref - } - try leb.writeUleb128(binary_writer, @as(u32, @intCast(f.indirect_function_table.entries.len))); - for (f.indirect_function_table.keys()) |func_index| { - try leb.writeUleb128(binary_writer, @intFromEnum(func_index)); - } + try emitInit(bw, .{ .i32_const = 1 }); + if (flags == 0x02) try bw.writeUleb128(0); // represents funcref + try bw.writeLeb128(f.indirect_function_table.entries.len); + for (f.indirect_function_table.keys()) |func_index| try bw.writeLeb128(@intFromEnum(func_index)); - replaceVecSectionHeader(binary_bytes, header_offset, .element, 1); + replaceVecSectionHeader(&aw, header_offset, .element, 1); section_index += 1; } // When the shared-memory option is enabled, we *must* emit the 'data count' section. if (f.data_segment_groups.items.len > 0) { - const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); - replaceVecSectionHeader(binary_bytes, header_offset, .data_count, @intCast(f.data_segment_groups.items.len)); + const header_offset = try reserveVecSectionHeader(bw); + replaceVecSectionHeader(&aw, header_offset, .data_count, @intCast(f.data_segment_groups.items.len)); } // Code section. if (wasm.functions.count() != 0) { - const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); + const header_offset = try reserveVecSectionHeader(bw); for (wasm.functions.keys()) |resolution| switch (resolution.unpack(wasm)) { .unresolved => unreachable, .__wasm_apply_global_tls_relocs => @panic("TODO lower __wasm_apply_global_tls_relocs"), .__wasm_call_ctors => { - const code_start = try reserveSize(gpa, binary_bytes); - defer replaceSize(binary_bytes, code_start); - try emitCallCtorsFunction(wasm, binary_bytes); + const code_start = try reserveSizeHeader(bw); + defer replaceSizeHeader(&aw, code_start); + try emitCallCtorsFunction(wasm, bw); }, .__wasm_init_memory => { - const code_start = try reserveSize(gpa, binary_bytes); - defer replaceSize(binary_bytes, code_start); - try emitInitMemoryFunction(wasm, binary_bytes, &virtual_addrs); + const code_start = try reserveSizeHeader(bw); + defer replaceSizeHeader(&aw, code_start); + try emitInitMemoryFunction(wasm, bw, &virtual_addrs); }, .__wasm_init_tls => { - const code_start = try reserveSize(gpa, binary_bytes); - defer replaceSize(binary_bytes, code_start); - try emitInitTlsFunction(wasm, binary_bytes); + const code_start = try reserveSizeHeader(bw); + defer replaceSizeHeader(&aw, code_start); + try emitInitTlsFunction(wasm, bw); }, .object_function => |i| { const ptr = i.ptr(wasm); const code = ptr.code.slice(wasm); - try leb.writeUleb128(binary_writer, code.len); - const code_start = binary_bytes.items.len; - try binary_bytes.appendSlice(gpa, code); - if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm); + try bw.writeLeb128(code.len); + const code_start = bw.count; + try bw.writeAll(code); + if (!is_obj) applyRelocs(aw.getWritten()[code_start..], ptr.offset, ptr.relocations(wasm), wasm); }, .zcu_func => |i| { - const code_start = try reserveSize(gpa, binary_bytes); - defer replaceSize(binary_bytes, code_start); + const code_start = try reserveSizeHeader(bw); + defer replaceSizeHeader(&aw, code_start); log.debug("lowering function code for '{s}'", .{resolution.name(wasm).?}); @@ -867,7 +855,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { const ip_index = i.key(wasm).*; switch (ip.indexToKey(ip_index)) { .enum_type => { - try emitTagNameFunction(wasm, binary_bytes, f.data_segments.get(.__zig_tag_name_table).?, i.value(wasm).tag_name.table_index, ip_index); + try emitTagNameFunction(wasm, bw, f.data_segments.get(.__zig_tag_name_table).?, i.value(wasm).tag_name.table_index, ip_index); }, else => { const func = i.value(wasm).function; @@ -882,13 +870,13 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { .func_tys = undefined, .error_name_table_ref_count = undefined, }; - try mir.lower(wasm, binary_bytes); + try mir.lower(wasm, bw); }, } }, }; - replaceVecSectionHeader(binary_bytes, header_offset, .code, @intCast(wasm.functions.entries.len)); + replaceVecSectionHeader(&aw, header_offset, .code, @intCast(wasm.functions.entries.len)); code_section_index = section_index; section_index += 1; } @@ -924,7 +912,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Data section. if (f.data_segment_groups.items.len != 0) { - const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); + const header_offset = try reserveVecSectionHeader(bw); var group_index: u32 = 0; var segment_offset: u32 = 0; @@ -932,7 +920,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { var group_end_addr = f.data_segment_groups.items[group_index].end_addr; for (segment_ids, segment_vaddrs) |segment_id, segment_vaddr| { if (segment_vaddr >= group_end_addr) { - try binary_bytes.appendNTimes(gpa, 0, group_end_addr - group_start_addr - segment_offset); + try bw.splatByteAll(0, group_end_addr - group_start_addr - segment_offset); group_index += 1; if (group_index >= f.data_segment_groups.items.len) { // All remaining segments are zero. @@ -946,12 +934,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { const group_size = group_end_addr - group_start_addr; log.debug("emit data section group, {d} bytes", .{group_size}); const flags: Object.DataSegmentFlags = if (segment_id.isPassive(wasm)) .passive else .active; - try leb.writeUleb128(binary_writer, @intFromEnum(flags)); + try bw.writeLeb128(@intFromEnum(flags)); // Passive segments are initialized at runtime. - if (flags != .passive) { - try emitInit(binary_writer, .{ .i32_const = @as(i32, @bitCast(group_start_addr)) }); - } - try leb.writeUleb128(binary_writer, group_size); + if (flags != .passive) try emitInit(bw, .{ .i32_const = @as(i32, @bitCast(group_start_addr)) }); + try bw.writeLeb128(group_size); } if (segment_id.isEmpty(wasm)) { // It counted for virtual memory but it does not go into the binary. @@ -960,62 +946,62 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Padding for alignment. const needed_offset = segment_vaddr - group_start_addr; - try binary_bytes.appendNTimes(gpa, 0, needed_offset - segment_offset); + try bw.splatByteAll(0, needed_offset - segment_offset); segment_offset = needed_offset; - const code_start = binary_bytes.items.len; + const code_start = bw.count; append: { const code = switch (segment_id.unpack(wasm)) { .__heap_base => { - mem.writeInt(u32, try binary_bytes.addManyAsArray(gpa, 4), virtual_addrs.heap_base, .little); + try bw.writeInt(u32, virtual_addrs.heap_base, .little); break :append; }, .__heap_end => { - mem.writeInt(u32, try binary_bytes.addManyAsArray(gpa, 4), virtual_addrs.heap_end, .little); + try bw.writeInt(u32, virtual_addrs.heap_end, .little); break :append; }, .__zig_error_names => { - try binary_bytes.appendSlice(gpa, wasm.error_name_bytes.items); + try bw.writeAll(wasm.error_name_bytes.items); break :append; }, .__zig_error_name_table => { if (is_obj) @panic("TODO error name table reloc"); const base = f.data_segments.get(.__zig_error_names).?; if (!is64) { - try emitTagNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u32); + try emitTagNameTable(bw, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u32); } else { - try emitTagNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u64); + try emitTagNameTable(bw, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u64); } break :append; }, .__zig_tag_names => { - try binary_bytes.appendSlice(gpa, wasm.tag_name_bytes.items); + try bw.writeAll(wasm.tag_name_bytes.items); break :append; }, .__zig_tag_name_table => { if (is_obj) @panic("TODO tag name table reloc"); const base = f.data_segments.get(.__zig_tag_names).?; if (!is64) { - try emitTagNameTable(gpa, binary_bytes, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u32); + try emitTagNameTable(bw, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u32); } else { - try emitTagNameTable(gpa, binary_bytes, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u64); + try emitTagNameTable(bw, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u64); } break :append; }, .object => |i| { const ptr = i.ptr(wasm); - try binary_bytes.appendSlice(gpa, ptr.payload.slice(wasm)); - if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm); + try bw.writeAll(ptr.payload.slice(wasm)); + if (!is_obj) applyRelocs(aw.getWritten()[code_start..], ptr.offset, ptr.relocations(wasm), wasm); break :append; }, inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code, }; - try binary_bytes.appendSlice(gpa, code.slice(wasm)); + try bw.writeAll(code.slice(wasm)); } - segment_offset += @intCast(binary_bytes.items.len - code_start); + segment_offset += @intCast(bw.count - code_start); } - replaceVecSectionHeader(binary_bytes, header_offset, .data, @intCast(f.data_segment_groups.items.len)); + replaceVecSectionHeader(&aw, header_offset, .data, @intCast(f.data_segment_groups.items.len)); data_section_index = section_index; section_index += 1; } @@ -1023,7 +1009,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { if (is_obj) { @panic("TODO emit link section for object file and emit modified relocations"); } else if (comp.config.debug_format != .strip) { - try emitNameSection(wasm, f.data_segment_groups.items, binary_bytes); + try emitNameSection(wasm, &aw, f.data_segment_groups.items); } if (comp.config.debug_format != .strip) { @@ -1033,17 +1019,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { .none => {}, .fast => { var id: [16]u8 = undefined; - std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{}); + std.crypto.hash.sha3.TurboShake128(null).hash(bw.getWritten(), &id, .{}); var uuid: [36]u8 = undefined; _ = try std.fmt.bufPrint(&uuid, "{x}-{x}-{x}-{x}-{x}", .{ id[0..4], id[4..6], id[6..8], id[8..10], id[10..], }); - try emitBuildIdSection(gpa, binary_bytes, &uuid); + try emitBuildIdSection(&aw, &uuid); }, .hexstring => |hs| { var buffer: [32 * 2]u8 = undefined; const str = std.fmt.bufPrint(&buffer, "{x}", .{hs.toSlice()}) catch unreachable; - try emitBuildIdSection(gpa, binary_bytes, str); + try emitBuildIdSection(&aw, str); }, else => |mode| { var err = try diags.addErrorWithNotes(0); @@ -1054,14 +1040,15 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { var debug_bytes = std.ArrayList(u8).init(gpa); defer debug_bytes.deinit(); - try emitProducerSection(gpa, binary_bytes); - try emitFeaturesSection(gpa, binary_bytes, target); + try emitProducerSection(&aw); + try emitFeaturesSection(&aw, target); } // Finally, write the entire binary into the file. const file = wasm.base.file.?; - try file.pwriteAll(binary_bytes.items, 0); - try file.setEndPos(binary_bytes.items.len); + const contents = aw.getWritten(); + try file.setEndPos(contents.len); + try file.pwriteAll(contents, 0); } const VirtualAddrs = struct { @@ -1076,170 +1063,155 @@ const VirtualAddrs = struct { fn emitNameSection( wasm: *Wasm, + aw: *std.io.AllocatingWriter, data_segment_groups: []const DataSegmentGroup, - binary_bytes: *std.ArrayListUnmanaged(u8), -) !void { +) anyerror!void { const f = &wasm.flush_buffer; - const comp = wasm.base.comp; - const gpa = comp.gpa; + const bw = &aw.buffered_writer; + const header_offset = try reserveSectionHeader(bw); + defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); - const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); - defer writeCustomSectionHeader(binary_bytes, header_offset); - - const name_name = "name"; - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, name_name.len)); - try binary_bytes.appendSlice(gpa, name_name); + const section_name = "name"; + try bw.writeLeb128(section_name.len); + try bw.writeAll(section_name); { - const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); - defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function)); - - const total_functions: u32 = @intCast(f.function_imports.entries.len + wasm.functions.entries.len); - try leb.writeUleb128(binary_bytes.writer(gpa), total_functions); + const sub_header_offset = try reserveSectionHeader(bw); + defer replaceSectionHeader(aw, sub_header_offset, @intFromEnum(std.wasm.NameSubsection.function)); + try bw.writeLeb128(f.function_imports.entries.len + wasm.functions.entries.len); for (f.function_imports.keys(), 0..) |name_index, function_index| { const name = name_index.slice(wasm); - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index))); - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); - try binary_bytes.appendSlice(gpa, name); + try bw.writeLeb128(function_index); + try bw.writeLeb128(name.len); + try bw.writeAll(name); } for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| { const name = resolution.name(wasm).?; - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index))); - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); - try binary_bytes.appendSlice(gpa, name); + try bw.writeLeb128(function_index); + try bw.writeLeb128(name.len); + try bw.writeAll(name); } } { - const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); - defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global)); - - const total_globals: u32 = @intCast(f.global_imports.entries.len + wasm.globals.entries.len); - try leb.writeUleb128(binary_bytes.writer(gpa), total_globals); + const sub_header_offset = try reserveSectionHeader(bw); + defer replaceSectionHeader(aw, sub_header_offset, @intFromEnum(std.wasm.NameSubsection.global)); + try bw.writeLeb128(f.global_imports.entries.len + wasm.globals.entries.len); for (f.global_imports.keys(), 0..) |name_index, global_index| { const name = name_index.slice(wasm); - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index))); - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); - try binary_bytes.appendSlice(gpa, name); + try bw.writeLeb128(global_index); + try bw.writeLeb128(name.len); + try bw.writeAll(name); } for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| { const name = resolution.name(wasm).?; - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index))); - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); - try binary_bytes.appendSlice(gpa, name); + try bw.writeLeb128(global_index); + try bw.writeLeb128(name.len); + try bw.writeAll(name); } } { - const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); - defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.data_segment)); + const sub_header_offset = try reserveSectionHeader(bw); + defer replaceSectionHeader(aw, sub_header_offset, @intFromEnum(std.wasm.NameSubsection.data_segment)); - const total_data_segments: u32 = @intCast(data_segment_groups.len); - try leb.writeUleb128(binary_bytes.writer(gpa), total_data_segments); - - for (data_segment_groups, 0..) |group, i| { + try bw.writeLeb128(data_segment_groups.len); + for (data_segment_groups, 0..) |group, group_index| { const name, _ = splitSegmentName(group.first_segment.name(wasm)); - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(i))); - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); - try binary_bytes.appendSlice(gpa, name); + try bw.writeLeb128(group_index); + try bw.writeLeb128(name.len); + try bw.writeAll(name); } } } -fn emitFeaturesSection( - gpa: Allocator, - binary_bytes: *std.ArrayListUnmanaged(u8), - target: *const std.Target, -) Allocator.Error!void { +fn emitFeaturesSection(aw: *std.io.AllocatingWriter, target: *const std.Target) anyerror!void { const feature_count = target.cpu.features.count(); if (feature_count == 0) return; - const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); - defer writeCustomSectionHeader(binary_bytes, header_offset); + const bw = &aw.buffered_writer; + const header_offset = try reserveSectionHeader(bw); + defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); - const writer = binary_bytes.writer(gpa); - const target_features = "target_features"; - try leb.writeUleb128(writer, @as(u32, @intCast(target_features.len))); - try writer.writeAll(target_features); - - try leb.writeUleb128(writer, @as(u32, @intCast(feature_count))); + const section_name = "target_features"; + try bw.writeLeb128(section_name.len); + try bw.writeAll(section_name); + try bw.writeLeb128(feature_count); var safety_count = feature_count; for (target.cpu.arch.allFeaturesList(), 0..) |*feature, i| { if (!target.cpu.has(.wasm, @as(std.Target.wasm.Feature, @enumFromInt(i)))) continue; safety_count -= 1; - try leb.writeUleb128(writer, @as(u32, '+')); + try bw.writeUleb128('+'); // Depends on llvm_name for the hyphenated version that matches wasm tooling conventions. const name = feature.llvm_name.?; - try leb.writeUleb128(writer, @as(u32, @intCast(name.len))); - try writer.writeAll(name); + try bw.writeLeb128(name.len); + try bw.writeAll(name); } assert(safety_count == 0); } -fn emitBuildIdSection(gpa: Allocator, binary_bytes: *std.ArrayListUnmanaged(u8), build_id: []const u8) !void { - const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); - defer writeCustomSectionHeader(binary_bytes, header_offset); +fn emitBuildIdSection(aw: *std.io.AllocatingWriter, build_id: []const u8) !void { + const bw = &aw.buffered_writer; + const header_offset = try reserveSectionHeader(bw); + defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); - const writer = binary_bytes.writer(gpa); - const hdr_build_id = "build_id"; - try leb.writeUleb128(writer, @as(u32, @intCast(hdr_build_id.len))); - try writer.writeAll(hdr_build_id); + const section_name = "build_id"; + try bw.writeLeb128(section_name.len); + try bw.writeAll(section_name); - try leb.writeUleb128(writer, @as(u32, 1)); - try leb.writeUleb128(writer, @as(u32, @intCast(build_id.len))); - try writer.writeAll(build_id); + try bw.writeUleb128(1); + try bw.writeLeb128(build_id.len); + try bw.writeAll(build_id); } -fn emitProducerSection(gpa: Allocator, binary_bytes: *std.ArrayListUnmanaged(u8)) !void { - const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); - defer writeCustomSectionHeader(binary_bytes, header_offset); +fn emitProducerSection(aw: *std.io.AllocatingWriter) !void { + const bw = &aw.buffered_writer; + const header_offset = try reserveSectionHeader(bw); + defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); - const writer = binary_bytes.writer(gpa); - const producers = "producers"; - try leb.writeUleb128(writer, @as(u32, @intCast(producers.len))); - try writer.writeAll(producers); + const section_name = "producers"; + try bw.writeLeb128(section_name.len); + try bw.writeAll(section_name); - try leb.writeUleb128(writer, @as(u32, 2)); // 2 fields: Language + processed-by - - // language field + try bw.writeUleb128(2); // 2 fields: language + processed-by { - const language = "language"; - try leb.writeUleb128(writer, @as(u32, @intCast(language.len))); - try writer.writeAll(language); + const field_name = "language"; + try bw.writeLeb128(field_name.len); + try bw.writeAll(field_name); // field_value_count (TODO: Parse object files for producer sections to detect their language) - try leb.writeUleb128(writer, @as(u32, 1)); + try bw.writeUleb128(1); // versioned name { - try leb.writeUleb128(writer, @as(u32, 3)); // len of "Zig" - try writer.writeAll("Zig"); + const field_value = "Zig"; + try bw.writeLeb128(field_value.len); + try bw.writeAll(field_value); - try leb.writeUleb128(writer, @as(u32, @intCast(build_options.version.len))); - try writer.writeAll(build_options.version); + try bw.writeLeb128(build_options.version.len); + try bw.writeAll(build_options.version); } } - - // processed-by field { - const processed_by = "processed-by"; - try leb.writeUleb128(writer, @as(u32, @intCast(processed_by.len))); - try writer.writeAll(processed_by); + const field_name = "processed-by"; + try bw.writeLeb128(field_name.len); + try bw.writeAll(field_name); // field_value_count (TODO: Parse object files for producer sections to detect other used tools) - try leb.writeUleb128(writer, @as(u32, 1)); + try bw.writeUleb128(1); // versioned name { - try leb.writeUleb128(writer, @as(u32, 3)); // len of "Zig" - try writer.writeAll("Zig"); + const field_value = "Zig"; + try bw.writeLeb128(field_value.len); + try bw.writeAll(field_value); - try leb.writeUleb128(writer, @as(u32, @intCast(build_options.version.len))); - try writer.writeAll(build_options.version); + try bw.writeLeb128(build_options.version.len); + try bw.writeAll(build_options.version); } } } @@ -1277,170 +1249,133 @@ fn wantSegmentMerge( } /// section id + fixed leb contents size + fixed leb vector length -const section_header_reserve_size = 1 + 5 + 5; -const section_header_size = 5 + 1; +const vec_section_header_size = section_header_size + size_header_size; -fn reserveVecSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 { - try bytes.appendNTimes(gpa, 0, section_header_reserve_size); - return @intCast(bytes.items.len - section_header_reserve_size); +fn reserveVecSectionHeader(bw: *std.io.BufferedWriter) anyerror!u32 { + const offset = bw.count; + _ = try bw.writableSlice(vec_section_header_size); + bw.advance(vec_section_header_size); + return @intCast(offset); } fn replaceVecSectionHeader( - bytes: *std.ArrayListUnmanaged(u8), + aw: *std.io.AllocatingWriter, offset: u32, section: std.wasm.Section, n_items: u32, ) void { - const size: u32 = @intCast(bytes.items.len - offset - section_header_reserve_size + uleb128size(n_items)); - var buf: [section_header_reserve_size]u8 = undefined; - var fbw = std.io.fixedBufferStream(&buf); - const w = fbw.writer(); - w.writeByte(@intFromEnum(section)) catch unreachable; - leb.writeUleb128(w, size) catch unreachable; - leb.writeUleb128(w, n_items) catch unreachable; - bytes.replaceRangeAssumeCapacity(offset, section_header_reserve_size, fbw.getWritten()); + const header = aw.getWritten()[offset..][0..vec_section_header_size]; + header[0] = @intFromEnum(section); + std.leb.writeUnsignedFixed(5, header[1..6], @intCast(aw.buffered_writer.count - offset - section_header_size)); + std.leb.writeUnsignedFixed(5, header[6..], n_items); } -fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 { - try bytes.appendNTimes(gpa, 0, section_header_size); - return @intCast(bytes.items.len - section_header_size); +const section_header_size = 1 + size_header_size; + +fn reserveSectionHeader(bw: *std.io.BufferedWriter) anyerror!u32 { + const offset = bw.count; + _ = try bw.writableSlice(section_header_size); + bw.advance(section_header_size); + return @intCast(offset); } -fn writeCustomSectionHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void { - return replaceHeader(bytes, offset, 0); // 0 = 'custom' section +fn replaceSectionHeader(aw: *std.io.AllocatingWriter, offset: u32, section: u8) void { + const header = aw.getWritten()[offset..][0..section_header_size]; + header[0] = section; + std.leb.writeUnsignedFixed(5, header[1..6], @intCast(aw.buffered_writer.count - offset - section_header_size)); } -fn replaceHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32, tag: u8) void { - const size: u32 = @intCast(bytes.items.len - offset - section_header_size); - var buf: [section_header_size]u8 = undefined; - var fbw = std.io.fixedBufferStream(&buf); - const w = fbw.writer(); - w.writeByte(tag) catch unreachable; - leb.writeUleb128(w, size) catch unreachable; - bytes.replaceRangeAssumeCapacity(offset, section_header_size, fbw.getWritten()); +const size_header_size = 5; + +fn reserveSizeHeader(bw: *std.io.BufferedWriter) anyerror!u32 { + const offset = bw.count; + _ = try bw.writableSlice(size_header_size); + bw.advance(size_header_size); + return @intCast(offset); } -const max_size_encoding = 5; - -fn reserveSize(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 { - try bytes.appendNTimes(gpa, 0, max_size_encoding); - return @intCast(bytes.items.len - max_size_encoding); +fn replaceSizeHeader(aw: *std.io.AllocatingWriter, offset: u32) void { + const header = aw.getWritten()[offset..][0..size_header_size]; + std.leb.writeUnsignedFixed(5, header[0..5], @intCast(aw.buffered_writer.count - offset - size_header_size)); } -fn replaceSize(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void { - const size: u32 = @intCast(bytes.items.len - offset - max_size_encoding); - var buf: [max_size_encoding]u8 = undefined; - var fbw = std.io.fixedBufferStream(&buf); - leb.writeUleb128(fbw.writer(), size) catch unreachable; - bytes.replaceRangeAssumeCapacity(offset, max_size_encoding, fbw.getWritten()); -} - -fn emitLimits( - gpa: Allocator, - binary_bytes: *std.ArrayListUnmanaged(u8), - limits: std.wasm.Limits, -) Allocator.Error!void { - try binary_bytes.append(gpa, @bitCast(limits.flags)); - try leb.writeUleb128(binary_bytes.writer(gpa), limits.min); - if (limits.flags.has_max) try leb.writeUleb128(binary_bytes.writer(gpa), limits.max); +fn emitLimits(bw: *std.io.BufferedWriter, limits: std.wasm.Limits) anyerror!void { + try bw.writeByte(@bitCast(limits.flags)); + try bw.writeLeb128(limits.min); + if (limits.flags.has_max) try bw.writeLeb128(limits.max); } fn emitMemoryImport( wasm: *Wasm, - binary_bytes: *std.ArrayListUnmanaged(u8), + bw: *std.io.BufferedWriter, name_index: String, memory_import: *const Wasm.MemoryImport, -) Allocator.Error!void { - const gpa = wasm.base.comp.gpa; +) anyerror!void { const module_name = memory_import.module_name.slice(wasm); - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(module_name.len))); - try binary_bytes.appendSlice(gpa, module_name); + try bw.writeLeb128(module_name.len); + try bw.writeAll(module_name); const name = name_index.slice(wasm); - try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); - try binary_bytes.appendSlice(gpa, name); + try bw.writeLeb128(name.len); + try bw.writeAll(name); - try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory)); - try emitLimits(gpa, binary_bytes, memory_import.limits()); + try bw.writeByte(@intFromEnum(std.wasm.ExternalKind.memory)); + try emitLimits(bw, memory_import.limits()); } -pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void { +pub fn emitInit(bw: *std.io.BufferedWriter, init_expr: std.wasm.InitExpression) anyerror!void { switch (init_expr) { - .i32_const => |val| { - try writer.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); - try leb.writeIleb128(writer, val); - }, - .i64_const => |val| { - try writer.writeByte(@intFromEnum(std.wasm.Opcode.i64_const)); - try leb.writeIleb128(writer, val); - }, - .f32_const => |val| { - try writer.writeByte(@intFromEnum(std.wasm.Opcode.f32_const)); - try writer.writeInt(u32, @bitCast(val), .little); - }, - .f64_const => |val| { - try writer.writeByte(@intFromEnum(std.wasm.Opcode.f64_const)); - try writer.writeInt(u64, @bitCast(val), .little); - }, - .global_get => |val| { - try writer.writeByte(@intFromEnum(std.wasm.Opcode.global_get)); - try leb.writeUleb128(writer, val); + inline else => |val, tag| { + try bw.writeByte(@intFromEnum(@field(std.wasm.Opcode, @tagName(tag)))); + switch (@typeInfo(@TypeOf(val))) { + .int => try bw.writeLeb128(val), + .float => |float| try bw.writeInt( + @Type(.{ .int = .{ .signedness = .unsigned, .bits = float.bits } }), + @bitCast(val), + .little, + ), + else => comptime unreachable, + } }, } - try writer.writeByte(@intFromEnum(std.wasm.Opcode.end)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); } -pub fn emitExpr(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), expr: Wasm.Expr) Allocator.Error!void { - const gpa = wasm.base.comp.gpa; +pub fn emitExpr(wasm: *const Wasm, bw: *std.io.BufferedWriter, expr: Wasm.Expr) anyerror!void { const slice = expr.slice(wasm); - try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode + try bw.writeAll(slice[0 .. slice.len + 1]); // +1 to include end opcode } -fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void { - const gpa = wasm.base.comp.gpa; - const writer = binary_bytes.writer(gpa); - try leb.writeUleb128(writer, @intFromEnum(Wasm.SubsectionType.segment_info)); - const segment_offset = binary_bytes.items.len; +fn emitSegmentInfo(wasm: *Wasm, aw: *std.io.BufferedWriter) anyerror!void { + const bw = &aw.buffered_writer; + const header_offset = try reserveSectionHeader(bw); + defer replaceSectionHeader(aw, header_offset, @intFromEnum(Wasm.SubsectionType.segment_info)); - try leb.writeUleb128(writer, @as(u32, @intCast(wasm.segment_info.count()))); + try bw.writeLeb128(wasm.segment_info.count()); for (wasm.segment_info.values()) |segment_info| { log.debug("Emit segment: {s} align({d}) flags({b})", .{ segment_info.name, segment_info.alignment, segment_info.flags, }); - try leb.writeUleb128(writer, @as(u32, @intCast(segment_info.name.len))); - try writer.writeAll(segment_info.name); - try leb.writeUleb128(writer, segment_info.alignment.toLog2Units()); - try leb.writeUleb128(writer, segment_info.flags); + try bw.writeLeb128(segment_info.name.len); + try bw.writeAll(segment_info.name); + try bw.writeLeb128(segment_info.alignment.toLog2Units()); + try bw.writeLeb128(segment_info.flags); } - - var buf: [5]u8 = undefined; - leb.writeUnsignedFixed(5, &buf, @as(u32, @intCast(binary_bytes.items.len - segment_offset))); - try binary_bytes.insertSlice(segment_offset, &buf); -} - -fn uleb128size(x: u32) u32 { - var value = x; - var size: u32 = 0; - while (value != 0) : (size += 1) value >>= 7; - return size; } fn emitTagNameTable( - gpa: Allocator, - code: *std.ArrayListUnmanaged(u8), + bw: *std.io.BufferedWriter, tag_name_offs: []const u32, tag_name_bytes: []const u8, base: u32, comptime Int: type, -) error{OutOfMemory}!void { - const ptr_size_bytes = @divExact(@bitSizeOf(Int), 8); - try code.ensureUnusedCapacity(gpa, ptr_size_bytes * 2 * tag_name_offs.len); +) anyerror!void { for (tag_name_offs) |off| { const name_len: u32 = @intCast(mem.indexOfScalar(u8, tag_name_bytes[off..], 0).?); - mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), base + off, .little); - mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), name_len, .little); + try bw.writeInt(Int, base + off, .little); + try bw.writeInt(Int, name_len, .little); } } @@ -1525,11 +1460,11 @@ fn reloc_u64_table_index(code: []u8, i: IndirectFunctionTableIndex) void { } fn reloc_sleb_table_index(code: []u8, i: IndirectFunctionTableIndex) void { - leb.writeSignedFixed(5, code[0..5], i.toAbi()); + std.leb.writeSignedFixed(5, code[0..5], i.toAbi()); } fn reloc_sleb64_table_index(code: []u8, i: IndirectFunctionTableIndex) void { - leb.writeSignedFixed(11, code[0..11], i.toAbi()); + std.leb.writeSignedFixed(11, code[0..11], i.toAbi()); } fn reloc_u32_function(code: []u8, function: Wasm.OutputFunctionIndex) void { @@ -1537,7 +1472,7 @@ fn reloc_u32_function(code: []u8, function: Wasm.OutputFunctionIndex) void { } fn reloc_leb_function(code: []u8, function: Wasm.OutputFunctionIndex) void { - leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(function)); + std.leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(function)); } fn reloc_u32_global(code: []u8, global: Wasm.GlobalIndex) void { @@ -1545,7 +1480,7 @@ fn reloc_u32_global(code: []u8, global: Wasm.GlobalIndex) void { } fn reloc_leb_global(code: []u8, global: Wasm.GlobalIndex) void { - leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(global)); + std.leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(global)); } const RelocAddr = struct { @@ -1581,35 +1516,31 @@ fn reloc_u64_addr(code: []u8, ra: RelocAddr) void { } fn reloc_leb_addr(code: []u8, ra: RelocAddr) void { - leb.writeUnsignedFixed(5, code[0..5], ra.addr); + std.leb.writeUnsignedFixed(5, code[0..5], ra.addr); } fn reloc_leb64_addr(code: []u8, ra: RelocAddr) void { - leb.writeUnsignedFixed(11, code[0..11], ra.addr); + std.leb.writeUnsignedFixed(11, code[0..11], ra.addr); } fn reloc_sleb_addr(code: []u8, ra: RelocAddr) void { - leb.writeSignedFixed(5, code[0..5], ra.addr); + std.leb.writeSignedFixed(5, code[0..5], ra.addr); } fn reloc_sleb64_addr(code: []u8, ra: RelocAddr) void { - leb.writeSignedFixed(11, code[0..11], ra.addr); + std.leb.writeSignedFixed(11, code[0..11], ra.addr); } fn reloc_leb_table(code: []u8, table: Wasm.TableIndex) void { - leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(table)); + std.leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(table)); } fn reloc_leb_type(code: []u8, index: FuncTypeIndex) void { - leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index)); + std.leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index)); } -fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!void { - const gpa = wasm.base.comp.gpa; - - try binary_bytes.ensureUnusedCapacity(gpa, 5 + 1); - appendReservedUleb32(binary_bytes, 0); // no locals - +fn emitCallCtorsFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter) anyerror!void { + try bw.writeUleb128(0); // no locals for (wasm.object_init_funcs.items) |init_func| { const func = init_func.function_index.ptr(wasm); if (!func.object_index.ptr(wasm).is_included) continue; @@ -1617,25 +1548,18 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanage const n_returns = ty.returns.slice(wasm).len; // Call function by its function index - try binary_bytes.ensureUnusedCapacity(gpa, 1 + 5 + n_returns + 1); const call_index: Wasm.OutputFunctionIndex = .fromObjectFunction(wasm, init_func.function_index); - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call)); - appendReservedUleb32(binary_bytes, @intFromEnum(call_index)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.call)); + try bw.writeLeb128(@intFromEnum(call_index)); // drop all returned values from the stack as __wasm_call_ctors has no return value - binary_bytes.appendNTimesAssumeCapacity(@intFromEnum(std.wasm.Opcode.drop), n_returns); + try bw.splatByteAll(@intFromEnum(std.wasm.Opcode.drop), n_returns); } - - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); // end function body + try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end function body } -fn emitInitMemoryFunction( - wasm: *const Wasm, - binary_bytes: *std.ArrayListUnmanaged(u8), - virtual_addrs: *const VirtualAddrs, -) Allocator.Error!void { +fn emitInitMemoryFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter, virtual_addrs: *const VirtualAddrs) anyerror!void { const comp = wasm.base.comp; - const gpa = comp.gpa; const shared_memory = comp.config.shared_memory; // Passive segments are used to avoid memory being reinitialized on each @@ -1645,39 +1569,40 @@ fn emitInitMemoryFunction( // function. assert(wasm.any_passive_inits); - try binary_bytes.ensureUnusedCapacity(gpa, 5 + 1); - appendReservedUleb32(binary_bytes, 0); // no locals + try bw.writeUleb128(0); // no locals if (virtual_addrs.init_memory_flag) |flag_address| { assert(shared_memory); - try binary_bytes.ensureUnusedCapacity(gpa, 2 * 3 + 6 * 3 + 1 + 6 * 3 + 1 + 5 * 4 + 1 + 1); // destination blocks // based on values we jump to corresponding label - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block)); // $drop - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.BlockType.empty)); - - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block)); // $wait - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.BlockType.empty)); - - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block)); // $init - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.BlockType.empty)); + try bw.writeAll(&.{ + @intFromEnum(std.wasm.Opcode.block), // $drop + @intFromEnum(std.wasm.BlockType.empty), + @intFromEnum(std.wasm.Opcode.block), // $wait + @intFromEnum(std.wasm.BlockType.empty), + @intFromEnum(std.wasm.Opcode.block), // $init + @intFromEnum(std.wasm.BlockType.empty), + }); // atomically check - appendReservedI32Const(binary_bytes, flag_address); - appendReservedI32Const(binary_bytes, 0); - appendReservedI32Const(binary_bytes, 1); - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix)); - appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_rmw_cmpxchg)); - appendReservedUleb32(binary_bytes, 2); // alignment - appendReservedUleb32(binary_bytes, 0); // offset + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeLeb128(@as(i32, @bitCast(flag_address))); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeSleb128(0); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeSleb128(1); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); + try bw.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_rmw_cmpxchg)); + try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try bw.writeUleb128(0); // offset // based on the value from the atomic check, jump to the label. - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br_table)); - appendReservedUleb32(binary_bytes, 2); // length of the table (we have 3 blocks but because of the mandatory default the length is 2). - appendReservedUleb32(binary_bytes, 0); // $init - appendReservedUleb32(binary_bytes, 1); // $wait - appendReservedUleb32(binary_bytes, 2); // $drop - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.br_table)); + try bw.writeUleb128(3 - 1); // length of the table (we have 3 blocks but because of the mandatory default the length is 2). + try bw.writeUleb128(0); // $init + try bw.writeUleb128(1); // $wait + try bw.writeUleb128(2); // $drop + try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); } const segment_groups = wasm.flush_buffer.data_segment_groups.items; @@ -1690,74 +1615,82 @@ fn emitInitMemoryFunction( const start_addr: u32 = @intCast(segment.alignment(wasm).forward(prev_end)); const segment_size: u32 = group.end_addr - start_addr; - try binary_bytes.ensureUnusedCapacity(gpa, 6 + 6 + 1 + 5 + 6 + 6 + 1 + 6 * 2 + 1 + 1); - // For passive BSS segments we can simply issue a memory.fill(0). For // non-BSS segments we do a memory.init. Both instructions take as // their first argument the destination address. - appendReservedI32Const(binary_bytes, start_addr); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeLeb128(@as(i32, @bitCast(start_addr))); if (shared_memory and segment.isTls(wasm)) { // When we initialize the TLS segment we also set the `__tls_base` // global. This allows the runtime to use this static copy of the // TLS data for the first/main thread. - appendReservedI32Const(binary_bytes, start_addr); - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_set)); - appendReservedUleb32(binary_bytes, virtual_addrs.tls_base.?); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeLeb128(@as(i32, @bitCast(start_addr))); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.global_set)); + try bw.writeLeb128(virtual_addrs.tls_base.?); } - appendReservedI32Const(binary_bytes, 0); - appendReservedI32Const(binary_bytes, segment_size); - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.misc_prefix)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeSleb128(0); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeLeb128(@as(i32, @bitCast(segment_size))); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); if (segment.isBss(wasm)) { // fill bss segment with zeroes - appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.MiscOpcode.memory_fill)); + try bw.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_fill)); } else { // initialize the segment - appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.MiscOpcode.memory_init)); - appendReservedUleb32(binary_bytes, @intCast(segment_index)); + try bw.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_init)); + try bw.writeLeb128(segment_index); } - binary_bytes.appendAssumeCapacity(0); // memory index immediate + try bw.writeByte(0); // memory index immediate } if (virtual_addrs.init_memory_flag) |flag_address| { assert(shared_memory); - try binary_bytes.ensureUnusedCapacity(gpa, 6 + 6 + 1 + 3 * 5 + 6 + 1 + 5 + 1 + 3 * 5 + 1 + 1 + 5 + 1 + 6 * 2 + 1 + 5 + 1 + 3 * 5 + 1 + 1 + 1); + // we set the init memory flag to value '2' - appendReservedI32Const(binary_bytes, flag_address); - appendReservedI32Const(binary_bytes, 2); - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix)); - appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_store)); - appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment - appendReservedUleb32(binary_bytes, @as(u32, 0)); // offset + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeLeb128(@as(i32, @bitCast(flag_address))); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeSleb128(2); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); + try bw.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_store)); + try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try bw.writeUleb128(0); // offset // notify any waiters for segment initialization completion - appendReservedI32Const(binary_bytes, flag_address); - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); - leb.writeIleb128(binary_bytes.fixedWriter(), @as(i32, -1)) catch unreachable; // number of waiters - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix)); - appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_notify)); - appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment - appendReservedUleb32(binary_bytes, @as(u32, 0)); // offset - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.drop)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeLeb128(@as(i32, @bitCast(flag_address))); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeSleb128(-1); // number of waiters + + try bw.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); + try bw.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_notify)); + try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try bw.writeUleb128(0); // offset + try bw.writeByte(@intFromEnum(std.wasm.Opcode.drop)); // branch and drop segments - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br)); - appendReservedUleb32(binary_bytes, @as(u32, 1)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.br)); + try bw.writeUleb128(1); // wait for thread to initialize memory segments - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); // end $wait - appendReservedI32Const(binary_bytes, flag_address); - appendReservedI32Const(binary_bytes, 1); // expected flag value - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const)); - leb.writeIleb128(binary_bytes.fixedWriter(), @as(i64, -1)) catch unreachable; // timeout - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix)); - appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_wait32)); - appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment - appendReservedUleb32(binary_bytes, @as(u32, 0)); // offset - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.drop)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end $wait + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeLeb128(@as(i32, @bitCast(flag_address))); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeSleb128(1); // expected flag value + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_const)); + try bw.writeSleb128(-1); // timeout + try bw.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); + try bw.writeByte(@intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_wait32)); + try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try bw.writeUleb128(0); // offset + try bw.writeByte(@intFromEnum(std.wasm.Opcode.drop)); - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); // end $drop + try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end $drop } for (segment_groups, 0..) |group, segment_index| { @@ -1768,26 +1701,20 @@ fn emitInitMemoryFunction( // during the initialization of each thread (__wasm_init_tls). if (shared_memory and segment.isTls(wasm)) continue; - try binary_bytes.ensureUnusedCapacity(gpa, 1 + 5 + 5 + 1); - - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.misc_prefix)); - appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.MiscOpcode.data_drop)); - appendReservedUleb32(binary_bytes, @intCast(segment_index)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); + try bw.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.data_drop)); + try bw.writeLeb128(segment_index); } // End of the function body - binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); } -fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!void { +fn emitInitTlsFunction(wasm: *const Wasm, bw: *std.io.BufferedWriter) anyerror!void { const comp = wasm.base.comp; - const gpa = comp.gpa; - assert(comp.config.shared_memory); - try bytes.ensureUnusedCapacity(gpa, 5 * 10 + 8); - - appendReservedUleb32(bytes, 0); // no locals + try bw.writeUleb128(0); // no locals // If there's a TLS segment, initialize it during runtime using the bulk-memory feature // TLS segment is always the first one due to how we sort the data segments. @@ -1796,36 +1723,35 @@ fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Al const start_addr = wasm.flush_buffer.data_segments.values()[0]; const end_addr = wasm.flush_buffer.data_segment_groups.items[0].end_addr; const group_size = end_addr - start_addr; - const data_segment_index = 0; + const data_segment_index: u32 = 0; const param_local: u32 = 0; - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); - appendReservedUleb32(bytes, param_local); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try bw.writeLeb128(param_local); const tls_base_global_index: Wasm.GlobalIndex = @enumFromInt(wasm.globals.getIndex(.__tls_base).?); - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_set)); - appendReservedUleb32(bytes, @intFromEnum(tls_base_global_index)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.global_set)); + try bw.writeLeb128(@intFromEnum(tls_base_global_index)); // load stack values for the bulk-memory operation { - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); - appendReservedUleb32(bytes, param_local); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try bw.writeLeb128(param_local); - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); - appendReservedUleb32(bytes, 0); //segment offset + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeSleb128(0); // segment offset - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); - appendReservedUleb32(bytes, group_size); //segment offset + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeLeb128(@as(i32, @bitCast(group_size))); // segment offset } // perform the bulk-memory operation to initialize the data segment - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.misc_prefix)); - appendReservedUleb32(bytes, @intFromEnum(std.wasm.MiscOpcode.memory_init)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); + try bw.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_init)); // segment immediate - appendReservedUleb32(bytes, data_segment_index); - // memory index immediate (always 0) - appendReservedUleb32(bytes, 0); + try bw.writeLeb128(data_segment_index); + try bw.writeByte(0); // memory index immediate } // If we have to perform any TLS relocations, call the corresponding function @@ -1833,56 +1759,59 @@ fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Al // generated by the linker. if (wasm.functions.getIndex(.__wasm_apply_global_tls_relocs)) |function_index| { const output_function_index: Wasm.OutputFunctionIndex = .fromFunctionIndex(wasm, @enumFromInt(function_index)); - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call)); - appendReservedUleb32(bytes, @intFromEnum(output_function_index)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.call)); + try bw.writeLeb128(@intFromEnum(output_function_index)); } - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); } -fn emitStartSection(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), i: Wasm.OutputFunctionIndex) !void { - const header_offset = try reserveVecSectionHeader(gpa, bytes); - replaceVecSectionHeader(bytes, header_offset, .start, @intFromEnum(i)); +fn emitStartSection(aw: *std.io.AllocatingWriter, i: Wasm.OutputFunctionIndex) !void { + const header_offset = try reserveVecSectionHeader(&aw.buffered_writer); + defer replaceVecSectionHeader(aw, header_offset, .start, @intFromEnum(i)); } fn emitTagNameFunction( wasm: *Wasm, - code: *std.ArrayListUnmanaged(u8), + bw: *std.io.BufferedWriter, table_base_addr: u32, table_index: u32, enum_type_ip: InternPool.Index, ) !void { const comp = wasm.base.comp; - const gpa = comp.gpa; const diags = &comp.link_diags; const zcu = comp.zcu.?; const ip = &zcu.intern_pool; const enum_type = ip.loadEnumType(enum_type_ip); const tag_values = enum_type.values.get(ip); - try code.ensureUnusedCapacity(gpa, 7 * 5 + 6 + 1 * 6); - appendReservedUleb32(code, 0); // no locals + try bw.writeUleb128(0); // no locals - const slice_abi_size = 8; - const encoded_alignment = @ctz(@as(u32, 4)); + const slice_abi_size: u32 = 8; if (tag_values.len == 0) { // Then it's auto-numbered and therefore a direct table lookup. - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); - appendReservedUleb32(code, 0); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try bw.writeUleb128(0); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); - appendReservedUleb32(code, 1); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try bw.writeUleb128(1); - appendReservedI32Const(code, slice_abi_size); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_mul)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + if (std.math.isPowerOfTwo(slice_abi_size)) { + try bw.writeLeb128(@as(i32, @bitCast(@as(u32, std.math.log2_int(u32, slice_abi_size))))); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_shl)); + } else { + try bw.writeLeb128(@as(i32, @bitCast(slice_abi_size))); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_mul)); + } - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_load)); - appendReservedUleb32(code, encoded_alignment); - appendReservedUleb32(code, table_base_addr + table_index * 8); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_load)); + try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try bw.writeLeb128(table_base_addr + slice_abi_size * table_index); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_store)); - appendReservedUleb32(code, encoded_alignment); - appendReservedUleb32(code, 0); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_store)); + try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try bw.writeUleb128(0); } else { const int_info = Zcu.Type.intInfo(.fromInterned(enum_type.tag_ty), zcu); const outer_block_type: std.wasm.BlockType = switch (int_info.bits) { @@ -1891,94 +1820,80 @@ fn emitTagNameFunction( else => return diags.fail("wasm linker does not yet implement @tagName for sparse enums with more than 64 bit integer tag types", .{}), }; - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); - appendReservedUleb32(code, 0); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try bw.writeUleb128(0); // Outer block that computes table offset. - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block)); - code.appendAssumeCapacity(@intFromEnum(outer_block_type)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.block)); + try bw.writeByte(@intFromEnum(outer_block_type)); for (tag_values, 0..) |tag_value, tag_index| { // block for this if case - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block)); - code.appendAssumeCapacity(@intFromEnum(std.wasm.BlockType.empty)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.block)); + try bw.writeByte(@intFromEnum(std.wasm.BlockType.empty)); // Tag value whose name should be returned. - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); - appendReservedUleb32(code, 1); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); + try bw.writeUleb128(1); const val: Zcu.Value = .fromInterned(tag_value); switch (outer_block_type) { .i32 => { - const x: u32 = switch (int_info.signedness) { - .signed => @bitCast(@as(i32, @intCast(val.toSignedInt(zcu)))), - .unsigned => @intCast(val.toUnsignedInt(zcu)), - }; - appendReservedI32Const(code, x); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_ne)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeLeb128(@as(i32, switch (int_info.signedness) { + .signed => @intCast(val.toSignedInt(zcu)), + .unsigned => @bitCast(@as(u32, @intCast(val.toUnsignedInt(zcu)))), + })); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_ne)); }, .i64 => { - const x: u64 = switch (int_info.signedness) { - .signed => @bitCast(val.toSignedInt(zcu)), - .unsigned => val.toUnsignedInt(zcu), - }; - appendReservedI64Const(code, x); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_ne)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_const)); + try bw.writeLeb128(@as(i64, switch (int_info.signedness) { + .signed => val.toSignedInt(zcu), + .unsigned => @bitCast(val.toUnsignedInt(zcu)), + })); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_ne)); }, else => unreachable, } // if they're not equal, break out of current branch - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br_if)); - appendReservedUleb32(code, 0); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.br_if)); + try bw.writeUleb128(0); // Put the table offset of the result on the stack. - appendReservedI32Const(code, @intCast(tag_index * slice_abi_size)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); + try bw.writeLeb128(@as(i32, @bitCast(@as(u32, @intCast(slice_abi_size * tag_index))))); // break outside blocks - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br)); - appendReservedUleb32(code, 1); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.br)); + try bw.writeUleb128(1); // end the block for this case - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); } - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.@"unreachable")); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.@"unreachable")); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_load)); - appendReservedUleb32(code, encoded_alignment); - appendReservedUleb32(code, table_base_addr + table_index * 8); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_load)); + try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try bw.writeLeb128(table_base_addr + slice_abi_size * table_index); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_store)); - appendReservedUleb32(code, encoded_alignment); - appendReservedUleb32(code, 0); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.i64_store)); + try bw.writeLeb128(comptime Alignment.@"4".toLog2Units()); + try bw.writeUleb128(0); } // End of the function body - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); } -/// Writes an unsigned 32-bit integer as a LEB128-encoded 'i32.const' value. -fn appendReservedI32Const(bytes: *std.ArrayListUnmanaged(u8), val: u32) void { - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); - leb.writeIleb128(bytes.fixedWriter(), @as(i32, @bitCast(val))) catch unreachable; -} - -/// Writes an unsigned 64-bit integer as a LEB128-encoded 'i64.const' value. -fn appendReservedI64Const(bytes: *std.ArrayListUnmanaged(u8), val: u64) void { - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const)); - leb.writeIleb128(bytes.fixedWriter(), @as(i64, @bitCast(val))) catch unreachable; -} - -fn appendReservedUleb32(bytes: *std.ArrayListUnmanaged(u8), val: u32) void { - leb.writeUleb128(bytes.fixedWriter(), val) catch unreachable; -} - -fn appendGlobal(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), mutable: u8, val: u32) Allocator.Error!void { - try bytes.ensureUnusedCapacity(gpa, 9); - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Valtype.i32)); - bytes.appendAssumeCapacity(mutable); - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); - appendReservedUleb32(bytes, val); - bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); +fn appendGlobal(bw: *std.io.BufferedWriter, mutable: bool, val: u32) anyerror!void { + try bw.writeAll(&.{ + @intFromEnum(std.wasm.Valtype.i32), + @intFromBool(mutable), + @intFromEnum(std.wasm.Opcode.i32_const), + }); + try bw.writeLeb128(val); + try bw.writeByte(@intFromEnum(std.wasm.Opcode.end)); } diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index fa7208c147..2f7d409390 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -252,7 +252,7 @@ pub const ScratchSpace = struct { pub fn parse( wasm: *Wasm, - bytes: []const u8, + br: *std.io.BufferedReader, path: Path, archive_member_name: ?[]const u8, host_name: Wasm.OptionalString, @@ -264,13 +264,9 @@ pub fn parse( const gpa = comp.gpa; const diags = &comp.link_diags; - var pos: usize = 0; + if (!std.mem.eql(u8, try br.takeArray(std.wasm.magic.len), &std.wasm.magic)) return error.BadObjectMagic; - if (!std.mem.eql(u8, bytes[0..std.wasm.magic.len], &std.wasm.magic)) return error.BadObjectMagic; - pos += std.wasm.magic.len; - - const version = std.mem.readInt(u32, bytes[pos..][0..4], .little); - pos += 4; + const version = try br.takeInt(u32, .little); const data_segment_start: u32 = @intCast(wasm.object_data_segments.items.len); const custom_segment_start: u32 = @intCast(wasm.object_custom_segments.entries.len); @@ -298,200 +294,187 @@ pub fn parse( var code_section_index: ?Wasm.ObjectSectionIndex = null; var global_section_index: ?Wasm.ObjectSectionIndex = null; var data_section_index: ?Wasm.ObjectSectionIndex = null; - while (pos < bytes.len) : (wasm.object_total_sections += 1) { + while (br.takeEnum(std.wasm.Section, .little)) |section_tag| : (wasm.object_total_sections += 1) { const section_index: Wasm.ObjectSectionIndex = @enumFromInt(wasm.object_total_sections); - const section_tag: std.wasm.Section = @enumFromInt(bytes[pos]); - pos += 1; - - const len, pos = readLeb(u32, bytes, pos); - const section_end = pos + len; + const len = try br.takeLeb128(u32); + const section_end = br.seek + len; switch (section_tag) { .custom => { - const section_name, pos = readBytes(bytes, pos); + const section_name = try br.take(try br.takeLeb128(u32)); if (std.mem.eql(u8, section_name, "linking")) { saw_linking_section = true; - const section_version, pos = readLeb(u32, bytes, pos); + const section_version = try br.takeLeb128(u32); log.debug("link meta data version: {d}", .{section_version}); if (section_version != 2) return error.UnsupportedVersion; - while (pos < section_end) { - const sub_type, pos = readLeb(u8, bytes, pos); - log.debug("found subsection: {s}", .{@tagName(@as(SubsectionType, @enumFromInt(sub_type)))}); - const payload_len, pos = readLeb(u32, bytes, pos); + while (br.seek < section_end) { + const sub_type = try br.takeEnum(SubsectionType, .little); + log.debug("found subsection: {s}", .{@tagName(sub_type)}); + const payload_len = try br.takeLeb128(u32); if (payload_len == 0) break; - const count, pos = readLeb(u32, bytes, pos); - - switch (@as(SubsectionType, @enumFromInt(sub_type))) { - .segment_info => { - for (try ss.segment_info.addManyAsSlice(gpa, count)) |*segment| { - const name, pos = readBytes(bytes, pos); - const alignment, pos = readLeb(u32, bytes, pos); - const flags_u32, pos = readLeb(u32, bytes, pos); - const flags: SegmentInfo.Flags = @bitCast(flags_u32); - const tls = flags.tls or - // Supports legacy object files that specified - // being TLS by the name instead of the TLS flag. - std.mem.startsWith(u8, name, ".tdata") or - std.mem.startsWith(u8, name, ".tbss"); - has_tls = has_tls or tls; - segment.* = .{ - .name = try wasm.internString(name), - .flags = .{ - .strings = flags.strings, - .tls = tls, - .alignment = @enumFromInt(alignment), - .retain = flags.retain, - }, - }; - } + const count = try br.takeLeb128(u32); + switch (sub_type) { + .segment_info => for (try ss.segment_info.addManyAsSlice(gpa, count)) |*segment| { + const name = try br.take(try br.takeLeb128(u32)); + const alignment: Alignment = .fromLog2Units(try br.takeLeb128(u32)); + const flags: SegmentInfo.Flags = @bitCast(try br.takeLeb128(u32)); + const tls = flags.tls or + // Supports legacy object files that specified + // being TLS by the name instead of the TLS flag. + std.mem.startsWith(u8, name, ".tdata") or + std.mem.startsWith(u8, name, ".tbss"); + has_tls = has_tls or tls; + segment.* = .{ + .name = try wasm.internString(name), + .flags = .{ + .strings = flags.strings, + .tls = tls, + .alignment = alignment, + .retain = flags.retain, + }, + }; }, - .init_funcs => { - for (try wasm.object_init_funcs.addManyAsSlice(gpa, count)) |*func| { - const priority, pos = readLeb(u32, bytes, pos); - const symbol_index, pos = readLeb(u32, bytes, pos); - if (symbol_index > ss.symbol_table.items.len) - return diags.failParse(path, "init_funcs before symbol table", .{}); - const sym = &ss.symbol_table.items[symbol_index]; - if (sym.pointee != .function) { - return diags.failParse(path, "init_func symbol '{s}' not a function", .{ - sym.name.slice(wasm).?, - }); - } else if (sym.flags.undefined) { - return diags.failParse(path, "init_func symbol '{s}' is an import", .{ - sym.name.slice(wasm).?, - }); - } - func.* = .{ - .priority = priority, - .function_index = sym.pointee.function, - }; + .init_funcs => for (try wasm.object_init_funcs.addManyAsSlice(gpa, count)) |*func| { + const priority = try br.takeLeb128(u32); + const symbol_index = try br.takeLeb128(u32); + if (symbol_index > ss.symbol_table.items.len) + return diags.failParse(path, "init_funcs before symbol table", .{}); + const sym = &ss.symbol_table.items[symbol_index]; + if (sym.pointee != .function) { + return diags.failParse(path, "init_func symbol '{s}' not a function", .{ + sym.name.slice(wasm).?, + }); + } else if (sym.flags.undefined) { + return diags.failParse(path, "init_func symbol '{s}' is an import", .{ + sym.name.slice(wasm).?, + }); } + func.* = .{ + .priority = priority, + .function_index = sym.pointee.function, + }; }, - .comdat_info => { - for (try wasm.object_comdats.addManyAsSlice(gpa, count)) |*comdat| { - const name, pos = readBytes(bytes, pos); - const flags, pos = readLeb(u32, bytes, pos); - if (flags != 0) return error.UnexpectedComdatFlags; - const symbol_count, pos = readLeb(u32, bytes, pos); - const start_off: u32 = @intCast(wasm.object_comdat_symbols.len); - try wasm.object_comdat_symbols.ensureUnusedCapacity(gpa, symbol_count); - for (0..symbol_count) |_| { - const kind, pos = readEnum(Wasm.Comdat.Symbol.Type, bytes, pos); - const index, pos = readLeb(u32, bytes, pos); - if (true) @panic("TODO rebase index depending on kind"); - wasm.object_comdat_symbols.appendAssumeCapacity(.{ - .kind = kind, - .index = index, - }); - } - comdat.* = .{ - .name = try wasm.internString(name), - .flags = flags, - .symbols = .{ - .off = start_off, - .len = @intCast(wasm.object_comdat_symbols.len - start_off), - }, - }; + .comdat_info => for (try wasm.object_comdats.addManyAsSlice(gpa, count)) |*comdat| { + const name = try br.take(try br.takeLeb128(u32)); + const flags = try br.takeLeb128(u32); + if (flags != 0) return error.UnexpectedComdatFlags; + const symbol_count = try br.takeLeb128(u32); + const start_off: u32 = @intCast(wasm.object_comdat_symbols.len); + try wasm.object_comdat_symbols.ensureUnusedCapacity(gpa, symbol_count); + for (0..symbol_count) |_| { + const kind = try br.takeEnum(Wasm.Comdat.Symbol.Type, .little); + const index = try br.takeLeb128(u32); + if (true) @panic("TODO rebase index depending on kind"); + wasm.object_comdat_symbols.appendAssumeCapacity(.{ + .kind = kind, + .index = index, + }); } + comdat.* = .{ + .name = try wasm.internString(name), + .flags = flags, + .symbols = .{ + .off = start_off, + .len = @intCast(wasm.object_comdat_symbols.len - start_off), + }, + }; }, - .symbol_table => { - for (try ss.symbol_table.addManyAsSlice(gpa, count)) |*symbol| { - const tag, pos = readEnum(Symbol.Tag, bytes, pos); - const flags, pos = readLeb(u32, bytes, pos); - symbol.* = .{ - .flags = @bitCast(flags), - .name = .none, - .pointee = undefined, - }; - symbol.flags.initZigSpecific(must_link, gc_sections); + .symbol_table => for (try ss.symbol_table.addManyAsSlice(gpa, count)) |*symbol| { + const tag = try br.takeEnum(Symbol.Tag, .little); + const flags: Wasm.SymbolFlags = @bitCast(try br.takeLeb128(u32)); + symbol.* = .{ + .flags = flags, + .name = .none, + .pointee = undefined, + }; + symbol.flags.initZigSpecific(must_link, gc_sections); - switch (tag) { - .data => { - const name, pos = readBytes(bytes, pos); - const interned_name = try wasm.internString(name); - symbol.name = interned_name.toOptional(); - if (symbol.flags.undefined) { - symbol.pointee = .data_import; - } else { - const segment_index, pos = readLeb(u32, bytes, pos); - const segment_offset, pos = readLeb(u32, bytes, pos); - const size, pos = readLeb(u32, bytes, pos); - try wasm.object_datas.append(gpa, .{ - .segment = @enumFromInt(data_segment_start + segment_index), - .offset = segment_offset, - .size = size, - .name = interned_name, - .flags = symbol.flags, - }); - symbol.pointee = .{ - .data = @enumFromInt(wasm.object_datas.items.len - 1), - }; - } - }, - .section => { - const local_section, pos = readLeb(u32, bytes, pos); - const section: Wasm.ObjectSectionIndex = @enumFromInt(local_section_index_base + local_section); - symbol.pointee = .{ .section = section }; - }, + switch (tag) { + .data => { + const name = try br.take(try br.takeLeb128(u32)); + const interned_name = try wasm.internString(name); + symbol.name = interned_name.toOptional(); + if (symbol.flags.undefined) { + symbol.pointee = .data_import; + } else { + const segment_index = try br.takeLeb128(u32); + const segment_offset = try br.takeLeb128(u32); + const size = try br.takeLeb128(u32); + try wasm.object_datas.append(gpa, .{ + .segment = @enumFromInt(data_segment_start + segment_index), + .offset = segment_offset, + .size = size, + .name = interned_name, + .flags = symbol.flags, + }); + symbol.pointee = .{ + .data = @enumFromInt(wasm.object_datas.items.len - 1), + }; + } + }, + .section => { + const local_section = try br.takeLeb128(u32); + const section: Wasm.ObjectSectionIndex = @enumFromInt(local_section_index_base + local_section); + symbol.pointee = .{ .section = section }; + }, - .function => { - const local_index, pos = readLeb(u32, bytes, pos); - if (symbol.flags.undefined) { - const function_import: ScratchSpace.FuncImportIndex = @enumFromInt(local_index); - symbol.pointee = .{ .function_import = function_import }; - if (symbol.flags.explicit_name) { - const name, pos = readBytes(bytes, pos); - symbol.name = (try wasm.internString(name)).toOptional(); - } else { - symbol.name = function_import.ptr(ss).name.toOptional(); - } - } else { - symbol.pointee = .{ .function = @enumFromInt(functions_start + (local_index - ss.func_imports.items.len)) }; - const name, pos = readBytes(bytes, pos); + .function => { + const local_index = try br.takeLeb128(u32); + if (symbol.flags.undefined) { + const function_import: ScratchSpace.FuncImportIndex = @enumFromInt(local_index); + symbol.pointee = .{ .function_import = function_import }; + if (symbol.flags.explicit_name) { + const name = try br.take(try br.takeLeb128(u32)); symbol.name = (try wasm.internString(name)).toOptional(); - } - }, - .global => { - const local_index, pos = readLeb(u32, bytes, pos); - if (symbol.flags.undefined) { - const global_import: ScratchSpace.GlobalImportIndex = @enumFromInt(local_index); - symbol.pointee = .{ .global_import = global_import }; - if (symbol.flags.explicit_name) { - const name, pos = readBytes(bytes, pos); - symbol.name = (try wasm.internString(name)).toOptional(); - } else { - symbol.name = global_import.ptr(ss).name.toOptional(); - } } else { - symbol.pointee = .{ .global = @enumFromInt(globals_start + (local_index - ss.global_imports.items.len)) }; - const name, pos = readBytes(bytes, pos); - symbol.name = (try wasm.internString(name)).toOptional(); + symbol.name = function_import.ptr(ss).name.toOptional(); } - }, - .table => { - const local_index, pos = readLeb(u32, bytes, pos); - if (symbol.flags.undefined) { - table_import_symbol_count += 1; - const table_import: ScratchSpace.TableImportIndex = @enumFromInt(local_index); - symbol.pointee = .{ .table_import = table_import }; - if (symbol.flags.explicit_name) { - const name, pos = readBytes(bytes, pos); - symbol.name = (try wasm.internString(name)).toOptional(); - } else { - symbol.name = table_import.ptr(ss).name.toOptional(); - } + } else { + symbol.pointee = .{ .function = @enumFromInt(functions_start + (local_index - ss.func_imports.items.len)) }; + const name = try br.take(try br.takeLeb128(u32)); + symbol.name = (try wasm.internString(name)).toOptional(); + } + }, + .global => { + const local_index = try br.takeLeb128(u32); + if (symbol.flags.undefined) { + const global_import: ScratchSpace.GlobalImportIndex = @enumFromInt(local_index); + symbol.pointee = .{ .global_import = global_import }; + if (symbol.flags.explicit_name) { + const name = try br.take(try br.takeLeb128(u32)); + symbol.name = (try wasm.internString(name)).toOptional(); } else { - symbol.pointee = .{ .table = @enumFromInt(tables_start + (local_index - ss.table_imports.items.len)) }; - const name, pos = readBytes(bytes, pos); - symbol.name = (try wasm.internString(name)).toOptional(); + symbol.name = global_import.ptr(ss).name.toOptional(); } - }, - else => { - log.debug("unrecognized symbol type tag: {x}", .{@intFromEnum(tag)}); - return error.UnrecognizedSymbolType; - }, - } + } else { + symbol.pointee = .{ .global = @enumFromInt(globals_start + (local_index - ss.global_imports.items.len)) }; + const name = try br.take(try br.takeLeb128(u32)); + symbol.name = (try wasm.internString(name)).toOptional(); + } + }, + .table => { + const local_index = try br.takeLeb128(u32); + if (symbol.flags.undefined) { + table_import_symbol_count += 1; + const table_import: ScratchSpace.TableImportIndex = @enumFromInt(local_index); + symbol.pointee = .{ .table_import = table_import }; + if (symbol.flags.explicit_name) { + const name = try br.take(try br.takeLeb128(u32)); + symbol.name = (try wasm.internString(name)).toOptional(); + } else { + symbol.name = table_import.ptr(ss).name.toOptional(); + } + } else { + symbol.pointee = .{ .table = @enumFromInt(tables_start + (local_index - ss.table_imports.items.len)) }; + const name = try br.take(try br.takeLeb128(u32)); + symbol.name = (try wasm.internString(name)).toOptional(); + } + }, + else => { + log.debug("unrecognized symbol type tag: {x}", .{@intFromEnum(tag)}); + return error.UnrecognizedSymbolType; + }, } }, } @@ -504,8 +487,8 @@ pub fn parse( // which section they apply to, and must be sequenced in // the module after that section." // "Relocation sections can only target code, data and custom sections." - const local_section, pos = readLeb(u32, bytes, pos); - const count, pos = readLeb(u32, bytes, pos); + const local_section = try br.takeLeb128(u32); + const count = try br.takeLeb128(u32); const section: Wasm.ObjectSectionIndex = @enumFromInt(local_section_index_base + local_section); log.debug("found {d} relocations for section={d}", .{ count, section }); @@ -513,10 +496,9 @@ pub fn parse( var prev_offset: u32 = 0; try wasm.object_relocations.ensureUnusedCapacity(gpa, count); for (0..count) |_| { - const tag: RelocationType = @enumFromInt(bytes[pos]); - pos += 1; - const offset, pos = readLeb(u32, bytes, pos); - const index, pos = readLeb(u32, bytes, pos); + const tag = try br.takeEnum(RelocationType, .little); + const offset = try br.takeLeb128(u32); + const index = try br.takeLeb128(u32); if (offset < prev_offset) return diags.failParse(path, "relocation entries not sorted by offset", .{}); @@ -537,7 +519,7 @@ pub fn parse( .memory_addr_locrel_i32, .memory_addr_tls_sleb64, => { - const addend: i32, pos = readLeb(i32, bytes, pos); + const addend = try br.takeLeb128(i32); wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) { .data => |data| .{ .tag = .fromType(tag), @@ -555,7 +537,7 @@ pub fn parse( }); }, .function_offset_i32, .function_offset_i64 => { - const addend: i32, pos = readLeb(i32, bytes, pos); + const addend = try br.takeLeb128(i32); wasm.object_relocations.appendAssumeCapacity(switch (sym.pointee) { .function => .{ .tag = .fromType(tag), @@ -573,7 +555,7 @@ pub fn parse( }); }, .section_offset_i32 => { - const addend: i32, pos = readLeb(i32, bytes, pos); + const addend = try br.takeLeb128(i32); wasm.object_relocations.appendAssumeCapacity(.{ .tag = .section_offset_i32, .offset = offset, @@ -658,10 +640,9 @@ pub fn parse( .len = count, }); } else if (std.mem.eql(u8, section_name, "target_features")) { - opt_features, pos = try parseFeatures(wasm, bytes, pos, path); + opt_features = try parseFeatures(wasm, br, path); } else if (std.mem.startsWith(u8, section_name, ".debug")) { - const debug_content = bytes[pos..section_end]; - pos = section_end; + const debug_content = try br.take(len); const data_off: u32 = @intCast(wasm.string_bytes.items.len); try wasm.string_bytes.appendSlice(gpa, debug_content); @@ -669,23 +650,20 @@ pub fn parse( try wasm.object_custom_segments.put(gpa, section_index, .{ .payload = .{ .off = @enumFromInt(data_off), - .len = @intCast(debug_content.len), + .len = @intCast(len), }, .flags = .{}, .section_name = try wasm.internString(section_name), }); - } else { - pos = section_end; - } + } else br.seek = section_end; }, .type => { - const func_types_len, pos = readLeb(u32, bytes, pos); + const func_types_len = try br.takeLeb128(u32); for (try ss.func_types.addManyAsSlice(gpa, func_types_len)) |*func_type| { - if (bytes[pos] != std.wasm.function_type) return error.ExpectedFuncType; - pos += 1; + if (try br.takeByte() != std.wasm.function_type) return error.ExpectedFuncType; - const params, pos = readBytes(bytes, pos); - const returns, pos = readBytes(bytes, pos); + const params = try br.take(try br.takeLeb128(u32)); + const returns = try br.take(try br.takeLeb128(u32)); func_type.* = try wasm.addFuncType(.{ .params = .fromString(try wasm.internString(params)), .returns = .fromString(try wasm.internString(returns)), @@ -693,16 +671,16 @@ pub fn parse( } }, .import => { - const imports_len, pos = readLeb(u32, bytes, pos); + const imports_len = try br.takeLeb128(u32); for (0..imports_len) |_| { - const module_name, pos = readBytes(bytes, pos); - const name, pos = readBytes(bytes, pos); - const kind, pos = readEnum(std.wasm.ExternalKind, bytes, pos); + const module_name = try br.take(try br.takeLeb128(u32)); + const name = try br.take(try br.takeLeb128(u32)); + const kind = try br.takeEnum(std.wasm.ExternalKind, .little); const interned_module_name = try wasm.internString(module_name); const interned_name = try wasm.internString(name); switch (kind) { .function => { - const function, pos = readLeb(u32, bytes, pos); + const function = try br.takeLeb128(u32); try ss.func_imports.append(gpa, .{ .module_name = interned_module_name, .name = interned_name, @@ -710,7 +688,7 @@ pub fn parse( }); }, .memory => { - const limits, pos = readLimits(bytes, pos); + const limits = try readLimits(br); const gop = try wasm.object_memory_imports.getOrPut(gpa, interned_name); if (gop.found_existing) { if (gop.value_ptr.module_name != interned_module_name) { @@ -736,9 +714,12 @@ pub fn parse( } }, .global => { - const valtype, pos = readEnum(std.wasm.Valtype, bytes, pos); - const mutable = bytes[pos] == 0x01; - pos += 1; + const valtype = try br.takeEnum(std.wasm.Valtype, .little); + const mutable = switch (try br.takeByte()) { + 0 => false, + 1 => true, + else => return error.InvalidMutability, + }; try ss.global_imports.append(gpa, .{ .name = interned_name, .valtype = valtype, @@ -747,8 +728,8 @@ pub fn parse( }); }, .table => { - const ref_type, pos = readEnum(std.wasm.RefType, bytes, pos); - const limits, pos = readLimits(bytes, pos); + const ref_type = try br.takeEnum(std.wasm.RefType, .little); + const limits = try readLimits(br); try ss.table_imports.append(gpa, .{ .name = interned_name, .module_name = interned_module_name, @@ -763,17 +744,16 @@ pub fn parse( } }, .function => { - const functions_len, pos = readLeb(u32, bytes, pos); + const functions_len = try br.takeLeb128(u32); for (try ss.func_type_indexes.addManyAsSlice(gpa, functions_len)) |*func_type_index| { - const i, pos = readLeb(u32, bytes, pos); - func_type_index.* = @enumFromInt(i); + func_type_index.* = @enumFromInt(try br.takeLeb128(u32)); } }, .table => { - const tables_len, pos = readLeb(u32, bytes, pos); + const tables_len = try br.takeLeb128(u32); for (try wasm.object_tables.addManyAsSlice(gpa, tables_len)) |*table| { - const ref_type, pos = readEnum(std.wasm.RefType, bytes, pos); - const limits, pos = readLimits(bytes, pos); + const ref_type = try br.takeEnum(std.wasm.RefType, .little); + const limits = try readLimits(br); table.* = .{ .name = .none, .module_name = .none, @@ -788,9 +768,9 @@ pub fn parse( } }, .memory => { - const memories_len, pos = readLeb(u32, bytes, pos); + const memories_len = try br.takeLeb128(u32); for (try wasm.object_memories.addManyAsSlice(gpa, memories_len)) |*memory| { - const limits, pos = readLimits(bytes, pos); + const limits = try readLimits(br); memory.* = .{ .name = .none, .flags = .{ @@ -807,14 +787,17 @@ pub fn parse( return diags.failParse(path, "object has more than one global section", .{}); global_section_index = section_index; - const section_start = pos; - const globals_len, pos = readLeb(u32, bytes, pos); + const section_start = br.seek; + const globals_len = try br.takeLeb128(u32); for (try wasm.object_globals.addManyAsSlice(gpa, globals_len)) |*global| { - const valtype, pos = readEnum(std.wasm.Valtype, bytes, pos); - const mutable = bytes[pos] == 0x01; - pos += 1; - const init_start = pos; - const expr, pos = try readInit(wasm, bytes, pos); + const valtype = try br.takeEnum(std.wasm.Valtype, .little); + const mutable = switch (try br.takeByte()) { + 0 => false, + 1 => true, + else => return error.InvalidMutability, + }; + const init_start = br.seek; + const expr = try readInit(wasm, br); global.* = .{ .name = .none, .flags = .{ @@ -826,20 +809,19 @@ pub fn parse( .expr = expr, .object_index = object_index, .offset = @intCast(init_start - section_start), - .size = @intCast(pos - init_start), + .size = @intCast(br.seek - init_start), }; } }, .@"export" => { - const exports_len, pos = readLeb(u32, bytes, pos); + const exports_len = try br.takeLeb128(u32); // Read into scratch space, and then later add this data as if // it were extra symbol table entries, but allow merging with // existing symbol table data if the name matches. for (try ss.exports.addManyAsSlice(gpa, exports_len)) |*exp| { - const name, pos = readBytes(bytes, pos); - const kind: std.wasm.ExternalKind = @enumFromInt(bytes[pos]); - pos += 1; - const index, pos = readLeb(u32, bytes, pos); + const name = try br.take(try br.takeLeb128(u32)); + const kind = try br.takeEnum(std.wasm.ExternalKind, .little); + const index = try br.takeLeb128(u32); exp.* = .{ .name = try wasm.internString(name), .pointee = switch (kind) { @@ -852,25 +834,24 @@ pub fn parse( } }, .start => { - const index, pos = readLeb(u32, bytes, pos); + const index = try br.takeLeb128(u32); start_function = @enumFromInt(functions_start + index); }, .element => { - log.warn("unimplemented: element section in {} {?s}", .{ path, archive_member_name }); - pos = section_end; + log.warn("unimplemented: element section in {f} {?s}", .{ path, archive_member_name }); + br.seek = section_end; }, .code => { if (code_section_index != null) return diags.failParse(path, "object has more than one code section", .{}); code_section_index = section_index; - const start = pos; - const count, pos = readLeb(u32, bytes, pos); + const start = br.seek; + const count = try br.takeLeb128(u32); for (try wasm.object_functions.addManyAsSlice(gpa, count)) |*elem| { - const code_len, pos = readLeb(u32, bytes, pos); - const offset: u32 = @intCast(pos - start); - const payload = try wasm.addRelocatableDataPayload(bytes[pos..][0..code_len]); - pos += code_len; + const code_len = try br.takeLeb128(u32); + const offset: u32 = @intCast(br.seek - start); + const payload = try wasm.addRelocatableDataPayload(try br.take(code_len)); elem.* = .{ .flags = .{}, // populated from symbol table .name = .none, // populated from symbol table @@ -886,20 +867,19 @@ pub fn parse( return diags.failParse(path, "object has more than one data section", .{}); data_section_index = section_index; - const section_start = pos; - const count, pos = readLeb(u32, bytes, pos); + const section_start = br.seek; + const count = try br.takeLeb128(u32); for (try wasm.object_data_segments.addManyAsSlice(gpa, count)) |*elem| { - const flags, pos = readEnum(DataSegmentFlags, bytes, pos); + const flags: DataSegmentFlags = @enumFromInt(try br.takeLeb128(u32)); if (flags == .active_memidx) { - const memidx, pos = readLeb(u32, bytes, pos); + const memidx = try br.takeLeb128(u32); if (memidx != 0) return diags.failParse(path, "data section uses mem index {d}", .{memidx}); } - //const expr, pos = if (flags != .passive) try readInit(wasm, bytes, pos) else .{ .none, pos }; - if (flags != .passive) pos = try skipInit(bytes, pos); - const data_len, pos = readLeb(u32, bytes, pos); - const segment_start = pos; - const payload = try wasm.addRelocatableDataPayload(bytes[pos..][0..data_len]); - pos += data_len; + //const expr = if (flags != .passive) try readInit(wasm, br) else .none; + if (flags != .passive) try skipInit(br); + const data_len = try br.takeLeb128(u32); + const segment_start = br.seek; + const payload = try wasm.addRelocatableDataPayload(try br.take(data_len)); elem.* = .{ .payload = payload, .name = .none, // Populated from segment_info @@ -911,10 +891,10 @@ pub fn parse( }; } }, - else => pos = section_end, + else => br.seek = section_end, } - if (pos != section_end) return error.MalformedSection; - } + if (br.seek != section_end) return error.MalformedSection; + } else |_| {} if (!saw_linking_section) return error.MissingLinkingSection; const cpu = comp.root_mod.resolved_target.result.cpu; @@ -984,10 +964,10 @@ pub fn parse( if (gop.value_ptr.type != fn_ty_index) { var err = try diags.addErrorWithNotes(2); try err.addMsg("symbol '{s}' mismatching function signatures", .{name.slice(wasm)}); - gop.value_ptr.source_location.addNote(&err, "imported as {} here", .{ + gop.value_ptr.source_location.addNote(&err, "imported as {f} here", .{ gop.value_ptr.type.fmt(wasm), }); - source_location.addNote(&err, "imported as {} here", .{fn_ty_index.fmt(wasm)}); + source_location.addNote(&err, "imported as {f} here", .{fn_ty_index.fmt(wasm)}); continue; } if (gop.value_ptr.module_name != ptr.module_name.toOptional()) { @@ -1155,11 +1135,11 @@ pub fn parse( if (gop.value_ptr.type != ptr.type_index) { var err = try diags.addErrorWithNotes(2); try err.addMsg("function signature mismatch: {s}", .{name.slice(wasm)}); - gop.value_ptr.source_location.addNote(&err, "exported as {} here", .{ + gop.value_ptr.source_location.addNote(&err, "exported as {f} here", .{ ptr.type_index.fmt(wasm), }); const word = if (gop.value_ptr.resolution == .unresolved) "imported" else "exported"; - source_location.addNote(&err, "{s} as {} here", .{ word, gop.value_ptr.type.fmt(wasm) }); + source_location.addNote(&err, "{s} as {f} here", .{ word, gop.value_ptr.type.fmt(wasm) }); continue; } if (gop.value_ptr.resolution == .unresolved or gop.value_ptr.flags.binding == .weak) { @@ -1176,8 +1156,8 @@ pub fn parse( } var err = try diags.addErrorWithNotes(2); try err.addMsg("symbol collision: {s}", .{name.slice(wasm)}); - gop.value_ptr.source_location.addNote(&err, "exported as {} here", .{ptr.type_index.fmt(wasm)}); - source_location.addNote(&err, "exported as {} here", .{gop.value_ptr.type.fmt(wasm)}); + gop.value_ptr.source_location.addNote(&err, "exported as {f} here", .{ptr.type_index.fmt(wasm)}); + source_location.addNote(&err, "exported as {f} here", .{gop.value_ptr.type.fmt(wasm)}); continue; } else { gop.value_ptr.* = .{ @@ -1422,27 +1402,21 @@ pub fn parse( /// Based on the "features" custom section, parses it into a list of /// features that tell the linker what features were enabled and may be mandatory /// to be able to link. -fn parseFeatures( - wasm: *Wasm, - bytes: []const u8, - start_pos: usize, - path: Path, -) error{ OutOfMemory, LinkFailure }!struct { Wasm.Feature.Set, usize } { +fn parseFeatures(wasm: *Wasm, br: *std.io.BufferedReader, path: Path) anyerror!Wasm.Feature.Set { const gpa = wasm.base.comp.gpa; const diags = &wasm.base.comp.link_diags; - const features_len, var pos = readLeb(u32, bytes, start_pos); + const features_len = try br.takeLeb128(u32); // This temporary allocation could be avoided by using the string_bytes buffer as a scratch space. const feature_buffer = try gpa.alloc(Wasm.Feature, features_len); defer gpa.free(feature_buffer); for (feature_buffer) |*feature| { - const prefix: Wasm.Feature.Prefix = switch (bytes[pos]) { + const prefix: Wasm.Feature.Prefix = switch (try br.takeByte()) { '-' => .@"-", '+' => .@"+", '=' => .@"=", else => |b| return diags.failParse(path, "invalid feature prefix: 0x{x}", .{b}), }; - pos += 1; - const name, pos = readBytes(bytes, pos); + const name = try br.take(try br.takeLeb128(u32)); const tag = std.meta.stringToEnum(Wasm.Feature.Tag, name) orelse { return diags.failParse(path, "unrecognized wasm feature in object: {s}", .{name}); }; @@ -1453,68 +1427,34 @@ fn parseFeatures( } std.mem.sortUnstable(Wasm.Feature, feature_buffer, {}, Wasm.Feature.lessThan); + return .fromString(try wasm.internString(@ptrCast(feature_buffer))); +} + +fn readLimits(br: *std.io.BufferedReader) anyerror!std.wasm.Limits { + const flags: std.wasm.Limits.Flags = @bitCast(try br.takeByte()); + const min = try br.takeLeb128(u32); + const max = if (flags.has_max) try br.takeLeb128(u32) else 0; return .{ - .fromString(try wasm.internString(@ptrCast(feature_buffer))), - pos, - }; -} - -fn readLeb(comptime T: type, bytes: []const u8, pos: usize) struct { T, usize } { - var fbr: std.io.FixedBufferStream = .{ .buffer = bytes[pos..] }; - return .{ - switch (@typeInfo(T).int.signedness) { - .signed => std.leb.readIleb128(T, fbr.reader()) catch unreachable, - .unsigned => std.leb.readUleb128(T, fbr.reader()) catch unreachable, - }, - pos + fbr.pos, - }; -} - -fn readBytes(bytes: []const u8, start_pos: usize) struct { []const u8, usize } { - const len, const pos = readLeb(u32, bytes, start_pos); - return .{ - bytes[pos..][0..len], - pos + len, - }; -} - -fn readEnum(comptime T: type, bytes: []const u8, pos: usize) struct { T, usize } { - const Tag = @typeInfo(T).@"enum".tag_type; - const int, const new_pos = readLeb(Tag, bytes, pos); - return .{ @enumFromInt(int), new_pos }; -} - -fn readLimits(bytes: []const u8, start_pos: usize) struct { std.wasm.Limits, usize } { - const flags: std.wasm.Limits.Flags = @bitCast(bytes[start_pos]); - const min, const max_pos = readLeb(u32, bytes, start_pos + 1); - const max, const end_pos = if (flags.has_max) readLeb(u32, bytes, max_pos) else .{ 0, max_pos }; - return .{ .{ .flags = flags, .min = min, .max = max, - }, end_pos }; -} - -fn readInit(wasm: *Wasm, bytes: []const u8, pos: usize) !struct { Wasm.Expr, usize } { - const end_pos = try skipInit(bytes, pos); // one after the end opcode - return .{ try wasm.addExpr(bytes[pos..end_pos]), end_pos }; -} - -pub fn exprEndPos(bytes: []const u8, pos: usize) error{InvalidInitOpcode}!usize { - const opcode = bytes[pos]; - return switch (@as(std.wasm.Opcode, @enumFromInt(opcode))) { - .i32_const => readLeb(i32, bytes, pos + 1)[1], - .i64_const => readLeb(i64, bytes, pos + 1)[1], - .f32_const => pos + 5, - .f64_const => pos + 9, - .global_get => readLeb(u32, bytes, pos + 1)[1], - else => return error.InvalidInitOpcode, }; } -fn skipInit(bytes: []const u8, pos: usize) !usize { - const end_pos = try exprEndPos(bytes, pos); - const op, const final_pos = readEnum(std.wasm.Opcode, bytes, end_pos); - if (op != .end) return error.InitExprMissingEnd; - return final_pos; +fn readInit(wasm: *Wasm, br: *std.io.BufferedReader) anyerror!Wasm.Expr { + const start = br.seek; + try skipInit(br); // one after the end opcode + return wasm.addExpr(br.storageBuffer()[start..br.seek]); +} + +pub fn skipInit(br: *std.io.BufferedReader) anyerror!void { + switch (try br.takeEnum(std.wasm.Opcode, .little)) { + .i32_const => _ = try br.takeLeb128(i32), + .i64_const => _ = try br.takeLeb128(i64), + .f32_const => try br.discard(5), + .f64_const => try br.discard(9), + .global_get => _ = try br.takeLeb128(u32), + else => return error.InvalidInitOpcode, + } + if (try br.takeEnum(std.wasm.Opcode, .little) != .end) return error.InitExprMissingEnd; } diff --git a/src/link/aarch64.zig b/src/link/aarch64.zig index d86939a156..0f508812e7 100644 --- a/src/link/aarch64.zig +++ b/src/link/aarch64.zig @@ -4,7 +4,7 @@ pub inline fn isArithmeticOp(inst: *const [4]u8) bool { } pub fn writeAddImmInst(value: u12, code: *[4]u8) void { - var inst = Instruction{ + var inst: Instruction = .{ .add_subtract_immediate = mem.bytesToValue(@FieldType( Instruction, @tagName(Instruction.add_subtract_immediate), @@ -33,7 +33,7 @@ pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i21 { } pub fn writeAdrpInst(pages: u21, code: *[4]u8) void { - var inst = Instruction{ + var inst: Instruction = .{ .pc_relative_address = mem.bytesToValue(@FieldType( Instruction, @tagName(Instruction.pc_relative_address), @@ -45,7 +45,7 @@ pub fn writeAdrpInst(pages: u21, code: *[4]u8) void { } pub fn writeBranchImm(disp: i28, code: *[4]u8) void { - var inst = Instruction{ + var inst: Instruction = .{ .unconditional_branch_immediate = mem.bytesToValue(@FieldType( Instruction, @tagName(Instruction.unconditional_branch_immediate), diff --git a/src/link/riscv.zig b/src/link/riscv.zig index 31f26b7287..c45d9efb72 100644 --- a/src/link/riscv.zig +++ b/src/link/riscv.zig @@ -1,52 +1,50 @@ -pub fn writeSetSub6(comptime op: enum { set, sub }, code: *[1]u8, addend: anytype) void { +pub fn writeSetSub6(comptime op: enum { set, sub }, addend: anytype, bw: *std.io.BufferedWriter) anyerror!void { const mask: u8 = 0b11_000000; const actual: i8 = @truncate(addend); - var value: u8 = mem.readInt(u8, code, .little); - switch (op) { - .set => value = (value & mask) | @as(u8, @bitCast(actual & ~mask)), - .sub => value = (value & mask) | (@as(u8, @bitCast(@as(i8, @bitCast(value)) -| actual)) & ~mask), - } - mem.writeInt(u8, code, value, .little); + const old_value = (try bw.writableSlice(1))[0]; + const new_value = (old_value & mask) | (@as(u8, switch (op) { + .set => @bitCast(actual), + .sub => @bitCast(@as(i8, @bitCast(old_value)) -| actual), + }) & ~mask); + try bw.writeByte(new_value); } -pub fn writeSetSubUleb(comptime op: enum { set, sub }, stream: *std.io.FixedBufferStream([]u8), addend: i64) !void { +pub fn writeSetSubUleb(comptime op: enum { set, sub }, addend: i64, bw: *std.io.BufferedWriter) anyerror!void { switch (op) { - .set => try overwriteUleb(stream, @intCast(addend)), + .set => try overwriteUleb(@intCast(addend), bw), .sub => { - const position = try stream.getPos(); - const value: u64 = try std.leb.readUleb128(u64, stream.reader()); - try stream.seekTo(position); - try overwriteUleb(stream, value -% @as(u64, @intCast(addend))); + var br: std.io.BufferedReader = undefined; + br.initFixed(try bw.writableSlice(1)); + const old_value = try br.takeLeb128(u64); + try overwriteUleb(old_value -% @as(u64, @intCast(addend)), bw); }, } } -fn overwriteUleb(stream: *std.io.FixedBufferStream([]u8), addend: u64) !void { - var value: u64 = addend; - const writer = stream.writer(); - +fn overwriteUleb(new_value: u64, bw: *std.io.BufferedWriter) anyerror!void { + var value: u64 = new_value; while (true) { - const byte = stream.buffer[stream.pos]; + const byte = (try bw.writableSlice(1))[0]; + try bw.writeByte((byte & 0x80) | @as(u7, @truncate(value))); if (byte & 0x80 == 0) break; - try writer.writeByte(0x80 | @as(u8, @truncate(value & 0x7f))); value >>= 7; } - stream.buffer[stream.pos] = @truncate(value & 0x7f); } pub fn writeAddend( comptime Int: type, comptime op: enum { add, sub }, - code: *[@typeInfo(Int).int.bits / 8]u8, value: anytype, -) void { - var V: Int = mem.readInt(Int, code, .little); + bw: *std.io.BufferedWriter, +) anyerror!void { + const n = @divExact(@bitSizeOf(Int), 8); + var V: Int = mem.readInt(Int, (try bw.writableSlice(n))[0..n], .little); const addend: Int = @truncate(value); switch (op) { .add => V +|= addend, // TODO: I think saturating arithmetic is correct here .sub => V -|= addend, } - mem.writeInt(Int, code, V, .little); + try bw.writeInt(Int, V, .little); } pub fn writeInstU(code: *[4]u8, value: u32) void { diff --git a/src/link/table_section.zig b/src/link/table_section.zig index c579198c91..0309acd3f0 100644 --- a/src/link/table_section.zig +++ b/src/link/table_section.zig @@ -39,17 +39,11 @@ pub fn TableSection(comptime Entry: type) type { return self.entries.items.len; } - pub fn format( - self: Self, - comptime unused_format_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = options; + pub fn format(self: Self, bw: *std.io.BufferedWriter, comptime unused_format_string: []const u8) anyerror!void { comptime assert(unused_format_string.len == 0); - try writer.writeAll("TableSection:\n"); + try bw.writeAll("TableSection:\n"); for (self.entries.items, 0..) |entry, i| { - try writer.print(" {d} => {}\n", .{ i, entry }); + try bw.print(" {d} => {}\n", .{ i, entry }); } } diff --git a/src/main.zig b/src/main.zig index b06ea57eb4..60b69ac6a3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -66,7 +66,7 @@ pub fn wasi_cwd() std.os.wasi.fd_t { const fatal = std.process.fatal; /// This can be global since stdout is a singleton. -var stdout_buffer: [4096]u8 = undefined; +var stdio_buffer: [4096]u8 = undefined; /// Shaming all the locations that inappropriately use an O(N) search algorithm. /// Please delete this and fix the compilation errors! @@ -5477,7 +5477,7 @@ fn jitCmd( defer comp.destroy(); if (options.server) { - var server = std.zig.Server{ + var server: std.zig.Server = .{ .out = fs.File.stdout(), .in = undefined, // won't be receiving messages .receive_fifo = undefined, // won't be receiving messages @@ -5672,7 +5672,7 @@ const ArgIteratorResponseFile = process.ArgIteratorGeneral(.{ .comments = true, /// Initialize the arguments from a Response File. "*.rsp" fn initArgIteratorResponseFile(allocator: Allocator, resp_file_path: []const u8) !ArgIteratorResponseFile { const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit - const cmd_line = try fs.cwd().readFileAlloc(allocator, resp_file_path, max_bytes); + const cmd_line = try fs.cwd().readFileAlloc(resp_file_path, allocator, .limited(max_bytes)); errdefer allocator.free(cmd_line); return ArgIteratorResponseFile.initTakeOwnership(allocator, cmd_line); @@ -6061,11 +6061,7 @@ fn cmdAstCheck( const tree = try Ast.parse(arena, source, mode); - var bw: std.io.BufferedWriter = .{ - .unbuffered_writer = fs.File.stdout().writer(), - .buffer = &stdout_buffer, - }; - + var stdout_bw = fs.File.stdout().writer().buffered(&stdio_buffer); switch (mode) { .zig => { const zir = try AstGen.generate(arena, tree); @@ -6109,7 +6105,7 @@ fn cmdAstCheck( const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes + zir.string_bytes.len * @sizeOf(u8); // zig fmt: off - try bw.print( + try stdout_bw.print( \\# Source bytes: {Bi} \\# Tokens: {} ({Bi}) \\# AST Nodes: {} ({Bi}) @@ -6130,8 +6126,8 @@ fn cmdAstCheck( // zig fmt: on } - try @import("print_zir.zig").renderAsText(arena, tree, zir, &bw); - try bw.flush(); + try @import("print_zir.zig").renderAsText(arena, tree, zir, &stdout_bw); + try stdout_bw.flush(); if (zir.hasCompileErrors()) { process.exit(1); @@ -6158,8 +6154,8 @@ fn cmdAstCheck( fatal("-t option only available in builds of zig with debug extensions", .{}); } - try @import("print_zoir.zig").renderToWriter(zoir, arena, &bw); - try bw.flush(); + try @import("print_zoir.zig").renderToWriter(zoir, arena, &stdout_bw); + try stdout_bw.flush(); return cleanExit(); }, } @@ -6187,8 +6183,7 @@ fn cmdDetectCpu(args: []const []const u8) !void { const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - const stdout = fs.File.stdout().writer(); - try stdout.writeAll(detect_cpu_usage); + try fs.File.stdout().writeAll(detect_cpu_usage); return cleanExit(); } else if (mem.eql(u8, arg, "--llvm")) { use_llvm = true; @@ -6280,13 +6275,10 @@ fn detectNativeCpuWithLLVM( } fn printCpu(cpu: std.Target.Cpu) !void { - var bw: std.io.BufferedWriter = .{ - .unbuffered_writer = fs.File.stdout().writer(), - .buffer = &stdout_buffer, - }; + var stdout_bw = fs.File.stdout().writer().buffered(&stdio_buffer); if (cpu.model.llvm_name) |llvm_name| { - try bw.print("{s}\n", .{llvm_name}); + try stdout_bw.print("{s}\n", .{llvm_name}); } const all_features = cpu.arch.allFeaturesList(); @@ -6295,10 +6287,10 @@ fn printCpu(cpu: std.Target.Cpu) !void { const index: std.Target.Cpu.Feature.Set.Index = @intCast(index_usize); const is_enabled = cpu.features.isEnabled(index); const plus_or_minus = "-+"[@intFromBool(is_enabled)]; - try bw.print("{c}{s}\n", .{ plus_or_minus, llvm_name }); + try stdout_bw.print("{c}{s}\n", .{ plus_or_minus, llvm_name }); } - try bw.flush(); + try stdout_bw.flush(); } fn cmdDumpLlvmInts( @@ -6331,16 +6323,13 @@ fn cmdDumpLlvmInts( const dl = tm.createTargetDataLayout(); const context = llvm.Context.create(); - var bw = io.bufferedWriter(fs.File.stdout().writer()); - const stdout = bw.writer(); - + var stdout_bw = fs.File.stdout().writer().buffered(&stdio_buffer); for ([_]u16{ 1, 8, 16, 32, 64, 128, 256 }) |bits| { const int_type = context.intType(bits); const alignment = dl.abiAlignmentOfType(int_type); - try stdout.print("LLVMABIAlignmentOfType(i{d}) == {d}\n", .{ bits, alignment }); + try stdout_bw.print("LLVMABIAlignmentOfType(i{d}) == {d}\n", .{ bits, alignment }); } - - try bw.flush(); + try stdout_bw.flush(); return cleanExit(); } @@ -6363,11 +6352,7 @@ fn cmdDumpZir( const zir = try Zcu.loadZirCache(arena, f); - var bw: std.io.BufferedWriter = .{ - .unbuffered_writer = fs.File.stdout().writer(), - .buffer = &stdout_buffer, - }; - + var stdout_bw = fs.File.stdout().writer().buffered(&stdio_buffer); { const instruction_bytes = zir.instructions.len * // Here we don't use @sizeOf(Zir.Inst.Data) because it would include @@ -6377,7 +6362,7 @@ fn cmdDumpZir( const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes + zir.string_bytes.len * @sizeOf(u8); // zig fmt: off - try bw.print( + try stdout_bw.print( \\# Total ZIR bytes: {Bi} \\# Instructions: {d} ({Bi}) \\# String Table Bytes: {Bi} @@ -6392,8 +6377,8 @@ fn cmdDumpZir( // zig fmt: on } - try @import("print_zir.zig").renderAsText(arena, null, zir, &bw); - try bw.flush(); + try @import("print_zir.zig").renderAsText(arena, null, zir, &stdout_bw); + try stdout_bw.flush(); } /// This is only enabled for debug builds. @@ -6451,21 +6436,18 @@ fn cmdChangelist( var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty; try Zcu.mapOldZirToNew(arena, old_zir, new_zir, &inst_map); - var bw: std.io.BufferedWriter = .{ - .unbuffered_writer = fs.File.stdout().writer(), - .buffer = &stdout_buffer, - }; + var stdout_bw = fs.File.stdout().writer().buffered(&stdio_buffer); { - try bw.print("Instruction mappings:\n", .{}); + try stdout_bw.print("Instruction mappings:\n", .{}); var it = inst_map.iterator(); while (it.next()) |entry| { - try bw.print(" %{d} => %{d}\n", .{ + try stdout_bw.print(" %{d} => %{d}\n", .{ @intFromEnum(entry.key_ptr.*), @intFromEnum(entry.value_ptr.*), }); } } - try bw.flush(); + try stdout_bw.flush(); } fn eatIntPrefix(arg: []const u8, base: u8) []const u8 { @@ -6800,8 +6782,7 @@ fn cmdFetch( const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - const stdout = fs.File.stdout().writer(); - try stdout.writeAll(usage_fetch); + try fs.File.stdout().writeAll(usage_fetch); return cleanExit(); } else if (mem.eql(u8, arg, "--global-cache-dir")) { if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg}); @@ -6914,7 +6895,9 @@ fn cmdFetch( const name = switch (save) { .no => { - try fs.File.stdout().writer().print("{s}\n", .{package_hash_slice}); + var stdout_bw = fs.File.stdout().writer().buffered(&stdio_buffer); + try stdout_bw.print("{s}\n", .{package_hash_slice}); + try stdout_bw.flush(); return cleanExit(); }, .yes, .exact => |name| name: { @@ -6950,7 +6933,7 @@ fn cmdFetch( var saved_path_or_url = path_or_url; if (fetch.latest_commit) |latest_commit| resolved: { - const latest_commit_hex = try std.fmt.allocPrint(arena, "{}", .{latest_commit}); + const latest_commit_hex = try std.fmt.allocPrint(arena, "{f}", .{latest_commit}); var uri = try std.Uri.parse(path_or_url); @@ -6963,7 +6946,7 @@ fn cmdFetch( std.log.info("resolved ref '{s}' to commit {s}", .{ target_ref, latest_commit_hex }); // include the original refspec in a query parameter, could be used to check for updates - uri.query = .{ .percent_encoded = try std.fmt.allocPrint(arena, "ref={%}", .{fragment}) }; + uri.query = .{ .percent_encoded = try std.fmt.allocPrint(arena, "ref={f%}", .{fragment}) }; } else { std.log.info("resolved to commit {s}", .{latest_commit_hex}); } @@ -6972,22 +6955,22 @@ fn cmdFetch( uri.fragment = .{ .raw = latest_commit_hex }; switch (save) { - .yes => saved_path_or_url = try std.fmt.allocPrint(arena, "{}", .{uri}), + .yes => saved_path_or_url = try std.fmt.allocPrint(arena, "{f}", .{uri}), .no, .exact => {}, // keep the original URL } } const new_node_init = try std.fmt.allocPrint(arena, \\.{{ - \\ .url = "{}", - \\ .hash = "{}", + \\ .url = "{f}", + \\ .hash = "{f}", \\ }} , .{ std.zig.fmtEscapes(saved_path_or_url), std.zig.fmtEscapes(package_hash_slice), }); - const new_node_text = try std.fmt.allocPrint(arena, ".{p_} = {s},\n", .{ + const new_node_text = try std.fmt.allocPrint(arena, ".{fp_} = {s},\n", .{ std.zig.fmtId(name), new_node_init, }); @@ -7014,12 +6997,12 @@ fn cmdFetch( const location_replace = try std.fmt.allocPrint( arena, - "\"{}\"", + "\"{f}\"", .{std.zig.fmtEscapes(saved_path_or_url)}, ); const hash_replace = try std.fmt.allocPrint( arena, - "\"{}\"", + "\"{f}\"", .{std.zig.fmtEscapes(package_hash_slice)}, ); @@ -7047,15 +7030,11 @@ fn cmdFetch( fatal("unable to create {s} file: {s}", .{ Package.Manifest.basename, err }); }; defer file.close(); - var buffer: [4096]u8 = undefined; - var bw: std.io.BufferedWriter = .{ - .unbuffered_writer = file.writer(), - .buffer = &buffer, - }; - ast.render(gpa, &bw, fixups) catch |err| fatal("failed to render AST to {s}: {s}", .{ + var stdout_bw = fs.File.stdout().writer().buffered(&stdio_buffer); + ast.render(gpa, &stdout_bw, fixups) catch |err| fatal("failed to render AST to {s}: {s}", .{ Package.Manifest.basename, err, }); - bw.flush() catch |err| fatal("failed to flush {s}: {s}", .{ Package.Manifest.basename, err }); + stdout_bw.flush() catch |err| fatal("failed to flush {s}: {s}", .{ Package.Manifest.basename, err }); return cleanExit(); } @@ -7208,9 +7187,9 @@ fn loadManifest( ) !struct { Package.Manifest, Ast } { const manifest_bytes = while (true) { break options.dir.readFileAllocOptions( - arena, Package.Manifest.basename, - Package.Manifest.max_bytes, + arena, + .limited(Package.Manifest.max_bytes), null, .@"1", 0, @@ -7287,7 +7266,7 @@ const Templates = struct { } const max_bytes = 10 * 1024 * 1024; - const contents = templates.dir.readFileAlloc(arena, template_path, max_bytes) catch |err| { + const contents = templates.dir.readFileAlloc(template_path, arena, .limited(max_bytes)) catch |err| { fatal("unable to read template file '{s}': {s}", .{ template_path, @errorName(err) }); }; templates.buffer.clearRetainingCapacity(); diff --git a/src/print_targets.zig b/src/print_targets.zig index 8d744f56d0..4af544cf89 100644 --- a/src/print_targets.zig +++ b/src/print_targets.zig @@ -27,9 +27,9 @@ fn print(arena: Allocator, output: *std.io.BufferedWriter, host: *const Target) defer zig_lib_directory.handle.close(); const abilists_contents = zig_lib_directory.handle.readFileAlloc( - arena, glibc.abilists_path, - glibc.abilists_max_size, + arena, + .limited(glibc.abilists_max_size), ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => fatal("unable to read " ++ glibc.abilists_path ++ ": {s}", .{@errorName(err)}), @@ -37,7 +37,7 @@ fn print(arena: Allocator, output: *std.io.BufferedWriter, host: *const Target) const glibc_abi = try glibc.loadMetaData(arena, abilists_contents); - var sz = std.zon.stringify.serializer(output, .{}); + var sz: std.zon.stringify.Serializer = .{ .writer = output }; { var root_obj = try sz.beginStruct(.{}); @@ -60,7 +60,7 @@ fn print(arena: Allocator, output: *std.io.BufferedWriter, host: *const Target) { var glibc_obj = try root_obj.beginTupleField("glibc", .{}); for (glibc_abi.all_versions) |ver| { - const tmp = try std.fmt.allocPrint(arena, "{}", .{ver}); + const tmp = try std.fmt.allocPrint(arena, "{f}", .{ver}); try glibc_obj.field(tmp, .{}); } try glibc_obj.end(); diff --git a/src/print_value.zig b/src/print_value.zig index 63ccf9f38a..6abcbc39ae 100644 --- a/src/print_value.zig +++ b/src/print_value.zig @@ -20,16 +20,10 @@ pub const FormatContext = struct { depth: u8, }; -pub fn formatSema( - ctx: FormatContext, - comptime fmt: []const u8, - options: std.fmt.Options, - writer: *std.io.BufferedWriter, -) anyerror!void { - _ = options; +pub fn formatSema(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { const sema = ctx.opt_sema.?; comptime std.debug.assert(fmt.len == 0); - return print(ctx.val, writer, ctx.depth, ctx.pt, sema) catch |err| switch (err) { + return print(ctx.val, bw, ctx.depth, ctx.pt, sema) catch |err| switch (err) { error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function error.ComptimeBreak, error.ComptimeReturn => unreachable, error.AnalysisFail => unreachable, // TODO: re-evaluate when we use `sema` more fully @@ -37,16 +31,10 @@ pub fn formatSema( }; } -pub fn format( - ctx: FormatContext, - comptime fmt: []const u8, - options: std.fmt.Options, - writer: *std.io.BufferedWriter, -) anyerror!void { - _ = options; +pub fn format(ctx: FormatContext, bw: *std.io.BufferedWriter, comptime fmt: []const u8) anyerror!void { std.debug.assert(ctx.opt_sema == null); comptime std.debug.assert(fmt.len == 0); - return print(ctx.val, writer, ctx.depth, ctx.pt, null) catch |err| switch (err) { + return print(ctx.val, bw, ctx.depth, ctx.pt, null) catch |err| switch (err) { error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function error.ComptimeBreak, error.ComptimeReturn, error.AnalysisFail => unreachable, else => |e| return e, @@ -55,7 +43,7 @@ pub fn format( pub fn print( val: Value, - writer: *std.io.BufferedWriter, + bw: *std.io.BufferedWriter, level: u8, pt: Zcu.PerThread, opt_sema: ?*Sema, @@ -79,61 +67,62 @@ pub fn print( .func_type, .error_set_type, .inferred_error_set_type, - => try Type.print(val.toType(), writer, pt), - .undef => try writer.writeAll("undefined"), + => try Type.print(val.toType(), bw, pt), + .undef => try bw.writeAll("undefined"), .simple_value => |simple_value| switch (simple_value) { - .void => try writer.writeAll("{}"), - .empty_tuple => try writer.writeAll(".{}"), - else => try writer.writeAll(@tagName(simple_value)), + .void => try bw.writeAll("{}"), + .empty_tuple => try bw.writeAll(".{}"), + else => try bw.writeAll(@tagName(simple_value)), }, - .variable => try writer.writeAll("(variable)"), - .@"extern" => |e| try writer.print("(extern '{}')", .{e.name.fmt(ip)}), - .func => |func| try writer.print("(function '{}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}), + .variable => try bw.writeAll("(variable)"), + .@"extern" => |e| try bw.print("(extern '{f}')", .{e.name.fmt(ip)}), + .func => |func| try bw.print("(function '{f}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}), .int => |int| switch (int.storage) { - inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}), + inline .u64, .i64 => |x| try bw.print("{d}", .{x}), + .big_int => |x| try bw.print("{f}", .{x}), .lazy_align => |ty| if (opt_sema != null) { const a = try Type.fromInterned(ty).abiAlignmentSema(pt); - try writer.print("{}", .{a.toByteUnits() orelse 0}); - } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(pt)}), + try bw.print("{}", .{a.toByteUnits() orelse 0}); + } else try bw.print("@alignOf({f})", .{Type.fromInterned(ty).fmt(pt)}), .lazy_size => |ty| if (opt_sema != null) { const s = try Type.fromInterned(ty).abiSizeSema(pt); - try writer.print("{}", .{s}); - } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(pt)}), + try bw.print("{}", .{s}); + } else try bw.print("@sizeOf({f})", .{Type.fromInterned(ty).fmt(pt)}), }, - .err => |err| try writer.print("error.{}", .{ + .err => |err| try bw.print("error.{f}", .{ err.name.fmt(ip), }), .error_union => |error_union| switch (error_union.val) { - .err_name => |err_name| try writer.print("error.{}", .{ + .err_name => |err_name| try bw.print("error.{f}", .{ err_name.fmt(ip), }), - .payload => |payload| try print(Value.fromInterned(payload), writer, level, pt, opt_sema), + .payload => |payload| try print(Value.fromInterned(payload), bw, level, pt, opt_sema), }, - .enum_literal => |enum_literal| try writer.print(".{}", .{ + .enum_literal => |enum_literal| try bw.print(".{f}", .{ enum_literal.fmt(ip), }), .enum_tag => |enum_tag| { const enum_type = ip.loadEnumType(val.typeOf(zcu).toIntern()); if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| { - return writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)}); + return bw.print(".{fi}", .{enum_type.names.get(ip)[tag_index].fmt(ip)}); } if (level == 0) { - return writer.writeAll("@enumFromInt(...)"); + return bw.writeAll("@enumFromInt(...)"); } - try writer.writeAll("@enumFromInt("); - try print(Value.fromInterned(enum_tag.int), writer, level - 1, pt, opt_sema); - try writer.writeAll(")"); + try bw.writeAll("@enumFromInt("); + try print(Value.fromInterned(enum_tag.int), bw, level - 1, pt, opt_sema); + try bw.writeAll(")"); }, - .empty_enum_value => try writer.writeAll("(empty enum value)"), + .empty_enum_value => try bw.writeAll("(empty enum value)"), .float => |float| switch (float.storage) { - inline else => |x| try writer.print("{d}", .{@as(f64, @floatCast(x))}), + inline else => |x| try bw.print("{d}", .{@as(f64, @floatCast(x))}), }, .slice => |slice| { if (ip.isUndef(slice.ptr)) { if (slice.len == .zero_usize) { - return writer.writeAll("&.{}"); + return bw.writeAll("&.{}"); } - try print(.fromInterned(slice.ptr), writer, level - 1, pt, opt_sema); + try print(.fromInterned(slice.ptr), bw, level - 1, pt, opt_sema); } else { const print_contents = switch (ip.getBackingAddrTag(slice.ptr).?) { .field, .arr_elem, .eu_payload, .opt_payload => unreachable, @@ -144,15 +133,15 @@ pub fn print( // TODO: eventually we want to load the slice as an array with `sema`, but that's // currently not possible without e.g. triggering compile errors. } - try printPtr(Value.fromInterned(slice.ptr), null, writer, level, pt, opt_sema); + try printPtr(Value.fromInterned(slice.ptr), null, bw, level, pt, opt_sema); } - try writer.writeAll("[0.."); + try bw.writeAll("[0.."); if (level == 0) { - try writer.writeAll("(...)"); + try bw.writeAll("(...)"); } else { - try print(Value.fromInterned(slice.len), writer, level - 1, pt, opt_sema); + try print(Value.fromInterned(slice.len), bw, level - 1, pt, opt_sema); } - try writer.writeAll("]"); + try bw.writeAll("]"); }, .ptr => { const print_contents = switch (ip.getBackingAddrTag(val.toIntern()).?) { @@ -164,29 +153,29 @@ pub fn print( // TODO: eventually we want to load the pointer with `sema`, but that's // currently not possible without e.g. triggering compile errors. } - try printPtr(val, .rvalue, writer, level, pt, opt_sema); + try printPtr(val, .rvalue, bw, level, pt, opt_sema); }, .opt => |opt| switch (opt.val) { - .none => try writer.writeAll("null"), - else => |payload| try print(Value.fromInterned(payload), writer, level, pt, opt_sema), + .none => try bw.writeAll("null"), + else => |payload| try print(Value.fromInterned(payload), bw, level, pt, opt_sema), }, - .aggregate => |aggregate| try printAggregate(val, aggregate, false, writer, level, pt, opt_sema), + .aggregate => |aggregate| try printAggregate(val, aggregate, false, bw, level, pt, opt_sema), .un => |un| { if (level == 0) { - try writer.writeAll(".{ ... }"); + try bw.writeAll(".{ ... }"); return; } if (un.tag == .none) { const backing_ty = try val.typeOf(zcu).unionBackingType(pt); - try writer.print("@bitCast(@as({}, ", .{backing_ty.fmt(pt)}); - try print(Value.fromInterned(un.val), writer, level - 1, pt, opt_sema); - try writer.writeAll("))"); + try bw.print("@bitCast(@as({f}, ", .{backing_ty.fmt(pt)}); + try print(Value.fromInterned(un.val), bw, level - 1, pt, opt_sema); + try bw.writeAll("))"); } else { - try writer.writeAll(".{ "); - try print(Value.fromInterned(un.tag), writer, level - 1, pt, opt_sema); - try writer.writeAll(" = "); - try print(Value.fromInterned(un.val), writer, level - 1, pt, opt_sema); - try writer.writeAll(" }"); + try bw.writeAll(".{ "); + try print(Value.fromInterned(un.tag), bw, level - 1, pt, opt_sema); + try bw.writeAll(" = "); + try print(Value.fromInterned(un.val), bw, level - 1, pt, opt_sema); + try bw.writeAll(" }"); } }, .memoized_call => unreachable, @@ -197,33 +186,33 @@ fn printAggregate( val: Value, aggregate: InternPool.Key.Aggregate, is_ref: bool, - writer: *std.io.BufferedWriter, + bw: *std.io.BufferedWriter, level: u8, pt: Zcu.PerThread, opt_sema: ?*Sema, ) anyerror!void { if (level == 0) { - if (is_ref) try writer.writeByte('&'); - return writer.writeAll(".{ ... }"); + if (is_ref) try bw.writeByte('&'); + return bw.writeAll(".{ ... }"); } const zcu = pt.zcu; const ip = &zcu.intern_pool; const ty = Type.fromInterned(aggregate.ty); switch (ty.zigTypeTag(zcu)) { .@"struct" => if (!ty.isTuple(zcu)) { - if (is_ref) try writer.writeByte('&'); + if (is_ref) try bw.writeByte('&'); if (ty.structFieldCount(zcu) == 0) { - return writer.writeAll(".{}"); + return bw.writeAll(".{}"); } - try writer.writeAll(".{ "); + try bw.writeAll(".{ "); const max_len = @min(ty.structFieldCount(zcu), max_aggregate_items); for (0..max_len) |i| { - if (i != 0) try writer.writeAll(", "); + if (i != 0) try bw.writeAll(", "); const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?; - try writer.print(".{i} = ", .{field_name.fmt(ip)}); - try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema); + try bw.print(".{fi} = ", .{field_name.fmt(ip)}); + try print(try val.fieldValue(pt, i), bw, level - 1, pt, opt_sema); } - try writer.writeAll(" }"); + try bw.writeAll(" }"); return; }, .array => { @@ -232,16 +221,16 @@ fn printAggregate( const len = ty.arrayLenIncludingSentinel(zcu); if (len == 0) break :string; const slice = bytes.toSlice(if (bytes.at(len - 1, ip) == 0) len - 1 else len, ip); - try writer.print("\"{}\"", .{std.zig.fmtEscapes(slice)}); - if (!is_ref) try writer.writeAll(".*"); + try bw.print("\"{f}\"", .{std.zig.fmtEscapes(slice)}); + if (!is_ref) try bw.writeAll(".*"); return; }, .elems, .repeated_elem => {}, } switch (ty.arrayLen(zcu)) { 0 => { - if (is_ref) try writer.writeByte('&'); - return writer.writeAll(".{}"); + if (is_ref) try bw.writeByte('&'); + return bw.writeAll(".{}"); }, 1 => one_byte_str: { // The repr isn't `bytes`, but we might still be able to print this as a string @@ -249,47 +238,47 @@ fn printAggregate( const elem_val = Value.fromInterned(aggregate.storage.values()[0]); if (elem_val.isUndef(zcu)) break :one_byte_str; const byte = elem_val.toUnsignedInt(zcu); - try writer.print("\"{}\"", .{std.zig.fmtEscapes(&.{@intCast(byte)})}); - if (!is_ref) try writer.writeAll(".*"); + try bw.print("\"{f}\"", .{std.zig.fmtEscapes(&.{@intCast(byte)})}); + if (!is_ref) try bw.writeAll(".*"); return; }, else => {}, } }, .vector => if (ty.arrayLen(zcu) == 0) { - if (is_ref) try writer.writeByte('&'); - return writer.writeAll(".{}"); + if (is_ref) try bw.writeByte('&'); + return bw.writeAll(".{}"); }, else => unreachable, } const len = ty.arrayLen(zcu); - if (is_ref) try writer.writeByte('&'); - try writer.writeAll(".{ "); + if (is_ref) try bw.writeByte('&'); + try bw.writeAll(".{ "); const max_len = @min(len, max_aggregate_items); for (0..max_len) |i| { - if (i != 0) try writer.writeAll(", "); - try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema); + if (i != 0) try bw.writeAll(", "); + try print(try val.fieldValue(pt, i), bw, level - 1, pt, opt_sema); } if (len > max_aggregate_items) { - try writer.writeAll(", ..."); + try bw.writeAll(", ..."); } - return writer.writeAll(" }"); + return bw.writeAll(" }"); } fn printPtr( ptr_val: Value, /// Whether to print `derivation` as an lvalue or rvalue. If `null`, the more concise option is chosen. want_kind: ?PrintPtrKind, - writer: *std.io.BufferedWriter, + bw: *std.io.BufferedWriter, level: u8, pt: Zcu.PerThread, opt_sema: ?*Sema, ) anyerror!void { const ptr = switch (pt.zcu.intern_pool.indexToKey(ptr_val.toIntern())) { - .undef => return writer.writeAll("undefined"), + .undef => return bw.writeAll("undefined"), .ptr => |ptr| ptr, else => unreachable, }; @@ -301,7 +290,7 @@ fn printPtr( Value.fromInterned(ptr.base_addr.uav.val), agg, true, - writer, + bw, level, pt, opt_sema, @@ -317,7 +306,7 @@ fn printPtr( else try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, false, null); - _ = try printPtrDerivation(derivation, writer, pt, want_kind, .{ .print_val = .{ + _ = try printPtrDerivation(derivation, bw, pt, want_kind, .{ .print_val = .{ .level = level, .opt_sema = opt_sema, } }, 20); @@ -329,7 +318,7 @@ const PrintPtrKind = enum { lvalue, rvalue }; /// Returns the root derivation, which may be ignored. pub fn printPtrDerivation( derivation: Value.PointerDeriveStep, - writer: *std.io.BufferedWriter, + bw: *std.io.BufferedWriter, pt: Zcu.PerThread, /// Whether to print `derivation` as an lvalue or rvalue. If `null`, the more concise option is chosen. /// If this is `.rvalue`, the result may look like `&foo`, so it's not necessarily valid to treat it as @@ -361,7 +350,7 @@ pub fn printPtrDerivation( => |step| continue :root step.parent.*, else => |step| break :root step, }; - try writer.writeAll("..."); + try bw.writeAll("..."); return root_step; } @@ -384,39 +373,39 @@ pub fn printPtrDerivation( const need_kind = want_kind orelse result_kind; if (need_kind == .rvalue and result_kind == .lvalue) { - try writer.writeByte('&'); + try bw.writeByte('&'); } // null if `derivation` is the root. const root_or_null: ?Value.PointerDeriveStep = switch (derivation) { .eu_payload_ptr => |info| root: { - try writer.writeByte('('); - const root = try printPtrDerivation(info.parent.*, writer, pt, .lvalue, root_strat, ptr_depth - 1); - try writer.writeAll(" catch unreachable)"); + try bw.writeByte('('); + const root = try printPtrDerivation(info.parent.*, bw, pt, .lvalue, root_strat, ptr_depth - 1); + try bw.writeAll(" catch unreachable)"); break :root root; }, .opt_payload_ptr => |info| root: { - const root = try printPtrDerivation(info.parent.*, writer, pt, .lvalue, root_strat, ptr_depth - 1); - try writer.writeAll(".?"); + const root = try printPtrDerivation(info.parent.*, bw, pt, .lvalue, root_strat, ptr_depth - 1); + try bw.writeAll(".?"); break :root root; }, .field_ptr => |field| root: { - const root = try printPtrDerivation(field.parent.*, writer, pt, null, root_strat, ptr_depth - 1); + const root = try printPtrDerivation(field.parent.*, bw, pt, null, root_strat, ptr_depth - 1); const agg_ty = (try field.parent.ptrType(pt)).childType(zcu); switch (agg_ty.zigTypeTag(zcu)) { .@"struct" => if (agg_ty.structFieldName(field.field_idx, zcu).unwrap()) |field_name| { - try writer.print(".{i}", .{field_name.fmt(ip)}); + try bw.print(".{fi}", .{field_name.fmt(ip)}); } else { - try writer.print("[{d}]", .{field.field_idx}); + try bw.print("[{d}]", .{field.field_idx}); }, .@"union" => { const tag_ty = agg_ty.unionTagTypeHypothetical(zcu); const field_name = tag_ty.enumFieldName(field.field_idx, zcu); - try writer.print(".{i}", .{field_name.fmt(ip)}); + try bw.print(".{fi}", .{field_name.fmt(ip)}); }, .pointer => switch (field.field_idx) { - Value.slice_ptr_index => try writer.writeAll(".ptr"), - Value.slice_len_index => try writer.writeAll(".len"), + Value.slice_ptr_index => try bw.writeAll(".ptr"), + Value.slice_len_index => try bw.writeAll(".len"), else => unreachable, }, else => unreachable, @@ -424,20 +413,20 @@ pub fn printPtrDerivation( break :root root; }, .elem_ptr => |elem| root: { - const root = try printPtrDerivation(elem.parent.*, writer, pt, null, root_strat, ptr_depth - 1); - try writer.print("[{d}]", .{elem.elem_idx}); + const root = try printPtrDerivation(elem.parent.*, bw, pt, null, root_strat, ptr_depth - 1); + try bw.print("[{d}]", .{elem.elem_idx}); break :root root; }, .offset_and_cast => |oac| if (oac.byte_offset == 0) root: { - try writer.print("@as({}, @ptrCast(", .{oac.new_ptr_ty.fmt(pt)}); - const root = try printPtrDerivation(oac.parent.*, writer, pt, .rvalue, root_strat, ptr_depth - 1); - try writer.writeAll("))"); + try bw.print("@as({f}, @ptrCast(", .{oac.new_ptr_ty.fmt(pt)}); + const root = try printPtrDerivation(oac.parent.*, bw, pt, .rvalue, root_strat, ptr_depth - 1); + try bw.writeAll("))"); break :root root; } else root: { - try writer.print("@as({}, @ptrFromInt(@intFromPtr(", .{oac.new_ptr_ty.fmt(pt)}); - const root = try printPtrDerivation(oac.parent.*, writer, pt, .rvalue, root_strat, ptr_depth - 1); - try writer.print(") + {d}))", .{oac.byte_offset}); + try bw.print("@as({f}, @ptrFromInt(@intFromPtr(", .{oac.new_ptr_ty.fmt(pt)}); + const root = try printPtrDerivation(oac.parent.*, bw, pt, .rvalue, root_strat, ptr_depth - 1); + try bw.print(") + {d}))", .{oac.byte_offset}); break :root root; }, @@ -445,33 +434,33 @@ pub fn printPtrDerivation( }; if (root_or_null == null) switch (root_strat) { - .str => |x| try writer.writeAll(x), + .str => |x| try bw.writeAll(x), .print_val => |x| switch (derivation) { - .int => |int| try writer.print("@as({}, @ptrFromInt(0x{x}))", .{ int.ptr_ty.fmt(pt), int.addr }), - .nav_ptr => |nav| try writer.print("{}", .{ip.getNav(nav).fqn.fmt(ip)}), + .int => |int| try bw.print("@as({f}, @ptrFromInt(0x{x}))", .{ int.ptr_ty.fmt(pt), int.addr }), + .nav_ptr => |nav| try bw.print("{f}", .{ip.getNav(nav).fqn.fmt(ip)}), .uav_ptr => |uav| { const ty = Value.fromInterned(uav.val).typeOf(zcu); - try writer.print("@as({}, ", .{ty.fmt(pt)}); - try print(Value.fromInterned(uav.val), writer, x.level - 1, pt, x.opt_sema); - try writer.writeByte(')'); + try bw.print("@as({f}, ", .{ty.fmt(pt)}); + try print(Value.fromInterned(uav.val), bw, x.level - 1, pt, x.opt_sema); + try bw.writeByte(')'); }, .comptime_alloc_ptr => |info| { - try writer.print("@as({}, ", .{info.val.typeOf(zcu).fmt(pt)}); - try print(info.val, writer, x.level - 1, pt, x.opt_sema); - try writer.writeByte(')'); + try bw.print("@as({f}, ", .{info.val.typeOf(zcu).fmt(pt)}); + try print(info.val, bw, x.level - 1, pt, x.opt_sema); + try bw.writeByte(')'); }, .comptime_field_ptr => |val| { const ty = val.typeOf(zcu); - try writer.print("@as({}, ", .{ty.fmt(pt)}); - try print(val, writer, x.level - 1, pt, x.opt_sema); - try writer.writeByte(')'); + try bw.print("@as({f}, ", .{ty.fmt(pt)}); + try print(val, bw, x.level - 1, pt, x.opt_sema); + try bw.writeByte(')'); }, else => unreachable, }, }; if (need_kind == .lvalue and result_kind == .rvalue) { - try writer.writeAll(".*"); + try bw.writeAll(".*"); } return root_or_null orelse derivation; diff --git a/src/print_zir.zig b/src/print_zir.zig index 05f58d3a50..d26057845b 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -41,7 +41,7 @@ pub fn renderAsText(gpa: Allocator, tree: ?Ast, zir: Zir, bw: *std.io.BufferedWr extra_index = item.end; const import_path = zir.nullTerminatedString(item.data.name); - try bw.print(" @import(\"{}\") ", .{ + try bw.print(" @import(\"{f}\") ", .{ std.zig.fmtEscapes(import_path), }); try writer.writeSrcTokAbs(bw, item.data.token); @@ -783,7 +783,7 @@ const Writer = struct { ) anyerror!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str; const str = inst_data.get(self.code); - try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)}); + try stream.print("\"{f}\")", .{std.zig.fmtEscapes(str)}); } fn writeSliceStart(self: *Writer, stream: *std.io.BufferedWriter, inst: Zir.Inst.Index) !void { @@ -939,7 +939,7 @@ const Writer = struct { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok; const extra = self.code.extraData(Zir.Inst.Param, inst_data.payload_index); const body = self.code.bodySlice(extra.end, extra.data.type.body_len); - try stream.print("\"{}\", ", .{ + try stream.print("\"{f}\", ", .{ std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)), }); @@ -1210,7 +1210,7 @@ const Writer = struct { try stream.writeAll(", "); } else { const asm_source = self.code.nullTerminatedString(extra.data.asm_source); - try stream.print("\"{}\", ", .{std.zig.fmtEscapes(asm_source)}); + try stream.print("\"{f}\", ", .{std.zig.fmtEscapes(asm_source)}); } try stream.writeAll(", "); @@ -1227,7 +1227,7 @@ const Writer = struct { const name = self.code.nullTerminatedString(output.data.name); const constraint = self.code.nullTerminatedString(output.data.constraint); - try stream.print("output({p}, \"{}\", ", .{ + try stream.print("output({fp}, \"{f}\", ", .{ std.zig.fmtId(name), std.zig.fmtEscapes(constraint), }); try self.writeFlag(stream, "->", is_type); @@ -1246,7 +1246,7 @@ const Writer = struct { const name = self.code.nullTerminatedString(input.data.name); const constraint = self.code.nullTerminatedString(input.data.constraint); - try stream.print("input({p}, \"{}\", ", .{ + try stream.print("input({fp}, \"{f}\", ", .{ std.zig.fmtId(name), std.zig.fmtEscapes(constraint), }); try self.writeInstRef(stream, input.data.operand); @@ -1262,7 +1262,7 @@ const Writer = struct { const str_index = self.code.extra[extra_i]; extra_i += 1; const clobber = self.code.nullTerminatedString(@enumFromInt(str_index)); - try stream.print("{p}", .{std.zig.fmtId(clobber)}); + try stream.print("{fp}", .{std.zig.fmtId(clobber)}); if (i + 1 < clobbers_len) { try stream.writeAll(", "); } @@ -1306,7 +1306,7 @@ const Writer = struct { .field => { const field_name = self.code.nullTerminatedString(extra.data.field_name_start); try self.writeInstRef(stream, extra.data.obj_ptr); - try stream.print(", \"{}\"", .{std.zig.fmtEscapes(field_name)}); + try stream.print(", \"{f}\"", .{std.zig.fmtEscapes(field_name)}); }, } try stream.writeAll(", ["); @@ -1526,7 +1526,7 @@ const Writer = struct { try self.writeFlag(stream, "comptime ", field.is_comptime); if (field.name != .empty) { const field_name = self.code.nullTerminatedString(field.name); - try stream.print("{p}: ", .{std.zig.fmtId(field_name)}); + try stream.print("{fp}: ", .{std.zig.fmtId(field_name)}); } else { try stream.print("@\"{d}\": ", .{i}); } @@ -1689,7 +1689,7 @@ const Writer = struct { extra_index += 1; try stream.splatByteAll(' ', self.indent); - try stream.print("{p}", .{std.zig.fmtId(field_name)}); + try stream.print("{fp}", .{std.zig.fmtId(field_name)}); if (has_type) { const field_type = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index])); @@ -1823,7 +1823,7 @@ const Writer = struct { extra_index += 1; try stream.splatByteAll(' ', self.indent); - try stream.print("{p}", .{std.zig.fmtId(field_name)}); + try stream.print("{fp}", .{std.zig.fmtId(field_name)}); if (has_tag_value) { const tag_value_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index])); @@ -1928,7 +1928,7 @@ const Writer = struct { const name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]); const name = self.code.nullTerminatedString(name_index); try stream.splatByteAll(' ', self.indent); - try stream.print("{p},\n", .{std.zig.fmtId(name)}); + try stream.print("{fp},\n", .{std.zig.fmtId(name)}); } self.indent -= 2; @@ -2210,7 +2210,7 @@ const Writer = struct { const extra = self.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; const name = self.code.nullTerminatedString(extra.field_name_start); try self.writeInstRef(stream, extra.lhs); - try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)}); + try stream.print(", \"{f}\") ", .{std.zig.fmtEscapes(name)}); try self.writeSrcNode(stream, inst_data.src_node); } @@ -2251,7 +2251,7 @@ const Writer = struct { ) anyerror!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_tok; const str = inst_data.get(self.code); - try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)}); + try stream.print("\"{f}\") ", .{std.zig.fmtEscapes(str)}); try self.writeSrcTok(stream, inst_data.src_tok); } @@ -2259,7 +2259,7 @@ const Writer = struct { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_op; const str = inst_data.getStr(self.code); try self.writeInstRef(stream, inst_data.operand); - try stream.print(", \"{}\")", .{std.zig.fmtEscapes(str)}); + try stream.print(", \"{f}\")", .{std.zig.fmtEscapes(str)}); } fn writeFunc( @@ -2700,10 +2700,10 @@ const Writer = struct { try stream.writeAll("load "); try self.writeInstIndex(stream, ptr_inst); }, - .decl_val => |str| try stream.print("decl_val \"{}\"", .{ + .decl_val => |str| try stream.print("decl_val \"{f}\"", .{ std.zig.fmtEscapes(self.code.nullTerminatedString(str)), }), - .decl_ref => |str| try stream.print("decl_ref \"{}\"", .{ + .decl_ref => |str| try stream.print("decl_ref \"{f}\"", .{ std.zig.fmtEscapes(self.code.nullTerminatedString(str)), }), } @@ -2837,7 +2837,7 @@ const Writer = struct { const extra = self.code.extraData(Zir.Inst.Import, inst_data.payload_index).data; try self.writeInstRef(stream, extra.res_ty); const import_path = self.code.nullTerminatedString(extra.path); - try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(import_path)}); + try stream.print(", \"{f}\") ", .{std.zig.fmtEscapes(import_path)}); try self.writeSrcTok(stream, inst_data.src_tok); } }; diff --git a/src/print_zoir.zig b/src/print_zoir.zig index 649abfe235..a9118fc632 100644 --- a/src/print_zoir.zig +++ b/src/print_zoir.zig @@ -70,8 +70,8 @@ const PrintZon = struct { }, .float_literal => |x| try pz.w.print("float({d})", .{x}), .char_literal => |x| try pz.w.print("char({d})", .{x}), - .enum_literal => |x| try pz.w.print("enum_literal({p})", .{std.zig.fmtId(x.get(zoir))}), - .string_literal => |x| try pz.w.print("str(\"{}\")", .{std.zig.fmtEscapes(x)}), + .enum_literal => |x| try pz.w.print("enum_literal({fp})", .{std.zig.fmtId(x.get(zoir))}), + .string_literal => |x| try pz.w.print("str(\"{f}\")", .{std.zig.fmtEscapes(x)}), .empty_literal => try pz.w.writeAll("empty_literal(.{})"), .array_literal => |vals| { try pz.w.writeAll("array_literal({"); @@ -90,7 +90,7 @@ const PrintZon = struct { pz.indent += 1; for (s.names, 0..s.vals.len) |name, idx| { try pz.newline(); - try pz.w.print("[{p}] ", .{std.zig.fmtId(name.get(zoir))}); + try pz.w.print("[{fp}] ", .{std.zig.fmtId(name.get(zoir))}); try pz.renderNode(s.vals.at(@intCast(idx))); try pz.w.writeByte(','); } diff --git a/src/register_manager.zig b/src/register_manager.zig index 90fe09980a..bc6761ad3b 100644 --- a/src/register_manager.zig +++ b/src/register_manager.zig @@ -238,7 +238,7 @@ pub fn RegisterManager( if (i < count) return null; for (regs, insts) |reg, inst| { - log.debug("tryAllocReg {} for inst {?}", .{ reg, inst }); + log.debug("tryAllocReg {} for inst {?f}", .{ reg, inst }); self.markRegAllocated(reg); if (inst) |tracked_inst| { @@ -317,7 +317,7 @@ pub fn RegisterManager( tracked_index: TrackedIndex, inst: ?Air.Inst.Index, ) AllocationError!void { - log.debug("getReg {} for inst {?}", .{ regAtTrackedIndex(tracked_index), inst }); + log.debug("getReg {} for inst {?f}", .{ regAtTrackedIndex(tracked_index), inst }); if (!self.isRegIndexFree(tracked_index)) { // Move the instruction that was previously there to a // stack allocation. @@ -349,7 +349,7 @@ pub fn RegisterManager( tracked_index: TrackedIndex, inst: ?Air.Inst.Index, ) void { - log.debug("getRegAssumeFree {} for inst {?}", .{ regAtTrackedIndex(tracked_index), inst }); + log.debug("getRegAssumeFree {} for inst {?f}", .{ regAtTrackedIndex(tracked_index), inst }); self.markRegIndexAllocated(tracked_index); assert(self.isRegIndexFree(tracked_index)); diff --git a/src/translate_c.zig b/src/translate_c.zig index 4fe066b1e4..865b6939c2 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -357,7 +357,7 @@ fn transFileScopeAsm(c: *Context, scope: *Scope, file_scope_asm: *const clang.Fi var len: usize = undefined; const bytes_ptr = asm_string.getString_bytes_begin_size(&len); - const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])}); + const str = try std.fmt.allocPrint(c.arena, "\"{f}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])}); const str_node = try Tag.string_literal.create(c.arena, str); const asm_node = try Tag.asm_simple.create(c.arena, str_node); @@ -2276,7 +2276,7 @@ fn transNarrowStringLiteral( var len: usize = undefined; const bytes_ptr = stmt.getString_bytes_begin_size(&len); - const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])}); + const str = try std.fmt.allocPrint(c.arena, "\"{f}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])}); const node = try Tag.string_literal.create(c.arena, str); return maybeSuppressResult(c, result_used, node); } @@ -3338,7 +3338,7 @@ fn transPredefinedExpr(c: *Context, scope: *Scope, expr: *const clang.Predefined fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!Node { return Tag.char_literal.create(c.arena, if (narrow) - try std.fmt.allocPrint(c.arena, "'{'}'", .{std.zig.fmtEscapes(&.{@as(u8, @intCast(val))})}) + try std.fmt.allocPrint(c.arena, "'{f'}'", .{std.zig.fmtEscapes(&.{@as(u8, @intCast(val))})}) else try std.fmt.allocPrint(c.arena, "'\\u{{{x}}}'", .{val})); } @@ -5832,7 +5832,7 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { num += c - 'A' + 10; }, else => { - i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); + i += std.fmt.printInt(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); num = 0; if (c == '\\') state = .escape @@ -5858,7 +5858,7 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { }; num += c - '0'; } else { - i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); + i += std.fmt.printInt(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); num = 0; count = 0; if (c == '\\') @@ -5872,7 +5872,7 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { } } if (state == .hex or state == .octal) - i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); + i += std.fmt.printInt(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); return bytes[0..i]; } @@ -5884,9 +5884,9 @@ fn escapeUnprintables(ctx: *Context, m: *MacroCtx) ![]const u8 { if (std.unicode.utf8ValidateSlice(zigified)) return zigified; const formatter = std.fmt.fmtSliceEscapeLower(zigified); - const encoded_size = @as(usize, @intCast(std.fmt.count("{s}", .{formatter}))); + const encoded_size = std.fmt.count("{f}", .{formatter}); const output = try ctx.arena.alloc(u8, encoded_size); - return std.fmt.bufPrint(output, "{s}", .{formatter}) catch |err| switch (err) { + return std.fmt.bufPrint(output, "{f}", .{formatter}) catch |err| switch (err) { error.NoSpaceLeft => unreachable, else => |e| return e, };