authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-29 03:48:45-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-08-29 03:48:45-07:00
log4b948e8556b80cbc874415aa7c4bf9ac0027ffed
treeca48e7208aa23a24db82e8521c37a6c2abcd5dc1
parent640c11171bf8d13776629941f3305cf11c62c1f3
parent43fbc37a490442ffcecf9817877f542251fee664
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #25036 from ziglang/GenericWriter

std.Io: delete GenericWriter, AnyWriter, and null_writer

106 files changed, 2450 insertions(+), 3606 deletions(-)

lib/compiler/aro/aro/Attribute.zig+1-1
...@@ -780,7 +780,7 @@ fn ignoredAttrErr(p: *Parser, tok: TokenIndex, attr: Attribute.Tag, context: []c...@@ -780,7 +780,7 @@ fn ignoredAttrErr(p: *Parser, tok: TokenIndex, attr: Attribute.Tag, context: []c
780 const strings_top = p.strings.items.len;780 const strings_top = p.strings.items.len;
781 defer p.strings.items.len = strings_top;781 defer p.strings.items.len = strings_top;
782782
783 try p.strings.writer().print("attribute '{s}' ignored on {s}", .{ @tagName(attr), context });783 try p.strings.print("attribute '{s}' ignored on {s}", .{ @tagName(attr), context });
784 const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);784 const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
785 try p.errStr(.ignored_attribute, tok, str);785 try p.errStr(.ignored_attribute, tok, str);
786}786}
lib/compiler/aro/aro/Builtins/Builtin.zig+2-3
...@@ -119,8 +119,7 @@ pub fn nameFromUniqueIndex(index: u16, buf: []u8) []u8 {...@@ -119,8 +119,7 @@ pub fn nameFromUniqueIndex(index: u16, buf: []u8) []u8 {
119119
120 var node_index: u16 = 0;120 var node_index: u16 = 0;
121 var count: u16 = index;121 var count: u16 = index;
122 var fbs = std.io.fixedBufferStream(buf);122 var w: std.Io.Writer = .fixed(buf);
123 const w = fbs.writer();
124123
125 while (true) {124 while (true) {
126 var sibling_index = dafsa[node_index].child_index;125 var sibling_index = dafsa[node_index].child_index;
...@@ -142,7 +141,7 @@ pub fn nameFromUniqueIndex(index: u16, buf: []u8) []u8 {...@@ -142,7 +141,7 @@ pub fn nameFromUniqueIndex(index: u16, buf: []u8) []u8 {
142 if (count == 0) break;141 if (count == 0) break;
143 }142 }
144143
145 return fbs.getWritten();144 return w.buffered();
146}145}
147146
148/// We're 1 bit shy of being able to fit this in a u32:147/// We're 1 bit shy of being able to fit this in a u32:
lib/compiler/aro/aro/Compilation.zig+36-28
...@@ -16,6 +16,7 @@ const Pragma = @import("Pragma.zig");...@@ -16,6 +16,7 @@ const Pragma = @import("Pragma.zig");
16const StrInt = @import("StringInterner.zig");16const StrInt = @import("StringInterner.zig");
17const record_layout = @import("record_layout.zig");17const record_layout = @import("record_layout.zig");
18const target_util = @import("target.zig");18const target_util = @import("target.zig");
19const Writer = std.Io.Writer;
1920
20pub const Error = error{21pub const Error = error{
21 /// A fatal error has ocurred and compilation has stopped.22 /// A fatal error has ocurred and compilation has stopped.
...@@ -199,7 +200,7 @@ fn getTimestamp(comp: *Compilation) !u47 {...@@ -199,7 +200,7 @@ fn getTimestamp(comp: *Compilation) !u47 {
199 return @intCast(std.math.clamp(timestamp, 0, max_timestamp));200 return @intCast(std.math.clamp(timestamp, 0, max_timestamp));
200}201}
201202
202fn generateDateAndTime(w: anytype, timestamp: u47) !void {203fn generateDateAndTime(w: *Writer, timestamp: u47) !void {
203 const epoch_seconds = EpochSeconds{ .secs = timestamp };204 const epoch_seconds = EpochSeconds{ .secs = timestamp };
204 const epoch_day = epoch_seconds.getEpochDay();205 const epoch_day = epoch_seconds.getEpochDay();
205 const day_seconds = epoch_seconds.getDaySeconds();206 const day_seconds = epoch_seconds.getDaySeconds();
...@@ -242,7 +243,7 @@ pub const SystemDefinesMode = enum {...@@ -242,7 +243,7 @@ pub const SystemDefinesMode = enum {
242 include_system_defines,243 include_system_defines,
243};244};
244245
245fn generateSystemDefines(comp: *Compilation, w: anytype) !void {246fn generateSystemDefines(comp: *Compilation, w: *Writer) !void {
246 const ptr_width = comp.target.ptrBitWidth();247 const ptr_width = comp.target.ptrBitWidth();
247248
248 if (comp.langopts.gnuc_version > 0) {249 if (comp.langopts.gnuc_version > 0) {
...@@ -533,11 +534,20 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {...@@ -533,11 +534,20 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
533pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefinesMode) !Source {534pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefinesMode) !Source {
534 try comp.generateBuiltinTypes();535 try comp.generateBuiltinTypes();
535536
536 var buf = std.array_list.Managed(u8).init(comp.gpa);537 var allocating: std.Io.Writer.Allocating = .init(comp.gpa);
537 defer buf.deinit();538 defer allocating.deinit();
539
540 generateBuiltinMacrosWriter(comp, system_defines_mode, &allocating.writer) catch |err| switch (err) {
541 error.WriteFailed => return error.OutOfMemory,
542 else => |e| return e,
543 };
544
545 return comp.addSourceFromBuffer("<builtin>", allocating.written());
546}
538547
548pub fn generateBuiltinMacrosWriter(comp: *Compilation, system_defines_mode: SystemDefinesMode, buf: *Writer) !void {
539 if (system_defines_mode == .include_system_defines) {549 if (system_defines_mode == .include_system_defines) {
540 try buf.appendSlice(550 try buf.writeAll(
541 \\#define __VERSION__ "Aro551 \\#define __VERSION__ "Aro
542 ++ " " ++ @import("../backend.zig").version_str ++ "\"\n" ++552 ++ " " ++ @import("../backend.zig").version_str ++ "\"\n" ++
543 \\#define __Aro__553 \\#define __Aro__
...@@ -545,11 +555,11 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi...@@ -545,11 +555,11 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
545 );555 );
546 }556 }
547557
548 try buf.appendSlice("#define __STDC__ 1\n");558 try buf.writeAll("#define __STDC__ 1\n");
549 try buf.writer().print("#define __STDC_HOSTED__ {d}\n", .{@intFromBool(comp.target.os.tag != .freestanding)});559 try buf.print("#define __STDC_HOSTED__ {d}\n", .{@intFromBool(comp.target.os.tag != .freestanding)});
550560
551 // standard macros561 // standard macros
552 try buf.appendSlice(562 try buf.writeAll(
553 \\#define __STDC_NO_COMPLEX__ 1563 \\#define __STDC_NO_COMPLEX__ 1
554 \\#define __STDC_NO_THREADS__ 1564 \\#define __STDC_NO_THREADS__ 1
555 \\#define __STDC_NO_VLA__ 1565 \\#define __STDC_NO_VLA__ 1
...@@ -561,23 +571,21 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi...@@ -561,23 +571,21 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
561 \\571 \\
562 );572 );
563 if (comp.langopts.standard.StdCVersionMacro()) |stdc_version| {573 if (comp.langopts.standard.StdCVersionMacro()) |stdc_version| {
564 try buf.appendSlice("#define __STDC_VERSION__ ");574 try buf.writeAll("#define __STDC_VERSION__ ");
565 try buf.appendSlice(stdc_version);575 try buf.writeAll(stdc_version);
566 try buf.append('\n');576 try buf.writeByte('\n');
567 }577 }
568578
569 // timestamps579 // timestamps
570 const timestamp = try comp.getTimestamp();580 const timestamp = try comp.getTimestamp();
571 try generateDateAndTime(buf.writer(), timestamp);581 try generateDateAndTime(buf, timestamp);
572582
573 if (system_defines_mode == .include_system_defines) {583 if (system_defines_mode == .include_system_defines) {
574 try comp.generateSystemDefines(buf.writer());584 try comp.generateSystemDefines(buf);
575 }585 }
576
577 return comp.addSourceFromBuffer("<builtin>", buf.items);
578}586}
579587
580fn generateFloatMacros(w: anytype, prefix: []const u8, semantics: target_util.FPSemantics, ext: []const u8) !void {588fn generateFloatMacros(w: *Writer, prefix: []const u8, semantics: target_util.FPSemantics, ext: []const u8) !void {
581 const denormMin = semantics.chooseValue(589 const denormMin = semantics.chooseValue(
582 []const u8,590 []const u8,
583 .{591 .{
...@@ -656,7 +664,7 @@ fn generateFloatMacros(w: anytype, prefix: []const u8, semantics: target_util.FP...@@ -656,7 +664,7 @@ fn generateFloatMacros(w: anytype, prefix: []const u8, semantics: target_util.FP
656 try w.print("#define {s}MIN__ {s}{s}\n", .{ prefix_slice, min, ext });664 try w.print("#define {s}MIN__ {s}{s}\n", .{ prefix_slice, min, ext });
657}665}
658666
659fn generateTypeMacro(w: anytype, mapper: StrInt.TypeMapper, name: []const u8, ty: Type, langopts: LangOpts) !void {667fn generateTypeMacro(w: *Writer, mapper: StrInt.TypeMapper, name: []const u8, ty: Type, langopts: LangOpts) !void {
660 try w.print("#define {s} ", .{name});668 try w.print("#define {s} ", .{name});
661 try ty.print(mapper, langopts, w);669 try ty.print(mapper, langopts, w);
662 try w.writeByte('\n');670 try w.writeByte('\n');
...@@ -762,7 +770,7 @@ fn generateFastOrLeastType(...@@ -762,7 +770,7 @@ fn generateFastOrLeastType(
762 bits: usize,770 bits: usize,
763 kind: enum { least, fast },771 kind: enum { least, fast },
764 signedness: std.builtin.Signedness,772 signedness: std.builtin.Signedness,
765 w: anytype,773 w: *Writer,
766 mapper: StrInt.TypeMapper,774 mapper: StrInt.TypeMapper,
767) !void {775) !void {
768 const ty = comp.intLeastN(bits, signedness); // defining the fast types as the least types is permitted776 const ty = comp.intLeastN(bits, signedness); // defining the fast types as the least types is permitted
...@@ -793,7 +801,7 @@ fn generateFastOrLeastType(...@@ -793,7 +801,7 @@ fn generateFastOrLeastType(
793 try comp.generateFmt(prefix, w, ty);801 try comp.generateFmt(prefix, w, ty);
794}802}
795803
796fn generateFastAndLeastWidthTypes(comp: *Compilation, w: anytype, mapper: StrInt.TypeMapper) !void {804fn generateFastAndLeastWidthTypes(comp: *Compilation, w: *Writer, mapper: StrInt.TypeMapper) !void {
797 const sizes = [_]usize{ 8, 16, 32, 64 };805 const sizes = [_]usize{ 8, 16, 32, 64 };
798 for (sizes) |size| {806 for (sizes) |size| {
799 try comp.generateFastOrLeastType(size, .least, .signed, w, mapper);807 try comp.generateFastOrLeastType(size, .least, .signed, w, mapper);
...@@ -803,7 +811,7 @@ fn generateFastAndLeastWidthTypes(comp: *Compilation, w: anytype, mapper: StrInt...@@ -803,7 +811,7 @@ fn generateFastAndLeastWidthTypes(comp: *Compilation, w: anytype, mapper: StrInt
803 }811 }
804}812}
805813
806fn generateExactWidthTypes(comp: *const Compilation, w: anytype, mapper: StrInt.TypeMapper) !void {814fn generateExactWidthTypes(comp: *const Compilation, w: *Writer, mapper: StrInt.TypeMapper) !void {
807 try comp.generateExactWidthType(w, mapper, .schar);815 try comp.generateExactWidthType(w, mapper, .schar);
808816
809 if (comp.intSize(.short) > comp.intSize(.char)) {817 if (comp.intSize(.short) > comp.intSize(.char)) {
...@@ -851,7 +859,7 @@ fn generateExactWidthTypes(comp: *const Compilation, w: anytype, mapper: StrInt....@@ -851,7 +859,7 @@ fn generateExactWidthTypes(comp: *const Compilation, w: anytype, mapper: StrInt.
851 }859 }
852}860}
853861
854fn generateFmt(comp: *const Compilation, prefix: []const u8, w: anytype, ty: Type) !void {862fn generateFmt(comp: *const Compilation, prefix: []const u8, w: *Writer, ty: Type) !void {
855 const unsigned = ty.isUnsignedInt(comp);863 const unsigned = ty.isUnsignedInt(comp);
856 const modifier = ty.formatModifier();864 const modifier = ty.formatModifier();
857 const formats = if (unsigned) "ouxX" else "di";865 const formats = if (unsigned) "ouxX" else "di";
...@@ -860,7 +868,7 @@ fn generateFmt(comp: *const Compilation, prefix: []const u8, w: anytype, ty: Typ...@@ -860,7 +868,7 @@ fn generateFmt(comp: *const Compilation, prefix: []const u8, w: anytype, ty: Typ
860 }868 }
861}869}
862870
863fn generateSuffixMacro(comp: *const Compilation, prefix: []const u8, w: anytype, ty: Type) !void {871fn generateSuffixMacro(comp: *const Compilation, prefix: []const u8, w: *Writer, ty: Type) !void {
864 return w.print("#define {s}_C_SUFFIX__ {s}\n", .{ prefix, ty.intValueSuffix(comp) });872 return w.print("#define {s}_C_SUFFIX__ {s}\n", .{ prefix, ty.intValueSuffix(comp) });
865}873}
866874
...@@ -868,7 +876,7 @@ fn generateSuffixMacro(comp: *const Compilation, prefix: []const u8, w: anytype,...@@ -868,7 +876,7 @@ fn generateSuffixMacro(comp: *const Compilation, prefix: []const u8, w: anytype,
868/// Name macro (e.g. #define __UINT32_TYPE__ unsigned int)876/// Name macro (e.g. #define __UINT32_TYPE__ unsigned int)
869/// Format strings (e.g. #define __UINT32_FMTu__ "u")877/// Format strings (e.g. #define __UINT32_FMTu__ "u")
870/// Suffix macro (e.g. #define __UINT32_C_SUFFIX__ U)878/// Suffix macro (e.g. #define __UINT32_C_SUFFIX__ U)
871fn generateExactWidthType(comp: *const Compilation, w: anytype, mapper: StrInt.TypeMapper, specifier: Type.Specifier) !void {879fn generateExactWidthType(comp: *const Compilation, w: *Writer, mapper: StrInt.TypeMapper, specifier: Type.Specifier) !void {
872 var ty = Type{ .specifier = specifier };880 var ty = Type{ .specifier = specifier };
873 const width = 8 * ty.sizeof(comp).?;881 const width = 8 * ty.sizeof(comp).?;
874 const unsigned = ty.isUnsignedInt(comp);882 const unsigned = ty.isUnsignedInt(comp);
...@@ -998,7 +1006,7 @@ fn generateVaListType(comp: *Compilation) !Type {...@@ -998,7 +1006,7 @@ fn generateVaListType(comp: *Compilation) !Type {
998 return ty;1006 return ty;
999}1007}
10001008
1001fn generateIntMax(comp: *const Compilation, w: anytype, name: []const u8, ty: Type) !void {1009fn generateIntMax(comp: *const Compilation, w: *Writer, name: []const u8, ty: Type) !void {
1002 const bit_count: u8 = @intCast(ty.sizeof(comp).? * 8);1010 const bit_count: u8 = @intCast(ty.sizeof(comp).? * 8);
1003 const unsigned = ty.isUnsignedInt(comp);1011 const unsigned = ty.isUnsignedInt(comp);
1004 const max: u128 = switch (bit_count) {1012 const max: u128 = switch (bit_count) {
...@@ -1023,7 +1031,7 @@ pub fn wcharMax(comp: *const Compilation) u32 {...@@ -1023,7 +1031,7 @@ pub fn wcharMax(comp: *const Compilation) u32 {
1023 };1031 };
1024}1032}
10251033
1026fn generateExactWidthIntMax(comp: *const Compilation, w: anytype, specifier: Type.Specifier) !void {1034fn generateExactWidthIntMax(comp: *const Compilation, w: *Writer, specifier: Type.Specifier) !void {
1027 var ty = Type{ .specifier = specifier };1035 var ty = Type{ .specifier = specifier };
1028 const bit_count: u8 = @intCast(ty.sizeof(comp).? * 8);1036 const bit_count: u8 = @intCast(ty.sizeof(comp).? * 8);
1029 const unsigned = ty.isUnsignedInt(comp);1037 const unsigned = ty.isUnsignedInt(comp);
...@@ -1040,16 +1048,16 @@ fn generateExactWidthIntMax(comp: *const Compilation, w: anytype, specifier: Typ...@@ -1040,16 +1048,16 @@ fn generateExactWidthIntMax(comp: *const Compilation, w: anytype, specifier: Typ
1040 return comp.generateIntMax(w, name, ty);1048 return comp.generateIntMax(w, name, ty);
1041}1049}
10421050
1043fn generateIntWidth(comp: *Compilation, w: anytype, name: []const u8, ty: Type) !void {1051fn generateIntWidth(comp: *Compilation, w: *Writer, name: []const u8, ty: Type) !void {
1044 try w.print("#define __{s}_WIDTH__ {d}\n", .{ name, 8 * ty.sizeof(comp).? });1052 try w.print("#define __{s}_WIDTH__ {d}\n", .{ name, 8 * ty.sizeof(comp).? });
1045}1053}
10461054
1047fn generateIntMaxAndWidth(comp: *Compilation, w: anytype, name: []const u8, ty: Type) !void {1055fn generateIntMaxAndWidth(comp: *Compilation, w: *Writer, name: []const u8, ty: Type) !void {
1048 try comp.generateIntMax(w, name, ty);1056 try comp.generateIntMax(w, name, ty);
1049 try comp.generateIntWidth(w, name, ty);1057 try comp.generateIntWidth(w, name, ty);
1050}1058}
10511059
1052fn generateSizeofType(comp: *Compilation, w: anytype, name: []const u8, ty: Type) !void {1060fn generateSizeofType(comp: *Compilation, w: *Writer, name: []const u8, ty: Type) !void {
1053 try w.print("#define {s} {d}\n", .{ name, ty.sizeof(comp).? });1061 try w.print("#define {s} {d}\n", .{ name, ty.sizeof(comp).? });
1054}1062}
10551063
lib/compiler/aro/aro/Parser.zig+121-45
...@@ -101,7 +101,7 @@ value_map: Tree.ValueMap,...@@ -101,7 +101,7 @@ value_map: Tree.ValueMap,
101101
102// buffers used during compilation102// buffers used during compilation
103syms: SymbolStack = .{},103syms: SymbolStack = .{},
104strings: std.array_list.AlignedManaged(u8, .@"4"),104strings: std.array_list.Managed(u8),
105labels: std.array_list.Managed(Label),105labels: std.array_list.Managed(Label),
106list_buf: NodeList,106list_buf: NodeList,
107decl_buf: NodeList,107decl_buf: NodeList,
...@@ -447,7 +447,17 @@ pub fn typeStr(p: *Parser, ty: Type) ![]const u8 {...@@ -447,7 +447,17 @@ pub fn typeStr(p: *Parser, ty: Type) ![]const u8 {
447 defer p.strings.items.len = strings_top;447 defer p.strings.items.len = strings_top;
448448
449 const mapper = p.comp.string_interner.getSlowTypeMapper();449 const mapper = p.comp.string_interner.getSlowTypeMapper();
450 try ty.print(mapper, p.comp.langopts, p.strings.writer());450 {
451 var unmanaged = p.strings.moveToUnmanaged();
452 var allocating: std.Io.Writer.Allocating = .fromArrayList(p.comp.gpa, &unmanaged);
453 defer {
454 unmanaged = allocating.toArrayList();
455 p.strings = unmanaged.toManaged(p.comp.gpa);
456 }
457 ty.print(mapper, p.comp.langopts, &allocating.writer) catch |e| switch (e) {
458 error.WriteFailed => return error.OutOfMemory,
459 };
460 }
451 return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);461 return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
452}462}
453463
...@@ -455,7 +465,7 @@ pub fn typePairStr(p: *Parser, a: Type, b: Type) ![]const u8 {...@@ -455,7 +465,7 @@ pub fn typePairStr(p: *Parser, a: Type, b: Type) ![]const u8 {
455 return p.typePairStrExtra(a, " and ", b);465 return p.typePairStrExtra(a, " and ", b);
456}466}
457467
458pub fn typePairStrExtra(p: *Parser, a: Type, msg: []const u8, b: Type) ![]const u8 {468pub fn typePairStrExtra(p: *Parser, a: Type, msg: []const u8, b: Type) Error![]const u8 {
459 if (@import("builtin").mode != .Debug) {469 if (@import("builtin").mode != .Debug) {
460 if (a.is(.invalid) or b.is(.invalid)) {470 if (a.is(.invalid) or b.is(.invalid)) {
461 return "Tried to render invalid type - this is an aro bug.";471 return "Tried to render invalid type - this is an aro bug.";
...@@ -466,29 +476,60 @@ pub fn typePairStrExtra(p: *Parser, a: Type, msg: []const u8, b: Type) ![]const...@@ -466,29 +476,60 @@ pub fn typePairStrExtra(p: *Parser, a: Type, msg: []const u8, b: Type) ![]const
466476
467 try p.strings.append('\'');477 try p.strings.append('\'');
468 const mapper = p.comp.string_interner.getSlowTypeMapper();478 const mapper = p.comp.string_interner.getSlowTypeMapper();
469 try a.print(mapper, p.comp.langopts, p.strings.writer());479 {
480 var unmanaged = p.strings.moveToUnmanaged();
481 var allocating: std.Io.Writer.Allocating = .fromArrayList(p.comp.gpa, &unmanaged);
482 defer {
483 unmanaged = allocating.toArrayList();
484 p.strings = unmanaged.toManaged(p.comp.gpa);
485 }
486 a.print(mapper, p.comp.langopts, &allocating.writer) catch |e| switch (e) {
487 error.WriteFailed => return error.OutOfMemory,
488 };
489 }
470 try p.strings.append('\'');490 try p.strings.append('\'');
471 try p.strings.appendSlice(msg);491 try p.strings.appendSlice(msg);
472 try p.strings.append('\'');492 try p.strings.append('\'');
473 try b.print(mapper, p.comp.langopts, p.strings.writer());493 {
494 var unmanaged = p.strings.moveToUnmanaged();
495 var allocating: std.Io.Writer.Allocating = .fromArrayList(p.comp.gpa, &unmanaged);
496 defer {
497 unmanaged = allocating.toArrayList();
498 p.strings = unmanaged.toManaged(p.comp.gpa);
499 }
500 b.print(mapper, p.comp.langopts, &allocating.writer) catch |e| switch (e) {
501 error.WriteFailed => return error.OutOfMemory,
502 };
503 }
474 try p.strings.append('\'');504 try p.strings.append('\'');
475 return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);505 return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
476}506}
477507
478pub fn valueChangedStr(p: *Parser, res: *Result, old_value: Value, int_ty: Type) ![]const u8 {508pub fn valueChangedStr(p: *Parser, res: *Result, old_value: Value, int_ty: Type) Error![]const u8 {
479 const strings_top = p.strings.items.len;509 const strings_top = p.strings.items.len;
480 defer p.strings.items.len = strings_top;510 defer p.strings.items.len = strings_top;
481511
482 var w = p.strings.writer();
483 const type_pair_str = try p.typePairStrExtra(res.ty, " to ", int_ty);512 const type_pair_str = try p.typePairStrExtra(res.ty, " to ", int_ty);
484 try w.writeAll(type_pair_str);513 {
514 var unmanaged = p.strings.moveToUnmanaged();
515 var allocating: std.Io.Writer.Allocating = .fromArrayList(p.comp.gpa, &unmanaged);
516 defer {
517 unmanaged = allocating.toArrayList();
518 p.strings = unmanaged.toManaged(p.comp.gpa);
519 }
520 allocating.writer.writeAll(type_pair_str) catch return error.OutOfMemory;
485521
486 try w.writeAll(" changes ");522 allocating.writer.writeAll(" changes ") catch return error.OutOfMemory;
487 if (res.val.isZero(p.comp)) try w.writeAll("non-zero ");523 if (res.val.isZero(p.comp)) allocating.writer.writeAll("non-zero ") catch return error.OutOfMemory;
488 try w.writeAll("value from ");524 allocating.writer.writeAll("value from ") catch return error.OutOfMemory;
489 try old_value.print(res.ty, p.comp, w);525 old_value.print(res.ty, p.comp, &allocating.writer) catch |e| switch (e) {
490 try w.writeAll(" to ");526 error.WriteFailed => return error.OutOfMemory,
491 try res.val.print(int_ty, p.comp, w);527 };
528 allocating.writer.writeAll(" to ") catch return error.OutOfMemory;
529 res.val.print(int_ty, p.comp, &allocating.writer) catch |e| switch (e) {
530 error.WriteFailed => return error.OutOfMemory,
531 };
532 }
492533
493 return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);534 return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
494}535}
...@@ -498,9 +539,8 @@ fn checkDeprecatedUnavailable(p: *Parser, ty: Type, usage_tok: TokenIndex, decl_...@@ -498,9 +539,8 @@ fn checkDeprecatedUnavailable(p: *Parser, ty: Type, usage_tok: TokenIndex, decl_
498 const strings_top = p.strings.items.len;539 const strings_top = p.strings.items.len;
499 defer p.strings.items.len = strings_top;540 defer p.strings.items.len = strings_top;
500541
501 const w = p.strings.writer();
502 const msg_str = p.comp.interner.get(@"error".msg.ref()).bytes;542 const msg_str = p.comp.interner.get(@"error".msg.ref()).bytes;
503 try w.print("call to '{s}' declared with attribute error: {f}", .{543 try p.strings.print("call to '{s}' declared with attribute error: {f}", .{
504 p.tokSlice(@"error".__name_tok), std.zig.fmtString(msg_str),544 p.tokSlice(@"error".__name_tok), std.zig.fmtString(msg_str),
505 });545 });
506 const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);546 const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
...@@ -510,9 +550,8 @@ fn checkDeprecatedUnavailable(p: *Parser, ty: Type, usage_tok: TokenIndex, decl_...@@ -510,9 +550,8 @@ fn checkDeprecatedUnavailable(p: *Parser, ty: Type, usage_tok: TokenIndex, decl_
510 const strings_top = p.strings.items.len;550 const strings_top = p.strings.items.len;
511 defer p.strings.items.len = strings_top;551 defer p.strings.items.len = strings_top;
512552
513 const w = p.strings.writer();
514 const msg_str = p.comp.interner.get(warning.msg.ref()).bytes;553 const msg_str = p.comp.interner.get(warning.msg.ref()).bytes;
515 try w.print("call to '{s}' declared with attribute warning: {f}", .{554 try p.strings.print("call to '{s}' declared with attribute warning: {f}", .{
516 p.tokSlice(warning.__name_tok), std.zig.fmtString(msg_str),555 p.tokSlice(warning.__name_tok), std.zig.fmtString(msg_str),
517 });556 });
518 const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);557 const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
...@@ -532,17 +571,16 @@ fn errDeprecated(p: *Parser, tag: Diagnostics.Tag, tok_i: TokenIndex, msg: ?Valu...@@ -532,17 +571,16 @@ fn errDeprecated(p: *Parser, tag: Diagnostics.Tag, tok_i: TokenIndex, msg: ?Valu
532 const strings_top = p.strings.items.len;571 const strings_top = p.strings.items.len;
533 defer p.strings.items.len = strings_top;572 defer p.strings.items.len = strings_top;
534573
535 const w = p.strings.writer();574 try p.strings.print("'{s}' is ", .{p.tokSlice(tok_i)});
536 try w.print("'{s}' is ", .{p.tokSlice(tok_i)});
537 const reason: []const u8 = switch (tag) {575 const reason: []const u8 = switch (tag) {
538 .unavailable => "unavailable",576 .unavailable => "unavailable",
539 .deprecated_declarations => "deprecated",577 .deprecated_declarations => "deprecated",
540 else => unreachable,578 else => unreachable,
541 };579 };
542 try w.writeAll(reason);580 try p.strings.appendSlice(reason);
543 if (msg) |m| {581 if (msg) |m| {
544 const str = p.comp.interner.get(m.ref()).bytes;582 const str = p.comp.interner.get(m.ref()).bytes;
545 try w.print(": {f}", .{std.zig.fmtString(str)});583 try p.strings.print(": {f}", .{std.zig.fmtString(str)});
546 }584 }
547 const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);585 const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
548 return p.errStr(tag, tok_i, str);586 return p.errStr(tag, tok_i, str);
...@@ -681,7 +719,7 @@ fn diagnoseIncompleteDefinitions(p: *Parser) !void {...@@ -681,7 +719,7 @@ fn diagnoseIncompleteDefinitions(p: *Parser) !void {
681}719}
682720
683/// root : (decl | assembly ';' | staticAssert)*721/// root : (decl | assembly ';' | staticAssert)*
684pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {722pub fn parse(pp: *Preprocessor) Error!Tree {
685 assert(pp.linemarkers == .none);723 assert(pp.linemarkers == .none);
686 pp.comp.pragmaEvent(.before_parse);724 pp.comp.pragmaEvent(.before_parse);
687725
...@@ -693,7 +731,7 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {...@@ -693,7 +731,7 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {
693 .gpa = pp.comp.gpa,731 .gpa = pp.comp.gpa,
694 .arena = arena.allocator(),732 .arena = arena.allocator(),
695 .tok_ids = pp.tokens.items(.id),733 .tok_ids = pp.tokens.items(.id),
696 .strings = std.array_list.AlignedManaged(u8, .@"4").init(pp.comp.gpa),734 .strings = std.array_list.Managed(u8).init(pp.comp.gpa),
697 .value_map = Tree.ValueMap.init(pp.comp.gpa),735 .value_map = Tree.ValueMap.init(pp.comp.gpa),
698 .data = NodeList.init(pp.comp.gpa),736 .data = NodeList.init(pp.comp.gpa),
699 .labels = std.array_list.Managed(Label).init(pp.comp.gpa),737 .labels = std.array_list.Managed(Label).init(pp.comp.gpa),
...@@ -1218,38 +1256,46 @@ fn decl(p: *Parser) Error!bool {...@@ -1218,38 +1256,46 @@ fn decl(p: *Parser) Error!bool {
1218 return true;1256 return true;
1219}1257}
12201258
1221fn staticAssertMessage(p: *Parser, cond_node: NodeIndex, message: Result) !?[]const u8 {1259fn staticAssertMessage(p: *Parser, cond_node: NodeIndex, message: Result) Error!?[]const u8 {
1222 const cond_tag = p.nodes.items(.tag)[@intFromEnum(cond_node)];1260 const cond_tag = p.nodes.items(.tag)[@intFromEnum(cond_node)];
1223 if (cond_tag != .builtin_types_compatible_p and message.node == .none) return null;1261 if (cond_tag != .builtin_types_compatible_p and message.node == .none) return null;
12241262
1225 var buf = std.array_list.Managed(u8).init(p.gpa);1263 var allocating: std.Io.Writer.Allocating = .init(p.gpa);
1226 defer buf.deinit();1264 defer allocating.deinit();
1265
1266 const buf = &allocating.writer;
12271267
1228 if (cond_tag == .builtin_types_compatible_p) {1268 if (cond_tag == .builtin_types_compatible_p) {
1229 const mapper = p.comp.string_interner.getSlowTypeMapper();1269 const mapper = p.comp.string_interner.getSlowTypeMapper();
1230 const data = p.nodes.items(.data)[@intFromEnum(cond_node)].bin;1270 const data = p.nodes.items(.data)[@intFromEnum(cond_node)].bin;
12311271
1232 try buf.appendSlice("'__builtin_types_compatible_p(");1272 buf.writeAll("'__builtin_types_compatible_p(") catch return error.OutOfMemory;
12331273
1234 const lhs_ty = p.nodes.items(.ty)[@intFromEnum(data.lhs)];1274 const lhs_ty = p.nodes.items(.ty)[@intFromEnum(data.lhs)];
1235 try lhs_ty.print(mapper, p.comp.langopts, buf.writer());1275 lhs_ty.print(mapper, p.comp.langopts, buf) catch |e| switch (e) {
1236 try buf.appendSlice(", ");1276 error.WriteFailed => return error.OutOfMemory,
1277 };
1278 buf.writeAll(", ") catch return error.OutOfMemory;
12371279
1238 const rhs_ty = p.nodes.items(.ty)[@intFromEnum(data.rhs)];1280 const rhs_ty = p.nodes.items(.ty)[@intFromEnum(data.rhs)];
1239 try rhs_ty.print(mapper, p.comp.langopts, buf.writer());1281 rhs_ty.print(mapper, p.comp.langopts, buf) catch |e| switch (e) {
1282 error.WriteFailed => return error.OutOfMemory,
1283 };
12401284
1241 try buf.appendSlice(")'");1285 buf.writeAll(")'") catch return error.OutOfMemory;
1242 }1286 }
1243 if (message.node != .none) {1287 if (message.node != .none) {
1244 assert(p.nodes.items(.tag)[@intFromEnum(message.node)] == .string_literal_expr);1288 assert(p.nodes.items(.tag)[@intFromEnum(message.node)] == .string_literal_expr);
1245 if (buf.items.len > 0) {1289 if (buf.buffered().len > 0) {
1246 try buf.append(' ');1290 buf.writeByte(' ') catch return error.OutOfMemory;
1247 }1291 }
1248 const bytes = p.comp.interner.get(message.val.ref()).bytes;1292 const bytes = p.comp.interner.get(message.val.ref()).bytes;
1249 try buf.ensureUnusedCapacity(bytes.len);1293 try allocating.ensureUnusedCapacity(bytes.len);
1250 try Value.printString(bytes, message.ty, p.comp, buf.writer());1294 Value.printString(bytes, message.ty, p.comp, buf) catch |e| switch (e) {
1295 error.WriteFailed => return error.OutOfMemory,
1296 };
1251 }1297 }
1252 return try p.comp.diagnostics.arena.allocator().dupe(u8, buf.items);1298 return try p.comp.diagnostics.arena.allocator().dupe(u8, allocating.written());
1253}1299}
12541300
1255/// staticAssert1301/// staticAssert
...@@ -4981,7 +5027,7 @@ const CallExpr = union(enum) {...@@ -4981,7 +5027,7 @@ const CallExpr = union(enum) {
4981 return true;5027 return true;
4982 }5028 }
49835029
4984 fn checkVarArg(self: CallExpr, p: *Parser, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, arg_idx: u32) !void {5030 fn checkVarArg(self: CallExpr, p: *Parser, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, arg_idx: u32) Error!void {
4985 if (self == .standard) return;5031 if (self == .standard) return;
49865032
4987 const builtin_tok = p.nodes.items(.data)[@intFromEnum(self.builtin.node)].decl.name;5033 const builtin_tok = p.nodes.items(.data)[@intFromEnum(self.builtin.node)].decl.name;
...@@ -5183,7 +5229,17 @@ pub const Result = struct {...@@ -5183,7 +5229,17 @@ pub const Result = struct {
5183 const strings_top = p.strings.items.len;5229 const strings_top = p.strings.items.len;
5184 defer p.strings.items.len = strings_top;5230 defer p.strings.items.len = strings_top;
51855231
5186 try res.val.print(res.ty, p.comp, p.strings.writer());5232 {
5233 var unmanaged = p.strings.moveToUnmanaged();
5234 var allocating: std.Io.Writer.Allocating = .fromArrayList(p.comp.gpa, &unmanaged);
5235 defer {
5236 unmanaged = allocating.toArrayList();
5237 p.strings = unmanaged.toManaged(p.comp.gpa);
5238 }
5239 res.val.print(res.ty, p.comp, &allocating.writer) catch |e| switch (e) {
5240 error.WriteFailed => return error.OutOfMemory,
5241 };
5242 }
5187 return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);5243 return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
5188 }5244 }
51895245
...@@ -5347,7 +5403,7 @@ pub const Result = struct {...@@ -5347,7 +5403,7 @@ pub const Result = struct {
5347 conditional,5403 conditional,
5348 add,5404 add,
5349 sub,5405 sub,
5350 }) !bool {5406 }) Error!bool {
5351 if (b.ty.specifier == .invalid) {5407 if (b.ty.specifier == .invalid) {
5352 try a.saveValue(p);5408 try a.saveValue(p);
5353 a.ty = Type.invalid;5409 a.ty = Type.invalid;
...@@ -5643,7 +5699,7 @@ pub const Result = struct {...@@ -5643,7 +5699,7 @@ pub const Result = struct {
5643 }5699 }
5644 }5700 }
56455701
5646 fn floatToIntWarning(res: *Result, p: *Parser, int_ty: Type, old_value: Value, change_kind: Value.FloatToIntChangeKind, tok: TokenIndex) !void {5702 fn floatToIntWarning(res: *Result, p: *Parser, int_ty: Type, old_value: Value, change_kind: Value.FloatToIntChangeKind, tok: TokenIndex) Error!void {
5647 switch (change_kind) {5703 switch (change_kind) {
5648 .none => return p.errStr(.float_to_int, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),5704 .none => return p.errStr(.float_to_int, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),
5649 .out_of_range => return p.errStr(.float_out_of_range, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),5705 .out_of_range => return p.errStr(.float_out_of_range, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),
...@@ -5866,7 +5922,7 @@ pub const Result = struct {...@@ -5866,7 +5922,7 @@ pub const Result = struct {
5866 res.val = .{};5922 res.val = .{};
5867 }5923 }
58685924
5869 fn castType(res: *Result, p: *Parser, to: Type, operand_tok: TokenIndex, l_paren: TokenIndex) !void {5925 fn castType(res: *Result, p: *Parser, to: Type, operand_tok: TokenIndex, l_paren: TokenIndex) Error!void {
5870 var cast_kind: Tree.CastKind = undefined;5926 var cast_kind: Tree.CastKind = undefined;
58715927
5872 if (to.is(.void)) {5928 if (to.is(.void)) {
...@@ -7595,9 +7651,19 @@ fn validateFieldAccess(p: *Parser, record_ty: *const Type.Record, expr_ty: Type,...@@ -7595,9 +7651,19 @@ fn validateFieldAccess(p: *Parser, record_ty: *const Type.Record, expr_ty: Type,
75957651
7596 p.strings.items.len = 0;7652 p.strings.items.len = 0;
75977653
7598 try p.strings.writer().print("'{s}' in '", .{p.tokSlice(field_name_tok)});7654 try p.strings.print("'{s}' in '", .{p.tokSlice(field_name_tok)});
7599 const mapper = p.comp.string_interner.getSlowTypeMapper();7655 const mapper = p.comp.string_interner.getSlowTypeMapper();
7600 try expr_ty.print(mapper, p.comp.langopts, p.strings.writer());7656 {
7657 var unmanaged = p.strings.moveToUnmanaged();
7658 var allocating: std.Io.Writer.Allocating = .fromArrayList(p.comp.gpa, &unmanaged);
7659 defer {
7660 unmanaged = allocating.toArrayList();
7661 p.strings = unmanaged.toManaged(p.comp.gpa);
7662 }
7663 expr_ty.print(mapper, p.comp.langopts, &allocating.writer) catch |e| switch (e) {
7664 error.WriteFailed => return error.OutOfMemory,
7665 };
7666 }
7601 try p.strings.append('\'');7667 try p.strings.append('\'');
76027668
7603 const duped = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items);7669 const duped = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items);
...@@ -8016,7 +8082,17 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -8016,7 +8082,17 @@ fn primaryExpr(p: *Parser) Error!Result {
8016 defer p.strings.items.len = strings_top;8082 defer p.strings.items.len = strings_top;
80178083
8018 const mapper = p.comp.string_interner.getSlowTypeMapper();8084 const mapper = p.comp.string_interner.getSlowTypeMapper();
8019 try Type.printNamed(func_ty, p.tokSlice(p.func.name), mapper, p.comp.langopts, p.strings.writer());8085 {
8086 var unmanaged = p.strings.moveToUnmanaged();
8087 var allocating: std.Io.Writer.Allocating = .fromArrayList(p.comp.gpa, &unmanaged);
8088 defer {
8089 unmanaged = allocating.toArrayList();
8090 p.strings = unmanaged.toManaged(p.comp.gpa);
8091 }
8092 Type.printNamed(func_ty, p.tokSlice(p.func.name), mapper, p.comp.langopts, &allocating.writer) catch |e| switch (e) {
8093 error.WriteFailed => return error.OutOfMemory,
8094 };
8095 }
8020 try p.strings.append(0);8096 try p.strings.append(0);
8021 const predef = try p.makePredefinedIdentifier(strings_top);8097 const predef = try p.makePredefinedIdentifier(strings_top);
8022 ty = predef.ty;8098 ty = predef.ty;
lib/compiler/aro/aro/Preprocessor.zig+12-17
...@@ -15,6 +15,7 @@ const TokenWithExpansionLocs = Tree.TokenWithExpansionLocs;...@@ -15,6 +15,7 @@ const TokenWithExpansionLocs = Tree.TokenWithExpansionLocs;
15const Attribute = @import("Attribute.zig");15const Attribute = @import("Attribute.zig");
16const features = @import("features.zig");16const features = @import("features.zig");
17const Hideset = @import("Hideset.zig");17const Hideset = @import("Hideset.zig");
18const Writer = std.Io.Writer;
1819
19const DefineMap = std.StringHashMapUnmanaged(Macro);20const DefineMap = std.StringHashMapUnmanaged(Macro);
20const RawTokenList = std.array_list.Managed(RawToken);21const RawTokenList = std.array_list.Managed(RawToken);
...@@ -982,7 +983,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {...@@ -982,7 +983,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
982 .tok_i = @intCast(token_state.tokens_len),983 .tok_i = @intCast(token_state.tokens_len),
983 .arena = pp.arena.allocator(),984 .arena = pp.arena.allocator(),
984 .in_macro = true,985 .in_macro = true,
985 .strings = std.array_list.AlignedManaged(u8, .@"4").init(pp.comp.gpa),986 .strings = std.array_list.Managed(u8).init(pp.comp.gpa),
986987
987 .data = undefined,988 .data = undefined,
988 .value_map = undefined,989 .value_map = undefined,
...@@ -1193,24 +1194,21 @@ fn expandObjMacro(pp: *Preprocessor, simple_macro: *const Macro) Error!ExpandBuf...@@ -1193,24 +1194,21 @@ fn expandObjMacro(pp: *Preprocessor, simple_macro: *const Macro) Error!ExpandBuf
1193 .macro_file => {1194 .macro_file => {
1194 const start = pp.comp.generated_buf.items.len;1195 const start = pp.comp.generated_buf.items.len;
1195 const source = pp.comp.getSource(pp.expansion_source_loc.id);1196 const source = pp.comp.getSource(pp.expansion_source_loc.id);
1196 const w = pp.comp.generated_buf.writer(pp.gpa);1197 try pp.comp.generated_buf.print(pp.gpa, "\"{s}\"\n", .{source.path});
1197 try w.print("\"{s}\"\n", .{source.path});
11981198
1199 buf.appendAssumeCapacity(try pp.makeGeneratedToken(start, .string_literal, tok));1199 buf.appendAssumeCapacity(try pp.makeGeneratedToken(start, .string_literal, tok));
1200 },1200 },
1201 .macro_line => {1201 .macro_line => {
1202 const start = pp.comp.generated_buf.items.len;1202 const start = pp.comp.generated_buf.items.len;
1203 const source = pp.comp.getSource(pp.expansion_source_loc.id);1203 const source = pp.comp.getSource(pp.expansion_source_loc.id);
1204 const w = pp.comp.generated_buf.writer(pp.gpa);1204 try pp.comp.generated_buf.print(pp.gpa, "{d}\n", .{source.physicalLine(pp.expansion_source_loc)});
1205 try w.print("{d}\n", .{source.physicalLine(pp.expansion_source_loc)});
12061205
1207 buf.appendAssumeCapacity(try pp.makeGeneratedToken(start, .pp_num, tok));1206 buf.appendAssumeCapacity(try pp.makeGeneratedToken(start, .pp_num, tok));
1208 },1207 },
1209 .macro_counter => {1208 .macro_counter => {
1210 defer pp.counter += 1;1209 defer pp.counter += 1;
1211 const start = pp.comp.generated_buf.items.len;1210 const start = pp.comp.generated_buf.items.len;
1212 const w = pp.comp.generated_buf.writer(pp.gpa);1211 try pp.comp.generated_buf.print(pp.gpa, "{d}\n", .{pp.counter});
1213 try w.print("{d}\n", .{pp.counter});
12141212
1215 buf.appendAssumeCapacity(try pp.makeGeneratedToken(start, .pp_num, tok));1213 buf.appendAssumeCapacity(try pp.makeGeneratedToken(start, .pp_num, tok));
1216 },1214 },
...@@ -1682,8 +1680,7 @@ fn expandFuncMacro(...@@ -1682,8 +1680,7 @@ fn expandFuncMacro(
1682 break :blk false;1680 break :blk false;
1683 } else try pp.handleBuiltinMacro(raw.id, arg, macro_tok.loc);1681 } else try pp.handleBuiltinMacro(raw.id, arg, macro_tok.loc);
1684 const start = pp.comp.generated_buf.items.len;1682 const start = pp.comp.generated_buf.items.len;
1685 const w = pp.comp.generated_buf.writer(pp.gpa);1683 try pp.comp.generated_buf.print(pp.gpa, "{}\n", .{@intFromBool(result)});
1686 try w.print("{}\n", .{@intFromBool(result)});
1687 try buf.append(try pp.makeGeneratedToken(start, .pp_num, tokFromRaw(raw)));1684 try buf.append(try pp.makeGeneratedToken(start, .pp_num, tokFromRaw(raw)));
1688 },1685 },
1689 .macro_param_has_c_attribute => {1686 .macro_param_has_c_attribute => {
...@@ -2988,18 +2985,16 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {...@@ -2988,18 +2985,16 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
2988 // TODO: We currently only support systems with CHAR_BIT == 82985 // TODO: We currently only support systems with CHAR_BIT == 8
2989 // If the target's CHAR_BIT is not 8, we need to write out correctly-sized embed_bytes2986 // If the target's CHAR_BIT is not 8, we need to write out correctly-sized embed_bytes
2990 // and correctly account for the target's endianness2987 // and correctly account for the target's endianness
2991 const writer = pp.comp.generated_buf.writer(pp.gpa);
2992
2993 {2988 {
2994 const byte = embed_bytes[0];2989 const byte = embed_bytes[0];
2995 const start = pp.comp.generated_buf.items.len;2990 const start = pp.comp.generated_buf.items.len;
2996 try writer.print("{d}", .{byte});2991 try pp.comp.generated_buf.print(pp.gpa, "{d}", .{byte});
2997 pp.addTokenAssumeCapacity(try pp.makeGeneratedToken(start, .embed_byte, filename_tok));2992 pp.addTokenAssumeCapacity(try pp.makeGeneratedToken(start, .embed_byte, filename_tok));
2998 }2993 }
29992994
3000 for (embed_bytes[1..]) |byte| {2995 for (embed_bytes[1..]) |byte| {
3001 const start = pp.comp.generated_buf.items.len;2996 const start = pp.comp.generated_buf.items.len;
3002 try writer.print(",{d}", .{byte});2997 try pp.comp.generated_buf.print(pp.gpa, ",{d}", .{byte});
3003 pp.addTokenAssumeCapacity(.{ .id = .comma, .loc = .{ .id = .generated, .byte_offset = @intCast(start) } });2998 pp.addTokenAssumeCapacity(.{ .id = .comma, .loc = .{ .id = .generated, .byte_offset = @intCast(start) } });
3004 pp.addTokenAssumeCapacity(try pp.makeGeneratedToken(start + 1, .embed_byte, filename_tok));2999 pp.addTokenAssumeCapacity(try pp.makeGeneratedToken(start + 1, .embed_byte, filename_tok));
3005 }3000 }
...@@ -3241,7 +3236,7 @@ fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken,...@@ -3241,7 +3236,7 @@ fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken,
32413236
3242fn printLinemarker(3237fn printLinemarker(
3243 pp: *Preprocessor,3238 pp: *Preprocessor,
3244 w: anytype,3239 w: *Writer,
3245 line_no: u32,3240 line_no: u32,
3246 source: Source,3241 source: Source,
3247 start_resume: enum(u8) { start, @"resume", none },3242 start_resume: enum(u8) { start, @"resume", none },
...@@ -3301,7 +3296,7 @@ pub const DumpMode = enum {...@@ -3301,7 +3296,7 @@ pub const DumpMode = enum {
3301/// Pretty-print the macro define or undef at location `loc`.3296/// Pretty-print the macro define or undef at location `loc`.
3302/// We re-tokenize the directive because we are printing a macro that may have the same name as one in3297/// We re-tokenize the directive because we are printing a macro that may have the same name as one in
3303/// `pp.defines` but a different definition (due to being #undef'ed and then redefined)3298/// `pp.defines` but a different definition (due to being #undef'ed and then redefined)
3304fn prettyPrintMacro(pp: *Preprocessor, w: anytype, loc: Source.Location, parts: enum { name_only, name_and_body }) !void {3299fn prettyPrintMacro(pp: *Preprocessor, w: *Writer, loc: Source.Location, parts: enum { name_only, name_and_body }) !void {
3305 const source = pp.comp.getSource(loc.id);3300 const source = pp.comp.getSource(loc.id);
3306 var tokenizer: Tokenizer = .{3301 var tokenizer: Tokenizer = .{
3307 .buf = source.buf,3302 .buf = source.buf,
...@@ -3339,7 +3334,7 @@ fn prettyPrintMacro(pp: *Preprocessor, w: anytype, loc: Source.Location, parts:...@@ -3339,7 +3334,7 @@ fn prettyPrintMacro(pp: *Preprocessor, w: anytype, loc: Source.Location, parts:
3339 }3334 }
3340}3335}
33413336
3342fn prettyPrintMacrosOnly(pp: *Preprocessor, w: anytype) !void {3337fn prettyPrintMacrosOnly(pp: *Preprocessor, w: *Writer) !void {
3343 var it = pp.defines.valueIterator();3338 var it = pp.defines.valueIterator();
3344 while (it.next()) |macro| {3339 while (it.next()) |macro| {
3345 if (macro.is_builtin) continue;3340 if (macro.is_builtin) continue;
...@@ -3351,7 +3346,7 @@ fn prettyPrintMacrosOnly(pp: *Preprocessor, w: anytype) !void {...@@ -3351,7 +3346,7 @@ fn prettyPrintMacrosOnly(pp: *Preprocessor, w: anytype) !void {
3351}3346}
33523347
3353/// Pretty print tokens and try to preserve whitespace.3348/// Pretty print tokens and try to preserve whitespace.
3354pub fn prettyPrintTokens(pp: *Preprocessor, w: anytype, macro_dump_mode: DumpMode) !void {3349pub fn prettyPrintTokens(pp: *Preprocessor, w: *Writer, macro_dump_mode: DumpMode) !void {
3355 if (macro_dump_mode == .macros_only) {3350 if (macro_dump_mode == .macros_only) {
3356 return pp.prettyPrintMacrosOnly(w);3351 return pp.prettyPrintMacrosOnly(w);
3357 }3352 }
lib/compiler/aro/aro/Type.zig+9-8
...@@ -9,6 +9,7 @@ const StringInterner = @import("StringInterner.zig");...@@ -9,6 +9,7 @@ const StringInterner = @import("StringInterner.zig");
9const StringId = StringInterner.StringId;9const StringId = StringInterner.StringId;
10const target_util = @import("target.zig");10const target_util = @import("target.zig");
11const LangOpts = @import("LangOpts.zig");11const LangOpts = @import("LangOpts.zig");
12const Writer = std.Io.Writer;
1213
13pub const Qualifiers = packed struct {14pub const Qualifiers = packed struct {
14 @"const": bool = false,15 @"const": bool = false,
...@@ -23,7 +24,7 @@ pub const Qualifiers = packed struct {...@@ -23,7 +24,7 @@ pub const Qualifiers = packed struct {
23 return quals.@"const" or quals.restrict or quals.@"volatile" or quals.atomic;24 return quals.@"const" or quals.restrict or quals.@"volatile" or quals.atomic;
24 }25 }
2526
26 pub fn dump(quals: Qualifiers, w: anytype) !void {27 pub fn dump(quals: Qualifiers, w: *Writer) !void {
27 if (quals.@"const") try w.writeAll("const ");28 if (quals.@"const") try w.writeAll("const ");
28 if (quals.atomic) try w.writeAll("_Atomic ");29 if (quals.atomic) try w.writeAll("_Atomic ");
29 if (quals.@"volatile") try w.writeAll("volatile ");30 if (quals.@"volatile") try w.writeAll("volatile ");
...@@ -2411,12 +2412,12 @@ pub fn intValueSuffix(ty: Type, comp: *const Compilation) []const u8 {...@@ -2411,12 +2412,12 @@ pub fn intValueSuffix(ty: Type, comp: *const Compilation) []const u8 {
2411}2412}
24122413
2413/// Print type in C style2414/// Print type in C style
2414pub fn print(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: anytype) @TypeOf(w).Error!void {2415pub fn print(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: *Writer) Writer.Error!void {
2415 _ = try ty.printPrologue(mapper, langopts, w);2416 _ = try ty.printPrologue(mapper, langopts, w);
2416 try ty.printEpilogue(mapper, langopts, w);2417 try ty.printEpilogue(mapper, langopts, w);
2417}2418}
24182419
2419pub fn printNamed(ty: Type, name: []const u8, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: anytype) @TypeOf(w).Error!void {2420pub fn printNamed(ty: Type, name: []const u8, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: *Writer) Writer.Error!void {
2420 const simple = try ty.printPrologue(mapper, langopts, w);2421 const simple = try ty.printPrologue(mapper, langopts, w);
2421 if (simple) try w.writeByte(' ');2422 if (simple) try w.writeByte(' ');
2422 try w.writeAll(name);2423 try w.writeAll(name);
...@@ -2426,7 +2427,7 @@ pub fn printNamed(ty: Type, name: []const u8, mapper: StringInterner.TypeMapper,...@@ -2426,7 +2427,7 @@ pub fn printNamed(ty: Type, name: []const u8, mapper: StringInterner.TypeMapper,
2426const StringGetter = fn (TokenIndex) []const u8;2427const StringGetter = fn (TokenIndex) []const u8;
24272428
2428/// return true if `ty` is simple2429/// return true if `ty` is simple
2429fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: anytype) @TypeOf(w).Error!bool {2430fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: *Writer) Writer.Error!bool {
2430 if (ty.qual.atomic) {2431 if (ty.qual.atomic) {
2431 var non_atomic_ty = ty;2432 var non_atomic_ty = ty;
2432 non_atomic_ty.qual.atomic = false;2433 non_atomic_ty.qual.atomic = false;
...@@ -2497,7 +2498,7 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts...@@ -2497,7 +2498,7 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts
2497 return true;2498 return true;
2498}2499}
24992500
2500fn printEpilogue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: anytype) @TypeOf(w).Error!void {2501fn printEpilogue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: *Writer) Writer.Error!void {
2501 if (ty.qual.atomic) return;2502 if (ty.qual.atomic) return;
2502 if (ty.isPtr()) {2503 if (ty.isPtr()) {
2503 const elem_ty = ty.elemType();2504 const elem_ty = ty.elemType();
...@@ -2564,7 +2565,7 @@ fn printEpilogue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts...@@ -2564,7 +2565,7 @@ fn printEpilogue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts
2564const dump_detailed_containers = false;2565const dump_detailed_containers = false;
25652566
2566// Print as Zig types since those are actually readable2567// Print as Zig types since those are actually readable
2567pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: anytype) @TypeOf(w).Error!void {2568pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: *Writer) Writer.Error!void {
2568 try ty.qual.dump(w);2569 try ty.qual.dump(w);
2569 switch (ty.specifier) {2570 switch (ty.specifier) {
2570 .invalid => try w.writeAll("invalid"),2571 .invalid => try w.writeAll("invalid"),
...@@ -2656,7 +2657,7 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:...@@ -2656,7 +2657,7 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
2656 }2657 }
2657}2658}
26582659
2659fn dumpEnum(@"enum": *Enum, mapper: StringInterner.TypeMapper, w: anytype) @TypeOf(w).Error!void {2660fn dumpEnum(@"enum": *Enum, mapper: StringInterner.TypeMapper, w: *Writer) Writer.Error!void {
2660 try w.writeAll(" {");2661 try w.writeAll(" {");
2661 for (@"enum".fields) |field| {2662 for (@"enum".fields) |field| {
2662 try w.print(" {s} = {d},", .{ mapper.lookup(field.name), field.value });2663 try w.print(" {s} = {d},", .{ mapper.lookup(field.name), field.value });
...@@ -2664,7 +2665,7 @@ fn dumpEnum(@"enum": *Enum, mapper: StringInterner.TypeMapper, w: anytype) @Type...@@ -2664,7 +2665,7 @@ fn dumpEnum(@"enum": *Enum, mapper: StringInterner.TypeMapper, w: anytype) @Type
2664 try w.writeAll(" }");2665 try w.writeAll(" }");
2665}2666}
26662667
2667fn dumpRecord(record: *Record, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: anytype) @TypeOf(w).Error!void {2668fn dumpRecord(record: *Record, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: *Writer) Writer.Error!void {
2668 try w.writeAll(" {");2669 try w.writeAll(" {");
2669 for (record.fields) |field| {2670 for (record.fields) |field| {
2670 try w.writeByte(' ');2671 try w.writeByte(' ');
lib/compiler/aro/aro/Value.zig+3-2
...@@ -9,6 +9,7 @@ const Compilation = @import("Compilation.zig");...@@ -9,6 +9,7 @@ const Compilation = @import("Compilation.zig");
9const Type = @import("Type.zig");9const Type = @import("Type.zig");
10const target_util = @import("target.zig");10const target_util = @import("target.zig");
11const annex_g = @import("annex_g.zig");11const annex_g = @import("annex_g.zig");
12const Writer = std.Io.Writer;
1213
13const Value = @This();14const Value = @This();
1415
...@@ -953,7 +954,7 @@ pub fn maxInt(ty: Type, comp: *Compilation) !Value {...@@ -953,7 +954,7 @@ pub fn maxInt(ty: Type, comp: *Compilation) !Value {
953 return twosCompIntLimit(.max, ty, comp);954 return twosCompIntLimit(.max, ty, comp);
954}955}
955956
956pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {957pub fn print(v: Value, ty: Type, comp: *const Compilation, w: *Writer) Writer.Error!void {
957 if (ty.is(.bool)) {958 if (ty.is(.bool)) {
958 return w.writeAll(if (v.isZero(comp)) "false" else "true");959 return w.writeAll(if (v.isZero(comp)) "false" else "true");
959 }960 }
...@@ -977,7 +978,7 @@ pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w...@@ -977,7 +978,7 @@ pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w
977 }978 }
978}979}
979980
980pub fn printString(bytes: []const u8, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {981pub fn printString(bytes: []const u8, ty: Type, comp: *const Compilation, w: *Writer) Writer.Error!void {
981 const size: Compilation.CharUnitSize = @enumFromInt(ty.elemType().sizeof(comp).?);982 const size: Compilation.CharUnitSize = @enumFromInt(ty.elemType().sizeof(comp).?);
982 const without_null = bytes[0 .. bytes.len - @intFromEnum(size)];983 const without_null = bytes[0 .. bytes.len - @intFromEnum(size)];
983 try w.writeByte('"');984 try w.writeByte('"');
lib/compiler/aro_translate_c.zig+10-8
...@@ -116,15 +116,17 @@ pub fn translate(...@@ -116,15 +116,17 @@ pub fn translate(
116 var driver: aro.Driver = .{ .comp = comp };116 var driver: aro.Driver = .{ .comp = comp };
117 defer driver.deinit();117 defer driver.deinit();
118118
119 var macro_buf = std.array_list.Managed(u8).init(gpa);119 var macro_buf: std.Io.Writer.Allocating = .init(gpa);
120 defer macro_buf.deinit();120 defer macro_buf.deinit();
121121
122 assert(!try driver.parseArgs(std.io.null_writer, macro_buf.writer(), args));122 var trash: [64]u8 = undefined;
123 var discarding: std.Io.Writer.Discarding = .init(&trash);
124 assert(!try driver.parseArgs(&discarding.writer, &macro_buf.writer, args));
123 assert(driver.inputs.items.len == 1);125 assert(driver.inputs.items.len == 1);
124 const source = driver.inputs.items[0];126 const source = driver.inputs.items[0];
125127
126 const builtin_macros = try comp.generateBuiltinMacros(.include_system_defines);128 const builtin_macros = try comp.generateBuiltinMacros(.include_system_defines);
127 const user_macros = try comp.addSourceFromBuffer("<command line>", macro_buf.items);129 const user_macros = try comp.addSourceFromBuffer("<command line>", macro_buf.written());
128130
129 var pp = try aro.Preprocessor.initDefault(comp);131 var pp = try aro.Preprocessor.initDefault(comp);
130 defer pp.deinit();132 defer pp.deinit();
...@@ -698,11 +700,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_...@@ -698,11 +700,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_
698}700}
699701
700fn getTypeStr(c: *Context, ty: Type) ![]const u8 {702fn getTypeStr(c: *Context, ty: Type) ![]const u8 {
701 var buf: std.ArrayListUnmanaged(u8) = .empty;703 var allocating: std.Io.Writer.Allocating = .init(c.gpa);
702 defer buf.deinit(c.gpa);704 defer allocating.deinit();
703 const w = buf.writer(c.gpa);705 ty.print(c.mapper, c.comp.langopts, &allocating.writer) catch return error.OutOfMemory;
704 try ty.print(c.mapper, c.comp.langopts, w);706 return c.arena.dupe(u8, allocating.written());
705 return c.arena.dupe(u8, buf.items);
706}707}
707708
708fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualHandling, source_loc: TokenIndex) TypeError!ZigNode {709fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualHandling, source_loc: TokenIndex) TypeError!ZigNode {
...@@ -1820,6 +1821,7 @@ pub fn main() !void {...@@ -1820,6 +1821,7 @@ pub fn main() !void {
1820 var tree = translate(gpa, &aro_comp, args) catch |err| switch (err) {1821 var tree = translate(gpa, &aro_comp, args) catch |err| switch (err) {
1821 error.ParsingFailed, error.FatalError => renderErrorsAndExit(&aro_comp),1822 error.ParsingFailed, error.FatalError => renderErrorsAndExit(&aro_comp),
1822 error.OutOfMemory => return error.OutOfMemory,1823 error.OutOfMemory => return error.OutOfMemory,
1824 error.WriteFailed => return error.WriteFailed,
1823 error.StreamTooLong => std.process.fatal("An input file was larger than 4GiB", .{}),1825 error.StreamTooLong => std.process.fatal("An input file was larger than 4GiB", .{}),
1824 };1826 };
1825 defer tree.deinit(gpa);1827 defer tree.deinit(gpa);
lib/compiler/aro_translate_c/ast.zig+1-1
...@@ -832,7 +832,7 @@ const Context = struct {...@@ -832,7 +832,7 @@ const Context = struct {
832832
833 fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex {833 fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex {
834 const start_index = c.buf.items.len;834 const start_index = c.buf.items.len;
835 try c.buf.writer().print(format ++ " ", args);835 try c.buf.print(format ++ " ", args);
836836
837 try c.tokens.append(c.gpa, .{837 try c.tokens.append(c.gpa, .{
838 .tag = tag,838 .tag = tag,
lib/compiler/resinator/ani.zig+13-13
...@@ -16,31 +16,31 @@ const std = @import("std");...@@ -16,31 +16,31 @@ const std = @import("std");
1616
17const AF_ICON: u32 = 1;17const AF_ICON: u32 = 1;
1818
19pub fn isAnimatedIcon(reader: anytype) bool {19pub fn isAnimatedIcon(reader: *std.Io.Reader) bool {
20 const flags = getAniheaderFlags(reader) catch return false;20 const flags = getAniheaderFlags(reader) catch return false;
21 return flags & AF_ICON == AF_ICON;21 return flags & AF_ICON == AF_ICON;
22}22}
2323
24fn getAniheaderFlags(reader: anytype) !u32 {24fn getAniheaderFlags(reader: *std.Io.Reader) !u32 {
25 const riff_header = try reader.readBytesNoEof(4);25 const riff_header = try reader.takeArray(4);
26 if (!std.mem.eql(u8, &riff_header, "RIFF")) return error.InvalidFormat;26 if (!std.mem.eql(u8, riff_header, "RIFF")) return error.InvalidFormat;
2727
28 _ = try reader.readInt(u32, .little); // size of RIFF chunk28 _ = try reader.takeInt(u32, .little); // size of RIFF chunk
2929
30 const form_type = try reader.readBytesNoEof(4);30 const form_type = try reader.takeArray(4);
31 if (!std.mem.eql(u8, &form_type, "ACON")) return error.InvalidFormat;31 if (!std.mem.eql(u8, form_type, "ACON")) return error.InvalidFormat;
3232
33 while (true) {33 while (true) {
34 const chunk_id = try reader.readBytesNoEof(4);34 const chunk_id = try reader.takeArray(4);
35 const chunk_len = try reader.readInt(u32, .little);35 const chunk_len = try reader.takeInt(u32, .little);
36 if (!std.mem.eql(u8, &chunk_id, "anih")) {36 if (!std.mem.eql(u8, chunk_id, "anih")) {
37 // TODO: Move file cursor instead of skipBytes37 // TODO: Move file cursor instead of skipBytes
38 try reader.skipBytes(chunk_len, .{});38 try reader.discardAll(chunk_len);
39 continue;39 continue;
40 }40 }
4141
42 const aniheader = try reader.readStruct(ANIHEADER);42 const aniheader = try reader.takeStruct(ANIHEADER, .little);
43 return std.mem.nativeToLittle(u32, aniheader.flags);43 return aniheader.flags;
44 }44 }
45}45}
4646
lib/compiler/resinator/ast.zig+40-40
...@@ -22,13 +22,13 @@ pub const Tree = struct {...@@ -22,13 +22,13 @@ pub const Tree = struct {
22 return @alignCast(@fieldParentPtr("base", self.node));22 return @alignCast(@fieldParentPtr("base", self.node));
23 }23 }
2424
25 pub fn dump(self: *Tree, writer: anytype) @TypeOf(writer).Error!void {25 pub fn dump(self: *Tree, writer: *std.io.Writer) !void {
26 try self.node.dump(self, writer, 0);26 try self.node.dump(self, writer, 0);
27 }27 }
28};28};
2929
30pub const CodePageLookup = struct {30pub const CodePageLookup = struct {
31 lookup: std.ArrayListUnmanaged(SupportedCodePage) = .empty,31 lookup: std.ArrayList(SupportedCodePage) = .empty,
32 allocator: Allocator,32 allocator: Allocator,
33 default_code_page: SupportedCodePage,33 default_code_page: SupportedCodePage,
3434
...@@ -726,10 +726,10 @@ pub const Node = struct {...@@ -726,10 +726,10 @@ pub const Node = struct {
726 pub fn dump(726 pub fn dump(
727 node: *const Node,727 node: *const Node,
728 tree: *const Tree,728 tree: *const Tree,
729 writer: anytype,729 writer: *std.io.Writer,
730 indent: usize,730 indent: usize,
731 ) @TypeOf(writer).Error!void {731 ) std.io.Writer.Error!void {
732 try writer.writeByteNTimes(' ', indent);732 try writer.splatByteAll(' ', indent);
733 try writer.writeAll(@tagName(node.id));733 try writer.writeAll(@tagName(node.id));
734 switch (node.id) {734 switch (node.id) {
735 .root => {735 .root => {
...@@ -768,11 +768,11 @@ pub const Node = struct {...@@ -768,11 +768,11 @@ pub const Node = struct {
768 .grouped_expression => {768 .grouped_expression => {
769 const grouped: *const Node.GroupedExpression = @alignCast(@fieldParentPtr("base", node));769 const grouped: *const Node.GroupedExpression = @alignCast(@fieldParentPtr("base", node));
770 try writer.writeAll("\n");770 try writer.writeAll("\n");
771 try writer.writeByteNTimes(' ', indent);771 try writer.splatByteAll(' ', indent);
772 try writer.writeAll(grouped.open_token.slice(tree.source));772 try writer.writeAll(grouped.open_token.slice(tree.source));
773 try writer.writeAll("\n");773 try writer.writeAll("\n");
774 try grouped.expression.dump(tree, writer, indent + 1);774 try grouped.expression.dump(tree, writer, indent + 1);
775 try writer.writeByteNTimes(' ', indent);775 try writer.splatByteAll(' ', indent);
776 try writer.writeAll(grouped.close_token.slice(tree.source));776 try writer.writeAll(grouped.close_token.slice(tree.source));
777 try writer.writeAll("\n");777 try writer.writeAll("\n");
778 },778 },
...@@ -790,13 +790,13 @@ pub const Node = struct {...@@ -790,13 +790,13 @@ pub const Node = struct {
790 for (accelerators.optional_statements) |statement| {790 for (accelerators.optional_statements) |statement| {
791 try statement.dump(tree, writer, indent + 1);791 try statement.dump(tree, writer, indent + 1);
792 }792 }
793 try writer.writeByteNTimes(' ', indent);793 try writer.splatByteAll(' ', indent);
794 try writer.writeAll(accelerators.begin_token.slice(tree.source));794 try writer.writeAll(accelerators.begin_token.slice(tree.source));
795 try writer.writeAll("\n");795 try writer.writeAll("\n");
796 for (accelerators.accelerators) |accelerator| {796 for (accelerators.accelerators) |accelerator| {
797 try accelerator.dump(tree, writer, indent + 1);797 try accelerator.dump(tree, writer, indent + 1);
798 }798 }
799 try writer.writeByteNTimes(' ', indent);799 try writer.splatByteAll(' ', indent);
800 try writer.writeAll(accelerators.end_token.slice(tree.source));800 try writer.writeAll(accelerators.end_token.slice(tree.source));
801 try writer.writeAll("\n");801 try writer.writeAll("\n");
802 },802 },
...@@ -815,25 +815,25 @@ pub const Node = struct {...@@ -815,25 +815,25 @@ pub const Node = struct {
815 const dialog: *const Node.Dialog = @alignCast(@fieldParentPtr("base", node));815 const dialog: *const Node.Dialog = @alignCast(@fieldParentPtr("base", node));
816 try writer.print(" {s} {s} [{d} common_resource_attributes]\n", .{ dialog.id.slice(tree.source), dialog.type.slice(tree.source), dialog.common_resource_attributes.len });816 try writer.print(" {s} {s} [{d} common_resource_attributes]\n", .{ dialog.id.slice(tree.source), dialog.type.slice(tree.source), dialog.common_resource_attributes.len });
817 inline for (.{ "x", "y", "width", "height" }) |arg| {817 inline for (.{ "x", "y", "width", "height" }) |arg| {
818 try writer.writeByteNTimes(' ', indent + 1);818 try writer.splatByteAll(' ', indent + 1);
819 try writer.writeAll(arg ++ ":\n");819 try writer.writeAll(arg ++ ":\n");
820 try @field(dialog, arg).dump(tree, writer, indent + 2);820 try @field(dialog, arg).dump(tree, writer, indent + 2);
821 }821 }
822 if (dialog.help_id) |help_id| {822 if (dialog.help_id) |help_id| {
823 try writer.writeByteNTimes(' ', indent + 1);823 try writer.splatByteAll(' ', indent + 1);
824 try writer.writeAll("help_id:\n");824 try writer.writeAll("help_id:\n");
825 try help_id.dump(tree, writer, indent + 2);825 try help_id.dump(tree, writer, indent + 2);
826 }826 }
827 for (dialog.optional_statements) |statement| {827 for (dialog.optional_statements) |statement| {
828 try statement.dump(tree, writer, indent + 1);828 try statement.dump(tree, writer, indent + 1);
829 }829 }
830 try writer.writeByteNTimes(' ', indent);830 try writer.splatByteAll(' ', indent);
831 try writer.writeAll(dialog.begin_token.slice(tree.source));831 try writer.writeAll(dialog.begin_token.slice(tree.source));
832 try writer.writeAll("\n");832 try writer.writeAll("\n");
833 for (dialog.controls) |control| {833 for (dialog.controls) |control| {
834 try control.dump(tree, writer, indent + 1);834 try control.dump(tree, writer, indent + 1);
835 }835 }
836 try writer.writeByteNTimes(' ', indent);836 try writer.splatByteAll(' ', indent);
837 try writer.writeAll(dialog.end_token.slice(tree.source));837 try writer.writeAll(dialog.end_token.slice(tree.source));
838 try writer.writeAll("\n");838 try writer.writeAll("\n");
839 },839 },
...@@ -845,30 +845,30 @@ pub const Node = struct {...@@ -845,30 +845,30 @@ pub const Node = struct {
845 }845 }
846 try writer.writeByte('\n');846 try writer.writeByte('\n');
847 if (control.class) |class| {847 if (control.class) |class| {
848 try writer.writeByteNTimes(' ', indent + 1);848 try writer.splatByteAll(' ', indent + 1);
849 try writer.writeAll("class:\n");849 try writer.writeAll("class:\n");
850 try class.dump(tree, writer, indent + 2);850 try class.dump(tree, writer, indent + 2);
851 }851 }
852 inline for (.{ "id", "x", "y", "width", "height" }) |arg| {852 inline for (.{ "id", "x", "y", "width", "height" }) |arg| {
853 try writer.writeByteNTimes(' ', indent + 1);853 try writer.splatByteAll(' ', indent + 1);
854 try writer.writeAll(arg ++ ":\n");854 try writer.writeAll(arg ++ ":\n");
855 try @field(control, arg).dump(tree, writer, indent + 2);855 try @field(control, arg).dump(tree, writer, indent + 2);
856 }856 }
857 inline for (.{ "style", "exstyle", "help_id" }) |arg| {857 inline for (.{ "style", "exstyle", "help_id" }) |arg| {
858 if (@field(control, arg)) |val_node| {858 if (@field(control, arg)) |val_node| {
859 try writer.writeByteNTimes(' ', indent + 1);859 try writer.splatByteAll(' ', indent + 1);
860 try writer.writeAll(arg ++ ":\n");860 try writer.writeAll(arg ++ ":\n");
861 try val_node.dump(tree, writer, indent + 2);861 try val_node.dump(tree, writer, indent + 2);
862 }862 }
863 }863 }
864 if (control.extra_data_begin != null) {864 if (control.extra_data_begin != null) {
865 try writer.writeByteNTimes(' ', indent);865 try writer.splatByteAll(' ', indent);
866 try writer.writeAll(control.extra_data_begin.?.slice(tree.source));866 try writer.writeAll(control.extra_data_begin.?.slice(tree.source));
867 try writer.writeAll("\n");867 try writer.writeAll("\n");
868 for (control.extra_data) |data_node| {868 for (control.extra_data) |data_node| {
869 try data_node.dump(tree, writer, indent + 1);869 try data_node.dump(tree, writer, indent + 1);
870 }870 }
871 try writer.writeByteNTimes(' ', indent);871 try writer.splatByteAll(' ', indent);
872 try writer.writeAll(control.extra_data_end.?.slice(tree.source));872 try writer.writeAll(control.extra_data_end.?.slice(tree.source));
873 try writer.writeAll("\n");873 try writer.writeAll("\n");
874 }874 }
...@@ -877,17 +877,17 @@ pub const Node = struct {...@@ -877,17 +877,17 @@ pub const Node = struct {
877 const toolbar: *const Node.Toolbar = @alignCast(@fieldParentPtr("base", node));877 const toolbar: *const Node.Toolbar = @alignCast(@fieldParentPtr("base", node));
878 try writer.print(" {s} {s} [{d} common_resource_attributes]\n", .{ toolbar.id.slice(tree.source), toolbar.type.slice(tree.source), toolbar.common_resource_attributes.len });878 try writer.print(" {s} {s} [{d} common_resource_attributes]\n", .{ toolbar.id.slice(tree.source), toolbar.type.slice(tree.source), toolbar.common_resource_attributes.len });
879 inline for (.{ "button_width", "button_height" }) |arg| {879 inline for (.{ "button_width", "button_height" }) |arg| {
880 try writer.writeByteNTimes(' ', indent + 1);880 try writer.splatByteAll(' ', indent + 1);
881 try writer.writeAll(arg ++ ":\n");881 try writer.writeAll(arg ++ ":\n");
882 try @field(toolbar, arg).dump(tree, writer, indent + 2);882 try @field(toolbar, arg).dump(tree, writer, indent + 2);
883 }883 }
884 try writer.writeByteNTimes(' ', indent);884 try writer.splatByteAll(' ', indent);
885 try writer.writeAll(toolbar.begin_token.slice(tree.source));885 try writer.writeAll(toolbar.begin_token.slice(tree.source));
886 try writer.writeAll("\n");886 try writer.writeAll("\n");
887 for (toolbar.buttons) |button_or_sep| {887 for (toolbar.buttons) |button_or_sep| {
888 try button_or_sep.dump(tree, writer, indent + 1);888 try button_or_sep.dump(tree, writer, indent + 1);
889 }889 }
890 try writer.writeByteNTimes(' ', indent);890 try writer.splatByteAll(' ', indent);
891 try writer.writeAll(toolbar.end_token.slice(tree.source));891 try writer.writeAll(toolbar.end_token.slice(tree.source));
892 try writer.writeAll("\n");892 try writer.writeAll("\n");
893 },893 },
...@@ -898,17 +898,17 @@ pub const Node = struct {...@@ -898,17 +898,17 @@ pub const Node = struct {
898 try statement.dump(tree, writer, indent + 1);898 try statement.dump(tree, writer, indent + 1);
899 }899 }
900 if (menu.help_id) |help_id| {900 if (menu.help_id) |help_id| {
901 try writer.writeByteNTimes(' ', indent + 1);901 try writer.splatByteAll(' ', indent + 1);
902 try writer.writeAll("help_id:\n");902 try writer.writeAll("help_id:\n");
903 try help_id.dump(tree, writer, indent + 2);903 try help_id.dump(tree, writer, indent + 2);
904 }904 }
905 try writer.writeByteNTimes(' ', indent);905 try writer.splatByteAll(' ', indent);
906 try writer.writeAll(menu.begin_token.slice(tree.source));906 try writer.writeAll(menu.begin_token.slice(tree.source));
907 try writer.writeAll("\n");907 try writer.writeAll("\n");
908 for (menu.items) |item| {908 for (menu.items) |item| {
909 try item.dump(tree, writer, indent + 1);909 try item.dump(tree, writer, indent + 1);
910 }910 }
911 try writer.writeByteNTimes(' ', indent);911 try writer.splatByteAll(' ', indent);
912 try writer.writeAll(menu.end_token.slice(tree.source));912 try writer.writeAll(menu.end_token.slice(tree.source));
913 try writer.writeAll("\n");913 try writer.writeAll("\n");
914 },914 },
...@@ -926,7 +926,7 @@ pub const Node = struct {...@@ -926,7 +926,7 @@ pub const Node = struct {
926 try writer.print(" {s} {s}\n", .{ menu_item.menuitem.slice(tree.source), menu_item.text.slice(tree.source) });926 try writer.print(" {s} {s}\n", .{ menu_item.menuitem.slice(tree.source), menu_item.text.slice(tree.source) });
927 inline for (.{ "id", "type", "state" }) |arg| {927 inline for (.{ "id", "type", "state" }) |arg| {
928 if (@field(menu_item, arg)) |val_node| {928 if (@field(menu_item, arg)) |val_node| {
929 try writer.writeByteNTimes(' ', indent + 1);929 try writer.splatByteAll(' ', indent + 1);
930 try writer.writeAll(arg ++ ":\n");930 try writer.writeAll(arg ++ ":\n");
931 try val_node.dump(tree, writer, indent + 2);931 try val_node.dump(tree, writer, indent + 2);
932 }932 }
...@@ -935,13 +935,13 @@ pub const Node = struct {...@@ -935,13 +935,13 @@ pub const Node = struct {
935 .popup => {935 .popup => {
936 const popup: *const Node.Popup = @alignCast(@fieldParentPtr("base", node));936 const popup: *const Node.Popup = @alignCast(@fieldParentPtr("base", node));
937 try writer.print(" {s} {s} [{d} options]\n", .{ popup.popup.slice(tree.source), popup.text.slice(tree.source), popup.option_list.len });937 try writer.print(" {s} {s} [{d} options]\n", .{ popup.popup.slice(tree.source), popup.text.slice(tree.source), popup.option_list.len });
938 try writer.writeByteNTimes(' ', indent);938 try writer.splatByteAll(' ', indent);
939 try writer.writeAll(popup.begin_token.slice(tree.source));939 try writer.writeAll(popup.begin_token.slice(tree.source));
940 try writer.writeAll("\n");940 try writer.writeAll("\n");
941 for (popup.items) |item| {941 for (popup.items) |item| {
942 try item.dump(tree, writer, indent + 1);942 try item.dump(tree, writer, indent + 1);
943 }943 }
944 try writer.writeByteNTimes(' ', indent);944 try writer.splatByteAll(' ', indent);
945 try writer.writeAll(popup.end_token.slice(tree.source));945 try writer.writeAll(popup.end_token.slice(tree.source));
946 try writer.writeAll("\n");946 try writer.writeAll("\n");
947 },947 },
...@@ -950,18 +950,18 @@ pub const Node = struct {...@@ -950,18 +950,18 @@ pub const Node = struct {
950 try writer.print(" {s} {s}\n", .{ popup.popup.slice(tree.source), popup.text.slice(tree.source) });950 try writer.print(" {s} {s}\n", .{ popup.popup.slice(tree.source), popup.text.slice(tree.source) });
951 inline for (.{ "id", "type", "state", "help_id" }) |arg| {951 inline for (.{ "id", "type", "state", "help_id" }) |arg| {
952 if (@field(popup, arg)) |val_node| {952 if (@field(popup, arg)) |val_node| {
953 try writer.writeByteNTimes(' ', indent + 1);953 try writer.splatByteAll(' ', indent + 1);
954 try writer.writeAll(arg ++ ":\n");954 try writer.writeAll(arg ++ ":\n");
955 try val_node.dump(tree, writer, indent + 2);955 try val_node.dump(tree, writer, indent + 2);
956 }956 }
957 }957 }
958 try writer.writeByteNTimes(' ', indent);958 try writer.splatByteAll(' ', indent);
959 try writer.writeAll(popup.begin_token.slice(tree.source));959 try writer.writeAll(popup.begin_token.slice(tree.source));
960 try writer.writeAll("\n");960 try writer.writeAll("\n");
961 for (popup.items) |item| {961 for (popup.items) |item| {
962 try item.dump(tree, writer, indent + 1);962 try item.dump(tree, writer, indent + 1);
963 }963 }
964 try writer.writeByteNTimes(' ', indent);964 try writer.splatByteAll(' ', indent);
965 try writer.writeAll(popup.end_token.slice(tree.source));965 try writer.writeAll(popup.end_token.slice(tree.source));
966 try writer.writeAll("\n");966 try writer.writeAll("\n");
967 },967 },
...@@ -971,13 +971,13 @@ pub const Node = struct {...@@ -971,13 +971,13 @@ pub const Node = struct {
971 for (version_info.fixed_info) |fixed_info| {971 for (version_info.fixed_info) |fixed_info| {
972 try fixed_info.dump(tree, writer, indent + 1);972 try fixed_info.dump(tree, writer, indent + 1);
973 }973 }
974 try writer.writeByteNTimes(' ', indent);974 try writer.splatByteAll(' ', indent);
975 try writer.writeAll(version_info.begin_token.slice(tree.source));975 try writer.writeAll(version_info.begin_token.slice(tree.source));
976 try writer.writeAll("\n");976 try writer.writeAll("\n");
977 for (version_info.block_statements) |block| {977 for (version_info.block_statements) |block| {
978 try block.dump(tree, writer, indent + 1);978 try block.dump(tree, writer, indent + 1);
979 }979 }
980 try writer.writeByteNTimes(' ', indent);980 try writer.splatByteAll(' ', indent);
981 try writer.writeAll(version_info.end_token.slice(tree.source));981 try writer.writeAll(version_info.end_token.slice(tree.source));
982 try writer.writeAll("\n");982 try writer.writeAll("\n");
983 },983 },
...@@ -994,13 +994,13 @@ pub const Node = struct {...@@ -994,13 +994,13 @@ pub const Node = struct {
994 for (block.values) |value| {994 for (block.values) |value| {
995 try value.dump(tree, writer, indent + 1);995 try value.dump(tree, writer, indent + 1);
996 }996 }
997 try writer.writeByteNTimes(' ', indent);997 try writer.splatByteAll(' ', indent);
998 try writer.writeAll(block.begin_token.slice(tree.source));998 try writer.writeAll(block.begin_token.slice(tree.source));
999 try writer.writeAll("\n");999 try writer.writeAll("\n");
1000 for (block.children) |child| {1000 for (block.children) |child| {
1001 try child.dump(tree, writer, indent + 1);1001 try child.dump(tree, writer, indent + 1);
1002 }1002 }
1003 try writer.writeByteNTimes(' ', indent);1003 try writer.splatByteAll(' ', indent);
1004 try writer.writeAll(block.end_token.slice(tree.source));1004 try writer.writeAll(block.end_token.slice(tree.source));
1005 try writer.writeAll("\n");1005 try writer.writeAll("\n");
1006 },1006 },
...@@ -1025,13 +1025,13 @@ pub const Node = struct {...@@ -1025,13 +1025,13 @@ pub const Node = struct {
1025 for (string_table.optional_statements) |statement| {1025 for (string_table.optional_statements) |statement| {
1026 try statement.dump(tree, writer, indent + 1);1026 try statement.dump(tree, writer, indent + 1);
1027 }1027 }
1028 try writer.writeByteNTimes(' ', indent);1028 try writer.splatByteAll(' ', indent);
1029 try writer.writeAll(string_table.begin_token.slice(tree.source));1029 try writer.writeAll(string_table.begin_token.slice(tree.source));
1030 try writer.writeAll("\n");1030 try writer.writeAll("\n");
1031 for (string_table.strings) |string| {1031 for (string_table.strings) |string| {
1032 try string.dump(tree, writer, indent + 1);1032 try string.dump(tree, writer, indent + 1);
1033 }1033 }
1034 try writer.writeByteNTimes(' ', indent);1034 try writer.splatByteAll(' ', indent);
1035 try writer.writeAll(string_table.end_token.slice(tree.source));1035 try writer.writeAll(string_table.end_token.slice(tree.source));
1036 try writer.writeAll("\n");1036 try writer.writeAll("\n");
1037 },1037 },
...@@ -1039,7 +1039,7 @@ pub const Node = struct {...@@ -1039,7 +1039,7 @@ pub const Node = struct {
1039 try writer.writeAll("\n");1039 try writer.writeAll("\n");
1040 const string: *const Node.StringTableString = @alignCast(@fieldParentPtr("base", node));1040 const string: *const Node.StringTableString = @alignCast(@fieldParentPtr("base", node));
1041 try string.id.dump(tree, writer, indent + 1);1041 try string.id.dump(tree, writer, indent + 1);
1042 try writer.writeByteNTimes(' ', indent + 1);1042 try writer.splatByteAll(' ', indent + 1);
1043 try writer.print("{s}\n", .{string.string.slice(tree.source)});1043 try writer.print("{s}\n", .{string.string.slice(tree.source)});
1044 },1044 },
1045 .language_statement => {1045 .language_statement => {
...@@ -1051,12 +1051,12 @@ pub const Node = struct {...@@ -1051,12 +1051,12 @@ pub const Node = struct {
1051 .font_statement => {1051 .font_statement => {
1052 const font: *const Node.FontStatement = @alignCast(@fieldParentPtr("base", node));1052 const font: *const Node.FontStatement = @alignCast(@fieldParentPtr("base", node));
1053 try writer.print(" {s} typeface: {s}\n", .{ font.identifier.slice(tree.source), font.typeface.slice(tree.source) });1053 try writer.print(" {s} typeface: {s}\n", .{ font.identifier.slice(tree.source), font.typeface.slice(tree.source) });
1054 try writer.writeByteNTimes(' ', indent + 1);1054 try writer.splatByteAll(' ', indent + 1);
1055 try writer.writeAll("point_size:\n");1055 try writer.writeAll("point_size:\n");
1056 try font.point_size.dump(tree, writer, indent + 2);1056 try font.point_size.dump(tree, writer, indent + 2);
1057 inline for (.{ "weight", "italic", "char_set" }) |arg| {1057 inline for (.{ "weight", "italic", "char_set" }) |arg| {
1058 if (@field(font, arg)) |arg_node| {1058 if (@field(font, arg)) |arg_node| {
1059 try writer.writeByteNTimes(' ', indent + 1);1059 try writer.splatByteAll(' ', indent + 1);
1060 try writer.writeAll(arg ++ ":\n");1060 try writer.writeAll(arg ++ ":\n");
1061 try arg_node.dump(tree, writer, indent + 2);1061 try arg_node.dump(tree, writer, indent + 2);
1062 }1062 }
...@@ -1071,7 +1071,7 @@ pub const Node = struct {...@@ -1071,7 +1071,7 @@ pub const Node = struct {
1071 const invalid: *const Node.Invalid = @alignCast(@fieldParentPtr("base", node));1071 const invalid: *const Node.Invalid = @alignCast(@fieldParentPtr("base", node));
1072 try writer.print(" context.len: {}\n", .{invalid.context.len});1072 try writer.print(" context.len: {}\n", .{invalid.context.len});
1073 for (invalid.context) |context_token| {1073 for (invalid.context) |context_token| {
1074 try writer.writeByteNTimes(' ', indent + 1);1074 try writer.splatByteAll(' ', indent + 1);
1075 try writer.print("{s}:{s}", .{ @tagName(context_token.id), context_token.slice(tree.source) });1075 try writer.print("{s}:{s}", .{ @tagName(context_token.id), context_token.slice(tree.source) });
1076 try writer.writeByte('\n');1076 try writer.writeByte('\n');
1077 }1077 }
lib/compiler/resinator/bmp.zig+25-15
...@@ -27,6 +27,7 @@ pub const windows_format_id = std.mem.readInt(u16, "BM", native_endian);...@@ -27,6 +27,7 @@ pub const windows_format_id = std.mem.readInt(u16, "BM", native_endian);
27pub const file_header_len = 14;27pub const file_header_len = 14;
2828
29pub const ReadError = error{29pub const ReadError = error{
30 ReadFailed,
30 UnexpectedEOF,31 UnexpectedEOF,
31 InvalidFileHeader,32 InvalidFileHeader,
32 ImpossiblePixelDataOffset,33 ImpossiblePixelDataOffset,
...@@ -94,9 +95,12 @@ pub const BitmapInfo = struct {...@@ -94,9 +95,12 @@ pub const BitmapInfo = struct {
94 }95 }
95};96};
9697
97pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {98pub fn read(reader: *std.Io.Reader, max_size: u64) ReadError!BitmapInfo {
98 var bitmap_info: BitmapInfo = undefined;99 var bitmap_info: BitmapInfo = undefined;
99 const file_header = reader.readBytesNoEof(file_header_len) catch return error.UnexpectedEOF;100 const file_header = reader.takeArray(file_header_len) catch |err| switch (err) {
101 error.EndOfStream => return error.UnexpectedEOF,
102 else => |e| return e,
103 };
100104
101 const id = std.mem.readInt(u16, file_header[0..2], native_endian);105 const id = std.mem.readInt(u16, file_header[0..2], native_endian);
102 if (id != windows_format_id) return error.InvalidFileHeader;106 if (id != windows_format_id) return error.InvalidFileHeader;
...@@ -104,14 +108,17 @@ pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {...@@ -104,14 +108,17 @@ pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {
104 bitmap_info.pixel_data_offset = std.mem.readInt(u32, file_header[10..14], .little);108 bitmap_info.pixel_data_offset = std.mem.readInt(u32, file_header[10..14], .little);
105 if (bitmap_info.pixel_data_offset > max_size) return error.ImpossiblePixelDataOffset;109 if (bitmap_info.pixel_data_offset > max_size) return error.ImpossiblePixelDataOffset;
106110
107 bitmap_info.dib_header_size = reader.readInt(u32, .little) catch return error.UnexpectedEOF;111 bitmap_info.dib_header_size = reader.takeInt(u32, .little) catch return error.UnexpectedEOF;
108 if (bitmap_info.pixel_data_offset < file_header_len + bitmap_info.dib_header_size) return error.ImpossiblePixelDataOffset;112 if (bitmap_info.pixel_data_offset < file_header_len + bitmap_info.dib_header_size) return error.ImpossiblePixelDataOffset;
109 const dib_version = BitmapHeader.Version.get(bitmap_info.dib_header_size);113 const dib_version = BitmapHeader.Version.get(bitmap_info.dib_header_size);
110 switch (dib_version) {114 switch (dib_version) {
111 .@"nt3.1", .@"nt4.0", .@"nt5.0" => {115 .@"nt3.1", .@"nt4.0", .@"nt5.0" => {
112 var dib_header_buf: [@sizeOf(BITMAPINFOHEADER)]u8 align(@alignOf(BITMAPINFOHEADER)) = undefined;116 var dib_header_buf: [@sizeOf(BITMAPINFOHEADER)]u8 align(@alignOf(BITMAPINFOHEADER)) = undefined;
113 std.mem.writeInt(u32, dib_header_buf[0..4], bitmap_info.dib_header_size, .little);117 std.mem.writeInt(u32, dib_header_buf[0..4], bitmap_info.dib_header_size, .little);
114 reader.readNoEof(dib_header_buf[4..]) catch return error.UnexpectedEOF;118 reader.readSliceAll(dib_header_buf[4..]) catch |err| switch (err) {
119 error.EndOfStream => return error.UnexpectedEOF,
120 error.ReadFailed => |e| return e,
121 };
115 var dib_header: *BITMAPINFOHEADER = @ptrCast(&dib_header_buf);122 var dib_header: *BITMAPINFOHEADER = @ptrCast(&dib_header_buf);
116 structFieldsLittleToNative(BITMAPINFOHEADER, dib_header);123 structFieldsLittleToNative(BITMAPINFOHEADER, dib_header);
117124
...@@ -126,7 +133,10 @@ pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {...@@ -126,7 +133,10 @@ pub fn read(reader: anytype, max_size: u64) ReadError!BitmapInfo {
126 .@"win2.0" => {133 .@"win2.0" => {
127 var dib_header_buf: [@sizeOf(BITMAPCOREHEADER)]u8 align(@alignOf(BITMAPCOREHEADER)) = undefined;134 var dib_header_buf: [@sizeOf(BITMAPCOREHEADER)]u8 align(@alignOf(BITMAPCOREHEADER)) = undefined;
128 std.mem.writeInt(u32, dib_header_buf[0..4], bitmap_info.dib_header_size, .little);135 std.mem.writeInt(u32, dib_header_buf[0..4], bitmap_info.dib_header_size, .little);
129 reader.readNoEof(dib_header_buf[4..]) catch return error.UnexpectedEOF;136 reader.readSliceAll(dib_header_buf[4..]) catch |err| switch (err) {
137 error.EndOfStream => return error.UnexpectedEOF,
138 error.ReadFailed => |e| return e,
139 };
130 const dib_header: *BITMAPCOREHEADER = @ptrCast(&dib_header_buf);140 const dib_header: *BITMAPCOREHEADER = @ptrCast(&dib_header_buf);
131 structFieldsLittleToNative(BITMAPCOREHEADER, dib_header);141 structFieldsLittleToNative(BITMAPCOREHEADER, dib_header);
132142
...@@ -238,26 +248,26 @@ fn structFieldsLittleToNative(comptime T: type, x: *T) void {...@@ -238,26 +248,26 @@ fn structFieldsLittleToNative(comptime T: type, x: *T) void {
238248
239test "read" {249test "read" {
240 var bmp_data = "BM<\x00\x00\x00\x00\x00\x00\x006\x00\x00\x00(\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x10\x00\x00\x00\x00\x00\x06\x00\x00\x00\x12\x0b\x00\x00\x12\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x7f\x00\x00\x00\x00".*;250 var bmp_data = "BM<\x00\x00\x00\x00\x00\x00\x006\x00\x00\x00(\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x10\x00\x00\x00\x00\x00\x06\x00\x00\x00\x12\x0b\x00\x00\x12\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x7f\x00\x00\x00\x00".*;
241 var fbs = std.io.fixedBufferStream(&bmp_data);251 var fbs: std.Io.Reader = .fixed(&bmp_data);
242252
243 {253 {
244 const bitmap = try read(fbs.reader(), bmp_data.len);254 const bitmap = try read(&fbs, bmp_data.len);
245 try std.testing.expectEqual(@as(u32, BitmapHeader.Version.@"nt3.1".len()), bitmap.dib_header_size);255 try std.testing.expectEqual(@as(u32, BitmapHeader.Version.@"nt3.1".len()), bitmap.dib_header_size);
246 }256 }
247257
248 {258 {
249 fbs.reset();259 fbs.seek = 0;
250 bmp_data[file_header_len] = 11;260 bmp_data[file_header_len] = 11;
251 try std.testing.expectError(error.UnknownBitmapVersion, read(fbs.reader(), bmp_data.len));261 try std.testing.expectError(error.UnknownBitmapVersion, read(&fbs, bmp_data.len));
252262
253 // restore263 // restore
254 bmp_data[file_header_len] = BitmapHeader.Version.@"nt3.1".len();264 bmp_data[file_header_len] = BitmapHeader.Version.@"nt3.1".len();
255 }265 }
256266
257 {267 {
258 fbs.reset();268 fbs.seek = 0;
259 bmp_data[0] = 'b';269 bmp_data[0] = 'b';
260 try std.testing.expectError(error.InvalidFileHeader, read(fbs.reader(), bmp_data.len));270 try std.testing.expectError(error.InvalidFileHeader, read(&fbs, bmp_data.len));
261271
262 // restore272 // restore
263 bmp_data[0] = 'B';273 bmp_data[0] = 'B';
...@@ -265,13 +275,13 @@ test "read" {...@@ -265,13 +275,13 @@ test "read" {
265275
266 {276 {
267 const cutoff_len = file_header_len + BitmapHeader.Version.@"nt3.1".len() - 1;277 const cutoff_len = file_header_len + BitmapHeader.Version.@"nt3.1".len() - 1;
268 var dib_cutoff_fbs = std.io.fixedBufferStream(bmp_data[0..cutoff_len]);278 var dib_cutoff_fbs: std.Io.Reader = .fixed(bmp_data[0..cutoff_len]);
269 try std.testing.expectError(error.UnexpectedEOF, read(dib_cutoff_fbs.reader(), bmp_data.len));279 try std.testing.expectError(error.UnexpectedEOF, read(&dib_cutoff_fbs, bmp_data.len));
270 }280 }
271281
272 {282 {
273 const cutoff_len = file_header_len - 1;283 const cutoff_len = file_header_len - 1;
274 var bmp_cutoff_fbs = std.io.fixedBufferStream(bmp_data[0..cutoff_len]);284 var bmp_cutoff_fbs: std.Io.Reader = .fixed(bmp_data[0..cutoff_len]);
275 try std.testing.expectError(error.UnexpectedEOF, read(bmp_cutoff_fbs.reader(), bmp_data.len));285 try std.testing.expectError(error.UnexpectedEOF, read(&bmp_cutoff_fbs, bmp_data.len));
276 }286 }
277}287}
lib/compiler/resinator/cli.zig+77-138
...@@ -80,20 +80,20 @@ pub const usage_string_after_command_name =...@@ -80,20 +80,20 @@ pub const usage_string_after_command_name =
80 \\80 \\
81;81;
8282
83pub fn writeUsage(writer: anytype, command_name: []const u8) !void {83pub fn writeUsage(writer: *std.Io.Writer, command_name: []const u8) !void {
84 try writer.writeAll("Usage: ");84 try writer.writeAll("Usage: ");
85 try writer.writeAll(command_name);85 try writer.writeAll(command_name);
86 try writer.writeAll(usage_string_after_command_name);86 try writer.writeAll(usage_string_after_command_name);
87}87}
8888
89pub const Diagnostics = struct {89pub const Diagnostics = struct {
90 errors: std.ArrayListUnmanaged(ErrorDetails) = .empty,90 errors: std.ArrayList(ErrorDetails) = .empty,
91 allocator: Allocator,91 allocator: Allocator,
9292
93 pub const ErrorDetails = struct {93 pub const ErrorDetails = struct {
94 arg_index: usize,94 arg_index: usize,
95 arg_span: ArgSpan = .{},95 arg_span: ArgSpan = .{},
96 msg: std.ArrayListUnmanaged(u8) = .empty,96 msg: std.ArrayList(u8) = .empty,
97 type: Type = .err,97 type: Type = .err,
98 print_args: bool = true,98 print_args: bool = true,
9999
...@@ -148,7 +148,7 @@ pub const Options = struct {...@@ -148,7 +148,7 @@ pub const Options = struct {
148 allocator: Allocator,148 allocator: Allocator,
149 input_source: IoSource = .{ .filename = &[_]u8{} },149 input_source: IoSource = .{ .filename = &[_]u8{} },
150 output_source: IoSource = .{ .filename = &[_]u8{} },150 output_source: IoSource = .{ .filename = &[_]u8{} },
151 extra_include_paths: std.ArrayListUnmanaged([]const u8) = .empty,151 extra_include_paths: std.ArrayList([]const u8) = .empty,
152 ignore_include_env_var: bool = false,152 ignore_include_env_var: bool = false,
153 preprocess: Preprocess = .yes,153 preprocess: Preprocess = .yes,
154 default_language_id: ?u16 = null,154 default_language_id: ?u16 = null,
...@@ -295,7 +295,7 @@ pub const Options = struct {...@@ -295,7 +295,7 @@ pub const Options = struct {
295 }295 }
296 }296 }
297297
298 pub fn dumpVerbose(self: *const Options, writer: anytype) !void {298 pub fn dumpVerbose(self: *const Options, writer: *std.Io.Writer) !void {
299 const input_source_name = switch (self.input_source) {299 const input_source_name = switch (self.input_source) {
300 .stdio => "<stdin>",300 .stdio => "<stdin>",
301 .filename => |filename| filename,301 .filename => |filename| filename,
...@@ -520,8 +520,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -520,8 +520,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
520 // - or / on its own is an error520 // - or / on its own is an error
521 else => {521 else => {
522 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };522 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
523 var msg_writer = err_details.msg.writer(allocator);523 try err_details.msg.print(allocator, "invalid option: {s}", .{arg.prefixSlice()});
524 try msg_writer.print("invalid option: {s}", .{arg.prefixSlice()});
525 try diagnostics.append(err_details);524 try diagnostics.append(err_details);
526 arg_i += 1;525 arg_i += 1;
527 continue :next_arg;526 continue :next_arg;
...@@ -532,8 +531,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -532,8 +531,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
532 const args_remaining = args.len - arg_i;531 const args_remaining = args.len - arg_i;
533 if (args_remaining <= 2 and arg.looksLikeFilepath()) {532 if (args_remaining <= 2 and arg.looksLikeFilepath()) {
534 var err_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = true, .arg_index = arg_i };533 var err_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = true, .arg_index = arg_i };
535 var msg_writer = err_details.msg.writer(allocator);534 try err_details.msg.appendSlice(allocator, "this argument was inferred to be a filepath, so argument parsing was terminated");
536 try msg_writer.writeAll("this argument was inferred to be a filepath, so argument parsing was terminated");
537 try diagnostics.append(err_details);535 try diagnostics.append(err_details);
538536
539 break;537 break;
...@@ -550,16 +548,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -550,16 +548,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
550 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":output-format")) {548 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":output-format")) {
551 const value = arg.value(":output-format".len, arg_i, args) catch {549 const value = arg.value(":output-format".len, arg_i, args) catch {
552 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };550 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
553 var msg_writer = err_details.msg.writer(allocator);551 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":output-format".len) });
554 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":output-format".len) });
555 try diagnostics.append(err_details);552 try diagnostics.append(err_details);
556 arg_i += 1;553 arg_i += 1;
557 break :next_arg;554 break :next_arg;
558 };555 };
559 output_format = std.meta.stringToEnum(Options.OutputFormat, value.slice) orelse blk: {556 output_format = std.meta.stringToEnum(Options.OutputFormat, value.slice) orelse blk: {
560 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };557 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
561 var msg_writer = err_details.msg.writer(allocator);558 try err_details.msg.print(allocator, "invalid output format setting: {s} ", .{value.slice});
562 try msg_writer.print("invalid output format setting: {s} ", .{value.slice});
563 try diagnostics.append(err_details);559 try diagnostics.append(err_details);
564 break :blk output_format;560 break :blk output_format;
565 };561 };
...@@ -569,16 +565,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -569,16 +565,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
569 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":auto-includes")) {565 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":auto-includes")) {
570 const value = arg.value(":auto-includes".len, arg_i, args) catch {566 const value = arg.value(":auto-includes".len, arg_i, args) catch {
571 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };567 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
572 var msg_writer = err_details.msg.writer(allocator);568 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":auto-includes".len) });
573 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":auto-includes".len) });
574 try diagnostics.append(err_details);569 try diagnostics.append(err_details);
575 arg_i += 1;570 arg_i += 1;
576 break :next_arg;571 break :next_arg;
577 };572 };
578 options.auto_includes = std.meta.stringToEnum(Options.AutoIncludes, value.slice) orelse blk: {573 options.auto_includes = std.meta.stringToEnum(Options.AutoIncludes, value.slice) orelse blk: {
579 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };574 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
580 var msg_writer = err_details.msg.writer(allocator);575 try err_details.msg.print(allocator, "invalid auto includes setting: {s} ", .{value.slice});
581 try msg_writer.print("invalid auto includes setting: {s} ", .{value.slice});
582 try diagnostics.append(err_details);576 try diagnostics.append(err_details);
583 break :blk options.auto_includes;577 break :blk options.auto_includes;
584 };578 };
...@@ -587,16 +581,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -587,16 +581,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
587 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":input-format")) {581 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":input-format")) {
588 const value = arg.value(":input-format".len, arg_i, args) catch {582 const value = arg.value(":input-format".len, arg_i, args) catch {
589 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };583 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
590 var msg_writer = err_details.msg.writer(allocator);584 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":input-format".len) });
591 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":input-format".len) });
592 try diagnostics.append(err_details);585 try diagnostics.append(err_details);
593 arg_i += 1;586 arg_i += 1;
594 break :next_arg;587 break :next_arg;
595 };588 };
596 input_format = std.meta.stringToEnum(Options.InputFormat, value.slice) orelse blk: {589 input_format = std.meta.stringToEnum(Options.InputFormat, value.slice) orelse blk: {
597 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };590 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
598 var msg_writer = err_details.msg.writer(allocator);591 try err_details.msg.print(allocator, "invalid input format setting: {s} ", .{value.slice});
599 try msg_writer.print("invalid input format setting: {s} ", .{value.slice});
600 try diagnostics.append(err_details);592 try diagnostics.append(err_details);
601 break :blk input_format;593 break :blk input_format;
602 };594 };
...@@ -606,16 +598,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -606,16 +598,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
606 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":depfile-fmt")) {598 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":depfile-fmt")) {
607 const value = arg.value(":depfile-fmt".len, arg_i, args) catch {599 const value = arg.value(":depfile-fmt".len, arg_i, args) catch {
608 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };600 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
609 var msg_writer = err_details.msg.writer(allocator);601 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile-fmt".len) });
610 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile-fmt".len) });
611 try diagnostics.append(err_details);602 try diagnostics.append(err_details);
612 arg_i += 1;603 arg_i += 1;
613 break :next_arg;604 break :next_arg;
614 };605 };
615 options.depfile_fmt = std.meta.stringToEnum(Options.DepfileFormat, value.slice) orelse blk: {606 options.depfile_fmt = std.meta.stringToEnum(Options.DepfileFormat, value.slice) orelse blk: {
616 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };607 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
617 var msg_writer = err_details.msg.writer(allocator);608 try err_details.msg.print(allocator, "invalid depfile format setting: {s} ", .{value.slice});
618 try msg_writer.print("invalid depfile format setting: {s} ", .{value.slice});
619 try diagnostics.append(err_details);609 try diagnostics.append(err_details);
620 break :blk options.depfile_fmt;610 break :blk options.depfile_fmt;
621 };611 };
...@@ -624,8 +614,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -624,8 +614,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
624 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":depfile")) {614 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":depfile")) {
625 const value = arg.value(":depfile".len, arg_i, args) catch {615 const value = arg.value(":depfile".len, arg_i, args) catch {
626 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };616 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
627 var msg_writer = err_details.msg.writer(allocator);617 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile".len) });
628 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":depfile".len) });
629 try diagnostics.append(err_details);618 try diagnostics.append(err_details);
630 arg_i += 1;619 arg_i += 1;
631 break :next_arg;620 break :next_arg;
...@@ -643,8 +632,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -643,8 +632,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
643 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":target")) {632 } else if (std.ascii.startsWithIgnoreCase(arg_name, ":target")) {
644 const value = arg.value(":target".len, arg_i, args) catch {633 const value = arg.value(":target".len, arg_i, args) catch {
645 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };634 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
646 var msg_writer = err_details.msg.writer(allocator);635 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":target".len) });
647 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(":target".len) });
648 try diagnostics.append(err_details);636 try diagnostics.append(err_details);
649 arg_i += 1;637 arg_i += 1;
650 break :next_arg;638 break :next_arg;
...@@ -655,8 +643,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -655,8 +643,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
655 const arch_str = target_it.first();643 const arch_str = target_it.first();
656 const arch = cvtres.supported_targets.Arch.fromStringIgnoreCase(arch_str) orelse {644 const arch = cvtres.supported_targets.Arch.fromStringIgnoreCase(arch_str) orelse {
657 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };645 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
658 var msg_writer = err_details.msg.writer(allocator);646 try err_details.msg.print(allocator, "invalid or unsupported target architecture: {s}", .{arch_str});
659 try msg_writer.print("invalid or unsupported target architecture: {s}", .{arch_str});
660 try diagnostics.append(err_details);647 try diagnostics.append(err_details);
661 arg_i += value.index_increment;648 arg_i += value.index_increment;
662 continue :next_arg;649 continue :next_arg;
...@@ -680,13 +667,11 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -680,13 +667,11 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
680 .prefix_len = arg.prefixSlice().len,667 .prefix_len = arg.prefixSlice().len,
681 .value_offset = arg.name_offset + 3,668 .value_offset = arg.name_offset + 3,
682 } };669 } };
683 var msg_writer = err_details.msg.writer(allocator);670 try err_details.msg.print(allocator, "missing value for {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
684 try msg_writer.print("missing value for {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
685 try diagnostics.append(err_details);671 try diagnostics.append(err_details);
686 }672 }
687 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };673 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
688 var msg_writer = err_details.msg.writer(allocator);674 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
689 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(3) });
690 try diagnostics.append(err_details);675 try diagnostics.append(err_details);
691 arg_i += 1;676 arg_i += 1;
692 continue :next_arg;677 continue :next_arg;
...@@ -695,16 +680,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -695,16 +680,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
695 else if (std.ascii.startsWithIgnoreCase(arg_name, "tn")) {680 else if (std.ascii.startsWithIgnoreCase(arg_name, "tn")) {
696 const value = arg.value(2, arg_i, args) catch no_value: {681 const value = arg.value(2, arg_i, args) catch no_value: {
697 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };682 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
698 var msg_writer = err_details.msg.writer(allocator);683 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
699 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
700 try diagnostics.append(err_details);684 try diagnostics.append(err_details);
701 // dummy zero-length slice starting where the value would have been685 // dummy zero-length slice starting where the value would have been
702 const value_start = arg.name_offset + 2;686 const value_start = arg.name_offset + 2;
703 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };687 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
704 };688 };
705 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };689 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
706 var msg_writer = err_details.msg.writer(allocator);690 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
707 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
708 try diagnostics.append(err_details);691 try diagnostics.append(err_details);
709 arg_i += value.index_increment;692 arg_i += value.index_increment;
710 continue :next_arg;693 continue :next_arg;
...@@ -716,16 +699,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -716,16 +699,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
716 {699 {
717 const value = arg.value(2, arg_i, args) catch no_value: {700 const value = arg.value(2, arg_i, args) catch no_value: {
718 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };701 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
719 var msg_writer = err_details.msg.writer(allocator);702 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
720 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
721 try diagnostics.append(err_details);703 try diagnostics.append(err_details);
722 // dummy zero-length slice starting where the value would have been704 // dummy zero-length slice starting where the value would have been
723 const value_start = arg.name_offset + 2;705 const value_start = arg.name_offset + 2;
724 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };706 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
725 };707 };
726 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };708 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
727 var msg_writer = err_details.msg.writer(allocator);709 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
728 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
729 try diagnostics.append(err_details);710 try diagnostics.append(err_details);
730 arg_i += value.index_increment;711 arg_i += value.index_increment;
731 continue :next_arg;712 continue :next_arg;
...@@ -733,8 +714,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -733,8 +714,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
733 // Unsupported MUI options that do not need a value714 // Unsupported MUI options that do not need a value
734 else if (std.ascii.startsWithIgnoreCase(arg_name, "g1")) {715 else if (std.ascii.startsWithIgnoreCase(arg_name, "g1")) {
735 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(2) };716 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(2) };
736 var msg_writer = err_details.msg.writer(allocator);717 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
737 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
738 try diagnostics.append(err_details);718 try diagnostics.append(err_details);
739 arg.name_offset += 2;719 arg.name_offset += 2;
740 }720 }
...@@ -747,15 +727,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -747,15 +727,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
747 std.ascii.startsWithIgnoreCase(arg_name, "ta"))727 std.ascii.startsWithIgnoreCase(arg_name, "ta"))
748 {728 {
749 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(2) };729 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(2) };
750 var msg_writer = err_details.msg.writer(allocator);730 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
751 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
752 try diagnostics.append(err_details);731 try diagnostics.append(err_details);
753 arg.name_offset += 2;732 arg.name_offset += 2;
754 } else if (std.ascii.startsWithIgnoreCase(arg_name, "fo")) {733 } else if (std.ascii.startsWithIgnoreCase(arg_name, "fo")) {
755 const value = arg.value(2, arg_i, args) catch {734 const value = arg.value(2, arg_i, args) catch {
756 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };735 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
757 var msg_writer = err_details.msg.writer(allocator);736 try err_details.msg.print(allocator, "missing output path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
758 try msg_writer.print("missing output path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
759 try diagnostics.append(err_details);737 try diagnostics.append(err_details);
760 arg_i += 1;738 arg_i += 1;
761 break :next_arg;739 break :next_arg;
...@@ -767,8 +745,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -767,8 +745,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
767 } else if (std.ascii.startsWithIgnoreCase(arg_name, "sl")) {745 } else if (std.ascii.startsWithIgnoreCase(arg_name, "sl")) {
768 const value = arg.value(2, arg_i, args) catch {746 const value = arg.value(2, arg_i, args) catch {
769 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };747 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
770 var msg_writer = err_details.msg.writer(allocator);748 try err_details.msg.print(allocator, "missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
771 try msg_writer.print("missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
772 try diagnostics.append(err_details);749 try diagnostics.append(err_details);
773 arg_i += 1;750 arg_i += 1;
774 break :next_arg;751 break :next_arg;
...@@ -776,24 +753,20 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -776,24 +753,20 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
776 const percent_str = value.slice;753 const percent_str = value.slice;
777 const percent: u32 = parsePercent(percent_str) catch {754 const percent: u32 = parsePercent(percent_str) catch {
778 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };755 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
779 var msg_writer = err_details.msg.writer(allocator);756 try err_details.msg.print(allocator, "invalid percent format '{s}'", .{percent_str});
780 try msg_writer.print("invalid percent format '{s}'", .{percent_str});
781 try diagnostics.append(err_details);757 try diagnostics.append(err_details);
782 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = false, .arg_index = arg_i };758 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = false, .arg_index = arg_i };
783 var note_writer = note_details.msg.writer(allocator);759 try note_details.msg.appendSlice(allocator, "string length percent must be an integer between 1 and 100 (inclusive)");
784 try note_writer.writeAll("string length percent must be an integer between 1 and 100 (inclusive)");
785 try diagnostics.append(note_details);760 try diagnostics.append(note_details);
786 arg_i += value.index_increment;761 arg_i += value.index_increment;
787 continue :next_arg;762 continue :next_arg;
788 };763 };
789 if (percent == 0 or percent > 100) {764 if (percent == 0 or percent > 100) {
790 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };765 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
791 var msg_writer = err_details.msg.writer(allocator);766 try err_details.msg.print(allocator, "percent out of range: {} (parsed from '{s}')", .{ percent, percent_str });
792 try msg_writer.print("percent out of range: {} (parsed from '{s}')", .{ percent, percent_str });
793 try diagnostics.append(err_details);767 try diagnostics.append(err_details);
794 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = false, .arg_index = arg_i };768 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = false, .arg_index = arg_i };
795 var note_writer = note_details.msg.writer(allocator);769 try note_details.msg.appendSlice(allocator, "string length percent must be an integer between 1 and 100 (inclusive)");
796 try note_writer.writeAll("string length percent must be an integer between 1 and 100 (inclusive)");
797 try diagnostics.append(note_details);770 try diagnostics.append(note_details);
798 arg_i += value.index_increment;771 arg_i += value.index_increment;
799 continue :next_arg;772 continue :next_arg;
...@@ -805,8 +778,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -805,8 +778,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
805 } else if (std.ascii.startsWithIgnoreCase(arg_name, "ln")) {778 } else if (std.ascii.startsWithIgnoreCase(arg_name, "ln")) {
806 const value = arg.value(2, arg_i, args) catch {779 const value = arg.value(2, arg_i, args) catch {
807 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };780 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
808 var msg_writer = err_details.msg.writer(allocator);781 try err_details.msg.print(allocator, "missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
809 try msg_writer.print("missing language tag after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(2) });
810 try diagnostics.append(err_details);782 try diagnostics.append(err_details);
811 arg_i += 1;783 arg_i += 1;
812 break :next_arg;784 break :next_arg;
...@@ -814,16 +786,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -814,16 +786,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
814 const tag = value.slice;786 const tag = value.slice;
815 options.default_language_id = lang.tagToInt(tag) catch {787 options.default_language_id = lang.tagToInt(tag) catch {
816 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };788 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
817 var msg_writer = err_details.msg.writer(allocator);789 try err_details.msg.print(allocator, "invalid language tag: {s}", .{tag});
818 try msg_writer.print("invalid language tag: {s}", .{tag});
819 try diagnostics.append(err_details);790 try diagnostics.append(err_details);
820 arg_i += value.index_increment;791 arg_i += value.index_increment;
821 continue :next_arg;792 continue :next_arg;
822 };793 };
823 if (options.default_language_id.? == lang.LOCALE_CUSTOM_UNSPECIFIED) {794 if (options.default_language_id.? == lang.LOCALE_CUSTOM_UNSPECIFIED) {
824 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };795 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };
825 var msg_writer = err_details.msg.writer(allocator);796 try err_details.msg.print(allocator, "language tag '{s}' does not have an assigned ID so it will be resolved to LOCALE_CUSTOM_UNSPECIFIED (id=0x{x})", .{ tag, lang.LOCALE_CUSTOM_UNSPECIFIED });
826 try msg_writer.print("language tag '{s}' does not have an assigned ID so it will be resolved to LOCALE_CUSTOM_UNSPECIFIED (id=0x{x})", .{ tag, lang.LOCALE_CUSTOM_UNSPECIFIED });
827 try diagnostics.append(err_details);797 try diagnostics.append(err_details);
828 }798 }
829 arg_i += value.index_increment;799 arg_i += value.index_increment;
...@@ -831,8 +801,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -831,8 +801,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
831 } else if (std.ascii.startsWithIgnoreCase(arg_name, "l")) {801 } else if (std.ascii.startsWithIgnoreCase(arg_name, "l")) {
832 const value = arg.value(1, arg_i, args) catch {802 const value = arg.value(1, arg_i, args) catch {
833 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };803 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
834 var msg_writer = err_details.msg.writer(allocator);804 try err_details.msg.print(allocator, "missing language ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
835 try msg_writer.print("missing language ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
836 try diagnostics.append(err_details);805 try diagnostics.append(err_details);
837 arg_i += 1;806 arg_i += 1;
838 break :next_arg;807 break :next_arg;
...@@ -840,8 +809,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -840,8 +809,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
840 const num_str = value.slice;809 const num_str = value.slice;
841 options.default_language_id = lang.parseInt(num_str) catch {810 options.default_language_id = lang.parseInt(num_str) catch {
842 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };811 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
843 var msg_writer = err_details.msg.writer(allocator);812 try err_details.msg.print(allocator, "invalid language ID: {s}", .{num_str});
844 try msg_writer.print("invalid language ID: {s}", .{num_str});
845 try diagnostics.append(err_details);813 try diagnostics.append(err_details);
846 arg_i += value.index_increment;814 arg_i += value.index_increment;
847 continue :next_arg;815 continue :next_arg;
...@@ -860,16 +828,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -860,16 +828,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
860 {828 {
861 const value = arg.value(1, arg_i, args) catch no_value: {829 const value = arg.value(1, arg_i, args) catch no_value: {
862 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };830 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
863 var msg_writer = err_details.msg.writer(allocator);831 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
864 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
865 try diagnostics.append(err_details);832 try diagnostics.append(err_details);
866 // dummy zero-length slice starting where the value would have been833 // dummy zero-length slice starting where the value would have been
867 const value_start = arg.name_offset + 1;834 const value_start = arg.name_offset + 1;
868 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };835 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
869 };836 };
870 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };837 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
871 var msg_writer = err_details.msg.writer(allocator);838 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
872 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
873 try diagnostics.append(err_details);839 try diagnostics.append(err_details);
874 arg_i += value.index_increment;840 arg_i += value.index_increment;
875 continue :next_arg;841 continue :next_arg;
...@@ -882,16 +848,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -882,16 +848,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
882 {848 {
883 const value = arg.value(1, arg_i, args) catch no_value: {849 const value = arg.value(1, arg_i, args) catch no_value: {
884 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };850 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
885 var msg_writer = err_details.msg.writer(allocator);851 try err_details.msg.print(allocator, "missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
886 try msg_writer.print("missing value after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
887 try diagnostics.append(err_details);852 try diagnostics.append(err_details);
888 // dummy zero-length slice starting where the value would have been853 // dummy zero-length slice starting where the value would have been
889 const value_start = arg.name_offset + 1;854 const value_start = arg.name_offset + 1;
890 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };855 break :no_value Arg.Value{ .slice = arg.full[value_start..value_start] };
891 };856 };
892 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };857 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
893 var msg_writer = err_details.msg.writer(allocator);858 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
894 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
895 try diagnostics.append(err_details);859 try diagnostics.append(err_details);
896 arg_i += value.index_increment;860 arg_i += value.index_increment;
897 continue :next_arg;861 continue :next_arg;
...@@ -899,15 +863,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -899,15 +863,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
899 // 1 char unsupported LCX/LCE options that do not need a value863 // 1 char unsupported LCX/LCE options that do not need a value
900 else if (std.ascii.startsWithIgnoreCase(arg_name, "t")) {864 else if (std.ascii.startsWithIgnoreCase(arg_name, "t")) {
901 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(1) };865 var err_details = Diagnostics.ErrorDetails{ .type = .err, .arg_index = arg_i, .arg_span = arg.optionSpan(1) };
902 var msg_writer = err_details.msg.writer(allocator);866 try err_details.msg.print(allocator, "the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
903 try msg_writer.print("the {s}{s} option is unsupported", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
904 try diagnostics.append(err_details);867 try diagnostics.append(err_details);
905 arg.name_offset += 1;868 arg.name_offset += 1;
906 } else if (std.ascii.startsWithIgnoreCase(arg_name, "c")) {869 } else if (std.ascii.startsWithIgnoreCase(arg_name, "c")) {
907 const value = arg.value(1, arg_i, args) catch {870 const value = arg.value(1, arg_i, args) catch {
908 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };871 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
909 var msg_writer = err_details.msg.writer(allocator);872 try err_details.msg.print(allocator, "missing code page ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
910 try msg_writer.print("missing code page ID after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
911 try diagnostics.append(err_details);873 try diagnostics.append(err_details);
912 arg_i += 1;874 arg_i += 1;
913 break :next_arg;875 break :next_arg;
...@@ -915,8 +877,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -915,8 +877,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
915 const num_str = value.slice;877 const num_str = value.slice;
916 const code_page_id = std.fmt.parseUnsigned(u16, num_str, 10) catch {878 const code_page_id = std.fmt.parseUnsigned(u16, num_str, 10) catch {
917 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };879 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
918 var msg_writer = err_details.msg.writer(allocator);880 try err_details.msg.print(allocator, "invalid code page ID: {s}", .{num_str});
919 try msg_writer.print("invalid code page ID: {s}", .{num_str});
920 try diagnostics.append(err_details);881 try diagnostics.append(err_details);
921 arg_i += value.index_increment;882 arg_i += value.index_increment;
922 continue :next_arg;883 continue :next_arg;
...@@ -924,16 +885,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -924,16 +885,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
924 options.default_code_page = code_pages.getByIdentifierEnsureSupported(code_page_id) catch |err| switch (err) {885 options.default_code_page = code_pages.getByIdentifierEnsureSupported(code_page_id) catch |err| switch (err) {
925 error.InvalidCodePage => {886 error.InvalidCodePage => {
926 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };887 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
927 var msg_writer = err_details.msg.writer(allocator);888 try err_details.msg.print(allocator, "invalid or unknown code page ID: {}", .{code_page_id});
928 try msg_writer.print("invalid or unknown code page ID: {}", .{code_page_id});
929 try diagnostics.append(err_details);889 try diagnostics.append(err_details);
930 arg_i += value.index_increment;890 arg_i += value.index_increment;
931 continue :next_arg;891 continue :next_arg;
932 },892 },
933 error.UnsupportedCodePage => {893 error.UnsupportedCodePage => {
934 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };894 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = value.argSpan(arg) };
935 var msg_writer = err_details.msg.writer(allocator);895 try err_details.msg.print(allocator, "unsupported code page: {s} (id={})", .{
936 try msg_writer.print("unsupported code page: {s} (id={})", .{
937 @tagName(code_pages.getByIdentifier(code_page_id) catch unreachable),896 @tagName(code_pages.getByIdentifier(code_page_id) catch unreachable),
938 code_page_id,897 code_page_id,
939 });898 });
...@@ -957,8 +916,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -957,8 +916,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
957 } else if (std.ascii.startsWithIgnoreCase(arg_name, "i")) {916 } else if (std.ascii.startsWithIgnoreCase(arg_name, "i")) {
958 const value = arg.value(1, arg_i, args) catch {917 const value = arg.value(1, arg_i, args) catch {
959 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };918 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
960 var msg_writer = err_details.msg.writer(allocator);919 try err_details.msg.print(allocator, "missing include path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
961 try msg_writer.print("missing include path after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
962 try diagnostics.append(err_details);920 try diagnostics.append(err_details);
963 arg_i += 1;921 arg_i += 1;
964 break :next_arg;922 break :next_arg;
...@@ -986,15 +944,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -986,15 +944,13 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
986 // Undocumented option with unknown function944 // Undocumented option with unknown function
987 // TODO: More investigation to figure out what it does (if anything)945 // TODO: More investigation to figure out what it does (if anything)
988 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = arg.optionSpan(1) };946 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = arg.optionSpan(1) };
989 var msg_writer = err_details.msg.writer(allocator);947 try err_details.msg.print(allocator, "option {s}{s} has no effect (it is undocumented and its function is unknown in the Win32 RC compiler)", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
990 try msg_writer.print("option {s}{s} has no effect (it is undocumented and its function is unknown in the Win32 RC compiler)", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
991 try diagnostics.append(err_details);948 try diagnostics.append(err_details);
992 arg.name_offset += 1;949 arg.name_offset += 1;
993 } else if (std.ascii.startsWithIgnoreCase(arg_name, "d")) {950 } else if (std.ascii.startsWithIgnoreCase(arg_name, "d")) {
994 const value = arg.value(1, arg_i, args) catch {951 const value = arg.value(1, arg_i, args) catch {
995 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };952 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
996 var msg_writer = err_details.msg.writer(allocator);953 try err_details.msg.print(allocator, "missing symbol to define after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
997 try msg_writer.print("missing symbol to define after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
998 try diagnostics.append(err_details);954 try diagnostics.append(err_details);
999 arg_i += 1;955 arg_i += 1;
1000 break :next_arg;956 break :next_arg;
...@@ -1009,8 +965,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1009,8 +965,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1009 try options.define(symbol, symbol_value);965 try options.define(symbol, symbol_value);
1010 } else {966 } else {
1011 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };967 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };
1012 var msg_writer = err_details.msg.writer(allocator);968 try err_details.msg.print(allocator, "symbol \"{s}\" is not a valid identifier and therefore cannot be defined", .{symbol});
1013 try msg_writer.print("symbol \"{s}\" is not a valid identifier and therefore cannot be defined", .{symbol});
1014 try diagnostics.append(err_details);969 try diagnostics.append(err_details);
1015 }970 }
1016 arg_i += value.index_increment;971 arg_i += value.index_increment;
...@@ -1018,8 +973,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1018,8 +973,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1018 } else if (std.ascii.startsWithIgnoreCase(arg_name, "u")) {973 } else if (std.ascii.startsWithIgnoreCase(arg_name, "u")) {
1019 const value = arg.value(1, arg_i, args) catch {974 const value = arg.value(1, arg_i, args) catch {
1020 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };975 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.missingSpan() };
1021 var msg_writer = err_details.msg.writer(allocator);976 try err_details.msg.print(allocator, "missing symbol to undefine after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
1022 try msg_writer.print("missing symbol to undefine after {s}{s} option", .{ arg.prefixSlice(), arg.optionWithoutPrefix(1) });
1023 try diagnostics.append(err_details);977 try diagnostics.append(err_details);
1024 arg_i += 1;978 arg_i += 1;
1025 break :next_arg;979 break :next_arg;
...@@ -1029,16 +983,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1029,16 +983,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1029 try options.undefine(symbol);983 try options.undefine(symbol);
1030 } else {984 } else {
1031 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };985 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = arg_i, .arg_span = value.argSpan(arg) };
1032 var msg_writer = err_details.msg.writer(allocator);986 try err_details.msg.print(allocator, "symbol \"{s}\" is not a valid identifier and therefore cannot be undefined", .{symbol});
1033 try msg_writer.print("symbol \"{s}\" is not a valid identifier and therefore cannot be undefined", .{symbol});
1034 try diagnostics.append(err_details);987 try diagnostics.append(err_details);
1035 }988 }
1036 arg_i += value.index_increment;989 arg_i += value.index_increment;
1037 continue :next_arg;990 continue :next_arg;
1038 } else {991 } else {
1039 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };992 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i, .arg_span = arg.optionAndAfterSpan() };
1040 var msg_writer = err_details.msg.writer(allocator);993 try err_details.msg.print(allocator, "invalid option: {s}{s}", .{ arg.prefixSlice(), arg.name() });
1041 try msg_writer.print("invalid option: {s}{s}", .{ arg.prefixSlice(), arg.name() });
1042 try diagnostics.append(err_details);994 try diagnostics.append(err_details);
1043 arg_i += 1;995 arg_i += 1;
1044 continue :next_arg;996 continue :next_arg;
...@@ -1055,16 +1007,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1055,16 +1007,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
10551007
1056 if (positionals.len == 0) {1008 if (positionals.len == 0) {
1057 var err_details = Diagnostics.ErrorDetails{ .print_args = false, .arg_index = arg_i };1009 var err_details = Diagnostics.ErrorDetails{ .print_args = false, .arg_index = arg_i };
1058 var msg_writer = err_details.msg.writer(allocator);1010 try err_details.msg.appendSlice(allocator, "missing input filename");
1059 try msg_writer.writeAll("missing input filename");
1060 try diagnostics.append(err_details);1011 try diagnostics.append(err_details);
10611012
1062 if (args.len > 0) {1013 if (args.len > 0) {
1063 const last_arg = args[args.len - 1];1014 const last_arg = args[args.len - 1];
1064 if (arg_i > 0 and last_arg.len > 0 and last_arg[0] == '/' and isSupportedInputExtension(std.fs.path.extension(last_arg))) {1015 if (arg_i > 0 and last_arg.len > 0 and last_arg[0] == '/' and isSupportedInputExtension(std.fs.path.extension(last_arg))) {
1065 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = true, .arg_index = arg_i - 1 };1016 var note_details = Diagnostics.ErrorDetails{ .type = .note, .print_args = true, .arg_index = arg_i - 1 };
1066 var note_writer = note_details.msg.writer(allocator);1017 try note_details.msg.appendSlice(allocator, "if this argument was intended to be the input filename, adding -- in front of it will exclude it from option parsing");
1067 try note_writer.writeAll("if this argument was intended to be the input filename, adding -- in front of it will exclude it from option parsing");
1068 try diagnostics.append(note_details);1018 try diagnostics.append(note_details);
1069 }1019 }
1070 }1020 }
...@@ -1099,16 +1049,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1099,16 +1049,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1099 if (positionals.len > 1) {1049 if (positionals.len > 1) {
1100 if (output_filename != null) {1050 if (output_filename != null) {
1101 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i + 1 };1051 var err_details = Diagnostics.ErrorDetails{ .arg_index = arg_i + 1 };
1102 var msg_writer = err_details.msg.writer(allocator);1052 try err_details.msg.appendSlice(allocator, "output filename already specified");
1103 try msg_writer.writeAll("output filename already specified");
1104 try diagnostics.append(err_details);1053 try diagnostics.append(err_details);
1105 var note_details = Diagnostics.ErrorDetails{1054 var note_details = Diagnostics.ErrorDetails{
1106 .type = .note,1055 .type = .note,
1107 .arg_index = output_filename_context.arg.index,1056 .arg_index = output_filename_context.arg.index,
1108 .arg_span = output_filename_context.arg.value.argSpan(output_filename_context.arg.arg),1057 .arg_span = output_filename_context.arg.value.argSpan(output_filename_context.arg.arg),
1109 };1058 };
1110 var note_writer = note_details.msg.writer(allocator);1059 try note_details.msg.appendSlice(allocator, "output filename previously specified here");
1111 try note_writer.writeAll("output filename previously specified here");
1112 try diagnostics.append(note_details);1060 try diagnostics.append(note_details);
1113 } else {1061 } else {
1114 output_filename = positionals[1];1062 output_filename = positionals[1];
...@@ -1173,16 +1121,15 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1173,16 +1121,15 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1173 var print_output_format_source_note: bool = false;1121 var print_output_format_source_note: bool = false;
1174 if (options.depfile_path != null and (options.input_format == .res or options.output_format == .rcpp)) {1122 if (options.depfile_path != null and (options.input_format == .res or options.output_format == .rcpp)) {
1175 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = depfile_context.index, .arg_span = depfile_context.value.argSpan(depfile_context.arg) };1123 var err_details = Diagnostics.ErrorDetails{ .type = .warning, .arg_index = depfile_context.index, .arg_span = depfile_context.value.argSpan(depfile_context.arg) };
1176 var msg_writer = err_details.msg.writer(allocator);
1177 if (options.input_format == .res) {1124 if (options.input_format == .res) {
1178 try msg_writer.print("the {s}{s} option was ignored because the input format is '{s}'", .{1125 try err_details.msg.print(allocator, "the {s}{s} option was ignored because the input format is '{s}'", .{
1179 depfile_context.arg.prefixSlice(),1126 depfile_context.arg.prefixSlice(),
1180 depfile_context.arg.optionWithoutPrefix(depfile_context.option_len),1127 depfile_context.arg.optionWithoutPrefix(depfile_context.option_len),
1181 @tagName(options.input_format),1128 @tagName(options.input_format),
1182 });1129 });
1183 print_input_format_source_note = true;1130 print_input_format_source_note = true;
1184 } else if (options.output_format == .rcpp) {1131 } else if (options.output_format == .rcpp) {
1185 try msg_writer.print("the {s}{s} option was ignored because the output format is '{s}'", .{1132 try err_details.msg.print(allocator, "the {s}{s} option was ignored because the output format is '{s}'", .{
1186 depfile_context.arg.prefixSlice(),1133 depfile_context.arg.prefixSlice(),
1187 depfile_context.arg.optionWithoutPrefix(depfile_context.option_len),1134 depfile_context.arg.optionWithoutPrefix(depfile_context.option_len),
1188 @tagName(options.output_format),1135 @tagName(options.output_format),
...@@ -1193,16 +1140,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1193,16 +1140,14 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1193 }1140 }
1194 if (!isSupportedTransformation(options.input_format, options.output_format)) {1141 if (!isSupportedTransformation(options.input_format, options.output_format)) {
1195 var err_details = Diagnostics.ErrorDetails{ .arg_index = input_filename_arg_i, .print_args = false };1142 var err_details = Diagnostics.ErrorDetails{ .arg_index = input_filename_arg_i, .print_args = false };
1196 var msg_writer = err_details.msg.writer(allocator);1143 try err_details.msg.print(allocator, "input format '{s}' cannot be converted to output format '{s}'", .{ @tagName(options.input_format), @tagName(options.output_format) });
1197 try msg_writer.print("input format '{s}' cannot be converted to output format '{s}'", .{ @tagName(options.input_format), @tagName(options.output_format) });
1198 try diagnostics.append(err_details);1144 try diagnostics.append(err_details);
1199 print_input_format_source_note = true;1145 print_input_format_source_note = true;
1200 print_output_format_source_note = true;1146 print_output_format_source_note = true;
1201 }1147 }
1202 if (options.preprocess == .only and options.output_format != .rcpp) {1148 if (options.preprocess == .only and options.output_format != .rcpp) {
1203 var err_details = Diagnostics.ErrorDetails{ .arg_index = preprocess_only_context.index };1149 var err_details = Diagnostics.ErrorDetails{ .arg_index = preprocess_only_context.index };
1204 var msg_writer = err_details.msg.writer(allocator);1150 try err_details.msg.print(allocator, "the {s}{s} option cannot be used with output format '{s}'", .{
1205 try msg_writer.print("the {s}{s} option cannot be used with output format '{s}'", .{
1206 preprocess_only_context.arg.prefixSlice(),1151 preprocess_only_context.arg.prefixSlice(),
1207 preprocess_only_context.arg.optionWithoutPrefix(preprocess_only_context.option_len),1152 preprocess_only_context.arg.optionWithoutPrefix(preprocess_only_context.option_len),
1208 @tagName(options.output_format),1153 @tagName(options.output_format),
...@@ -1214,8 +1159,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1214,8 +1159,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1214 switch (input_format_source) {1159 switch (input_format_source) {
1215 .inferred_from_input_filename => {1160 .inferred_from_input_filename => {
1216 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = input_filename_arg_i };1161 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = input_filename_arg_i };
1217 var msg_writer = err_details.msg.writer(allocator);1162 try err_details.msg.appendSlice(allocator, "the input format was inferred from the input filename");
1218 try msg_writer.writeAll("the input format was inferred from the input filename");
1219 try diagnostics.append(err_details);1163 try diagnostics.append(err_details);
1220 },1164 },
1221 .input_format_arg => {1165 .input_format_arg => {
...@@ -1224,8 +1168,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1224,8 +1168,7 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1224 .arg_index = input_format_context.index,1168 .arg_index = input_format_context.index,
1225 .arg_span = input_format_context.value.argSpan(input_format_context.arg),1169 .arg_span = input_format_context.value.argSpan(input_format_context.arg),
1226 };1170 };
1227 var msg_writer = err_details.msg.writer(allocator);1171 try err_details.msg.appendSlice(allocator, "the input format was specified here");
1228 try msg_writer.writeAll("the input format was specified here");
1229 try diagnostics.append(err_details);1172 try diagnostics.append(err_details);
1230 },1173 },
1231 }1174 }
...@@ -1234,11 +1177,10 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1234,11 +1177,10 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1234 switch (output_format_source) {1177 switch (output_format_source) {
1235 .inferred_from_input_filename, .unable_to_infer_from_input_filename => {1178 .inferred_from_input_filename, .unable_to_infer_from_input_filename => {
1236 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = input_filename_arg_i };1179 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = input_filename_arg_i };
1237 var msg_writer = err_details.msg.writer(allocator);
1238 if (output_format_source == .inferred_from_input_filename) {1180 if (output_format_source == .inferred_from_input_filename) {
1239 try msg_writer.writeAll("the output format was inferred from the input filename");1181 try err_details.msg.appendSlice(allocator, "the output format was inferred from the input filename");
1240 } else {1182 } else {
1241 try msg_writer.writeAll("the output format was unable to be inferred from the input filename, so the default was used");1183 try err_details.msg.appendSlice(allocator, "the output format was unable to be inferred from the input filename, so the default was used");
1242 }1184 }
1243 try diagnostics.append(err_details);1185 try diagnostics.append(err_details);
1244 },1186 },
...@@ -1248,11 +1190,10 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1248,11 +1190,10 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1248 .arg => |ctx| .{ .type = .note, .arg_index = ctx.index, .arg_span = ctx.value.argSpan(ctx.arg) },1190 .arg => |ctx| .{ .type = .note, .arg_index = ctx.index, .arg_span = ctx.value.argSpan(ctx.arg) },
1249 .unspecified => unreachable,1191 .unspecified => unreachable,
1250 };1192 };
1251 var msg_writer = err_details.msg.writer(allocator);
1252 if (output_format_source == .inferred_from_output_filename) {1193 if (output_format_source == .inferred_from_output_filename) {
1253 try msg_writer.writeAll("the output format was inferred from the output filename");1194 try err_details.msg.appendSlice(allocator, "the output format was inferred from the output filename");
1254 } else {1195 } else {
1255 try msg_writer.writeAll("the output format was unable to be inferred from the output filename, so the default was used");1196 try err_details.msg.appendSlice(allocator, "the output format was unable to be inferred from the output filename, so the default was used");
1256 }1197 }
1257 try diagnostics.append(err_details);1198 try diagnostics.append(err_details);
1258 },1199 },
...@@ -1262,14 +1203,12 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1262,14 +1203,12 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1262 .arg_index = output_format_context.index,1203 .arg_index = output_format_context.index,
1263 .arg_span = output_format_context.value.argSpan(output_format_context.arg),1204 .arg_span = output_format_context.value.argSpan(output_format_context.arg),
1264 };1205 };
1265 var msg_writer = err_details.msg.writer(allocator);1206 try err_details.msg.appendSlice(allocator, "the output format was specified here");
1266 try msg_writer.writeAll("the output format was specified here");
1267 try diagnostics.append(err_details);1207 try diagnostics.append(err_details);
1268 },1208 },
1269 .inferred_from_preprocess_only => {1209 .inferred_from_preprocess_only => {
1270 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = preprocess_only_context.index };1210 var err_details = Diagnostics.ErrorDetails{ .type = .note, .arg_index = preprocess_only_context.index };
1271 var msg_writer = err_details.msg.writer(allocator);1211 try err_details.msg.print(allocator, "the output format was inferred from the usage of the {s}{s} option", .{
1272 try msg_writer.print("the output format was inferred from the usage of the {s}{s} option", .{
1273 preprocess_only_context.arg.prefixSlice(),1212 preprocess_only_context.arg.prefixSlice(),
1274 preprocess_only_context.arg.optionWithoutPrefix(preprocess_only_context.option_len),1213 preprocess_only_context.arg.optionWithoutPrefix(preprocess_only_context.option_len),
1275 });1214 });
...@@ -1291,19 +1230,19 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn...@@ -1291,19 +1230,19 @@ pub fn parse(allocator: Allocator, args: []const []const u8, diagnostics: *Diagn
1291}1230}
12921231
1293pub fn filepathWithExtension(allocator: Allocator, path: []const u8, ext: []const u8) ![]const u8 {1232pub fn filepathWithExtension(allocator: Allocator, path: []const u8, ext: []const u8) ![]const u8 {
1294 var buf = std.array_list.Managed(u8).init(allocator);1233 var buf: std.ArrayList(u8) = .empty;
1295 errdefer buf.deinit();1234 errdefer buf.deinit(allocator);
1296 if (std.fs.path.dirname(path)) |dirname| {1235 if (std.fs.path.dirname(path)) |dirname| {
1297 var end_pos = dirname.len;1236 var end_pos = dirname.len;
1298 // We want to ensure that we write a path separator at the end, so if the dirname1237 // We want to ensure that we write a path separator at the end, so if the dirname
1299 // doesn't end with a path sep then include the char after the dirname1238 // doesn't end with a path sep then include the char after the dirname
1300 // which must be a path sep.1239 // which must be a path sep.
1301 if (!std.fs.path.isSep(dirname[dirname.len - 1])) end_pos += 1;1240 if (!std.fs.path.isSep(dirname[dirname.len - 1])) end_pos += 1;
1302 try buf.appendSlice(path[0..end_pos]);1241 try buf.appendSlice(allocator, path[0..end_pos]);
1303 }1242 }
1304 try buf.appendSlice(std.fs.path.stem(path));1243 try buf.appendSlice(allocator, std.fs.path.stem(path));
1305 try buf.appendSlice(ext);1244 try buf.appendSlice(allocator, ext);
1306 return try buf.toOwnedSlice();1245 return try buf.toOwnedSlice(allocator);
1307}1246}
13081247
1309pub fn isSupportedInputExtension(ext: []const u8) bool {1248pub fn isSupportedInputExtension(ext: []const u8) bool {
...@@ -1537,7 +1476,7 @@ fn testParseOutput(args: []const []const u8, expected_output: []const u8) !?Opti...@@ -1537,7 +1476,7 @@ fn testParseOutput(args: []const []const u8, expected_output: []const u8) !?Opti
1537 var options = parse(std.testing.allocator, args, &diagnostics) catch |err| switch (err) {1476 var options = parse(std.testing.allocator, args, &diagnostics) catch |err| switch (err) {
1538 error.ParseError => {1477 error.ParseError => {
1539 try diagnostics.renderToWriter(args, &output.writer, .no_color);1478 try diagnostics.renderToWriter(args, &output.writer, .no_color);
1540 try std.testing.expectEqualStrings(expected_output, output.getWritten());1479 try std.testing.expectEqualStrings(expected_output, output.written());
1541 return null;1480 return null;
1542 },1481 },
1543 else => |e| return e,1482 else => |e| return e,
...@@ -1545,7 +1484,7 @@ fn testParseOutput(args: []const []const u8, expected_output: []const u8) !?Opti...@@ -1545,7 +1484,7 @@ fn testParseOutput(args: []const []const u8, expected_output: []const u8) !?Opti
1545 errdefer options.deinit();1484 errdefer options.deinit();
15461485
1547 try diagnostics.renderToWriter(args, &output.writer, .no_color);1486 try diagnostics.renderToWriter(args, &output.writer, .no_color);
1548 try std.testing.expectEqualStrings(expected_output, output.getWritten());1487 try std.testing.expectEqualStrings(expected_output, output.written());
1549 return options;1488 return options;
1550}1489}
15511490
lib/compiler/resinator/compile.zig+219-309
...@@ -35,10 +35,7 @@ pub const CompileOptions = struct {...@@ -35,10 +35,7 @@ pub const CompileOptions = struct {
35 diagnostics: *Diagnostics,35 diagnostics: *Diagnostics,
36 source_mappings: ?*SourceMappings = null,36 source_mappings: ?*SourceMappings = null,
37 /// List of paths (absolute or relative to `cwd`) for every file that the resources within the .rc file depend on.37 /// List of paths (absolute or relative to `cwd`) for every file that the resources within the .rc file depend on.
38 /// Items within the list will be allocated using the allocator of the ArrayList and must be38 dependencies: ?*Dependencies = null,
39 /// freed by the caller.
40 /// TODO: Maybe a dedicated struct for this purpose so that it's a bit nicer to work with.
41 dependencies_list: ?*std.array_list.Managed([]const u8) = null,
42 default_code_page: SupportedCodePage = .windows1252,39 default_code_page: SupportedCodePage = .windows1252,
43 /// If true, the first #pragma code_page directive only sets the input code page, but not the output code page.40 /// If true, the first #pragma code_page directive only sets the input code page, but not the output code page.
44 /// This check must be done before comments are removed from the file.41 /// This check must be done before comments are removed from the file.
...@@ -61,7 +58,26 @@ pub const CompileOptions = struct {...@@ -61,7 +58,26 @@ pub const CompileOptions = struct {
61 warn_instead_of_error_on_invalid_code_page: bool = false,58 warn_instead_of_error_on_invalid_code_page: bool = false,
62};59};
6360
64pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, options: CompileOptions) !void {61pub const Dependencies = struct {
62 list: std.ArrayList([]const u8),
63 allocator: Allocator,
64
65 pub fn init(allocator: Allocator) Dependencies {
66 return .{
67 .list = .empty,
68 .allocator = allocator,
69 };
70 }
71
72 pub fn deinit(self: *Dependencies) void {
73 for (self.list.items) |item| {
74 self.allocator.free(item);
75 }
76 self.list.deinit(self.allocator);
77 }
78};
79
80pub fn compile(allocator: Allocator, source: []const u8, writer: *std.Io.Writer, options: CompileOptions) !void {
65 var lexer = lex.Lexer.init(source, .{81 var lexer = lex.Lexer.init(source, .{
66 .default_code_page = options.default_code_page,82 .default_code_page = options.default_code_page,
67 .source_mappings = options.source_mappings,83 .source_mappings = options.source_mappings,
...@@ -74,12 +90,12 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option...@@ -74,12 +90,12 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option
74 var tree = try parser.parse(allocator, options.diagnostics);90 var tree = try parser.parse(allocator, options.diagnostics);
75 defer tree.deinit();91 defer tree.deinit();
7692
77 var search_dirs = std.array_list.Managed(SearchDir).init(allocator);93 var search_dirs: std.ArrayList(SearchDir) = .empty;
78 defer {94 defer {
79 for (search_dirs.items) |*search_dir| {95 for (search_dirs.items) |*search_dir| {
80 search_dir.deinit(allocator);96 search_dir.deinit(allocator);
81 }97 }
82 search_dirs.deinit();98 search_dirs.deinit(allocator);
83 }99 }
84100
85 if (options.source_mappings) |source_mappings| {101 if (options.source_mappings) |source_mappings| {
...@@ -89,7 +105,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option...@@ -89,7 +105,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option
89 if (std.fs.path.dirname(root_path)) |root_dir_path| {105 if (std.fs.path.dirname(root_path)) |root_dir_path| {
90 var root_dir = try options.cwd.openDir(root_dir_path, .{});106 var root_dir = try options.cwd.openDir(root_dir_path, .{});
91 errdefer root_dir.close();107 errdefer root_dir.close();
92 try search_dirs.append(.{ .dir = root_dir, .path = try allocator.dupe(u8, root_dir_path) });108 try search_dirs.append(allocator, .{ .dir = root_dir, .path = try allocator.dupe(u8, root_dir_path) });
93 }109 }
94 }110 }
95 // Re-open the passed in cwd since we want to be able to close it (std.fs.cwd() shouldn't be closed)111 // Re-open the passed in cwd since we want to be able to close it (std.fs.cwd() shouldn't be closed)
...@@ -111,14 +127,14 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option...@@ -111,14 +127,14 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option
111 });127 });
112 return error.CompileError;128 return error.CompileError;
113 };129 };
114 try search_dirs.append(.{ .dir = cwd_dir, .path = null });130 try search_dirs.append(allocator, .{ .dir = cwd_dir, .path = null });
115 for (options.extra_include_paths) |extra_include_path| {131 for (options.extra_include_paths) |extra_include_path| {
116 var dir = openSearchPathDir(options.cwd, extra_include_path) catch {132 var dir = openSearchPathDir(options.cwd, extra_include_path) catch {
117 // TODO: maybe a warning that the search path is skipped?133 // TODO: maybe a warning that the search path is skipped?
118 continue;134 continue;
119 };135 };
120 errdefer dir.close();136 errdefer dir.close();
121 try search_dirs.append(.{ .dir = dir, .path = try allocator.dupe(u8, extra_include_path) });137 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, extra_include_path) });
122 }138 }
123 for (options.system_include_paths) |system_include_path| {139 for (options.system_include_paths) |system_include_path| {
124 var dir = openSearchPathDir(options.cwd, system_include_path) catch {140 var dir = openSearchPathDir(options.cwd, system_include_path) catch {
...@@ -126,7 +142,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option...@@ -126,7 +142,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option
126 continue;142 continue;
127 };143 };
128 errdefer dir.close();144 errdefer dir.close();
129 try search_dirs.append(.{ .dir = dir, .path = try allocator.dupe(u8, system_include_path) });145 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, system_include_path) });
130 }146 }
131 if (!options.ignore_include_env_var) {147 if (!options.ignore_include_env_var) {
132 const INCLUDE = std.process.getEnvVarOwned(allocator, "INCLUDE") catch "";148 const INCLUDE = std.process.getEnvVarOwned(allocator, "INCLUDE") catch "";
...@@ -142,7 +158,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option...@@ -142,7 +158,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option
142 while (it.next()) |search_path| {158 while (it.next()) |search_path| {
143 var dir = openSearchPathDir(options.cwd, search_path) catch continue;159 var dir = openSearchPathDir(options.cwd, search_path) catch continue;
144 errdefer dir.close();160 errdefer dir.close();
145 try search_dirs.append(.{ .dir = dir, .path = try allocator.dupe(u8, search_path) });161 try search_dirs.append(allocator, .{ .dir = dir, .path = try allocator.dupe(u8, search_path) });
146 }162 }
147 }163 }
148164
...@@ -156,7 +172,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option...@@ -156,7 +172,7 @@ pub fn compile(allocator: Allocator, source: []const u8, writer: anytype, option
156 .allocator = allocator,172 .allocator = allocator,
157 .cwd = options.cwd,173 .cwd = options.cwd,
158 .diagnostics = options.diagnostics,174 .diagnostics = options.diagnostics,
159 .dependencies_list = options.dependencies_list,175 .dependencies = options.dependencies,
160 .input_code_pages = &tree.input_code_pages,176 .input_code_pages = &tree.input_code_pages,
161 .output_code_pages = &tree.output_code_pages,177 .output_code_pages = &tree.output_code_pages,
162 // This is only safe because we know search_dirs won't be modified past this point178 // This is only safe because we know search_dirs won't be modified past this point
...@@ -178,7 +194,7 @@ pub const Compiler = struct {...@@ -178,7 +194,7 @@ pub const Compiler = struct {
178 cwd: std.fs.Dir,194 cwd: std.fs.Dir,
179 state: State = .{},195 state: State = .{},
180 diagnostics: *Diagnostics,196 diagnostics: *Diagnostics,
181 dependencies_list: ?*std.array_list.Managed([]const u8),197 dependencies: ?*Dependencies,
182 input_code_pages: *const CodePageLookup,198 input_code_pages: *const CodePageLookup,
183 output_code_pages: *const CodePageLookup,199 output_code_pages: *const CodePageLookup,
184 search_dirs: []SearchDir,200 search_dirs: []SearchDir,
...@@ -194,7 +210,7 @@ pub const Compiler = struct {...@@ -194,7 +210,7 @@ pub const Compiler = struct {
194 characteristics: u32 = 0,210 characteristics: u32 = 0,
195 };211 };
196212
197 pub fn writeRoot(self: *Compiler, root: *Node.Root, writer: anytype) !void {213 pub fn writeRoot(self: *Compiler, root: *Node.Root, writer: *std.Io.Writer) !void {
198 try writeEmptyResource(writer);214 try writeEmptyResource(writer);
199 for (root.body) |node| {215 for (root.body) |node| {
200 try self.writeNode(node, writer);216 try self.writeNode(node, writer);
...@@ -236,7 +252,7 @@ pub const Compiler = struct {...@@ -236,7 +252,7 @@ pub const Compiler = struct {
236 }252 }
237 }253 }
238254
239 pub fn writeNode(self: *Compiler, node: *Node, writer: anytype) !void {255 pub fn writeNode(self: *Compiler, node: *Node, writer: *std.Io.Writer) !void {
240 switch (node.id) {256 switch (node.id) {
241 .root => unreachable, // writeRoot should be called directly instead257 .root => unreachable, // writeRoot should be called directly instead
242 .resource_external => try self.writeResourceExternal(@alignCast(@fieldParentPtr("base", node)), writer),258 .resource_external => try self.writeResourceExternal(@alignCast(@fieldParentPtr("base", node)), writer),
...@@ -279,32 +295,32 @@ pub const Compiler = struct {...@@ -279,32 +295,32 @@ pub const Compiler = struct {
279 .literal, .number => {295 .literal, .number => {
280 const slice = literal_node.token.slice(self.source);296 const slice = literal_node.token.slice(self.source);
281 const code_page = self.input_code_pages.getForToken(literal_node.token);297 const code_page = self.input_code_pages.getForToken(literal_node.token);
282 var buf = try std.array_list.Managed(u8).initCapacity(self.allocator, slice.len);298 var buf = try std.ArrayList(u8).initCapacity(self.allocator, slice.len);
283 errdefer buf.deinit();299 errdefer buf.deinit(self.allocator);
284300
285 var index: usize = 0;301 var index: usize = 0;
286 while (code_page.codepointAt(index, slice)) |codepoint| : (index += codepoint.byte_len) {302 while (code_page.codepointAt(index, slice)) |codepoint| : (index += codepoint.byte_len) {
287 const c = codepoint.value;303 const c = codepoint.value;
288 if (c == code_pages.Codepoint.invalid) {304 if (c == code_pages.Codepoint.invalid) {
289 try buf.appendSlice("�");305 try buf.appendSlice(self.allocator, "�");
290 } else {306 } else {
291 // Anything that is not returned as an invalid codepoint must be encodable as UTF-8.307 // Anything that is not returned as an invalid codepoint must be encodable as UTF-8.
292 const utf8_len = std.unicode.utf8CodepointSequenceLength(c) catch unreachable;308 const utf8_len = std.unicode.utf8CodepointSequenceLength(c) catch unreachable;
293 try buf.ensureUnusedCapacity(utf8_len);309 try buf.ensureUnusedCapacity(self.allocator, utf8_len);
294 _ = std.unicode.utf8Encode(c, buf.unusedCapacitySlice()) catch unreachable;310 _ = std.unicode.utf8Encode(c, buf.unusedCapacitySlice()) catch unreachable;
295 buf.items.len += utf8_len;311 buf.items.len += utf8_len;
296 }312 }
297 }313 }
298314
299 return buf.toOwnedSlice();315 return buf.toOwnedSlice(self.allocator);
300 },316 },
301 .quoted_ascii_string, .quoted_wide_string => {317 .quoted_ascii_string, .quoted_wide_string => {
302 const slice = literal_node.token.slice(self.source);318 const slice = literal_node.token.slice(self.source);
303 const column = literal_node.token.calculateColumn(self.source, 8, null);319 const column = literal_node.token.calculateColumn(self.source, 8, null);
304 const bytes = SourceBytes{ .slice = slice, .code_page = self.input_code_pages.getForToken(literal_node.token) };320 const bytes = SourceBytes{ .slice = slice, .code_page = self.input_code_pages.getForToken(literal_node.token) };
305321
306 var buf = std.array_list.Managed(u8).init(self.allocator);322 var buf: std.ArrayList(u8) = .empty;
307 errdefer buf.deinit();323 errdefer buf.deinit(self.allocator);
308324
309 // Filenames are sort-of parsed as if they were wide strings, but the max escape width of325 // Filenames are sort-of parsed as if they were wide strings, but the max escape width of
310 // hex/octal escapes is still determined by the L prefix. Since we want to end up with326 // hex/octal escapes is still determined by the L prefix. Since we want to end up with
...@@ -320,19 +336,19 @@ pub const Compiler = struct {...@@ -320,19 +336,19 @@ pub const Compiler = struct {
320 while (try parser.nextUnchecked()) |parsed| {336 while (try parser.nextUnchecked()) |parsed| {
321 const c = parsed.codepoint;337 const c = parsed.codepoint;
322 if (c == code_pages.Codepoint.invalid) {338 if (c == code_pages.Codepoint.invalid) {
323 try buf.appendSlice("�");339 try buf.appendSlice(self.allocator, "�");
324 } else {340 } else {
325 var codepoint_buf: [4]u8 = undefined;341 var codepoint_buf: [4]u8 = undefined;
326 // If the codepoint cannot be encoded, we fall back to �342 // If the codepoint cannot be encoded, we fall back to �
327 if (std.unicode.utf8Encode(c, &codepoint_buf)) |len| {343 if (std.unicode.utf8Encode(c, &codepoint_buf)) |len| {
328 try buf.appendSlice(codepoint_buf[0..len]);344 try buf.appendSlice(self.allocator, codepoint_buf[0..len]);
329 } else |_| {345 } else |_| {
330 try buf.appendSlice("�");346 try buf.appendSlice(self.allocator, "�");
331 }347 }
332 }348 }
333 }349 }
334350
335 return buf.toOwnedSlice();351 return buf.toOwnedSlice(self.allocator);
336 },352 },
337 else => unreachable, // no other token types should be in a filename literal node353 else => unreachable, // no other token types should be in a filename literal node
338 }354 }
...@@ -386,10 +402,10 @@ pub const Compiler = struct {...@@ -386,10 +402,10 @@ pub const Compiler = struct {
386 const file = try utils.openFileNotDir(std.fs.cwd(), path, .{});402 const file = try utils.openFileNotDir(std.fs.cwd(), path, .{});
387 errdefer file.close();403 errdefer file.close();
388404
389 if (self.dependencies_list) |dependencies_list| {405 if (self.dependencies) |dependencies| {
390 const duped_path = try dependencies_list.allocator.dupe(u8, path);406 const duped_path = try dependencies.allocator.dupe(u8, path);
391 errdefer dependencies_list.allocator.free(duped_path);407 errdefer dependencies.allocator.free(duped_path);
392 try dependencies_list.append(duped_path);408 try dependencies.list.append(dependencies.allocator, duped_path);
393 }409 }
394 }410 }
395411
...@@ -398,12 +414,12 @@ pub const Compiler = struct {...@@ -398,12 +414,12 @@ pub const Compiler = struct {
398 if (utils.openFileNotDir(search_dir.dir, path, .{})) |file| {414 if (utils.openFileNotDir(search_dir.dir, path, .{})) |file| {
399 errdefer file.close();415 errdefer file.close();
400416
401 if (self.dependencies_list) |dependencies_list| {417 if (self.dependencies) |dependencies| {
402 const searched_file_path = try std.fs.path.join(dependencies_list.allocator, &.{418 const searched_file_path = try std.fs.path.join(dependencies.allocator, &.{
403 search_dir.path orelse "", path,419 search_dir.path orelse "", path,
404 });420 });
405 errdefer dependencies_list.allocator.free(searched_file_path);421 errdefer dependencies.allocator.free(searched_file_path);
406 try dependencies_list.append(searched_file_path);422 try dependencies.list.append(dependencies.allocator, searched_file_path);
407 }423 }
408424
409 return file;425 return file;
...@@ -421,8 +437,8 @@ pub const Compiler = struct {...@@ -421,8 +437,8 @@ pub const Compiler = struct {
421 const bytes = self.sourceBytesForToken(token);437 const bytes = self.sourceBytesForToken(token);
422 const output_code_page = self.output_code_pages.getForToken(token);438 const output_code_page = self.output_code_pages.getForToken(token);
423439
424 var buf = try std.array_list.Managed(u8).initCapacity(self.allocator, bytes.slice.len);440 var buf = try std.ArrayList(u8).initCapacity(self.allocator, bytes.slice.len);
425 errdefer buf.deinit();441 errdefer buf.deinit(self.allocator);
426442
427 var iterative_parser = literals.IterativeStringParser.init(bytes, .{443 var iterative_parser = literals.IterativeStringParser.init(bytes, .{
428 .start_column = token.calculateColumn(self.source, 8, null),444 .start_column = token.calculateColumn(self.source, 8, null),
...@@ -444,11 +460,11 @@ pub const Compiler = struct {...@@ -444,11 +460,11 @@ pub const Compiler = struct {
444 switch (iterative_parser.declared_string_type) {460 switch (iterative_parser.declared_string_type) {
445 .wide => {461 .wide => {
446 if (windows1252.bestFitFromCodepoint(c)) |best_fit| {462 if (windows1252.bestFitFromCodepoint(c)) |best_fit| {
447 try buf.append(best_fit);463 try buf.append(self.allocator, best_fit);
448 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid or parsed.escaped_surrogate_pair) {464 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid or parsed.escaped_surrogate_pair) {
449 try buf.append('?');465 try buf.append(self.allocator, '?');
450 } else {466 } else {
451 try buf.appendSlice("??");467 try buf.appendSlice(self.allocator, "??");
452 }468 }
453 },469 },
454 .ascii => {470 .ascii => {
...@@ -456,30 +472,30 @@ pub const Compiler = struct {...@@ -456,30 +472,30 @@ pub const Compiler = struct {
456 const truncated: u8 = @truncate(c);472 const truncated: u8 = @truncate(c);
457 switch (output_code_page) {473 switch (output_code_page) {
458 .utf8 => switch (truncated) {474 .utf8 => switch (truncated) {
459 0...0x7F => try buf.append(truncated),475 0...0x7F => try buf.append(self.allocator, truncated),
460 else => try buf.append('?'),476 else => try buf.append(self.allocator, '?'),
461 },477 },
462 .windows1252 => {478 .windows1252 => {
463 try buf.append(truncated);479 try buf.append(self.allocator, truncated);
464 },480 },
465 }481 }
466 } else {482 } else {
467 if (windows1252.bestFitFromCodepoint(c)) |best_fit| {483 if (windows1252.bestFitFromCodepoint(c)) |best_fit| {
468 try buf.append(best_fit);484 try buf.append(self.allocator, best_fit);
469 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid) {485 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid) {
470 try buf.append('?');486 try buf.append(self.allocator, '?');
471 } else {487 } else {
472 try buf.appendSlice("??");488 try buf.appendSlice(self.allocator, "??");
473 }489 }
474 }490 }
475 },491 },
476 }492 }
477 }493 }
478494
479 return buf.toOwnedSlice();495 return buf.toOwnedSlice(self.allocator);
480 }496 }
481497
482 pub fn writeResourceExternal(self: *Compiler, node: *Node.ResourceExternal, writer: anytype) !void {498 pub fn writeResourceExternal(self: *Compiler, node: *Node.ResourceExternal, writer: *std.Io.Writer) !void {
483 // Init header with data size zero for now, will need to fill it in later499 // Init header with data size zero for now, will need to fill it in later
484 var header = try self.resourceHeader(node.id, node.type, .{});500 var header = try self.resourceHeader(node.id, node.type, .{});
485 defer header.deinit(self.allocator);501 defer header.deinit(self.allocator);
...@@ -572,7 +588,7 @@ pub const Compiler = struct {...@@ -572,7 +588,7 @@ pub const Compiler = struct {
572 switch (predefined_type) {588 switch (predefined_type) {
573 .GROUP_ICON, .GROUP_CURSOR => {589 .GROUP_ICON, .GROUP_CURSOR => {
574 // Check for animated icon first590 // Check for animated icon first
575 if (ani.isAnimatedIcon(file_reader.interface.adaptToOldInterface())) {591 if (ani.isAnimatedIcon(&file_reader.interface)) {
576 // Animated icons are just put into the resource unmodified,592 // Animated icons are just put into the resource unmodified,
577 // and the resource type changes to ANIICON/ANICURSOR593 // and the resource type changes to ANIICON/ANICURSOR
578594
...@@ -584,7 +600,12 @@ pub const Compiler = struct {...@@ -584,7 +600,12 @@ pub const Compiler = struct {
584 header.type_value.ordinal = @intFromEnum(new_predefined_type);600 header.type_value.ordinal = @intFromEnum(new_predefined_type);
585 header.memory_flags = MemoryFlags.defaults(new_predefined_type);601 header.memory_flags = MemoryFlags.defaults(new_predefined_type);
586 header.applyMemoryFlags(node.common_resource_attributes, self.source);602 header.applyMemoryFlags(node.common_resource_attributes, self.source);
587 header.data_size = @intCast(try file_reader.getSize());603 header.data_size = std.math.cast(u32, try file_reader.getSize()) orelse {
604 return self.addErrorDetailsAndFail(.{
605 .err = .resource_data_size_exceeds_max,
606 .token = node.id,
607 });
608 };
588609
589 try header.write(writer, self.errContext(node.id));610 try header.write(writer, self.errContext(node.id));
590 try file_reader.seekTo(0);611 try file_reader.seekTo(0);
...@@ -595,7 +616,7 @@ pub const Compiler = struct {...@@ -595,7 +616,7 @@ pub const Compiler = struct {
595 // isAnimatedIcon moved the file cursor so reset to the start616 // isAnimatedIcon moved the file cursor so reset to the start
596 try file_reader.seekTo(0);617 try file_reader.seekTo(0);
597618
598 const icon_dir = ico.read(self.allocator, file_reader.interface.adaptToOldInterface(), try file_reader.getSize()) catch |err| switch (err) {619 const icon_dir = ico.read(self.allocator, &file_reader.interface, try file_reader.getSize()) catch |err| switch (err) {
599 error.OutOfMemory => |e| return e,620 error.OutOfMemory => |e| return e,
600 else => |e| {621 else => |e| {
601 return self.iconReadError(622 return self.iconReadError(
...@@ -861,7 +882,7 @@ pub const Compiler = struct {...@@ -861,7 +882,7 @@ pub const Compiler = struct {
861 header.applyMemoryFlags(node.common_resource_attributes, self.source);882 header.applyMemoryFlags(node.common_resource_attributes, self.source);
862 const file_size = try file_reader.getSize();883 const file_size = try file_reader.getSize();
863884
864 const bitmap_info = bmp.read(file_reader.interface.adaptToOldInterface(), file_size) catch |err| {885 const bitmap_info = bmp.read(&file_reader.interface, file_size) catch |err| {
865 const filename_string_index = try self.diagnostics.putString(filename_utf8);886 const filename_string_index = try self.diagnostics.putString(filename_utf8);
866 return self.addErrorDetailsAndFail(.{887 return self.addErrorDetailsAndFail(.{
867 .err = .bmp_read_error,888 .err = .bmp_read_error,
...@@ -969,13 +990,19 @@ pub const Compiler = struct {...@@ -969,13 +990,19 @@ pub const Compiler = struct {
969 header.data_size = @intCast(file_size);990 header.data_size = @intCast(file_size);
970 try header.write(writer, self.errContext(node.id));991 try header.write(writer, self.errContext(node.id));
971992
972 var header_slurping_reader = headerSlurpingReader(148, file_reader.interface.adaptToOldInterface());993 // Slurp the first 148 bytes separately so we can store them in the FontDir
973 var adapter = header_slurping_reader.reader().adaptToNewApi(&.{});994 var font_dir_header_buf: [148]u8 = @splat(0);
974 try writeResourceData(writer, &adapter.new_interface, header.data_size);995 const populated_len: u32 = @intCast(try file_reader.interface.readSliceShort(&font_dir_header_buf));
996
997 // Write only the populated bytes slurped from the header
998 try writer.writeAll(font_dir_header_buf[0..populated_len]);
999 // Then write the rest of the bytes and the padding
1000 try writeResourceDataNoPadding(writer, &file_reader.interface, header.data_size - populated_len);
1001 try writeDataPadding(writer, header.data_size);
9751002
976 try self.state.font_dir.add(self.arena, FontDir.Font{1003 try self.state.font_dir.add(self.arena, FontDir.Font{
977 .id = header.name_value.ordinal,1004 .id = header.name_value.ordinal,
978 .header_bytes = header_slurping_reader.slurped_header,1005 .header_bytes = font_dir_header_buf,
979 }, node.id);1006 }, node.id);
980 return;1007 return;
981 },1008 },
...@@ -1053,7 +1080,7 @@ pub const Compiler = struct {...@@ -1053,7 +1080,7 @@ pub const Compiler = struct {
1053 }1080 }
1054 }1081 }
10551082
1056 pub fn write(self: Data, writer: anytype) !void {1083 pub fn write(self: Data, writer: *std.Io.Writer) !void {
1057 switch (self) {1084 switch (self) {
1058 .number => |number| switch (number.is_long) {1085 .number => |number| switch (number.is_long) {
1059 false => try writer.writeInt(WORD, number.asWord(), .little),1086 false => try writer.writeInt(WORD, number.asWord(), .little),
...@@ -1225,38 +1252,30 @@ pub const Compiler = struct {...@@ -1225,38 +1252,30 @@ pub const Compiler = struct {
1225 }1252 }
1226 }1253 }
12271254
1228 pub fn writeResourceRawData(self: *Compiler, node: *Node.ResourceRawData, writer: anytype) !void {1255 pub fn writeResourceRawData(self: *Compiler, node: *Node.ResourceRawData, writer: *std.Io.Writer) !void {
1229 var data_buffer = std.array_list.Managed(u8).init(self.allocator);1256 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
1230 defer data_buffer.deinit();1257 defer data_buffer.deinit();
1231 // The header's data length field is a u32 so limit the resource's data size so that
1232 // we know we can always specify the real size.
1233 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));
1234 const data_writer = limited_writer.writer();
12351258
1236 for (node.raw_data) |expression| {1259 for (node.raw_data) |expression| {
1237 const data = try self.evaluateDataExpression(expression);1260 const data = try self.evaluateDataExpression(expression);
1238 defer data.deinit(self.allocator);1261 defer data.deinit(self.allocator);
1239 data.write(data_writer) catch |err| switch (err) {1262 try data.write(&data_buffer.writer);
1240 error.NoSpaceLeft => {
1241 return self.addErrorDetailsAndFail(.{
1242 .err = .resource_data_size_exceeds_max,
1243 .token = node.id,
1244 });
1245 },
1246 else => |e| return e,
1247 };
1248 }1263 }
12491264
1250 // This intCast can't fail because the limitedWriter above guarantees that1265 // TODO: Limit data_buffer in some way to error when writing more than u32 max bytes
1251 // we will never write more than maxInt(u32) bytes.1266 const data_len: u32 = std.math.cast(u32, data_buffer.written().len) orelse {
1252 const data_len: u32 = @intCast(data_buffer.items.len);1267 return self.addErrorDetailsAndFail(.{
1268 .err = .resource_data_size_exceeds_max,
1269 .token = node.id,
1270 });
1271 };
1253 try self.writeResourceHeader(writer, node.id, node.type, data_len, node.common_resource_attributes, self.state.language);1272 try self.writeResourceHeader(writer, node.id, node.type, data_len, node.common_resource_attributes, self.state.language);
12541273
1255 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);1274 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
1256 try writeResourceData(writer, &data_fbs, data_len);1275 try writeResourceData(writer, &data_fbs, data_len);
1257 }1276 }
12581277
1259 pub fn writeResourceHeader(self: *Compiler, writer: anytype, id_token: Token, type_token: Token, data_size: u32, common_resource_attributes: []Token, language: res.Language) !void {1278 pub fn writeResourceHeader(self: *Compiler, writer: *std.Io.Writer, id_token: Token, type_token: Token, data_size: u32, common_resource_attributes: []Token, language: res.Language) !void {
1260 var header = try self.resourceHeader(id_token, type_token, .{1279 var header = try self.resourceHeader(id_token, type_token, .{
1261 .language = language,1280 .language = language,
1262 .data_size = data_size,1281 .data_size = data_size,
...@@ -1272,7 +1291,7 @@ pub const Compiler = struct {...@@ -1272,7 +1291,7 @@ pub const Compiler = struct {
1272 try data_reader.streamExact(writer, data_size);1291 try data_reader.streamExact(writer, data_size);
1273 }1292 }
12741293
1275 pub fn writeResourceData(writer: anytype, data_reader: *std.Io.Reader, data_size: u32) !void {1294 pub fn writeResourceData(writer: *std.Io.Writer, data_reader: *std.Io.Reader, data_size: u32) !void {
1276 try writeResourceDataNoPadding(writer, data_reader, data_size);1295 try writeResourceDataNoPadding(writer, data_reader, data_size);
1277 try writeDataPadding(writer, data_size);1296 try writeDataPadding(writer, data_size);
1278 }1297 }
...@@ -1305,28 +1324,19 @@ pub const Compiler = struct {...@@ -1305,28 +1324,19 @@ pub const Compiler = struct {
1305 }1324 }
1306 }1325 }
13071326
1308 pub fn writeAccelerators(self: *Compiler, node: *Node.Accelerators, writer: anytype) !void {1327 pub fn writeAccelerators(self: *Compiler, node: *Node.Accelerators, writer: *std.Io.Writer) !void {
1309 var data_buffer = std.array_list.Managed(u8).init(self.allocator);1328 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
1310 defer data_buffer.deinit();1329 defer data_buffer.deinit();
13111330
1312 // The header's data length field is a u32 so limit the resource's data size so that1331 try self.writeAcceleratorsData(node, &data_buffer.writer);
1313 // we know we can always specify the real size.
1314 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));
1315 const data_writer = limited_writer.writer();
13161332
1317 self.writeAcceleratorsData(node, data_writer) catch |err| switch (err) {1333 // TODO: Limit data_buffer in some way to error when writing more than u32 max bytes
1318 error.NoSpaceLeft => {1334 const data_size: u32 = std.math.cast(u32, data_buffer.written().len) orelse {
1319 return self.addErrorDetailsAndFail(.{1335 return self.addErrorDetailsAndFail(.{
1320 .err = .resource_data_size_exceeds_max,1336 .err = .resource_data_size_exceeds_max,
1321 .token = node.id,1337 .token = node.id,
1322 });1338 });
1323 },
1324 else => |e| return e,
1325 };1339 };
1326
1327 // This intCast can't fail because the limitedWriter above guarantees that
1328 // we will never write more than maxInt(u32) bytes.
1329 const data_size: u32 = @intCast(data_buffer.items.len);
1330 var header = try self.resourceHeader(node.id, node.type, .{1340 var header = try self.resourceHeader(node.id, node.type, .{
1331 .data_size = data_size,1341 .data_size = data_size,
1332 });1342 });
...@@ -1337,13 +1347,13 @@ pub const Compiler = struct {...@@ -1337,13 +1347,13 @@ pub const Compiler = struct {
13371347
1338 try header.write(writer, self.errContext(node.id));1348 try header.write(writer, self.errContext(node.id));
13391349
1340 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);1350 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
1341 try writeResourceData(writer, &data_fbs, data_size);1351 try writeResourceData(writer, &data_fbs, data_size);
1342 }1352 }
13431353
1344 /// Expects `data_writer` to be a LimitedWriter limited to u32, meaning all writes to1354 /// Expects `data_writer` to be a LimitedWriter limited to u32, meaning all writes to
1345 /// the writer within this function could return error.NoSpaceLeft1355 /// the writer within this function could return error.NoSpaceLeft
1346 pub fn writeAcceleratorsData(self: *Compiler, node: *Node.Accelerators, data_writer: anytype) !void {1356 pub fn writeAcceleratorsData(self: *Compiler, node: *Node.Accelerators, data_writer: *std.Io.Writer) !void {
1347 for (node.accelerators, 0..) |accel_node, i| {1357 for (node.accelerators, 0..) |accel_node, i| {
1348 const accelerator: *Node.Accelerator = @alignCast(@fieldParentPtr("base", accel_node));1358 const accelerator: *Node.Accelerator = @alignCast(@fieldParentPtr("base", accel_node));
1349 var modifiers = res.AcceleratorModifiers{};1359 var modifiers = res.AcceleratorModifiers{};
...@@ -1404,13 +1414,9 @@ pub const Compiler = struct {...@@ -1404,13 +1414,9 @@ pub const Compiler = struct {
1404 caption: ?Token = null,1414 caption: ?Token = null,
1405 };1415 };
14061416
1407 pub fn writeDialog(self: *Compiler, node: *Node.Dialog, writer: anytype) !void {1417 pub fn writeDialog(self: *Compiler, node: *Node.Dialog, writer: *std.Io.Writer) !void {
1408 var data_buffer = std.array_list.Managed(u8).init(self.allocator);1418 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
1409 defer data_buffer.deinit();1419 defer data_buffer.deinit();
1410 // The header's data length field is a u32 so limit the resource's data size so that
1411 // we know we can always specify the real size.
1412 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));
1413 const data_writer = limited_writer.writer();
14141420
1415 const resource = ResourceType.fromString(.{1421 const resource = ResourceType.fromString(.{
1416 .slice = node.type.slice(self.source),1422 .slice = node.type.slice(self.source),
...@@ -1671,21 +1677,18 @@ pub const Compiler = struct {...@@ -1671,21 +1677,18 @@ pub const Compiler = struct {
1671 optional_statement_values.style |= res.WS.CAPTION;1677 optional_statement_values.style |= res.WS.CAPTION;
1672 }1678 }
16731679
1674 self.writeDialogHeaderAndStrings(1680 // NOTE: Dialog header and menu/class/title strings can never exceed u32 bytes
1681 // on their own.
1682 try self.writeDialogHeaderAndStrings(
1675 node,1683 node,
1676 data_writer,1684 &data_buffer.writer,
1677 resource,1685 resource,
1678 &optional_statement_values,1686 &optional_statement_values,
1679 x,1687 x,
1680 y,1688 y,
1681 width,1689 width,
1682 height,1690 height,
1683 ) catch |err| switch (err) {1691 );
1684 // Dialog header and menu/class/title strings can never exceed u32 bytes
1685 // on their own, so this error is unreachable.
1686 error.NoSpaceLeft => unreachable,
1687 else => |e| return e,
1688 };
16891692
1690 var controls_by_id = std.AutoHashMap(u32, *const Node.ControlStatement).init(self.allocator);1693 var controls_by_id = std.AutoHashMap(u32, *const Node.ControlStatement).init(self.allocator);
1691 // Number of controls are guaranteed by the parser to be within maxInt(u16).1694 // Number of controls are guaranteed by the parser to be within maxInt(u16).
...@@ -1695,31 +1698,30 @@ pub const Compiler = struct {...@@ -1695,31 +1698,30 @@ pub const Compiler = struct {
1695 for (node.controls) |control_node| {1698 for (node.controls) |control_node| {
1696 const control: *Node.ControlStatement = @alignCast(@fieldParentPtr("base", control_node));1699 const control: *Node.ControlStatement = @alignCast(@fieldParentPtr("base", control_node));
16971700
1698 self.writeDialogControl(1701 try self.writeDialogControl(
1699 control,1702 control,
1700 data_writer,1703 &data_buffer.writer,
1701 resource,1704 resource,
1702 // We know the data_buffer len is limited to u32 max.1705 // We know the data_buffer len is limited to u32 max.
1703 @intCast(data_buffer.items.len),1706 @intCast(data_buffer.written().len),
1704 &controls_by_id,1707 &controls_by_id,
1705 ) catch |err| switch (err) {1708 );
1706 error.NoSpaceLeft => {1709
1707 try self.addErrorDetails(.{1710 if (data_buffer.written().len > std.math.maxInt(u32)) {
1708 .err = .resource_data_size_exceeds_max,1711 try self.addErrorDetails(.{
1709 .token = node.id,1712 .err = .resource_data_size_exceeds_max,
1710 });1713 .token = node.id,
1711 return self.addErrorDetailsAndFail(.{1714 });
1712 .err = .resource_data_size_exceeds_max,1715 return self.addErrorDetailsAndFail(.{
1713 .type = .note,1716 .err = .resource_data_size_exceeds_max,
1714 .token = control.type,1717 .type = .note,
1715 });1718 .token = control.type,
1716 },1719 });
1717 else => |e| return e,1720 }
1718 };
1719 }1721 }
17201722
1721 // We know the data_buffer len is limited to u32 max.1723 // We know the data_buffer len is limited to u32 max.
1722 const data_size: u32 = @intCast(data_buffer.items.len);1724 const data_size: u32 = @intCast(data_buffer.written().len);
1723 var header = try self.resourceHeader(node.id, node.type, .{1725 var header = try self.resourceHeader(node.id, node.type, .{
1724 .data_size = data_size,1726 .data_size = data_size,
1725 });1727 });
...@@ -1730,14 +1732,14 @@ pub const Compiler = struct {...@@ -1730,14 +1732,14 @@ pub const Compiler = struct {
17301732
1731 try header.write(writer, self.errContext(node.id));1733 try header.write(writer, self.errContext(node.id));
17321734
1733 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);1735 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
1734 try writeResourceData(writer, &data_fbs, data_size);1736 try writeResourceData(writer, &data_fbs, data_size);
1735 }1737 }
17361738
1737 fn writeDialogHeaderAndStrings(1739 fn writeDialogHeaderAndStrings(
1738 self: *Compiler,1740 self: *Compiler,
1739 node: *Node.Dialog,1741 node: *Node.Dialog,
1740 data_writer: anytype,1742 data_writer: *std.Io.Writer,
1741 resource: ResourceType,1743 resource: ResourceType,
1742 optional_statement_values: *const DialogOptionalStatementValues,1744 optional_statement_values: *const DialogOptionalStatementValues,
1743 x: Number,1745 x: Number,
...@@ -1797,7 +1799,7 @@ pub const Compiler = struct {...@@ -1797,7 +1799,7 @@ pub const Compiler = struct {
1797 fn writeDialogControl(1799 fn writeDialogControl(
1798 self: *Compiler,1800 self: *Compiler,
1799 control: *Node.ControlStatement,1801 control: *Node.ControlStatement,
1800 data_writer: anytype,1802 data_writer: *std.Io.Writer,
1801 resource: ResourceType,1803 resource: ResourceType,
1802 bytes_written_so_far: u32,1804 bytes_written_so_far: u32,
1803 controls_by_id: *std.AutoHashMap(u32, *const Node.ControlStatement),1805 controls_by_id: *std.AutoHashMap(u32, *const Node.ControlStatement),
...@@ -1821,7 +1823,7 @@ pub const Compiler = struct {...@@ -1821,7 +1823,7 @@ pub const Compiler = struct {
1821 .token = control.type,1823 .token = control.type,
1822 });1824 });
1823 }1825 }
1824 try data_writer.writeByteNTimes(0, num_padding);1826 try data_writer.splatByteAll(0, num_padding);
18251827
1826 const style = if (control.style) |style_expression|1828 const style = if (control.style) |style_expression|
1827 // Certain styles are implied by the control type1829 // Certain styles are implied by the control type
...@@ -1973,40 +1975,37 @@ pub const Compiler = struct {...@@ -1973,40 +1975,37 @@ pub const Compiler = struct {
1973 try NameOrOrdinal.writeEmpty(data_writer);1975 try NameOrOrdinal.writeEmpty(data_writer);
1974 }1976 }
19751977
1976 var extra_data_buf = std.array_list.Managed(u8).init(self.allocator);
1977 defer extra_data_buf.deinit();
1978 // The extra data byte length must be able to fit within a u16.1978 // The extra data byte length must be able to fit within a u16.
1979 var limited_extra_data_writer = limitedWriter(extra_data_buf.writer(), std.math.maxInt(u16));1979 var extra_data_buf: std.Io.Writer.Allocating = .init(self.allocator);
1980 const extra_data_writer = limited_extra_data_writer.writer();1980 defer extra_data_buf.deinit();
1981 for (control.extra_data) |data_expression| {1981 for (control.extra_data) |data_expression| {
1982 const data = try self.evaluateDataExpression(data_expression);1982 const data = try self.evaluateDataExpression(data_expression);
1983 defer data.deinit(self.allocator);1983 defer data.deinit(self.allocator);
1984 data.write(extra_data_writer) catch |err| switch (err) {1984 try data.write(&extra_data_buf.writer);
1985 error.NoSpaceLeft => {1985
1986 try self.addErrorDetails(.{1986 if (extra_data_buf.written().len > std.math.maxInt(u16)) {
1987 .err = .control_extra_data_size_exceeds_max,1987 try self.addErrorDetails(.{
1988 .token = control.type,1988 .err = .control_extra_data_size_exceeds_max,
1989 });1989 .token = control.type,
1990 return self.addErrorDetailsAndFail(.{1990 });
1991 .err = .control_extra_data_size_exceeds_max,1991 return self.addErrorDetailsAndFail(.{
1992 .type = .note,1992 .err = .control_extra_data_size_exceeds_max,
1993 .token = data_expression.getFirstToken(),1993 .type = .note,
1994 .token_span_end = data_expression.getLastToken(),1994 .token = data_expression.getFirstToken(),
1995 });1995 .token_span_end = data_expression.getLastToken(),
1996 },1996 });
1997 else => |e| return e,1997 }
1998 };
1999 }1998 }
2000 // We know the extra_data_buf size fits within a u16.1999 // We know the extra_data_buf size fits within a u16.
2001 const extra_data_size: u16 = @intCast(extra_data_buf.items.len);2000 const extra_data_size: u16 = @intCast(extra_data_buf.written().len);
2002 try data_writer.writeInt(u16, extra_data_size, .little);2001 try data_writer.writeInt(u16, extra_data_size, .little);
2003 try data_writer.writeAll(extra_data_buf.items);2002 try data_writer.writeAll(extra_data_buf.written());
2004 }2003 }
20052004
2006 pub fn writeToolbar(self: *Compiler, node: *Node.Toolbar, writer: anytype) !void {2005 pub fn writeToolbar(self: *Compiler, node: *Node.Toolbar, writer: *std.Io.Writer) !void {
2007 var data_buffer = std.array_list.Managed(u8).init(self.allocator);2006 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
2008 defer data_buffer.deinit();2007 defer data_buffer.deinit();
2009 const data_writer = data_buffer.writer();2008 const data_writer = &data_buffer.writer;
20102009
2011 const button_width = evaluateNumberExpression(node.button_width, self.source, self.input_code_pages);2010 const button_width = evaluateNumberExpression(node.button_width, self.source, self.input_code_pages);
2012 const button_height = evaluateNumberExpression(node.button_height, self.source, self.input_code_pages);2011 const button_height = evaluateNumberExpression(node.button_height, self.source, self.input_code_pages);
...@@ -2034,7 +2033,7 @@ pub const Compiler = struct {...@@ -2034,7 +2033,7 @@ pub const Compiler = struct {
2034 }2033 }
2035 }2034 }
20362035
2037 const data_size: u32 = @intCast(data_buffer.items.len);2036 const data_size: u32 = @intCast(data_buffer.written().len);
2038 var header = try self.resourceHeader(node.id, node.type, .{2037 var header = try self.resourceHeader(node.id, node.type, .{
2039 .data_size = data_size,2038 .data_size = data_size,
2040 });2039 });
...@@ -2044,7 +2043,7 @@ pub const Compiler = struct {...@@ -2044,7 +2043,7 @@ pub const Compiler = struct {
20442043
2045 try header.write(writer, self.errContext(node.id));2044 try header.write(writer, self.errContext(node.id));
20462045
2047 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);2046 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
2048 try writeResourceData(writer, &data_fbs, data_size);2047 try writeResourceData(writer, &data_fbs, data_size);
2049 }2048 }
20502049
...@@ -2056,7 +2055,7 @@ pub const Compiler = struct {...@@ -2056,7 +2055,7 @@ pub const Compiler = struct {
2056 node: *Node.FontStatement,2055 node: *Node.FontStatement,
2057 };2056 };
20582057
2059 pub fn writeDialogFont(self: *Compiler, resource: ResourceType, values: FontStatementValues, writer: anytype) !void {2058 pub fn writeDialogFont(self: *Compiler, resource: ResourceType, values: FontStatementValues, writer: *std.Io.Writer) !void {
2060 const node = values.node;2059 const node = values.node;
2061 const point_size = evaluateNumberExpression(node.point_size, self.source, self.input_code_pages);2060 const point_size = evaluateNumberExpression(node.point_size, self.source, self.input_code_pages);
2062 try writer.writeInt(u16, point_size.asWord(), .little);2061 try writer.writeInt(u16, point_size.asWord(), .little);
...@@ -2081,13 +2080,9 @@ pub const Compiler = struct {...@@ -2081,13 +2080,9 @@ pub const Compiler = struct {
2081 try writer.writeAll(std.mem.sliceAsBytes(typeface[0 .. typeface.len + 1]));2080 try writer.writeAll(std.mem.sliceAsBytes(typeface[0 .. typeface.len + 1]));
2082 }2081 }
20832082
2084 pub fn writeMenu(self: *Compiler, node: *Node.Menu, writer: anytype) !void {2083 pub fn writeMenu(self: *Compiler, node: *Node.Menu, writer: *std.Io.Writer) !void {
2085 var data_buffer = std.array_list.Managed(u8).init(self.allocator);2084 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
2086 defer data_buffer.deinit();2085 defer data_buffer.deinit();
2087 // The header's data length field is a u32 so limit the resource's data size so that
2088 // we know we can always specify the real size.
2089 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u32));
2090 const data_writer = limited_writer.writer();
20912086
2092 const type_bytes = SourceBytes{2087 const type_bytes = SourceBytes{
2093 .slice = node.type.slice(self.source),2088 .slice = node.type.slice(self.source),
...@@ -2096,21 +2091,15 @@ pub const Compiler = struct {...@@ -2096,21 +2091,15 @@ pub const Compiler = struct {
2096 const resource = ResourceType.fromString(type_bytes);2091 const resource = ResourceType.fromString(type_bytes);
2097 std.debug.assert(resource == .menu or resource == .menuex);2092 std.debug.assert(resource == .menu or resource == .menuex);
20982093
2099 var adapted = data_writer.adaptToNewApi(&.{});2094 try self.writeMenuData(node, &data_buffer.writer, resource);
21002095
2101 self.writeMenuData(node, &adapted.new_interface, resource) catch |err| switch (err) {2096 // TODO: Limit data_buffer in some way to error when writing more than u32 max bytes
2102 error.WriteFailed => {2097 const data_size: u32 = std.math.cast(u32, data_buffer.written().len) orelse {
2103 return self.addErrorDetailsAndFail(.{2098 return self.addErrorDetailsAndFail(.{
2104 .err = .resource_data_size_exceeds_max,2099 .err = .resource_data_size_exceeds_max,
2105 .token = node.id,2100 .token = node.id,
2106 });2101 });
2107 },
2108 else => |e| return e,
2109 };2102 };
2110
2111 // This intCast can't fail because the limitedWriter above guarantees that
2112 // we will never write more than maxInt(u32) bytes.
2113 const data_size: u32 = @intCast(data_buffer.items.len);
2114 var header = try self.resourceHeader(node.id, node.type, .{2103 var header = try self.resourceHeader(node.id, node.type, .{
2115 .data_size = data_size,2104 .data_size = data_size,
2116 });2105 });
...@@ -2121,7 +2110,7 @@ pub const Compiler = struct {...@@ -2121,7 +2110,7 @@ pub const Compiler = struct {
21212110
2122 try header.write(writer, self.errContext(node.id));2111 try header.write(writer, self.errContext(node.id));
21232112
2124 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);2113 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
2125 try writeResourceData(writer, &data_fbs, data_size);2114 try writeResourceData(writer, &data_fbs, data_size);
2126 }2115 }
21272116
...@@ -2264,13 +2253,11 @@ pub const Compiler = struct {...@@ -2264,13 +2253,11 @@ pub const Compiler = struct {
2264 }2253 }
2265 }2254 }
22662255
2267 pub fn writeVersionInfo(self: *Compiler, node: *Node.VersionInfo, writer: anytype) !void {2256 pub fn writeVersionInfo(self: *Compiler, node: *Node.VersionInfo, writer: *std.Io.Writer) !void {
2268 var data_buffer = std.array_list.Managed(u8).init(self.allocator);2257 // NOTE: The node's length field (which is inclusive of the length of all of its children) is a u16
2258 var data_buffer: std.Io.Writer.Allocating = .init(self.allocator);
2269 defer data_buffer.deinit();2259 defer data_buffer.deinit();
2270 // The node's length field (which is inclusive of the length of all of its children) is a u162260 const data_writer = &data_buffer.writer;
2271 // so limit the node's data size so that we know we can always specify the real size.
2272 var limited_writer = limitedWriter(data_buffer.writer(), std.math.maxInt(u16));
2273 const data_writer = limited_writer.writer();
22742261
2275 try data_writer.writeInt(u16, 0, .little); // placeholder size2262 try data_writer.writeInt(u16, 0, .little); // placeholder size
2276 try data_writer.writeInt(u16, res.FixedFileInfo.byte_len, .little);2263 try data_writer.writeInt(u16, res.FixedFileInfo.byte_len, .little);
...@@ -2354,29 +2341,32 @@ pub const Compiler = struct {...@@ -2354,29 +2341,32 @@ pub const Compiler = struct {
2354 try fixed_file_info.write(data_writer);2341 try fixed_file_info.write(data_writer);
23552342
2356 for (node.block_statements) |statement| {2343 for (node.block_statements) |statement| {
2357 var adapted = data_writer.adaptToNewApi(&.{});2344 var overflow = false;
2358 self.writeVersionNode(statement, &adapted.new_interface, &data_buffer) catch |err| switch (err) {2345 self.writeVersionNode(statement, data_writer) catch |err| switch (err) {
2359 error.WriteFailed => {2346 error.NoSpaceLeft => {
2360 try self.addErrorDetails(.{2347 overflow = true;
2361 .err = .version_node_size_exceeds_max,
2362 .token = node.id,
2363 });
2364 return self.addErrorDetailsAndFail(.{
2365 .err = .version_node_size_exceeds_max,
2366 .type = .note,
2367 .token = statement.getFirstToken(),
2368 .token_span_end = statement.getLastToken(),
2369 });
2370 },2348 },
2371 else => |e| return e,2349 else => |e| return e,
2372 };2350 };
2351 if (overflow or data_buffer.written().len > std.math.maxInt(u16)) {
2352 try self.addErrorDetails(.{
2353 .err = .version_node_size_exceeds_max,
2354 .token = node.id,
2355 });
2356 return self.addErrorDetailsAndFail(.{
2357 .err = .version_node_size_exceeds_max,
2358 .type = .note,
2359 .token = statement.getFirstToken(),
2360 .token_span_end = statement.getLastToken(),
2361 });
2362 }
2373 }2363 }
23742364
2375 // We know that data_buffer.items.len is within the limits of a u16, since we2365 // We know that data_buffer len is within the limits of a u16, since we check in the block
2376 // limited the writer to maxInt(u16)2366 // statements loop above which is the only place it can overflow.
2377 const data_size: u16 = @intCast(data_buffer.items.len);2367 const data_size: u16 = @intCast(data_buffer.written().len);
2378 // And now that we know the full size of this node (including its children), set its size2368 // And now that we know the full size of this node (including its children), set its size
2379 std.mem.writeInt(u16, data_buffer.items[0..2], data_size, .little);2369 std.mem.writeInt(u16, data_buffer.written()[0..2], data_size, .little);
23802370
2381 var header = try self.resourceHeader(node.id, node.versioninfo, .{2371 var header = try self.resourceHeader(node.id, node.versioninfo, .{
2382 .data_size = data_size,2372 .data_size = data_size,
...@@ -2387,22 +2377,21 @@ pub const Compiler = struct {...@@ -2387,22 +2377,21 @@ pub const Compiler = struct {
23872377
2388 try header.write(writer, self.errContext(node.id));2378 try header.write(writer, self.errContext(node.id));
23892379
2390 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);2380 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
2391 try writeResourceData(writer, &data_fbs, data_size);2381 try writeResourceData(writer, &data_fbs, data_size);
2392 }2382 }
23932383
2394 /// Expects writer to be a LimitedWriter limited to u16, meaning all writes to2384 /// Assumes that writer is Writer.Allocating (specifically, that buffered() gets the entire data)
2395 /// the writer within this function could return error.NoSpaceLeft, and that buf.items.len2385 /// TODO: This function could be nicer if writer was guaranteed to fail if it wrote more than u16 max bytes
2396 /// will never be able to exceed maxInt(u16).2386 pub fn writeVersionNode(self: *Compiler, node: *Node, writer: *std.Io.Writer) !void {
2397 pub fn writeVersionNode(self: *Compiler, node: *Node, writer: *std.Io.Writer, buf: *std.array_list.Managed(u8)) !void {
2398 // We can assume that buf.items.len will never be able to exceed the limits of a u162387 // We can assume that buf.items.len will never be able to exceed the limits of a u16
2399 try writeDataPadding(writer, @as(u16, @intCast(buf.items.len)));2388 try writeDataPadding(writer, std.math.cast(u16, writer.buffered().len) orelse return error.NoSpaceLeft);
24002389
2401 const node_and_children_size_offset = buf.items.len;2390 const node_and_children_size_offset = writer.buffered().len;
2402 try writer.writeInt(u16, 0, .little); // placeholder for size2391 try writer.writeInt(u16, 0, .little); // placeholder for size
2403 const data_size_offset = buf.items.len;2392 const data_size_offset = writer.buffered().len;
2404 try writer.writeInt(u16, 0, .little); // placeholder for data size2393 try writer.writeInt(u16, 0, .little); // placeholder for data size
2405 const data_type_offset = buf.items.len;2394 const data_type_offset = writer.buffered().len;
2406 // Data type is string unless the node contains values that are numbers.2395 // Data type is string unless the node contains values that are numbers.
2407 try writer.writeInt(u16, res.VersionNode.type_string, .little);2396 try writer.writeInt(u16, res.VersionNode.type_string, .little);
24082397
...@@ -2432,7 +2421,7 @@ pub const Compiler = struct {...@@ -2432,7 +2421,7 @@ pub const Compiler = struct {
2432 // during parsing, so we can just do the correct thing here.2421 // during parsing, so we can just do the correct thing here.
2433 var values_size: usize = 0;2422 var values_size: usize = 0;
24342423
2435 try writeDataPadding(writer, @intCast(buf.items.len));2424 try writeDataPadding(writer, std.math.cast(u16, writer.buffered().len) orelse return error.NoSpaceLeft);
24362425
2437 for (block_or_value.values, 0..) |value_value_node_uncasted, i| {2426 for (block_or_value.values, 0..) |value_value_node_uncasted, i| {
2438 const value_value_node = value_value_node_uncasted.cast(.block_value_value).?;2427 const value_value_node = value_value_node_uncasted.cast(.block_value_value).?;
...@@ -2471,26 +2460,26 @@ pub const Compiler = struct {...@@ -2471,26 +2460,26 @@ pub const Compiler = struct {
2471 }2460 }
2472 }2461 }
2473 }2462 }
2474 var data_size_slice = buf.items[data_size_offset..];2463 var data_size_slice = writer.buffered()[data_size_offset..];
2475 std.mem.writeInt(u16, data_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(values_size)), .little);2464 std.mem.writeInt(u16, data_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(values_size)), .little);
24762465
2477 if (has_number_value) {2466 if (has_number_value) {
2478 const data_type_slice = buf.items[data_type_offset..];2467 const data_type_slice = writer.buffered()[data_type_offset..];
2479 std.mem.writeInt(u16, data_type_slice[0..@sizeOf(u16)], res.VersionNode.type_binary, .little);2468 std.mem.writeInt(u16, data_type_slice[0..@sizeOf(u16)], res.VersionNode.type_binary, .little);
2480 }2469 }
24812470
2482 if (node_type == .block) {2471 if (node_type == .block) {
2483 const block = block_or_value;2472 const block = block_or_value;
2484 for (block.children) |child| {2473 for (block.children) |child| {
2485 try self.writeVersionNode(child, writer, buf);2474 try self.writeVersionNode(child, writer);
2486 }2475 }
2487 }2476 }
2488 },2477 },
2489 else => unreachable,2478 else => unreachable,
2490 }2479 }
24912480
2492 const node_and_children_size = buf.items.len - node_and_children_size_offset;2481 const node_and_children_size = writer.buffered().len - node_and_children_size_offset;
2493 const node_and_children_size_slice = buf.items[node_and_children_size_offset..];2482 const node_and_children_size_slice = writer.buffered()[node_and_children_size_offset..];
2494 std.mem.writeInt(u16, node_and_children_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(node_and_children_size)), .little);2483 std.mem.writeInt(u16, node_and_children_size_slice[0..@sizeOf(u16)], @as(u16, @intCast(node_and_children_size)), .little);
2495 }2484 }
24962485
...@@ -2683,11 +2672,11 @@ pub const Compiler = struct {...@@ -2683,11 +2672,11 @@ pub const Compiler = struct {
2683 return .{ .bytes = header_size, .padding_after_name = padding_after_name };2672 return .{ .bytes = header_size, .padding_after_name = padding_after_name };
2684 }2673 }
26852674
2686 pub fn writeAssertNoOverflow(self: ResourceHeader, writer: anytype) !void {2675 pub fn writeAssertNoOverflow(self: ResourceHeader, writer: *std.Io.Writer) !void {
2687 return self.writeSizeInfo(writer, self.calcSize() catch unreachable);2676 return self.writeSizeInfo(writer, self.calcSize() catch unreachable);
2688 }2677 }
26892678
2690 pub fn write(self: ResourceHeader, writer: anytype, err_ctx: errors.DiagnosticsContext) !void {2679 pub fn write(self: ResourceHeader, writer: *std.Io.Writer, err_ctx: errors.DiagnosticsContext) !void {
2691 const size_info = self.calcSize() catch {2680 const size_info = self.calcSize() catch {
2692 try err_ctx.diagnostics.append(.{2681 try err_ctx.diagnostics.append(.{
2693 .err = .resource_data_size_exceeds_max,2682 .err = .resource_data_size_exceeds_max,
...@@ -2825,7 +2814,7 @@ pub const Compiler = struct {...@@ -2825,7 +2814,7 @@ pub const Compiler = struct {
2825 return null;2814 return null;
2826 }2815 }
28272816
2828 pub fn writeEmptyResource(writer: anytype) !void {2817 pub fn writeEmptyResource(writer: *std.Io.Writer) !void {
2829 const header = ResourceHeader{2818 const header = ResourceHeader{
2830 .name_value = .{ .ordinal = 0 },2819 .name_value = .{ .ordinal = 0 },
2831 .type_value = .{ .ordinal = 0 },2820 .type_value = .{ .ordinal = 0 },
...@@ -2942,87 +2931,8 @@ pub const SearchDir = struct {...@@ -2942,87 +2931,8 @@ pub const SearchDir = struct {
2942 }2931 }
2943};2932};
29442933
2945/// Slurps the first `size` bytes read into `slurped_header`
2946pub fn HeaderSlurpingReader(comptime size: usize, comptime ReaderType: anytype) type {
2947 return struct {
2948 child_reader: ReaderType,
2949 bytes_read: usize = 0,
2950 slurped_header: [size]u8 = [_]u8{0x00} ** size,
2951
2952 pub const Error = ReaderType.Error;
2953 pub const Reader = std.io.GenericReader(*@This(), Error, read);
2954
2955 pub fn read(self: *@This(), buf: []u8) Error!usize {
2956 const amt = try self.child_reader.read(buf);
2957 if (self.bytes_read < size) {
2958 const bytes_to_add = @min(amt, size - self.bytes_read);
2959 const end_index = self.bytes_read + bytes_to_add;
2960 @memcpy(self.slurped_header[self.bytes_read..end_index], buf[0..bytes_to_add]);
2961 }
2962 self.bytes_read +|= amt;
2963 return amt;
2964 }
2965
2966 pub fn reader(self: *@This()) Reader {
2967 return .{ .context = self };
2968 }
2969 };
2970}
2971
2972pub fn headerSlurpingReader(comptime size: usize, reader: anytype) HeaderSlurpingReader(size, @TypeOf(reader)) {
2973 return .{ .child_reader = reader };
2974}
2975
2976/// Sort of like std.io.LimitedReader, but a Writer.
2977/// Returns an error if writing the requested number of bytes
2978/// would ever exceed bytes_left, i.e. it does not always
2979/// write up to the limit and instead will error if the
2980/// limit would be breached if the entire slice was written.
2981pub fn LimitedWriter(comptime WriterType: type) type {
2982 return struct {
2983 inner_writer: WriterType,
2984 bytes_left: u64,
2985
2986 pub const Error = error{NoSpaceLeft} || WriterType.Error;
2987 pub const Writer = std.io.GenericWriter(*Self, Error, write);
2988
2989 const Self = @This();
2990
2991 pub fn write(self: *Self, bytes: []const u8) Error!usize {
2992 if (bytes.len > self.bytes_left) return error.NoSpaceLeft;
2993 const amt = try self.inner_writer.write(bytes);
2994 self.bytes_left -= amt;
2995 return amt;
2996 }
2997
2998 pub fn writer(self: *Self) Writer {
2999 return .{ .context = self };
3000 }
3001 };
3002}
3003
3004/// Returns an initialised `LimitedWriter`
3005/// `bytes_left` is a `u64` to be able to take 64 bit file offsets
3006pub fn limitedWriter(inner_writer: anytype, bytes_left: u64) LimitedWriter(@TypeOf(inner_writer)) {
3007 return .{ .inner_writer = inner_writer, .bytes_left = bytes_left };
3008}
3009
3010test "limitedWriter basic usage" {
3011 var buf: [4]u8 = undefined;
3012 var fbs = std.io.fixedBufferStream(&buf);
3013 var limited_stream = limitedWriter(fbs.writer(), 4);
3014 var writer = limited_stream.writer();
3015
3016 try std.testing.expectEqual(@as(usize, 3), try writer.write("123"));
3017 try std.testing.expectEqualSlices(u8, "123", buf[0..3]);
3018 try std.testing.expectError(error.NoSpaceLeft, writer.write("45"));
3019 try std.testing.expectEqual(@as(usize, 1), try writer.write("4"));
3020 try std.testing.expectEqualSlices(u8, "1234", buf[0..4]);
3021 try std.testing.expectError(error.NoSpaceLeft, writer.write("5"));
3022}
3023
3024pub const FontDir = struct {2934pub const FontDir = struct {
3025 fonts: std.ArrayListUnmanaged(Font) = .empty,2935 fonts: std.ArrayList(Font) = .empty,
3026 /// To keep track of which ids are set and where they were set from2936 /// To keep track of which ids are set and where they were set from
3027 ids: std.AutoHashMapUnmanaged(u16, Token) = .empty,2937 ids: std.AutoHashMapUnmanaged(u16, Token) = .empty,
30282938
...@@ -3040,7 +2950,7 @@ pub const FontDir = struct {...@@ -3040,7 +2950,7 @@ pub const FontDir = struct {
3040 try self.fonts.append(allocator, font);2950 try self.fonts.append(allocator, font);
3041 }2951 }
30422952
3043 pub fn writeResData(self: *FontDir, compiler: *Compiler, writer: anytype) !void {2953 pub fn writeResData(self: *FontDir, compiler: *Compiler, writer: *std.Io.Writer) !void {
3044 if (self.fonts.items.len == 0) return;2954 if (self.fonts.items.len == 0) return;
30452955
3046 // We know the number of fonts is limited to maxInt(u16) because fonts2956 // We know the number of fonts is limited to maxInt(u16) because fonts
...@@ -3164,7 +3074,7 @@ pub const StringTable = struct {...@@ -3164,7 +3074,7 @@ pub const StringTable = struct {
3164 blocks: std.AutoArrayHashMapUnmanaged(u16, Block) = .empty,3074 blocks: std.AutoArrayHashMapUnmanaged(u16, Block) = .empty,
31653075
3166 pub const Block = struct {3076 pub const Block = struct {
3167 strings: std.ArrayListUnmanaged(Token) = .empty,3077 strings: std.ArrayList(Token) = .empty,
3168 set_indexes: std.bit_set.IntegerBitSet(16) = .{ .mask = 0 },3078 set_indexes: std.bit_set.IntegerBitSet(16) = .{ .mask = 0 },
3169 memory_flags: MemoryFlags = MemoryFlags.defaults(res.RT.STRING),3079 memory_flags: MemoryFlags = MemoryFlags.defaults(res.RT.STRING),
3170 characteristics: u32,3080 characteristics: u32,
...@@ -3245,10 +3155,10 @@ pub const StringTable = struct {...@@ -3245,10 +3155,10 @@ pub const StringTable = struct {
3245 try std.testing.expectEqualStrings("a", trimToDoubleNUL(u8, "a\x00\x00b"));3155 try std.testing.expectEqualStrings("a", trimToDoubleNUL(u8, "a\x00\x00b"));
3246 }3156 }
32473157
3248 pub fn writeResData(self: *Block, compiler: *Compiler, language: res.Language, block_id: u16, writer: anytype) !void {3158 pub fn writeResData(self: *Block, compiler: *Compiler, language: res.Language, block_id: u16, writer: *std.Io.Writer) !void {
3249 var data_buffer = std.array_list.Managed(u8).init(compiler.allocator);3159 var data_buffer: std.Io.Writer.Allocating = .init(compiler.allocator);
3250 defer data_buffer.deinit();3160 defer data_buffer.deinit();
3251 const data_writer = data_buffer.writer();3161 const data_writer = &data_buffer.writer;
32523162
3253 var i: u8 = 0;3163 var i: u8 = 0;
3254 var string_i: u8 = 0;3164 var string_i: u8 = 0;
...@@ -3307,7 +3217,7 @@ pub const StringTable = struct {...@@ -3307,7 +3217,7 @@ pub const StringTable = struct {
3307 // 16 * (131,070 + 2) = 2,097,152 which is well within the u32 max.3217 // 16 * (131,070 + 2) = 2,097,152 which is well within the u32 max.
3308 //3218 //
3309 // Note: The string literal maximum length is enforced by the lexer.3219 // Note: The string literal maximum length is enforced by the lexer.
3310 const data_size: u32 = @intCast(data_buffer.items.len);3220 const data_size: u32 = @intCast(data_buffer.written().len);
33113221
3312 const header = Compiler.ResourceHeader{3222 const header = Compiler.ResourceHeader{
3313 .name_value = .{ .ordinal = block_id },3223 .name_value = .{ .ordinal = block_id },
...@@ -3322,7 +3232,7 @@ pub const StringTable = struct {...@@ -3322,7 +3232,7 @@ pub const StringTable = struct {
3322 // we fully control and know are numbers, so they have a fixed size.3232 // we fully control and know are numbers, so they have a fixed size.
3323 try header.writeAssertNoOverflow(writer);3233 try header.writeAssertNoOverflow(writer);
33243234
3325 var data_fbs: std.Io.Reader = .fixed(data_buffer.items);3235 var data_fbs: std.Io.Reader = .fixed(data_buffer.written());
3326 try Compiler.writeResourceData(writer, &data_fbs, data_size);3236 try Compiler.writeResourceData(writer, &data_fbs, data_size);
3327 }3237 }
3328 };3238 };
lib/compiler/resinator/cvtres.zig+12-12
...@@ -43,7 +43,7 @@ pub const Resource = struct {...@@ -43,7 +43,7 @@ pub const Resource = struct {
43};43};
4444
45pub const ParsedResources = struct {45pub const ParsedResources = struct {
46 list: std.ArrayListUnmanaged(Resource) = .empty,46 list: std.ArrayList(Resource) = .empty,
47 allocator: Allocator,47 allocator: Allocator,
4848
49 pub fn init(allocator: Allocator) ParsedResources {49 pub fn init(allocator: Allocator) ParsedResources {
...@@ -157,7 +157,7 @@ pub fn parseNameOrOrdinal(allocator: Allocator, reader: *std.Io.Reader) !NameOrO...@@ -157,7 +157,7 @@ pub fn parseNameOrOrdinal(allocator: Allocator, reader: *std.Io.Reader) !NameOrO
157 const ordinal_value = try reader.takeInt(u16, .little);157 const ordinal_value = try reader.takeInt(u16, .little);
158 return .{ .ordinal = ordinal_value };158 return .{ .ordinal = ordinal_value };
159 }159 }
160 var name_buf = try std.ArrayListUnmanaged(u16).initCapacity(allocator, 16);160 var name_buf = try std.ArrayList(u16).initCapacity(allocator, 16);
161 errdefer name_buf.deinit(allocator);161 errdefer name_buf.deinit(allocator);
162 var code_unit = first_code_unit;162 var code_unit = first_code_unit;
163 while (code_unit != 0) {163 while (code_unit != 0) {
...@@ -373,7 +373,7 @@ pub fn writeCoff(allocator: Allocator, writer: *std.Io.Writer, resources: []cons...@@ -373,7 +373,7 @@ pub fn writeCoff(allocator: Allocator, writer: *std.Io.Writer, resources: []cons
373 try writer.writeAll(string_table.bytes.items);373 try writer.writeAll(string_table.bytes.items);
374}374}
375375
376fn writeSymbol(writer: anytype, symbol: std.coff.Symbol) !void {376fn writeSymbol(writer: *std.Io.Writer, symbol: std.coff.Symbol) !void {
377 try writer.writeAll(&symbol.name);377 try writer.writeAll(&symbol.name);
378 try writer.writeInt(u32, symbol.value, .little);378 try writer.writeInt(u32, symbol.value, .little);
379 try writer.writeInt(u16, @intFromEnum(symbol.section_number), .little);379 try writer.writeInt(u16, @intFromEnum(symbol.section_number), .little);
...@@ -383,7 +383,7 @@ fn writeSymbol(writer: anytype, symbol: std.coff.Symbol) !void {...@@ -383,7 +383,7 @@ fn writeSymbol(writer: anytype, symbol: std.coff.Symbol) !void {
383 try writer.writeInt(u8, symbol.number_of_aux_symbols, .little);383 try writer.writeInt(u8, symbol.number_of_aux_symbols, .little);
384}384}
385385
386fn writeSectionDefinition(writer: anytype, def: std.coff.SectionDefinition) !void {386fn writeSectionDefinition(writer: *std.Io.Writer, def: std.coff.SectionDefinition) !void {
387 try writer.writeInt(u32, def.length, .little);387 try writer.writeInt(u32, def.length, .little);
388 try writer.writeInt(u16, def.number_of_relocations, .little);388 try writer.writeInt(u16, def.number_of_relocations, .little);
389 try writer.writeInt(u16, def.number_of_linenumbers, .little);389 try writer.writeInt(u16, def.number_of_linenumbers, .little);
...@@ -417,7 +417,7 @@ pub const ResourceDirectoryEntry = extern struct {...@@ -417,7 +417,7 @@ pub const ResourceDirectoryEntry = extern struct {
417 to_subdirectory: bool,417 to_subdirectory: bool,
418 },418 },
419419
420 pub fn writeCoff(self: ResourceDirectoryEntry, writer: anytype) !void {420 pub fn writeCoff(self: ResourceDirectoryEntry, writer: *std.Io.Writer) !void {
421 try writer.writeInt(u32, @bitCast(self.entry), .little);421 try writer.writeInt(u32, @bitCast(self.entry), .little);
422 try writer.writeInt(u32, @bitCast(self.offset), .little);422 try writer.writeInt(u32, @bitCast(self.offset), .little);
423 }423 }
...@@ -435,7 +435,7 @@ const ResourceTree = struct {...@@ -435,7 +435,7 @@ const ResourceTree = struct {
435 type_to_name_map: std.ArrayHashMapUnmanaged(NameOrOrdinal, NameToLanguageMap, NameOrOrdinalHashContext, true),435 type_to_name_map: std.ArrayHashMapUnmanaged(NameOrOrdinal, NameToLanguageMap, NameOrOrdinalHashContext, true),
436 rsrc_string_table: std.ArrayHashMapUnmanaged(NameOrOrdinal, void, NameOrOrdinalHashContext, true),436 rsrc_string_table: std.ArrayHashMapUnmanaged(NameOrOrdinal, void, NameOrOrdinalHashContext, true),
437 deduplicated_data: std.StringArrayHashMapUnmanaged(u32),437 deduplicated_data: std.StringArrayHashMapUnmanaged(u32),
438 data_offsets: std.ArrayListUnmanaged(u32),438 data_offsets: std.ArrayList(u32),
439 rsrc02_len: u32,439 rsrc02_len: u32,
440 coff_options: CoffOptions,440 coff_options: CoffOptions,
441 allocator: Allocator,441 allocator: Allocator,
...@@ -675,13 +675,13 @@ const ResourceTree = struct {...@@ -675,13 +675,13 @@ const ResourceTree = struct {
675 return &.{};675 return &.{};
676 }676 }
677677
678 var level2_list: std.ArrayListUnmanaged(*const NameToLanguageMap) = .empty;678 var level2_list: std.ArrayList(*const NameToLanguageMap) = .empty;
679 defer level2_list.deinit(allocator);679 defer level2_list.deinit(allocator);
680680
681 var level3_list: std.ArrayListUnmanaged(*const LanguageToResourceMap) = .empty;681 var level3_list: std.ArrayList(*const LanguageToResourceMap) = .empty;
682 defer level3_list.deinit(allocator);682 defer level3_list.deinit(allocator);
683683
684 var resources_list: std.ArrayListUnmanaged(*const RelocatableResource) = .empty;684 var resources_list: std.ArrayList(*const RelocatableResource) = .empty;
685 defer resources_list.deinit(allocator);685 defer resources_list.deinit(allocator);
686686
687 var relocations = Relocations.init(allocator);687 var relocations = Relocations.init(allocator);
...@@ -896,7 +896,7 @@ const ResourceTree = struct {...@@ -896,7 +896,7 @@ const ResourceTree = struct {
896 return symbols;896 return symbols;
897 }897 }
898898
899 fn writeRelocation(writer: anytype, relocation: std.coff.Relocation) !void {899 fn writeRelocation(writer: *std.Io.Writer, relocation: std.coff.Relocation) !void {
900 try writer.writeInt(u32, relocation.virtual_address, .little);900 try writer.writeInt(u32, relocation.virtual_address, .little);
901 try writer.writeInt(u32, relocation.symbol_table_index, .little);901 try writer.writeInt(u32, relocation.symbol_table_index, .little);
902 try writer.writeInt(u16, relocation.type, .little);902 try writer.writeInt(u16, relocation.type, .little);
...@@ -928,7 +928,7 @@ const Relocation = struct {...@@ -928,7 +928,7 @@ const Relocation = struct {
928928
929const Relocations = struct {929const Relocations = struct {
930 allocator: Allocator,930 allocator: Allocator,
931 list: std.ArrayListUnmanaged(Relocation) = .empty,931 list: std.ArrayList(Relocation) = .empty,
932 cur_symbol_index: u32 = 5,932 cur_symbol_index: u32 = 5,
933933
934 pub fn init(allocator: Allocator) Relocations {934 pub fn init(allocator: Allocator) Relocations {
...@@ -952,7 +952,7 @@ const Relocations = struct {...@@ -952,7 +952,7 @@ const Relocations = struct {
952/// Does not do deduplication (only because there's no chance of duplicate strings in this952/// Does not do deduplication (only because there's no chance of duplicate strings in this
953/// instance).953/// instance).
954const StringTable = struct {954const StringTable = struct {
955 bytes: std.ArrayListUnmanaged(u8) = .empty,955 bytes: std.ArrayList(u8) = .empty,
956956
957 pub fn deinit(self: *StringTable, allocator: Allocator) void {957 pub fn deinit(self: *StringTable, allocator: Allocator) void {
958 self.bytes.deinit(allocator);958 self.bytes.deinit(allocator);
lib/compiler/resinator/errors.zig+25-28
...@@ -15,10 +15,10 @@ const builtin = @import("builtin");...@@ -15,10 +15,10 @@ const builtin = @import("builtin");
15const native_endian = builtin.cpu.arch.endian();15const native_endian = builtin.cpu.arch.endian();
1616
17pub const Diagnostics = struct {17pub const Diagnostics = struct {
18 errors: std.ArrayListUnmanaged(ErrorDetails) = .empty,18 errors: std.ArrayList(ErrorDetails) = .empty,
19 /// Append-only, cannot handle removing strings.19 /// Append-only, cannot handle removing strings.
20 /// Expects to own all strings within the list.20 /// Expects to own all strings within the list.
21 strings: std.ArrayListUnmanaged([]const u8) = .empty,21 strings: std.ArrayList([]const u8) = .empty,
22 allocator: std.mem.Allocator,22 allocator: std.mem.Allocator,
2323
24 pub fn init(allocator: std.mem.Allocator) Diagnostics {24 pub fn init(allocator: std.mem.Allocator) Diagnostics {
...@@ -256,7 +256,7 @@ pub const ErrorDetails = struct {...@@ -256,7 +256,7 @@ pub const ErrorDetails = struct {
256 .{ "literal", "unquoted literal" },256 .{ "literal", "unquoted literal" },
257 });257 });
258258
259 pub fn writeCommaSeparated(self: ExpectedTypes, writer: anytype) !void {259 pub fn writeCommaSeparated(self: ExpectedTypes, writer: *std.Io.Writer) !void {
260 const struct_info = @typeInfo(ExpectedTypes).@"struct";260 const struct_info = @typeInfo(ExpectedTypes).@"struct";
261 const num_real_fields = struct_info.fields.len - 1;261 const num_real_fields = struct_info.fields.len - 1;
262 const num_padding_bits = @bitSizeOf(ExpectedTypes) - num_real_fields;262 const num_padding_bits = @bitSizeOf(ExpectedTypes) - num_real_fields;
...@@ -441,7 +441,7 @@ pub const ErrorDetails = struct {...@@ -441,7 +441,7 @@ pub const ErrorDetails = struct {
441 } };441 } };
442 }442 }
443443
444 pub fn render(self: ErrorDetails, writer: anytype, source: []const u8, strings: []const []const u8) !void {444 pub fn render(self: ErrorDetails, writer: *std.Io.Writer, source: []const u8, strings: []const []const u8) !void {
445 switch (self.err) {445 switch (self.err) {
446 .unfinished_string_literal => {446 .unfinished_string_literal => {
447 return writer.print("unfinished string literal at '{f}', expected closing '\"'", .{self.fmtToken(source)});447 return writer.print("unfinished string literal at '{f}', expected closing '\"'", .{self.fmtToken(source)});
...@@ -987,12 +987,14 @@ pub fn renderErrorMessage(writer: *std.io.Writer, tty_config: std.io.tty.Config,...@@ -987,12 +987,14 @@ pub fn renderErrorMessage(writer: *std.io.Writer, tty_config: std.io.tty.Config,
987 if (corresponding_span != null and corresponding_file != null) {987 if (corresponding_span != null and corresponding_file != null) {
988 var worth_printing_lines: bool = true;988 var worth_printing_lines: bool = true;
989 var initial_lines_err: ?anyerror = null;989 var initial_lines_err: ?anyerror = null;
990 var file_reader_buf: [max_source_line_bytes * 2]u8 = undefined;
990 var corresponding_lines: ?CorrespondingLines = CorrespondingLines.init(991 var corresponding_lines: ?CorrespondingLines = CorrespondingLines.init(
991 cwd,992 cwd,
992 err_details,993 err_details,
993 source_line_for_display.line,994 source_line_for_display.line,
994 corresponding_span.?,995 corresponding_span.?,
995 corresponding_file.?,996 corresponding_file.?,
997 &file_reader_buf,
996 ) catch |err| switch (err) {998 ) catch |err| switch (err) {
997 error.NotWorthPrintingLines => blk: {999 error.NotWorthPrintingLines => blk: {
998 worth_printing_lines = false;1000 worth_printing_lines = false;
...@@ -1078,10 +1080,17 @@ const CorrespondingLines = struct {...@@ -1078,10 +1080,17 @@ const CorrespondingLines = struct {
1078 at_eof: bool = false,1080 at_eof: bool = false,
1079 span: SourceMappings.CorrespondingSpan,1081 span: SourceMappings.CorrespondingSpan,
1080 file: std.fs.File,1082 file: std.fs.File,
1081 buffered_reader: std.fs.File.Reader,1083 file_reader: std.fs.File.Reader,
1082 code_page: SupportedCodePage,1084 code_page: SupportedCodePage,
10831085
1084 pub fn init(cwd: std.fs.Dir, err_details: ErrorDetails, line_for_comparison: []const u8, corresponding_span: SourceMappings.CorrespondingSpan, corresponding_file: []const u8) !CorrespondingLines {1086 pub fn init(
1087 cwd: std.fs.Dir,
1088 err_details: ErrorDetails,
1089 line_for_comparison: []const u8,
1090 corresponding_span: SourceMappings.CorrespondingSpan,
1091 corresponding_file: []const u8,
1092 file_reader_buf: []u8,
1093 ) !CorrespondingLines {
1085 // We don't do line comparison for this error, so don't print the note if the line1094 // We don't do line comparison for this error, so don't print the note if the line
1086 // number is different1095 // number is different
1087 if (err_details.err == .string_literal_too_long and err_details.token.line_number != corresponding_span.start_line) {1096 if (err_details.err == .string_literal_too_long and err_details.token.line_number != corresponding_span.start_line) {
...@@ -1096,18 +1105,14 @@ const CorrespondingLines = struct {...@@ -1096,18 +1105,14 @@ const CorrespondingLines = struct {
1096 var corresponding_lines = CorrespondingLines{1105 var corresponding_lines = CorrespondingLines{
1097 .span = corresponding_span,1106 .span = corresponding_span,
1098 .file = try utils.openFileNotDir(cwd, corresponding_file, .{}),1107 .file = try utils.openFileNotDir(cwd, corresponding_file, .{}),
1099 .buffered_reader = undefined,
1100 .code_page = err_details.code_page,1108 .code_page = err_details.code_page,
1109 .file_reader = undefined,
1101 };1110 };
1102 corresponding_lines.buffered_reader = corresponding_lines.file.reader(&.{});1111 corresponding_lines.file_reader = corresponding_lines.file.reader(file_reader_buf);
1103 errdefer corresponding_lines.deinit();1112 errdefer corresponding_lines.deinit();
11041113
1105 var fbs = std.io.fixedBufferStream(&corresponding_lines.line_buf);
1106 const writer = fbs.writer();
1107
1108 try corresponding_lines.writeLineFromStreamVerbatim(1114 try corresponding_lines.writeLineFromStreamVerbatim(
1109 writer,1115 &corresponding_lines.file_reader.interface,
1110 corresponding_lines.buffered_reader.interface.adaptToOldInterface(),
1111 corresponding_span.start_line,1116 corresponding_span.start_line,
1112 );1117 );
11131118
...@@ -1145,12 +1150,8 @@ const CorrespondingLines = struct {...@@ -1145,12 +1150,8 @@ const CorrespondingLines = struct {
1145 self.line_len = 0;1150 self.line_len = 0;
1146 self.visual_line_len = 0;1151 self.visual_line_len = 0;
11471152
1148 var fbs = std.io.fixedBufferStream(&self.line_buf);
1149 const writer = fbs.writer();
1150
1151 try self.writeLineFromStreamVerbatim(1153 try self.writeLineFromStreamVerbatim(
1152 writer,1154 &self.file_reader.interface,
1153 self.buffered_reader.interface.adaptToOldInterface(),
1154 self.line_num,1155 self.line_num,
1155 );1156 );
11561157
...@@ -1164,7 +1165,7 @@ const CorrespondingLines = struct {...@@ -1164,7 +1165,7 @@ const CorrespondingLines = struct {
1164 return visual_line;1165 return visual_line;
1165 }1166 }
11661167
1167 fn writeLineFromStreamVerbatim(self: *CorrespondingLines, writer: anytype, input: anytype, line_num: usize) !void {1168 fn writeLineFromStreamVerbatim(self: *CorrespondingLines, input: *std.Io.Reader, line_num: usize) !void {
1168 while (try readByteOrEof(input)) |byte| {1169 while (try readByteOrEof(input)) |byte| {
1169 switch (byte) {1170 switch (byte) {
1170 '\n', '\r' => {1171 '\n', '\r' => {
...@@ -1184,13 +1185,9 @@ const CorrespondingLines = struct {...@@ -1184,13 +1185,9 @@ const CorrespondingLines = struct {
1184 }1185 }
1185 },1186 },
1186 else => {1187 else => {
1187 if (self.line_num == line_num) {1188 if (self.line_num == line_num and self.line_len < self.line_buf.len) {
1188 if (writer.writeByte(byte)) {1189 self.line_buf[self.line_len] = byte;
1189 self.line_len += 1;1190 self.line_len += 1;
1190 } else |err| switch (err) {
1191 error.NoSpaceLeft => {},
1192 else => |e| return e,
1193 }
1194 }1191 }
1195 },1192 },
1196 }1193 }
...@@ -1201,8 +1198,8 @@ const CorrespondingLines = struct {...@@ -1201,8 +1198,8 @@ const CorrespondingLines = struct {
1201 self.line_num += 1;1198 self.line_num += 1;
1202 }1199 }
12031200
1204 fn readByteOrEof(reader: anytype) !?u8 {1201 fn readByteOrEof(reader: *std.Io.Reader) !?u8 {
1205 return reader.readByte() catch |err| switch (err) {1202 return reader.takeByte() catch |err| switch (err) {
1206 error.EndOfStream => return null,1203 error.EndOfStream => return null,
1207 else => |e| return e,1204 else => |e| return e,
1208 };1205 };
lib/compiler/resinator/ico.zig+43-57
...@@ -8,80 +8,66 @@ const std = @import("std");...@@ -8,80 +8,66 @@ const std = @import("std");
8const builtin = @import("builtin");8const builtin = @import("builtin");
9const native_endian = builtin.cpu.arch.endian();9const native_endian = builtin.cpu.arch.endian();
1010
11pub const ReadError = std.mem.Allocator.Error || error{ InvalidHeader, InvalidImageType, ImpossibleDataSize, UnexpectedEOF, ReadError };11pub const ReadError = std.mem.Allocator.Error || error{ InvalidHeader, InvalidImageType, ImpossibleDataSize, UnexpectedEOF, ReadFailed };
1212
13pub fn read(allocator: std.mem.Allocator, reader: anytype, max_size: u64) ReadError!IconDir {13pub fn read(allocator: std.mem.Allocator, reader: *std.Io.Reader, max_size: u64) ReadError!IconDir {
14 // Some Reader implementations have an empty ReadError error set which would14 return readInner(allocator, reader, max_size) catch |err| switch (err) {
15 // cause 'unreachable else' if we tried to use an else in the switch, so we15 error.OutOfMemory,
16 // need to detect this case and not try to translate to ReadError16 error.InvalidHeader,
17 const anyerror_reader_errorset = @TypeOf(reader).Error == anyerror;17 error.InvalidImageType,
18 const empty_reader_errorset = @typeInfo(@TypeOf(reader).Error).error_set == null or @typeInfo(@TypeOf(reader).Error).error_set.?.len == 0;18 error.ImpossibleDataSize,
19 if (empty_reader_errorset and !anyerror_reader_errorset) {19 error.ReadFailed,
20 return readAnyError(allocator, reader, max_size) catch |err| switch (err) {20 => |e| return e,
21 error.EndOfStream => error.UnexpectedEOF,21 error.EndOfStream => error.UnexpectedEOF,
22 else => |e| return e,22 };
23 };
24 } else {
25 return readAnyError(allocator, reader, max_size) catch |err| switch (err) {
26 error.OutOfMemory,
27 error.InvalidHeader,
28 error.InvalidImageType,
29 error.ImpossibleDataSize,
30 => |e| return e,
31 error.EndOfStream => error.UnexpectedEOF,
32 // The remaining errors are dependent on the `reader`, so
33 // we just translate them all to generic ReadError
34 else => error.ReadError,
35 };
36 }
37}23}
3824
39// TODO: This seems like a somewhat strange pattern, could be a better way25// TODO: This seems like a somewhat strange pattern, could be a better way
40// to do this. Maybe it makes more sense to handle the translation26// to do this. Maybe it makes more sense to handle the translation
41// at the call site instead of having a helper function here.27// at the call site instead of having a helper function here.
42pub fn readAnyError(allocator: std.mem.Allocator, reader: anytype, max_size: u64) !IconDir {28fn readInner(allocator: std.mem.Allocator, reader: *std.Io.Reader, max_size: u64) !IconDir {
43 const reserved = try reader.readInt(u16, .little);29 const reserved = try reader.takeInt(u16, .little);
44 if (reserved != 0) {30 if (reserved != 0) {
45 return error.InvalidHeader;31 return error.InvalidHeader;
46 }32 }
4733
48 const image_type = reader.readEnum(ImageType, .little) catch |err| switch (err) {34 const image_type = reader.takeEnum(ImageType, .little) catch |err| switch (err) {
49 error.InvalidValue => return error.InvalidImageType,35 error.InvalidEnumTag => return error.InvalidImageType,
50 else => |e| return e,36 else => |e| return e,
51 };37 };
5238
53 const num_images = try reader.readInt(u16, .little);39 const num_images = try reader.takeInt(u16, .little);
5440
55 // To avoid over-allocation in the case of a file that says it has way more41 // To avoid over-allocation in the case of a file that says it has way more
56 // entries than it actually does, we use an ArrayList with a conservatively42 // entries than it actually does, we use an ArrayList with a conservatively
57 // limited initial capacity instead of allocating the entire slice at once.43 // limited initial capacity instead of allocating the entire slice at once.
58 const initial_capacity = @min(num_images, 8);44 const initial_capacity = @min(num_images, 8);
59 var entries = try std.array_list.Managed(Entry).initCapacity(allocator, initial_capacity);45 var entries = try std.ArrayList(Entry).initCapacity(allocator, initial_capacity);
60 errdefer entries.deinit();46 errdefer entries.deinit(allocator);
6147
62 var i: usize = 0;48 var i: usize = 0;
63 while (i < num_images) : (i += 1) {49 while (i < num_images) : (i += 1) {
64 var entry: Entry = undefined;50 var entry: Entry = undefined;
65 entry.width = try reader.readByte();51 entry.width = try reader.takeByte();
66 entry.height = try reader.readByte();52 entry.height = try reader.takeByte();
67 entry.num_colors = try reader.readByte();53 entry.num_colors = try reader.takeByte();
68 entry.reserved = try reader.readByte();54 entry.reserved = try reader.takeByte();
69 switch (image_type) {55 switch (image_type) {
70 .icon => {56 .icon => {
71 entry.type_specific_data = .{ .icon = .{57 entry.type_specific_data = .{ .icon = .{
72 .color_planes = try reader.readInt(u16, .little),58 .color_planes = try reader.takeInt(u16, .little),
73 .bits_per_pixel = try reader.readInt(u16, .little),59 .bits_per_pixel = try reader.takeInt(u16, .little),
74 } };60 } };
75 },61 },
76 .cursor => {62 .cursor => {
77 entry.type_specific_data = .{ .cursor = .{63 entry.type_specific_data = .{ .cursor = .{
78 .hotspot_x = try reader.readInt(u16, .little),64 .hotspot_x = try reader.takeInt(u16, .little),
79 .hotspot_y = try reader.readInt(u16, .little),65 .hotspot_y = try reader.takeInt(u16, .little),
80 } };66 } };
81 },67 },
82 }68 }
83 entry.data_size_in_bytes = try reader.readInt(u32, .little);69 entry.data_size_in_bytes = try reader.takeInt(u32, .little);
84 entry.data_offset_from_start_of_file = try reader.readInt(u32, .little);70 entry.data_offset_from_start_of_file = try reader.takeInt(u32, .little);
85 // Validate that the offset/data size is feasible71 // Validate that the offset/data size is feasible
86 if (@as(u64, entry.data_offset_from_start_of_file) + entry.data_size_in_bytes > max_size) {72 if (@as(u64, entry.data_offset_from_start_of_file) + entry.data_size_in_bytes > max_size) {
87 return error.ImpossibleDataSize;73 return error.ImpossibleDataSize;
...@@ -101,12 +87,12 @@ pub fn readAnyError(allocator: std.mem.Allocator, reader: anytype, max_size: u64...@@ -101,12 +87,12 @@ pub fn readAnyError(allocator: std.mem.Allocator, reader: anytype, max_size: u64
101 if (entry.data_size_in_bytes < 16) {87 if (entry.data_size_in_bytes < 16) {
102 return error.ImpossibleDataSize;88 return error.ImpossibleDataSize;
103 }89 }
104 try entries.append(entry);90 try entries.append(allocator, entry);
105 }91 }
10692
107 return .{93 return .{
108 .image_type = image_type,94 .image_type = image_type,
109 .entries = try entries.toOwnedSlice(),95 .entries = try entries.toOwnedSlice(allocator),
110 .allocator = allocator,96 .allocator = allocator,
111 };97 };
112}98}
...@@ -135,7 +121,7 @@ pub const IconDir = struct {...@@ -135,7 +121,7 @@ pub const IconDir = struct {
135 return @intCast(IconDir.res_header_byte_len + self.entries.len * Entry.res_byte_len);121 return @intCast(IconDir.res_header_byte_len + self.entries.len * Entry.res_byte_len);
136 }122 }
137123
138 pub fn writeResData(self: IconDir, writer: anytype, first_image_id: u16) !void {124 pub fn writeResData(self: IconDir, writer: *std.Io.Writer, first_image_id: u16) !void {
139 try writer.writeInt(u16, 0, .little);125 try writer.writeInt(u16, 0, .little);
140 try writer.writeInt(u16, @intFromEnum(self.image_type), .little);126 try writer.writeInt(u16, @intFromEnum(self.image_type), .little);
141 // We know that entries.len must fit into a u16127 // We know that entries.len must fit into a u16
...@@ -173,7 +159,7 @@ pub const Entry = struct {...@@ -173,7 +159,7 @@ pub const Entry = struct {
173159
174 pub const res_byte_len = 14;160 pub const res_byte_len = 14;
175161
176 pub fn writeResData(self: Entry, writer: anytype, id: u16) !void {162 pub fn writeResData(self: Entry, writer: *std.Io.Writer, id: u16) !void {
177 switch (self.type_specific_data) {163 switch (self.type_specific_data) {
178 .icon => |icon_data| {164 .icon => |icon_data| {
179 try writer.writeInt(u8, @as(u8, @truncate(self.width)), .little);165 try writer.writeInt(u8, @as(u8, @truncate(self.width)), .little);
...@@ -198,8 +184,8 @@ pub const Entry = struct {...@@ -198,8 +184,8 @@ pub const Entry = struct {
198184
199test "icon" {185test "icon" {
200 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;186 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;
201 var fbs = std.io.fixedBufferStream(data);187 var fbs: std.Io.Reader = .fixed(data);
202 const icon = try read(std.testing.allocator, fbs.reader(), data.len);188 const icon = try read(std.testing.allocator, &fbs, data.len);
203 defer icon.deinit();189 defer icon.deinit();
204190
205 try std.testing.expectEqual(ImageType.icon, icon.image_type);191 try std.testing.expectEqual(ImageType.icon, icon.image_type);
...@@ -211,26 +197,26 @@ test "icon too many images" {...@@ -211,26 +197,26 @@ test "icon too many images" {
211 // it's not possible to hit EOF when looking for more RESDIR structures, since they are197 // it's not possible to hit EOF when looking for more RESDIR structures, since they are
212 // themselves 16 bytes long, so we'll always hit ImpossibleDataSize instead.198 // themselves 16 bytes long, so we'll always hit ImpossibleDataSize instead.
213 const data = "\x00\x00\x01\x00\x02\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;199 const data = "\x00\x00\x01\x00\x02\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;
214 var fbs = std.io.fixedBufferStream(data);200 var fbs: std.Io.Reader = .fixed(data);
215 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));201 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
216}202}
217203
218test "icon data size past EOF" {204test "icon data size past EOF" {
219 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x01\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;205 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x01\x00\x00\x16\x00\x00\x00" ++ [_]u8{0} ** 16;
220 var fbs = std.io.fixedBufferStream(data);206 var fbs: std.Io.Reader = .fixed(data);
221 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));207 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
222}208}
223209
224test "icon data offset past EOF" {210test "icon data offset past EOF" {
225 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x17\x00\x00\x00" ++ [_]u8{0} ** 16;211 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x10\x00\x00\x00\x17\x00\x00\x00" ++ [_]u8{0} ** 16;
226 var fbs = std.io.fixedBufferStream(data);212 var fbs: std.Io.Reader = .fixed(data);
227 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));213 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
228}214}
229215
230test "icon data size too small" {216test "icon data size too small" {
231 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x0F\x00\x00\x00\x16\x00\x00\x00";217 const data = "\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x10\x00\x0F\x00\x00\x00\x16\x00\x00\x00";
232 var fbs = std.io.fixedBufferStream(data);218 var fbs: std.Io.Reader = .fixed(data);
233 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, fbs.reader(), data.len));219 try std.testing.expectError(error.ImpossibleDataSize, read(std.testing.allocator, &fbs, data.len));
234}220}
235221
236pub const ImageFormat = enum(u2) {222pub const ImageFormat = enum(u2) {
lib/compiler/resinator/lang.zig+6-5
...@@ -119,6 +119,7 @@ test tagToId {...@@ -119,6 +119,7 @@ test tagToId {
119}119}
120120
121test "exhaustive tagToId" {121test "exhaustive tagToId" {
122 @setEvalBranchQuota(2000);
122 inline for (@typeInfo(LanguageId).@"enum".fields) |field| {123 inline for (@typeInfo(LanguageId).@"enum".fields) |field| {
123 const id = tagToId(field.name) catch |err| {124 const id = tagToId(field.name) catch |err| {
124 std.debug.print("tag: {s}\n", .{field.name});125 std.debug.print("tag: {s}\n", .{field.name});
...@@ -131,8 +132,8 @@ test "exhaustive tagToId" {...@@ -131,8 +132,8 @@ test "exhaustive tagToId" {
131 }132 }
132 var buf: [32]u8 = undefined;133 var buf: [32]u8 = undefined;
133 inline for (valid_alternate_sorts) |parsed_sort| {134 inline for (valid_alternate_sorts) |parsed_sort| {
134 var fbs = std.io.fixedBufferStream(&buf);135 var fbs: std.Io.Writer = .fixed(&buf);
135 const writer = fbs.writer();136 const writer = &fbs;
136 writer.writeAll(parsed_sort.language_code) catch unreachable;137 writer.writeAll(parsed_sort.language_code) catch unreachable;
137 writer.writeAll("-") catch unreachable;138 writer.writeAll("-") catch unreachable;
138 writer.writeAll(parsed_sort.country_code.?) catch unreachable;139 writer.writeAll(parsed_sort.country_code.?) catch unreachable;
...@@ -146,12 +147,12 @@ test "exhaustive tagToId" {...@@ -146,12 +147,12 @@ test "exhaustive tagToId" {
146 break :field name_buf;147 break :field name_buf;
147 };148 };
148 const expected = @field(LanguageId, &expected_field_name);149 const expected = @field(LanguageId, &expected_field_name);
149 const id = tagToId(fbs.getWritten()) catch |err| {150 const id = tagToId(fbs.buffered()) catch |err| {
150 std.debug.print("tag: {s}\n", .{fbs.getWritten()});151 std.debug.print("tag: {s}\n", .{fbs.buffered()});
151 return err;152 return err;
152 };153 };
153 try std.testing.expectEqual(expected, id orelse {154 try std.testing.expectEqual(expected, id orelse {
154 std.debug.print("tag: {s}, expected: {}, got null\n", .{ fbs.getWritten(), expected });155 std.debug.print("tag: {s}, expected: {}, got null\n", .{ fbs.buffered(), expected });
155 return error.TestExpectedEqual;156 return error.TestExpectedEqual;
156 });157 });
157 }158 }
lib/compiler/resinator/literals.zig+22-22
...@@ -469,8 +469,8 @@ pub fn parseQuotedString(...@@ -469,8 +469,8 @@ pub fn parseQuotedString(
469 const T = if (literal_type == .ascii) u8 else u16;469 const T = if (literal_type == .ascii) u8 else u16;
470 std.debug.assert(bytes.slice.len >= 2); // must at least have 2 double quote chars470 std.debug.assert(bytes.slice.len >= 2); // must at least have 2 double quote chars
471471
472 var buf = try std.array_list.Managed(T).initCapacity(allocator, bytes.slice.len);472 var buf = try std.ArrayList(T).initCapacity(allocator, bytes.slice.len);
473 errdefer buf.deinit();473 errdefer buf.deinit(allocator);
474474
475 var iterative_parser = IterativeStringParser.init(bytes, options);475 var iterative_parser = IterativeStringParser.init(bytes, options);
476476
...@@ -480,13 +480,13 @@ pub fn parseQuotedString(...@@ -480,13 +480,13 @@ pub fn parseQuotedString(
480 .ascii => switch (options.output_code_page) {480 .ascii => switch (options.output_code_page) {
481 .windows1252 => {481 .windows1252 => {
482 if (parsed.from_escaped_integer) {482 if (parsed.from_escaped_integer) {
483 try buf.append(@truncate(c));483 try buf.append(allocator, @truncate(c));
484 } else if (windows1252.bestFitFromCodepoint(c)) |best_fit| {484 } else if (windows1252.bestFitFromCodepoint(c)) |best_fit| {
485 try buf.append(best_fit);485 try buf.append(allocator, best_fit);
486 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid) {486 } else if (c < 0x10000 or c == code_pages.Codepoint.invalid) {
487 try buf.append('?');487 try buf.append(allocator, '?');
488 } else {488 } else {
489 try buf.appendSlice("??");489 try buf.appendSlice(allocator, "??");
490 }490 }
491 },491 },
492 .utf8 => {492 .utf8 => {
...@@ -500,35 +500,35 @@ pub fn parseQuotedString(...@@ -500,35 +500,35 @@ pub fn parseQuotedString(
500 }500 }
501 var utf8_buf: [4]u8 = undefined;501 var utf8_buf: [4]u8 = undefined;
502 const utf8_len = std.unicode.utf8Encode(codepoint_to_encode, &utf8_buf) catch unreachable;502 const utf8_len = std.unicode.utf8Encode(codepoint_to_encode, &utf8_buf) catch unreachable;
503 try buf.appendSlice(utf8_buf[0..utf8_len]);503 try buf.appendSlice(allocator, utf8_buf[0..utf8_len]);
504 },504 },
505 },505 },
506 .wide => {506 .wide => {
507 // Parsing any string type as a wide string is handled separately, see parseQuotedStringAsWideString507 // Parsing any string type as a wide string is handled separately, see parseQuotedStringAsWideString
508 std.debug.assert(iterative_parser.declared_string_type == .wide);508 std.debug.assert(iterative_parser.declared_string_type == .wide);
509 if (parsed.from_escaped_integer) {509 if (parsed.from_escaped_integer) {
510 try buf.append(std.mem.nativeToLittle(u16, @truncate(c)));510 try buf.append(allocator, std.mem.nativeToLittle(u16, @truncate(c)));
511 } else if (c == code_pages.Codepoint.invalid) {511 } else if (c == code_pages.Codepoint.invalid) {
512 try buf.append(std.mem.nativeToLittle(u16, '�'));512 try buf.append(allocator, std.mem.nativeToLittle(u16, '�'));
513 } else if (c < 0x10000) {513 } else if (c < 0x10000) {
514 const short: u16 = @intCast(c);514 const short: u16 = @intCast(c);
515 try buf.append(std.mem.nativeToLittle(u16, short));515 try buf.append(allocator, std.mem.nativeToLittle(u16, short));
516 } else {516 } else {
517 if (!parsed.escaped_surrogate_pair) {517 if (!parsed.escaped_surrogate_pair) {
518 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;518 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;
519 try buf.append(std.mem.nativeToLittle(u16, high));519 try buf.append(allocator, std.mem.nativeToLittle(u16, high));
520 }520 }
521 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;521 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;
522 try buf.append(std.mem.nativeToLittle(u16, low));522 try buf.append(allocator, std.mem.nativeToLittle(u16, low));
523 }523 }
524 },524 },
525 }525 }
526 }526 }
527527
528 if (literal_type == .wide) {528 if (literal_type == .wide) {
529 return buf.toOwnedSliceSentinel(0);529 return buf.toOwnedSliceSentinel(allocator, 0);
530 } else {530 } else {
531 return buf.toOwnedSlice();531 return buf.toOwnedSlice(allocator);
532 }532 }
533}533}
534534
...@@ -564,8 +564,8 @@ pub fn parseQuotedStringAsWideString(allocator: std.mem.Allocator, bytes: Source...@@ -564,8 +564,8 @@ pub fn parseQuotedStringAsWideString(allocator: std.mem.Allocator, bytes: Source
564 // Note: We're only handling the case of parsing an ASCII string into a wide string from here on out.564 // Note: We're only handling the case of parsing an ASCII string into a wide string from here on out.
565 // TODO: The logic below is similar to that in AcceleratorKeyCodepointTranslator, might be worth merging the two565 // TODO: The logic below is similar to that in AcceleratorKeyCodepointTranslator, might be worth merging the two
566566
567 var buf = try std.array_list.Managed(u16).initCapacity(allocator, bytes.slice.len);567 var buf = try std.ArrayList(u16).initCapacity(allocator, bytes.slice.len);
568 errdefer buf.deinit();568 errdefer buf.deinit(allocator);
569569
570 var iterative_parser = IterativeStringParser.init(bytes, options);570 var iterative_parser = IterativeStringParser.init(bytes, options);
571571
...@@ -578,23 +578,23 @@ pub fn parseQuotedStringAsWideString(allocator: std.mem.Allocator, bytes: Source...@@ -578,23 +578,23 @@ pub fn parseQuotedStringAsWideString(allocator: std.mem.Allocator, bytes: Source
578 .windows1252 => windows1252.toCodepoint(byte_to_interpret),578 .windows1252 => windows1252.toCodepoint(byte_to_interpret),
579 .utf8 => if (byte_to_interpret > 0x7F) '�' else byte_to_interpret,579 .utf8 => if (byte_to_interpret > 0x7F) '�' else byte_to_interpret,
580 };580 };
581 try buf.append(std.mem.nativeToLittle(u16, code_unit_to_encode));581 try buf.append(allocator, std.mem.nativeToLittle(u16, code_unit_to_encode));
582 } else if (c == code_pages.Codepoint.invalid) {582 } else if (c == code_pages.Codepoint.invalid) {
583 try buf.append(std.mem.nativeToLittle(u16, '�'));583 try buf.append(allocator, std.mem.nativeToLittle(u16, '�'));
584 } else if (c < 0x10000) {584 } else if (c < 0x10000) {
585 const short: u16 = @intCast(c);585 const short: u16 = @intCast(c);
586 try buf.append(std.mem.nativeToLittle(u16, short));586 try buf.append(allocator, std.mem.nativeToLittle(u16, short));
587 } else {587 } else {
588 if (!parsed.escaped_surrogate_pair) {588 if (!parsed.escaped_surrogate_pair) {
589 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;589 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;
590 try buf.append(std.mem.nativeToLittle(u16, high));590 try buf.append(allocator, std.mem.nativeToLittle(u16, high));
591 }591 }
592 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;592 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;
593 try buf.append(std.mem.nativeToLittle(u16, low));593 try buf.append(allocator, std.mem.nativeToLittle(u16, low));
594 }594 }
595 }595 }
596596
597 return buf.toOwnedSliceSentinel(0);597 return buf.toOwnedSliceSentinel(allocator, 0);
598}598}
599599
600test "parse quoted ascii string" {600test "parse quoted ascii string" {
lib/compiler/resinator/main.zig+68-62
...@@ -3,6 +3,7 @@ const builtin = @import("builtin");...@@ -3,6 +3,7 @@ const builtin = @import("builtin");
3const removeComments = @import("comments.zig").removeComments;3const removeComments = @import("comments.zig").removeComments;
4const parseAndRemoveLineCommands = @import("source_mapping.zig").parseAndRemoveLineCommands;4const parseAndRemoveLineCommands = @import("source_mapping.zig").parseAndRemoveLineCommands;
5const compile = @import("compile.zig").compile;5const compile = @import("compile.zig").compile;
6const Dependencies = @import("compile.zig").Dependencies;
6const Diagnostics = @import("errors.zig").Diagnostics;7const Diagnostics = @import("errors.zig").Diagnostics;
7const cli = @import("cli.zig");8const cli = @import("cli.zig");
8const preprocess = @import("preprocess.zig");9const preprocess = @import("preprocess.zig");
...@@ -13,8 +14,6 @@ const hasDisjointCodePage = @import("disjoint_code_page.zig").hasDisjointCodePag...@@ -13,8 +14,6 @@ const hasDisjointCodePage = @import("disjoint_code_page.zig").hasDisjointCodePag
13const fmtResourceType = @import("res.zig").NameOrOrdinal.fmtResourceType;14const fmtResourceType = @import("res.zig").NameOrOrdinal.fmtResourceType;
14const aro = @import("aro");15const aro = @import("aro");
1516
16var stdout_buffer: [1024]u8 = undefined;
17
18pub fn main() !void {17pub fn main() !void {
19 var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;18 var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
20 defer std.debug.assert(gpa.deinit() == .ok);19 defer std.debug.assert(gpa.deinit() == .ok);
...@@ -43,11 +42,13 @@ pub fn main() !void {...@@ -43,11 +42,13 @@ pub fn main() !void {
43 cli_args = args[3..];42 cli_args = args[3..];
44 }43 }
4544
46 var stdout_writer2 = std.fs.File.stdout().writer(&stdout_buffer);45 var stdout_buffer: [1024]u8 = undefined;
46 var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
47 const stdout = &stdout_writer.interface;
47 var error_handler: ErrorHandler = switch (zig_integration) {48 var error_handler: ErrorHandler = switch (zig_integration) {
48 true => .{49 true => .{
49 .server = .{50 .server = .{
50 .out = &stdout_writer2.interface,51 .out = stdout,
51 .in = undefined, // won't be receiving messages52 .in = undefined, // won't be receiving messages
52 },53 },
53 },54 },
...@@ -83,28 +84,23 @@ pub fn main() !void {...@@ -83,28 +84,23 @@ pub fn main() !void {
83 defer options.deinit();84 defer options.deinit();
8485
85 if (options.print_help_and_exit) {86 if (options.print_help_and_exit) {
86 const stdout = std.fs.File.stdout();87 try cli.writeUsage(stdout, "zig rc");
87 try cli.writeUsage(stdout.deprecatedWriter(), "zig rc");88 try stdout.flush();
88 return;89 return;
89 }90 }
9091
91 // Don't allow verbose when integrating with Zig via stdout92 // Don't allow verbose when integrating with Zig via stdout
92 options.verbose = false;93 options.verbose = false;
9394
94 const stdout_writer = std.fs.File.stdout().deprecatedWriter();
95 if (options.verbose) {95 if (options.verbose) {
96 try options.dumpVerbose(stdout_writer);96 try options.dumpVerbose(stdout);
97 try stdout_writer.writeByte('\n');97 try stdout.writeByte('\n');
98 try stdout.flush();
98 }99 }
99100
100 var dependencies_list = std.array_list.Managed([]const u8).init(allocator);101 var dependencies = Dependencies.init(allocator);
101 defer {102 defer dependencies.deinit();
102 for (dependencies_list.items) |item| {103 const maybe_dependencies: ?*Dependencies = if (options.depfile_path != null) &dependencies else null;
103 allocator.free(item);
104 }
105 dependencies_list.deinit();
106 }
107 const maybe_dependencies_list: ?*std.array_list.Managed([]const u8) = if (options.depfile_path != null) &dependencies_list else null;
108104
109 var include_paths = LazyIncludePaths{105 var include_paths = LazyIncludePaths{
110 .arena = arena,106 .arena = arena,
...@@ -115,7 +111,7 @@ pub fn main() !void {...@@ -115,7 +111,7 @@ pub fn main() !void {
115111
116 const full_input = full_input: {112 const full_input = full_input: {
117 if (options.input_format == .rc and options.preprocess != .no) {113 if (options.input_format == .rc and options.preprocess != .no) {
118 var preprocessed_buf = std.array_list.Managed(u8).init(allocator);114 var preprocessed_buf: std.Io.Writer.Allocating = .init(allocator);
119 errdefer preprocessed_buf.deinit();115 errdefer preprocessed_buf.deinit();
120116
121 // We're going to throw away everything except the final preprocessed output anyway,117 // We're going to throw away everything except the final preprocessed output anyway,
...@@ -127,26 +123,27 @@ pub fn main() !void {...@@ -127,26 +123,27 @@ pub fn main() !void {
127 var comp = aro.Compilation.init(aro_arena, std.fs.cwd());123 var comp = aro.Compilation.init(aro_arena, std.fs.cwd());
128 defer comp.deinit();124 defer comp.deinit();
129125
130 var argv = std.array_list.Managed([]const u8).init(comp.gpa);126 var argv: std.ArrayList([]const u8) = .empty;
131 defer argv.deinit();127 defer argv.deinit(aro_arena);
132128
133 try argv.append("arocc"); // dummy command name129 try argv.append(aro_arena, "arocc"); // dummy command name
134 const resolved_include_paths = try include_paths.get(&error_handler);130 const resolved_include_paths = try include_paths.get(&error_handler);
135 try preprocess.appendAroArgs(aro_arena, &argv, options, resolved_include_paths);131 try preprocess.appendAroArgs(aro_arena, &argv, options, resolved_include_paths);
136 try argv.append(switch (options.input_source) {132 try argv.append(aro_arena, switch (options.input_source) {
137 .stdio => "-",133 .stdio => "-",
138 .filename => |filename| filename,134 .filename => |filename| filename,
139 });135 });
140136
141 if (options.verbose) {137 if (options.verbose) {
142 try stdout_writer.writeAll("Preprocessor: arocc (built-in)\n");138 try stdout.writeAll("Preprocessor: arocc (built-in)\n");
143 for (argv.items[0 .. argv.items.len - 1]) |arg| {139 for (argv.items[0 .. argv.items.len - 1]) |arg| {
144 try stdout_writer.print("{s} ", .{arg});140 try stdout.print("{s} ", .{arg});
145 }141 }
146 try stdout_writer.print("{s}\n\n", .{argv.items[argv.items.len - 1]});142 try stdout.print("{s}\n\n", .{argv.items[argv.items.len - 1]});
143 try stdout.flush();
147 }144 }
148145
149 preprocess.preprocess(&comp, preprocessed_buf.writer(), argv.items, maybe_dependencies_list) catch |err| switch (err) {146 preprocess.preprocess(&comp, &preprocessed_buf.writer, argv.items, maybe_dependencies) catch |err| switch (err) {
150 error.GeneratedSourceError => {147 error.GeneratedSourceError => {
151 try error_handler.emitAroDiagnostics(allocator, "failed during preprocessor setup (this is always a bug):", &comp);148 try error_handler.emitAroDiagnostics(allocator, "failed during preprocessor setup (this is always a bug):", &comp);
152 std.process.exit(1);149 std.process.exit(1);
...@@ -249,14 +246,15 @@ pub fn main() !void {...@@ -249,14 +246,15 @@ pub fn main() !void {
249 defer diagnostics.deinit();246 defer diagnostics.deinit();
250247
251 var output_buffer: [4096]u8 = undefined;248 var output_buffer: [4096]u8 = undefined;
252 var res_stream_writer = res_stream.source.writer(allocator).adaptToNewApi(&output_buffer);249 var res_stream_writer = res_stream.source.writer(allocator, &output_buffer);
253 const output_buffered_stream = &res_stream_writer.new_interface;250 defer res_stream_writer.deinit(&res_stream.source);
251 const output_buffered_stream = res_stream_writer.interface();
254252
255 compile(allocator, final_input, output_buffered_stream, .{253 compile(allocator, final_input, output_buffered_stream, .{
256 .cwd = std.fs.cwd(),254 .cwd = std.fs.cwd(),
257 .diagnostics = &diagnostics,255 .diagnostics = &diagnostics,
258 .source_mappings = &mapping_results.mappings,256 .source_mappings = &mapping_results.mappings,
259 .dependencies_list = maybe_dependencies_list,257 .dependencies = maybe_dependencies,
260 .ignore_include_env_var = options.ignore_include_env_var,258 .ignore_include_env_var = options.ignore_include_env_var,
261 .extra_include_paths = options.extra_include_paths.items,259 .extra_include_paths = options.extra_include_paths.items,
262 .system_include_paths = try include_paths.get(&error_handler),260 .system_include_paths = try include_paths.get(&error_handler),
...@@ -303,7 +301,7 @@ pub fn main() !void {...@@ -303,7 +301,7 @@ pub fn main() !void {
303 };301 };
304302
305 try write_stream.beginArray();303 try write_stream.beginArray();
306 for (dependencies_list.items) |dep_path| {304 for (dependencies.list.items) |dep_path| {
307 try write_stream.write(dep_path);305 try write_stream.write(dep_path);
308 }306 }
309 try write_stream.endArray();307 try write_stream.endArray();
...@@ -342,10 +340,10 @@ pub fn main() !void {...@@ -342,10 +340,10 @@ pub fn main() !void {
342 defer coff_stream.deinit(allocator);340 defer coff_stream.deinit(allocator);
343341
344 var coff_output_buffer: [4096]u8 = undefined;342 var coff_output_buffer: [4096]u8 = undefined;
345 var coff_output_buffered_stream = coff_stream.source.writer(allocator).adaptToNewApi(&coff_output_buffer);343 var coff_output_buffered_stream = coff_stream.source.writer(allocator, &coff_output_buffer);
346344
347 var cvtres_diagnostics: cvtres.Diagnostics = .{ .none = {} };345 var cvtres_diagnostics: cvtres.Diagnostics = .{ .none = {} };
348 cvtres.writeCoff(allocator, &coff_output_buffered_stream.new_interface, resources.list.items, options.coff_options, &cvtres_diagnostics) catch |err| {346 cvtres.writeCoff(allocator, coff_output_buffered_stream.interface(), resources.list.items, options.coff_options, &cvtres_diagnostics) catch |err| {
349 switch (err) {347 switch (err) {
350 error.DuplicateResource => {348 error.DuplicateResource => {
351 const duplicate_resource = resources.list.items[cvtres_diagnostics.duplicate_resource];349 const duplicate_resource = resources.list.items[cvtres_diagnostics.duplicate_resource];
...@@ -382,7 +380,7 @@ pub fn main() !void {...@@ -382,7 +380,7 @@ pub fn main() !void {
382 std.process.exit(1);380 std.process.exit(1);
383 };381 };
384382
385 try coff_output_buffered_stream.new_interface.flush();383 try coff_output_buffered_stream.interface().flush();
386}384}
387385
388const IoStream = struct {386const IoStream = struct {
...@@ -425,7 +423,7 @@ const IoStream = struct {...@@ -425,7 +423,7 @@ const IoStream = struct {
425 pub const Source = union(enum) {423 pub const Source = union(enum) {
426 file: std.fs.File,424 file: std.fs.File,
427 stdio: std.fs.File,425 stdio: std.fs.File,
428 memory: std.ArrayListUnmanaged(u8),426 memory: std.ArrayList(u8),
429 /// The source has been closed and any usage of the Source in this state is illegal (except deinit).427 /// The source has been closed and any usage of the Source in this state is illegal (except deinit).
430 closed: void,428 closed: void,
431429
...@@ -472,26 +470,34 @@ const IoStream = struct {...@@ -472,26 +470,34 @@ const IoStream = struct {
472 };470 };
473 }471 }
474472
475 pub const WriterContext = struct {473 pub const Writer = union(enum) {
476 self: *Source,474 file: std.fs.File.Writer,
477 allocator: std.mem.Allocator,475 allocating: std.Io.Writer.Allocating,
478 };476
479 pub const WriteError = std.mem.Allocator.Error || std.fs.File.WriteError;477 pub const Error = std.mem.Allocator.Error || std.fs.File.WriteError;
480 pub const Writer = std.io.GenericWriter(WriterContext, WriteError, write);478
481479 pub fn interface(this: *@This()) *std.Io.Writer {
482 pub fn write(ctx: WriterContext, bytes: []const u8) WriteError!usize {480 return switch (this.*) {
483 switch (ctx.self.*) {481 .file => |*fw| &fw.interface,
484 inline .file, .stdio => |file| return file.write(bytes),482 .allocating => |*a| &a.writer,
485 .memory => |*list| {483 };
486 try list.appendSlice(ctx.allocator, bytes);
487 return bytes.len;
488 },
489 .closed => unreachable,
490 }484 }
491 }
492485
493 pub fn writer(self: *Source, allocator: std.mem.Allocator) Writer {486 pub fn deinit(this: *@This(), source: *Source) void {
494 return .{ .context = .{ .self = self, .allocator = allocator } };487 switch (this.*) {
488 .file => {},
489 .allocating => |*a| source.memory = a.toArrayList(),
490 }
491 this.* = undefined;
492 }
493 };
494
495 pub fn writer(source: *Source, allocator: std.mem.Allocator, buffer: []u8) Writer {
496 return switch (source.*) {
497 .file, .stdio => |file| .{ .file = file.writer(buffer) },
498 .memory => |*list| .{ .allocating = .fromArrayList(allocator, list) },
499 .closed => unreachable,
500 };
495 }501 }
496 };502 };
497};503};
...@@ -721,7 +727,7 @@ fn cliDiagnosticsToErrorBundle(...@@ -721,7 +727,7 @@ fn cliDiagnosticsToErrorBundle(
721 });727 });
722728
723 var cur_err: ?ErrorBundle.ErrorMessage = null;729 var cur_err: ?ErrorBundle.ErrorMessage = null;
724 var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .empty;730 var cur_notes: std.ArrayList(ErrorBundle.ErrorMessage) = .empty;
725 defer cur_notes.deinit(gpa);731 defer cur_notes.deinit(gpa);
726 for (diagnostics.errors.items) |err_details| {732 for (diagnostics.errors.items) |err_details| {
727 switch (err_details.type) {733 switch (err_details.type) {
...@@ -763,10 +769,10 @@ fn diagnosticsToErrorBundle(...@@ -763,10 +769,10 @@ fn diagnosticsToErrorBundle(
763 try bundle.init(gpa);769 try bundle.init(gpa);
764 errdefer bundle.deinit();770 errdefer bundle.deinit();
765771
766 var msg_buf: std.ArrayListUnmanaged(u8) = .empty;772 var msg_buf: std.Io.Writer.Allocating = .init(gpa);
767 defer msg_buf.deinit(gpa);773 defer msg_buf.deinit();
768 var cur_err: ?ErrorBundle.ErrorMessage = null;774 var cur_err: ?ErrorBundle.ErrorMessage = null;
769 var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .empty;775 var cur_notes: std.ArrayList(ErrorBundle.ErrorMessage) = .empty;
770 defer cur_notes.deinit(gpa);776 defer cur_notes.deinit(gpa);
771 for (diagnostics.errors.items) |err_details| {777 for (diagnostics.errors.items) |err_details| {
772 switch (err_details.type) {778 switch (err_details.type) {
...@@ -789,7 +795,7 @@ fn diagnosticsToErrorBundle(...@@ -789,7 +795,7 @@ fn diagnosticsToErrorBundle(
789 const column = err_details.token.calculateColumn(source, 1, source_line_start) + 1;795 const column = err_details.token.calculateColumn(source, 1, source_line_start) + 1;
790796
791 msg_buf.clearRetainingCapacity();797 msg_buf.clearRetainingCapacity();
792 try err_details.render(msg_buf.writer(gpa), source, diagnostics.strings.items);798 try err_details.render(&msg_buf.writer, source, diagnostics.strings.items);
793799
794 const src_loc = src_loc: {800 const src_loc = src_loc: {
795 var src_loc: ErrorBundle.SourceLocation = .{801 var src_loc: ErrorBundle.SourceLocation = .{
...@@ -817,7 +823,7 @@ fn diagnosticsToErrorBundle(...@@ -817,7 +823,7 @@ fn diagnosticsToErrorBundle(
817 try flushErrorMessageIntoBundle(&bundle, err, cur_notes.items);823 try flushErrorMessageIntoBundle(&bundle, err, cur_notes.items);
818 }824 }
819 cur_err = .{825 cur_err = .{
820 .msg = try bundle.addString(msg_buf.items),826 .msg = try bundle.addString(msg_buf.written()),
821 .src_loc = src_loc,827 .src_loc = src_loc,
822 };828 };
823 cur_notes.clearRetainingCapacity();829 cur_notes.clearRetainingCapacity();
...@@ -825,7 +831,7 @@ fn diagnosticsToErrorBundle(...@@ -825,7 +831,7 @@ fn diagnosticsToErrorBundle(
825 .note => {831 .note => {
826 cur_err.?.notes_len += 1;832 cur_err.?.notes_len += 1;
827 try cur_notes.append(gpa, .{833 try cur_notes.append(gpa, .{
828 .msg = try bundle.addString(msg_buf.items),834 .msg = try bundle.addString(msg_buf.written()),
829 .src_loc = src_loc,835 .src_loc = src_loc,
830 });836 });
831 },837 },
...@@ -876,7 +882,7 @@ fn aroDiagnosticsToErrorBundle(...@@ -876,7 +882,7 @@ fn aroDiagnosticsToErrorBundle(
876 var msg_writer = MsgWriter.init(gpa);882 var msg_writer = MsgWriter.init(gpa);
877 defer msg_writer.deinit();883 defer msg_writer.deinit();
878 var cur_err: ?ErrorBundle.ErrorMessage = null;884 var cur_err: ?ErrorBundle.ErrorMessage = null;
879 var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .empty;885 var cur_notes: std.ArrayList(ErrorBundle.ErrorMessage) = .empty;
880 defer cur_notes.deinit(gpa);886 defer cur_notes.deinit(gpa);
881 for (comp.diagnostics.list.items) |msg| {887 for (comp.diagnostics.list.items) |msg| {
882 switch (msg.kind) {888 switch (msg.kind) {
...@@ -971,11 +977,11 @@ const MsgWriter = struct {...@@ -971,11 +977,11 @@ const MsgWriter = struct {
971 }977 }
972978
973 pub fn print(m: *MsgWriter, comptime fmt: []const u8, args: anytype) void {979 pub fn print(m: *MsgWriter, comptime fmt: []const u8, args: anytype) void {
974 m.buf.writer().print(fmt, args) catch {};980 m.buf.print(fmt, args) catch {};
975 }981 }
976982
977 pub fn write(m: *MsgWriter, msg: []const u8) void {983 pub fn write(m: *MsgWriter, msg: []const u8) void {
978 m.buf.writer().writeAll(msg) catch {};984 m.buf.appendSlice(msg) catch {};
979 }985 }
980986
981 pub fn setColor(m: *MsgWriter, color: std.io.tty.Color) void {987 pub fn setColor(m: *MsgWriter, color: std.io.tty.Color) void {
lib/compiler/resinator/parse.zig+26-26
...@@ -82,8 +82,8 @@ pub const Parser = struct {...@@ -82,8 +82,8 @@ pub const Parser = struct {
82 }82 }
8383
84 fn parseRoot(self: *Self) Error!*Node {84 fn parseRoot(self: *Self) Error!*Node {
85 var statements = std.array_list.Managed(*Node).init(self.state.allocator);85 var statements: std.ArrayList(*Node) = .empty;
86 defer statements.deinit();86 defer statements.deinit(self.state.allocator);
8787
88 try self.parseStatements(&statements);88 try self.parseStatements(&statements);
89 try self.check(.eof);89 try self.check(.eof);
...@@ -95,7 +95,7 @@ pub const Parser = struct {...@@ -95,7 +95,7 @@ pub const Parser = struct {
95 return &node.base;95 return &node.base;
96 }96 }
9797
98 fn parseStatements(self: *Self, statements: *std.array_list.Managed(*Node)) Error!void {98 fn parseStatements(self: *Self, statements: *std.ArrayList(*Node)) Error!void {
99 while (true) {99 while (true) {
100 try self.nextToken(.whitespace_delimiter_only);100 try self.nextToken(.whitespace_delimiter_only);
101 if (self.state.token.id == .eof) break;101 if (self.state.token.id == .eof) break;
...@@ -105,7 +105,7 @@ pub const Parser = struct {...@@ -105,7 +105,7 @@ pub const Parser = struct {
105 // (usually it will end up with bogus things like 'file105 // (usually it will end up with bogus things like 'file
106 // not found: {')106 // not found: {')
107 const statement = try self.parseStatement();107 const statement = try self.parseStatement();
108 try statements.append(statement);108 try statements.append(self.state.allocator, statement);
109 }109 }
110 }110 }
111111
...@@ -115,7 +115,7 @@ pub const Parser = struct {...@@ -115,7 +115,7 @@ pub const Parser = struct {
115 /// current token is unchanged.115 /// current token is unchanged.
116 /// The returned slice is allocated by the parser's arena116 /// The returned slice is allocated by the parser's arena
117 fn parseCommonResourceAttributes(self: *Self) ![]Token {117 fn parseCommonResourceAttributes(self: *Self) ![]Token {
118 var common_resource_attributes: std.ArrayListUnmanaged(Token) = .empty;118 var common_resource_attributes: std.ArrayList(Token) = .empty;
119 while (true) {119 while (true) {
120 const maybe_common_resource_attribute = try self.lookaheadToken(.normal);120 const maybe_common_resource_attribute = try self.lookaheadToken(.normal);
121 if (maybe_common_resource_attribute.id == .literal and rc.CommonResourceAttributes.map.has(maybe_common_resource_attribute.slice(self.lexer.buffer))) {121 if (maybe_common_resource_attribute.id == .literal and rc.CommonResourceAttributes.map.has(maybe_common_resource_attribute.slice(self.lexer.buffer))) {
...@@ -135,7 +135,7 @@ pub const Parser = struct {...@@ -135,7 +135,7 @@ pub const Parser = struct {
135 /// current token is unchanged.135 /// current token is unchanged.
136 /// The returned slice is allocated by the parser's arena136 /// The returned slice is allocated by the parser's arena
137 fn parseOptionalStatements(self: *Self, resource: ResourceType) ![]*Node {137 fn parseOptionalStatements(self: *Self, resource: ResourceType) ![]*Node {
138 var optional_statements: std.ArrayListUnmanaged(*Node) = .empty;138 var optional_statements: std.ArrayList(*Node) = .empty;
139139
140 const num_statement_types = @typeInfo(rc.OptionalStatements).@"enum".fields.len;140 const num_statement_types = @typeInfo(rc.OptionalStatements).@"enum".fields.len;
141 var statement_type_has_duplicates = [_]bool{false} ** num_statement_types;141 var statement_type_has_duplicates = [_]bool{false} ** num_statement_types;
...@@ -355,8 +355,8 @@ pub const Parser = struct {...@@ -355,8 +355,8 @@ pub const Parser = struct {
355 const begin_token = self.state.token;355 const begin_token = self.state.token;
356 try self.check(.begin);356 try self.check(.begin);
357357
358 var strings = std.array_list.Managed(*Node).init(self.state.allocator);358 var strings: std.ArrayList(*Node) = .empty;
359 defer strings.deinit();359 defer strings.deinit(self.state.allocator);
360 while (true) {360 while (true) {
361 const maybe_end_token = try self.lookaheadToken(.normal);361 const maybe_end_token = try self.lookaheadToken(.normal);
362 switch (maybe_end_token.id) {362 switch (maybe_end_token.id) {
...@@ -392,7 +392,7 @@ pub const Parser = struct {...@@ -392,7 +392,7 @@ pub const Parser = struct {
392 .maybe_comma = comma_token,392 .maybe_comma = comma_token,
393 .string = self.state.token,393 .string = self.state.token,
394 };394 };
395 try strings.append(&string_node.base);395 try strings.append(self.state.allocator, &string_node.base);
396 }396 }
397397
398 if (strings.items.len == 0) {398 if (strings.items.len == 0) {
...@@ -501,7 +501,7 @@ pub const Parser = struct {...@@ -501,7 +501,7 @@ pub const Parser = struct {
501 const begin_token = self.state.token;501 const begin_token = self.state.token;
502 try self.check(.begin);502 try self.check(.begin);
503503
504 var accelerators: std.ArrayListUnmanaged(*Node) = .empty;504 var accelerators: std.ArrayList(*Node) = .empty;
505505
506 while (true) {506 while (true) {
507 const lookahead = try self.lookaheadToken(.normal);507 const lookahead = try self.lookaheadToken(.normal);
...@@ -519,7 +519,7 @@ pub const Parser = struct {...@@ -519,7 +519,7 @@ pub const Parser = struct {
519519
520 const idvalue = try self.parseExpression(.{ .allowed_types = .{ .number = true } });520 const idvalue = try self.parseExpression(.{ .allowed_types = .{ .number = true } });
521521
522 var type_and_options: std.ArrayListUnmanaged(Token) = .empty;522 var type_and_options: std.ArrayList(Token) = .empty;
523 while (true) {523 while (true) {
524 if (!(try self.parseOptionalToken(.comma))) break;524 if (!(try self.parseOptionalToken(.comma))) break;
525525
...@@ -584,7 +584,7 @@ pub const Parser = struct {...@@ -584,7 +584,7 @@ pub const Parser = struct {
584 const begin_token = self.state.token;584 const begin_token = self.state.token;
585 try self.check(.begin);585 try self.check(.begin);
586586
587 var controls: std.ArrayListUnmanaged(*Node) = .empty;587 var controls: std.ArrayList(*Node) = .empty;
588 defer controls.deinit(self.state.allocator);588 defer controls.deinit(self.state.allocator);
589 while (try self.parseControlStatement(resource)) |control_node| {589 while (try self.parseControlStatement(resource)) |control_node| {
590 // The number of controls must fit in a u16 in order for it to590 // The number of controls must fit in a u16 in order for it to
...@@ -643,7 +643,7 @@ pub const Parser = struct {...@@ -643,7 +643,7 @@ pub const Parser = struct {
643 const begin_token = self.state.token;643 const begin_token = self.state.token;
644 try self.check(.begin);644 try self.check(.begin);
645645
646 var buttons: std.ArrayListUnmanaged(*Node) = .empty;646 var buttons: std.ArrayList(*Node) = .empty;
647 defer buttons.deinit(self.state.allocator);647 defer buttons.deinit(self.state.allocator);
648 while (try self.parseToolbarButtonStatement()) |button_node| {648 while (try self.parseToolbarButtonStatement()) |button_node| {
649 // The number of buttons must fit in a u16 in order for it to649 // The number of buttons must fit in a u16 in order for it to
...@@ -701,7 +701,7 @@ pub const Parser = struct {...@@ -701,7 +701,7 @@ pub const Parser = struct {
701 const begin_token = self.state.token;701 const begin_token = self.state.token;
702 try self.check(.begin);702 try self.check(.begin);
703703
704 var items: std.ArrayListUnmanaged(*Node) = .empty;704 var items: std.ArrayList(*Node) = .empty;
705 defer items.deinit(self.state.allocator);705 defer items.deinit(self.state.allocator);
706 while (try self.parseMenuItemStatement(resource, id_token, 1)) |item_node| {706 while (try self.parseMenuItemStatement(resource, id_token, 1)) |item_node| {
707 try items.append(self.state.allocator, item_node);707 try items.append(self.state.allocator, item_node);
...@@ -735,7 +735,7 @@ pub const Parser = struct {...@@ -735,7 +735,7 @@ pub const Parser = struct {
735 // common resource attributes must all be contiguous and come before optional-statements735 // common resource attributes must all be contiguous and come before optional-statements
736 const common_resource_attributes = try self.parseCommonResourceAttributes();736 const common_resource_attributes = try self.parseCommonResourceAttributes();
737737
738 var fixed_info: std.ArrayListUnmanaged(*Node) = .empty;738 var fixed_info: std.ArrayList(*Node) = .empty;
739 while (try self.parseVersionStatement()) |version_statement| {739 while (try self.parseVersionStatement()) |version_statement| {
740 try fixed_info.append(self.state.arena, version_statement);740 try fixed_info.append(self.state.arena, version_statement);
741 }741 }
...@@ -744,7 +744,7 @@ pub const Parser = struct {...@@ -744,7 +744,7 @@ pub const Parser = struct {
744 const begin_token = self.state.token;744 const begin_token = self.state.token;
745 try self.check(.begin);745 try self.check(.begin);
746746
747 var block_statements: std.ArrayListUnmanaged(*Node) = .empty;747 var block_statements: std.ArrayList(*Node) = .empty;
748 while (try self.parseVersionBlockOrValue(id_token, 1)) |block_node| {748 while (try self.parseVersionBlockOrValue(id_token, 1)) |block_node| {
749 try block_statements.append(self.state.arena, block_node);749 try block_statements.append(self.state.arena, block_node);
750 }750 }
...@@ -852,8 +852,8 @@ pub const Parser = struct {...@@ -852,8 +852,8 @@ pub const Parser = struct {
852 /// Expects the current token to be a begin token.852 /// Expects the current token to be a begin token.
853 /// After return, the current token will be the end token.853 /// After return, the current token will be the end token.
854 fn parseRawDataBlock(self: *Self) Error![]*Node {854 fn parseRawDataBlock(self: *Self) Error![]*Node {
855 var raw_data = std.array_list.Managed(*Node).init(self.state.allocator);855 var raw_data: std.ArrayList(*Node) = .empty;
856 defer raw_data.deinit();856 defer raw_data.deinit(self.state.allocator);
857 while (true) {857 while (true) {
858 const maybe_end_token = try self.lookaheadToken(.normal);858 const maybe_end_token = try self.lookaheadToken(.normal);
859 switch (maybe_end_token.id) {859 switch (maybe_end_token.id) {
...@@ -888,7 +888,7 @@ pub const Parser = struct {...@@ -888,7 +888,7 @@ pub const Parser = struct {
888 else => {},888 else => {},
889 }889 }
890 const expression = try self.parseExpression(.{ .allowed_types = .{ .number = true, .string = true } });890 const expression = try self.parseExpression(.{ .allowed_types = .{ .number = true, .string = true } });
891 try raw_data.append(expression);891 try raw_data.append(self.state.allocator, expression);
892892
893 if (expression.isNumberExpression()) {893 if (expression.isNumberExpression()) {
894 const maybe_close_paren = try self.lookaheadToken(.normal);894 const maybe_close_paren = try self.lookaheadToken(.normal);
...@@ -1125,7 +1125,7 @@ pub const Parser = struct {...@@ -1125,7 +1125,7 @@ pub const Parser = struct {
11251125
1126 _ = try self.parseOptionalToken(.comma);1126 _ = try self.parseOptionalToken(.comma);
11271127
1128 var options: std.ArrayListUnmanaged(Token) = .empty;1128 var options: std.ArrayList(Token) = .empty;
1129 while (true) {1129 while (true) {
1130 const option_token = try self.lookaheadToken(.normal);1130 const option_token = try self.lookaheadToken(.normal);
1131 if (!rc.MenuItem.Option.map.has(option_token.slice(self.lexer.buffer))) {1131 if (!rc.MenuItem.Option.map.has(option_token.slice(self.lexer.buffer))) {
...@@ -1160,7 +1160,7 @@ pub const Parser = struct {...@@ -1160,7 +1160,7 @@ pub const Parser = struct {
1160 }1160 }
1161 try self.skipAnyCommas();1161 try self.skipAnyCommas();
11621162
1163 var options: std.ArrayListUnmanaged(Token) = .empty;1163 var options: std.ArrayList(Token) = .empty;
1164 while (true) {1164 while (true) {
1165 const option_token = try self.lookaheadToken(.normal);1165 const option_token = try self.lookaheadToken(.normal);
1166 if (!rc.MenuItem.Option.map.has(option_token.slice(self.lexer.buffer))) {1166 if (!rc.MenuItem.Option.map.has(option_token.slice(self.lexer.buffer))) {
...@@ -1175,7 +1175,7 @@ pub const Parser = struct {...@@ -1175,7 +1175,7 @@ pub const Parser = struct {
1175 const begin_token = self.state.token;1175 const begin_token = self.state.token;
1176 try self.check(.begin);1176 try self.check(.begin);
11771177
1178 var items: std.ArrayListUnmanaged(*Node) = .empty;1178 var items: std.ArrayList(*Node) = .empty;
1179 while (try self.parseMenuItemStatement(resource, top_level_menu_id_token, nesting_level + 1)) |item_node| {1179 while (try self.parseMenuItemStatement(resource, top_level_menu_id_token, nesting_level + 1)) |item_node| {
1180 try items.append(self.state.arena, item_node);1180 try items.append(self.state.arena, item_node);
1181 }1181 }
...@@ -1245,7 +1245,7 @@ pub const Parser = struct {...@@ -1245,7 +1245,7 @@ pub const Parser = struct {
1245 const begin_token = self.state.token;1245 const begin_token = self.state.token;
1246 try self.check(.begin);1246 try self.check(.begin);
12471247
1248 var items: std.ArrayListUnmanaged(*Node) = .empty;1248 var items: std.ArrayList(*Node) = .empty;
1249 while (try self.parseMenuItemStatement(resource, top_level_menu_id_token, nesting_level + 1)) |item_node| {1249 while (try self.parseMenuItemStatement(resource, top_level_menu_id_token, nesting_level + 1)) |item_node| {
1250 try items.append(self.state.arena, item_node);1250 try items.append(self.state.arena, item_node);
1251 }1251 }
...@@ -1322,7 +1322,7 @@ pub const Parser = struct {...@@ -1322,7 +1322,7 @@ pub const Parser = struct {
1322 switch (statement_type) {1322 switch (statement_type) {
1323 .file_version, .product_version => {1323 .file_version, .product_version => {
1324 var parts_buffer: [4]*Node = undefined;1324 var parts_buffer: [4]*Node = undefined;
1325 var parts = std.ArrayListUnmanaged(*Node).initBuffer(&parts_buffer);1325 var parts = std.ArrayList(*Node).initBuffer(&parts_buffer);
13261326
1327 while (true) {1327 while (true) {
1328 const value = try self.parseExpression(.{ .allowed_types = .{ .number = true } });1328 const value = try self.parseExpression(.{ .allowed_types = .{ .number = true } });
...@@ -1402,7 +1402,7 @@ pub const Parser = struct {...@@ -1402,7 +1402,7 @@ pub const Parser = struct {
1402 const begin_token = self.state.token;1402 const begin_token = self.state.token;
1403 try self.check(.begin);1403 try self.check(.begin);
14041404
1405 var children: std.ArrayListUnmanaged(*Node) = .empty;1405 var children: std.ArrayList(*Node) = .empty;
1406 while (try self.parseVersionBlockOrValue(top_level_version_id_token, nesting_level + 1)) |value_node| {1406 while (try self.parseVersionBlockOrValue(top_level_version_id_token, nesting_level + 1)) |value_node| {
1407 try children.append(self.state.arena, value_node);1407 try children.append(self.state.arena, value_node);
1408 }1408 }
...@@ -1435,7 +1435,7 @@ pub const Parser = struct {...@@ -1435,7 +1435,7 @@ pub const Parser = struct {
1435 }1435 }
14361436
1437 fn parseBlockValuesList(self: *Self, had_comma_before_first_value: bool) Error![]*Node {1437 fn parseBlockValuesList(self: *Self, had_comma_before_first_value: bool) Error![]*Node {
1438 var values: std.ArrayListUnmanaged(*Node) = .empty;1438 var values: std.ArrayList(*Node) = .empty;
1439 var seen_number: bool = false;1439 var seen_number: bool = false;
1440 var first_string_value: ?*Node = null;1440 var first_string_value: ?*Node = null;
1441 while (true) {1441 while (true) {
lib/compiler/resinator/preprocess.zig+28-22
...@@ -2,28 +2,32 @@ const std = @import("std");...@@ -2,28 +2,32 @@ const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
4const cli = @import("cli.zig");4const cli = @import("cli.zig");
5const Dependencies = @import("compile.zig").Dependencies;
5const aro = @import("aro");6const aro = @import("aro");
67
7const PreprocessError = error{ ArgError, GeneratedSourceError, PreprocessError, StreamTooLong, OutOfMemory };8const PreprocessError = error{ ArgError, GeneratedSourceError, PreprocessError, StreamTooLong, OutOfMemory };
89
9pub fn preprocess(10pub fn preprocess(
10 comp: *aro.Compilation,11 comp: *aro.Compilation,
11 writer: anytype,12 writer: *std.Io.Writer,
12 /// Expects argv[0] to be the command name13 /// Expects argv[0] to be the command name
13 argv: []const []const u8,14 argv: []const []const u8,
14 maybe_dependencies_list: ?*std.array_list.Managed([]const u8),15 maybe_dependencies: ?*Dependencies,
15) PreprocessError!void {16) PreprocessError!void {
16 try comp.addDefaultPragmaHandlers();17 try comp.addDefaultPragmaHandlers();
1718
18 var driver: aro.Driver = .{ .comp = comp, .aro_name = "arocc" };19 var driver: aro.Driver = .{ .comp = comp, .aro_name = "arocc" };
19 defer driver.deinit();20 defer driver.deinit();
2021
21 var macro_buf = std.array_list.Managed(u8).init(comp.gpa);22 var macro_buf: std.Io.Writer.Allocating = .init(comp.gpa);
22 defer macro_buf.deinit();23 defer macro_buf.deinit();
2324
24 _ = driver.parseArgs(std.io.null_writer, macro_buf.writer(), argv) catch |err| switch (err) {25 var trash: [64]u8 = undefined;
26 var discarding: std.Io.Writer.Discarding = .init(&trash);
27 _ = driver.parseArgs(&discarding.writer, &macro_buf.writer, argv) catch |err| switch (err) {
25 error.FatalError => return error.ArgError,28 error.FatalError => return error.ArgError,
26 error.OutOfMemory => |e| return e,29 error.OutOfMemory => |e| return e,
30 error.WriteFailed => return error.OutOfMemory,
27 };31 };
2832
29 if (hasAnyErrors(comp)) return error.ArgError;33 if (hasAnyErrors(comp)) return error.ArgError;
...@@ -33,7 +37,7 @@ pub fn preprocess(...@@ -33,7 +37,7 @@ pub fn preprocess(
33 error.FatalError => return error.GeneratedSourceError,37 error.FatalError => return error.GeneratedSourceError,
34 else => |e| return e,38 else => |e| return e,
35 };39 };
36 const user_macros = comp.addSourceFromBuffer("<command line>", macro_buf.items) catch |err| switch (err) {40 const user_macros = comp.addSourceFromBuffer("<command line>", macro_buf.written()) catch |err| switch (err) {
37 error.FatalError => return error.GeneratedSourceError,41 error.FatalError => return error.GeneratedSourceError,
38 else => |e| return e,42 else => |e| return e,
39 };43 };
...@@ -59,15 +63,17 @@ pub fn preprocess(...@@ -59,15 +63,17 @@ pub fn preprocess(
5963
60 if (hasAnyErrors(comp)) return error.PreprocessError;64 if (hasAnyErrors(comp)) return error.PreprocessError;
6165
62 try pp.prettyPrintTokens(writer, .result_only);66 pp.prettyPrintTokens(writer, .result_only) catch |err| switch (err) {
67 error.WriteFailed => return error.OutOfMemory,
68 };
6369
64 if (maybe_dependencies_list) |dependencies_list| {70 if (maybe_dependencies) |dependencies| {
65 for (comp.sources.values()) |comp_source| {71 for (comp.sources.values()) |comp_source| {
66 if (comp_source.id == builtin_macros.id or comp_source.id == user_macros.id) continue;72 if (comp_source.id == builtin_macros.id or comp_source.id == user_macros.id) continue;
67 if (comp_source.id == .unused or comp_source.id == .generated) continue;73 if (comp_source.id == .unused or comp_source.id == .generated) continue;
68 const duped_path = try dependencies_list.allocator.dupe(u8, comp_source.path);74 const duped_path = try dependencies.allocator.dupe(u8, comp_source.path);
69 errdefer dependencies_list.allocator.free(duped_path);75 errdefer dependencies.allocator.free(duped_path);
70 try dependencies_list.append(duped_path);76 try dependencies.list.append(dependencies.allocator, duped_path);
71 }77 }
72 }78 }
73}79}
...@@ -87,8 +93,8 @@ fn hasAnyErrors(comp: *aro.Compilation) bool {...@@ -87,8 +93,8 @@ fn hasAnyErrors(comp: *aro.Compilation) bool {
8793
88/// `arena` is used for temporary -D argument strings and the INCLUDE environment variable.94/// `arena` is used for temporary -D argument strings and the INCLUDE environment variable.
89/// The arena should be kept alive at least as long as `argv`.95/// The arena should be kept alive at least as long as `argv`.
90pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8), options: cli.Options, system_include_paths: []const []const u8) !void {96pub fn appendAroArgs(arena: Allocator, argv: *std.ArrayList([]const u8), options: cli.Options, system_include_paths: []const []const u8) !void {
91 try argv.appendSlice(&.{97 try argv.appendSlice(arena, &.{
92 "-E",98 "-E",
93 "--comments",99 "--comments",
94 "-fuse-line-directives",100 "-fuse-line-directives",
...@@ -99,13 +105,13 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)...@@ -99,13 +105,13 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)
99 "-D_WIN32", // undocumented, but defined by default105 "-D_WIN32", // undocumented, but defined by default
100 });106 });
101 for (options.extra_include_paths.items) |extra_include_path| {107 for (options.extra_include_paths.items) |extra_include_path| {
102 try argv.append("-I");108 try argv.append(arena, "-I");
103 try argv.append(extra_include_path);109 try argv.append(arena, extra_include_path);
104 }110 }
105111
106 for (system_include_paths) |include_path| {112 for (system_include_paths) |include_path| {
107 try argv.append("-isystem");113 try argv.append(arena, "-isystem");
108 try argv.append(include_path);114 try argv.append(arena, include_path);
109 }115 }
110116
111 if (!options.ignore_include_env_var) {117 if (!options.ignore_include_env_var) {
...@@ -119,8 +125,8 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)...@@ -119,8 +125,8 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)
119 };125 };
120 var it = std.mem.tokenizeScalar(u8, INCLUDE, delimiter);126 var it = std.mem.tokenizeScalar(u8, INCLUDE, delimiter);
121 while (it.next()) |include_path| {127 while (it.next()) |include_path| {
122 try argv.append("-isystem");128 try argv.append(arena, "-isystem");
123 try argv.append(include_path);129 try argv.append(arena, include_path);
124 }130 }
125 }131 }
126132
...@@ -128,13 +134,13 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)...@@ -128,13 +134,13 @@ pub fn appendAroArgs(arena: Allocator, argv: *std.array_list.Managed([]const u8)
128 while (symbol_it.next()) |entry| {134 while (symbol_it.next()) |entry| {
129 switch (entry.value_ptr.*) {135 switch (entry.value_ptr.*) {
130 .define => |value| {136 .define => |value| {
131 try argv.append("-D");137 try argv.append(arena, "-D");
132 const define_arg = try std.fmt.allocPrint(arena, "{s}={s}", .{ entry.key_ptr.*, value });138 const define_arg = try std.fmt.allocPrint(arena, "{s}={s}", .{ entry.key_ptr.*, value });
133 try argv.append(define_arg);139 try argv.append(arena, define_arg);
134 },140 },
135 .undefine => {141 .undefine => {
136 try argv.append("-U");142 try argv.append(arena, "-U");
137 try argv.append(entry.key_ptr.*);143 try argv.append(arena, entry.key_ptr.*);
138 },144 },
139 }145 }
140 }146 }
lib/compiler/resinator/res.zig+11-11
...@@ -258,7 +258,7 @@ pub const NameOrOrdinal = union(enum) {...@@ -258,7 +258,7 @@ pub const NameOrOrdinal = union(enum) {
258 }258 }
259 }259 }
260260
261 pub fn write(self: NameOrOrdinal, writer: anytype) !void {261 pub fn write(self: NameOrOrdinal, writer: *std.Io.Writer) !void {
262 switch (self) {262 switch (self) {
263 .name => |name| {263 .name => |name| {
264 try writer.writeAll(std.mem.sliceAsBytes(name[0 .. name.len + 1]));264 try writer.writeAll(std.mem.sliceAsBytes(name[0 .. name.len + 1]));
...@@ -270,7 +270,7 @@ pub const NameOrOrdinal = union(enum) {...@@ -270,7 +270,7 @@ pub const NameOrOrdinal = union(enum) {
270 }270 }
271 }271 }
272272
273 pub fn writeEmpty(writer: anytype) !void {273 pub fn writeEmpty(writer: *std.Io.Writer) !void {
274 try writer.writeInt(u16, 0, .little);274 try writer.writeInt(u16, 0, .little);
275 }275 }
276276
...@@ -283,8 +283,8 @@ pub const NameOrOrdinal = union(enum) {...@@ -283,8 +283,8 @@ pub const NameOrOrdinal = union(enum) {
283283
284 pub fn nameFromString(allocator: Allocator, bytes: SourceBytes) !NameOrOrdinal {284 pub fn nameFromString(allocator: Allocator, bytes: SourceBytes) !NameOrOrdinal {
285 // Names have a limit of 256 UTF-16 code units + null terminator285 // Names have a limit of 256 UTF-16 code units + null terminator
286 var buf = try std.array_list.Managed(u16).initCapacity(allocator, @min(257, bytes.slice.len));286 var buf = try std.ArrayList(u16).initCapacity(allocator, @min(257, bytes.slice.len));
287 errdefer buf.deinit();287 errdefer buf.deinit(allocator);
288288
289 var i: usize = 0;289 var i: usize = 0;
290 while (bytes.code_page.codepointAt(i, bytes.slice)) |codepoint| : (i += codepoint.byte_len) {290 while (bytes.code_page.codepointAt(i, bytes.slice)) |codepoint| : (i += codepoint.byte_len) {
...@@ -292,27 +292,27 @@ pub const NameOrOrdinal = union(enum) {...@@ -292,27 +292,27 @@ pub const NameOrOrdinal = union(enum) {
292292
293 const c = codepoint.value;293 const c = codepoint.value;
294 if (c == Codepoint.invalid) {294 if (c == Codepoint.invalid) {
295 try buf.append(std.mem.nativeToLittle(u16, '�'));295 try buf.append(allocator, std.mem.nativeToLittle(u16, '�'));
296 } else if (c < 0x7F) {296 } else if (c < 0x7F) {
297 // ASCII chars in names are always converted to uppercase297 // ASCII chars in names are always converted to uppercase
298 try buf.append(std.mem.nativeToLittle(u16, std.ascii.toUpper(@intCast(c))));298 try buf.append(allocator, std.mem.nativeToLittle(u16, std.ascii.toUpper(@intCast(c))));
299 } else if (c < 0x10000) {299 } else if (c < 0x10000) {
300 const short: u16 = @intCast(c);300 const short: u16 = @intCast(c);
301 try buf.append(std.mem.nativeToLittle(u16, short));301 try buf.append(allocator, std.mem.nativeToLittle(u16, short));
302 } else {302 } else {
303 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;303 const high = @as(u16, @intCast((c - 0x10000) >> 10)) + 0xD800;
304 try buf.append(std.mem.nativeToLittle(u16, high));304 try buf.append(allocator, std.mem.nativeToLittle(u16, high));
305305
306 // Note: This can cut-off in the middle of a UTF-16 surrogate pair,306 // Note: This can cut-off in the middle of a UTF-16 surrogate pair,
307 // i.e. it can make the string end with an unpaired high surrogate307 // i.e. it can make the string end with an unpaired high surrogate
308 if (buf.items.len == 256) break;308 if (buf.items.len == 256) break;
309309
310 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;310 const low = @as(u16, @intCast(c & 0x3FF)) + 0xDC00;
311 try buf.append(std.mem.nativeToLittle(u16, low));311 try buf.append(allocator, std.mem.nativeToLittle(u16, low));
312 }312 }
313 }313 }
314314
315 return NameOrOrdinal{ .name = try buf.toOwnedSliceSentinel(0) };315 return NameOrOrdinal{ .name = try buf.toOwnedSliceSentinel(allocator, 0) };
316 }316 }
317317
318 /// Returns `null` if the bytes do not form a valid number.318 /// Returns `null` if the bytes do not form a valid number.
...@@ -1079,7 +1079,7 @@ pub const FixedFileInfo = struct {...@@ -1079,7 +1079,7 @@ pub const FixedFileInfo = struct {
1079 }1079 }
1080 };1080 };
10811081
1082 pub fn write(self: FixedFileInfo, writer: anytype) !void {1082 pub fn write(self: FixedFileInfo, writer: *std.Io.Writer) !void {
1083 try writer.writeInt(u32, signature, .little);1083 try writer.writeInt(u32, signature, .little);
1084 try writer.writeInt(u32, version, .little);1084 try writer.writeInt(u32, version, .little);
1085 try writer.writeInt(u32, self.file_version.mostSignificantCombinedParts(), .little);1085 try writer.writeInt(u32, self.file_version.mostSignificantCombinedParts(), .little);
lib/compiler/resinator/source_mapping.zig+5-5
...@@ -10,7 +10,7 @@ pub const ParseLineCommandsResult = struct {...@@ -10,7 +10,7 @@ pub const ParseLineCommandsResult = struct {
1010
11const CurrentMapping = struct {11const CurrentMapping = struct {
12 line_num: usize = 1,12 line_num: usize = 1,
13 filename: std.ArrayListUnmanaged(u8) = .empty,13 filename: std.ArrayList(u8) = .empty,
14 pending: bool = true,14 pending: bool = true,
15 ignore_contents: bool = false,15 ignore_contents: bool = false,
16};16};
...@@ -574,8 +574,8 @@ fn parseFilename(allocator: Allocator, str: []const u8) error{ OutOfMemory, Inva...@@ -574,8 +574,8 @@ fn parseFilename(allocator: Allocator, str: []const u8) error{ OutOfMemory, Inva
574 escape_u,574 escape_u,
575 };575 };
576576
577 var filename = try std.array_list.Managed(u8).initCapacity(allocator, str.len);577 var filename = try std.ArrayList(u8).initCapacity(allocator, str.len);
578 errdefer filename.deinit();578 errdefer filename.deinit(allocator);
579 var state: State = .string;579 var state: State = .string;
580 var index: usize = 0;580 var index: usize = 0;
581 var escape_len: usize = undefined;581 var escape_len: usize = undefined;
...@@ -693,7 +693,7 @@ fn parseFilename(allocator: Allocator, str: []const u8) error{ OutOfMemory, Inva...@@ -693,7 +693,7 @@ fn parseFilename(allocator: Allocator, str: []const u8) error{ OutOfMemory, Inva
693 }693 }
694 }694 }
695695
696 return filename.toOwnedSlice();696 return filename.toOwnedSlice(allocator);
697}697}
698698
699fn testParseFilename(expected: []const u8, input: []const u8) !void {699fn testParseFilename(expected: []const u8, input: []const u8) !void {
...@@ -927,7 +927,7 @@ test "SourceMappings collapse" {...@@ -927,7 +927,7 @@ test "SourceMappings collapse" {
927927
928/// Same thing as StringTable in Zig's src/Wasm.zig928/// Same thing as StringTable in Zig's src/Wasm.zig
929pub const StringTable = struct {929pub const StringTable = struct {
930 data: std.ArrayListUnmanaged(u8) = .empty,930 data: std.ArrayList(u8) = .empty,
931 map: std.HashMapUnmanaged(u32, void, std.hash_map.StringIndexContext, std.hash_map.default_max_load_percentage) = .empty,931 map: std.HashMapUnmanaged(u32, void, std.hash_map.StringIndexContext, std.hash_map.default_max_load_percentage) = .empty,
932932
933 pub fn deinit(self: *StringTable, allocator: Allocator) void {933 pub fn deinit(self: *StringTable, allocator: Allocator) void {
lib/compiler/resinator/windows1252.zig-45
...@@ -1,36 +1,5 @@...@@ -1,36 +1,5 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn windows1252ToUtf8Stream(writer: anytype, reader: anytype) !usize {
4 var bytes_written: usize = 0;
5 var utf8_buf: [3]u8 = undefined;
6 while (true) {
7 const c = reader.readByte() catch |err| switch (err) {
8 error.EndOfStream => return bytes_written,
9 else => |e| return e,
10 };
11 const codepoint = toCodepoint(c);
12 if (codepoint <= 0x7F) {
13 try writer.writeByte(c);
14 bytes_written += 1;
15 } else {
16 const utf8_len = std.unicode.utf8Encode(codepoint, &utf8_buf) catch unreachable;
17 try writer.writeAll(utf8_buf[0..utf8_len]);
18 bytes_written += utf8_len;
19 }
20 }
21}
22
23/// Returns the number of code units written to the writer
24pub fn windows1252ToUtf16AllocZ(allocator: std.mem.Allocator, win1252_str: []const u8) ![:0]u16 {
25 // Guaranteed to need exactly the same number of code units as Windows-1252 bytes
26 var utf16_slice = try allocator.allocSentinel(u16, win1252_str.len, 0);
27 errdefer allocator.free(utf16_slice);
28 for (win1252_str, 0..) |c, i| {
29 utf16_slice[i] = toCodepoint(c);
30 }
31 return utf16_slice;
32}
33
34/// https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/bestfit1252.txt3/// https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/bestfit1252.txt
35pub fn toCodepoint(c: u8) u16 {4pub fn toCodepoint(c: u8) u16 {
36 return switch (c) {5 return switch (c) {
...@@ -572,17 +541,3 @@ pub fn bestFitFromCodepoint(codepoint: u21) ?u8 {...@@ -572,17 +541,3 @@ pub fn bestFitFromCodepoint(codepoint: u21) ?u8 {
572 else => null,541 else => null,
573 };542 };
574}543}
575
576test "windows-1252 to utf8" {
577 var buf = std.array_list.Managed(u8).init(std.testing.allocator);
578 defer buf.deinit();
579
580 const input_windows1252 = "\x81pqrstuvwxyz{|}~\x80\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8e\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9e\x9f\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
581 const expected_utf8 = "\xc2\x81pqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ";
582
583 var fbs = std.io.fixedBufferStream(input_windows1252);
584 const bytes_written = try windows1252ToUtf8Stream(buf.writer(), fbs.reader());
585
586 try std.testing.expectEqualStrings(expected_utf8, buf.items);
587 try std.testing.expectEqual(expected_utf8.len, bytes_written);
588}
lib/docs/wasm/Decl.zig+5-4
...@@ -6,6 +6,7 @@ const gpa = std.heap.wasm_allocator;...@@ -6,6 +6,7 @@ const gpa = std.heap.wasm_allocator;
6const assert = std.debug.assert;6const assert = std.debug.assert;
7const log = std.log;7const log = std.log;
8const Oom = error{OutOfMemory};8const Oom = error{OutOfMemory};
9const ArrayList = std.ArrayList;
910
10ast_node: Ast.Node.Index,11ast_node: Ast.Node.Index,
11file: Walk.File.Index,12file: Walk.File.Index,
...@@ -189,7 +190,7 @@ pub fn lookup(decl: *const Decl, name: []const u8) ?Decl.Index {...@@ -189,7 +190,7 @@ pub fn lookup(decl: *const Decl, name: []const u8) ?Decl.Index {
189}190}
190191
191/// Appends the fully qualified name to `out`.192/// Appends the fully qualified name to `out`.
192pub fn fqn(decl: *const Decl, out: *std.ArrayListUnmanaged(u8)) Oom!void {193pub fn fqn(decl: *const Decl, out: *ArrayList(u8)) Oom!void {
193 try decl.append_path(out);194 try decl.append_path(out);
194 if (decl.parent != .none) {195 if (decl.parent != .none) {
195 try append_parent_ns(out, decl.parent);196 try append_parent_ns(out, decl.parent);
...@@ -199,12 +200,12 @@ pub fn fqn(decl: *const Decl, out: *std.ArrayListUnmanaged(u8)) Oom!void {...@@ -199,12 +200,12 @@ pub fn fqn(decl: *const Decl, out: *std.ArrayListUnmanaged(u8)) Oom!void {
199 }200 }
200}201}
201202
202pub fn reset_with_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!void {203pub fn reset_with_path(decl: *const Decl, list: *ArrayList(u8)) Oom!void {
203 list.clearRetainingCapacity();204 list.clearRetainingCapacity();
204 try append_path(decl, list);205 try append_path(decl, list);
205}206}
206207
207pub fn append_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!void {208pub fn append_path(decl: *const Decl, list: *ArrayList(u8)) Oom!void {
208 const start = list.items.len;209 const start = list.items.len;
209 // Prefer the module name alias.210 // Prefer the module name alias.
210 for (Walk.modules.keys(), Walk.modules.values()) |pkg_name, pkg_file| {211 for (Walk.modules.keys(), Walk.modules.values()) |pkg_name, pkg_file| {
...@@ -230,7 +231,7 @@ pub fn append_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!voi...@@ -230,7 +231,7 @@ pub fn append_path(decl: *const Decl, list: *std.ArrayListUnmanaged(u8)) Oom!voi
230 }231 }
231}232}
232233
233pub fn append_parent_ns(list: *std.ArrayListUnmanaged(u8), parent: Decl.Index) Oom!void {234pub fn append_parent_ns(list: *ArrayList(u8), parent: Decl.Index) Oom!void {
234 assert(parent != .none);235 assert(parent != .none);
235 const decl = parent.get();236 const decl = parent.get();
236 if (decl.parent != .none) {237 if (decl.parent != .none) {
lib/docs/wasm/html_render.zig+10-8
...@@ -1,6 +1,8 @@...@@ -1,6 +1,8 @@
1const std = @import("std");1const std = @import("std");
2const Ast = std.zig.Ast;2const Ast = std.zig.Ast;
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const ArrayList = std.ArrayList;
5const Writer = std.Io.Writer;
46
5const Walk = @import("Walk");7const Walk = @import("Walk");
6const Decl = Walk.Decl;8const Decl = Walk.Decl;
...@@ -30,7 +32,7 @@ pub const Annotation = struct {...@@ -30,7 +32,7 @@ pub const Annotation = struct {
3032
31pub fn fileSourceHtml(33pub fn fileSourceHtml(
32 file_index: Walk.File.Index,34 file_index: Walk.File.Index,
33 out: *std.ArrayListUnmanaged(u8),35 out: *ArrayList(u8),
34 root_node: Ast.Node.Index,36 root_node: Ast.Node.Index,
35 options: RenderSourceOptions,37 options: RenderSourceOptions,
36) !void {38) !void {
...@@ -38,7 +40,7 @@ pub fn fileSourceHtml(...@@ -38,7 +40,7 @@ pub fn fileSourceHtml(
38 const file = file_index.get();40 const file = file_index.get();
3941
40 const g = struct {42 const g = struct {
41 var field_access_buffer: std.ArrayListUnmanaged(u8) = .empty;43 var field_access_buffer: ArrayList(u8) = .empty;
42 };44 };
4345
44 const start_token = ast.firstToken(root_node);46 const start_token = ast.firstToken(root_node);
...@@ -88,7 +90,7 @@ pub fn fileSourceHtml(...@@ -88,7 +90,7 @@ pub fn fileSourceHtml(
88 if (next_annotate_index >= options.source_location_annotations.len) break;90 if (next_annotate_index >= options.source_location_annotations.len) break;
89 const next_annotation = options.source_location_annotations[next_annotate_index];91 const next_annotation = options.source_location_annotations[next_annotate_index];
90 if (cursor <= next_annotation.file_byte_offset) break;92 if (cursor <= next_annotation.file_byte_offset) break;
91 try out.writer(gpa).print("<span id=\"{s}{d}\"></span>", .{93 try out.print(gpa, "<span id=\"{s}{d}\"></span>", .{
92 options.annotation_prefix, next_annotation.dom_id,94 options.annotation_prefix, next_annotation.dom_id,
93 });95 });
94 next_annotate_index += 1;96 next_annotate_index += 1;
...@@ -318,7 +320,7 @@ pub fn fileSourceHtml(...@@ -318,7 +320,7 @@ pub fn fileSourceHtml(
318 }320 }
319}321}
320322
321fn appendUnindented(out: *std.ArrayListUnmanaged(u8), s: []const u8, indent: usize) !void {323fn appendUnindented(out: *ArrayList(u8), s: []const u8, indent: usize) !void {
322 var it = std.mem.splitScalar(u8, s, '\n');324 var it = std.mem.splitScalar(u8, s, '\n');
323 var is_first_line = true;325 var is_first_line = true;
324 while (it.next()) |line| {326 while (it.next()) |line| {
...@@ -332,7 +334,7 @@ fn appendUnindented(out: *std.ArrayListUnmanaged(u8), s: []const u8, indent: usi...@@ -332,7 +334,7 @@ fn appendUnindented(out: *std.ArrayListUnmanaged(u8), s: []const u8, indent: usi
332 }334 }
333}335}
334336
335pub fn appendEscaped(out: *std.ArrayListUnmanaged(u8), s: []const u8) !void {337pub fn appendEscaped(out: *ArrayList(u8), s: []const u8) !void {
336 for (s) |c| {338 for (s) |c| {
337 try out.ensureUnusedCapacity(gpa, 6);339 try out.ensureUnusedCapacity(gpa, 6);
338 switch (c) {340 switch (c) {
...@@ -347,7 +349,7 @@ pub fn appendEscaped(out: *std.ArrayListUnmanaged(u8), s: []const u8) !void {...@@ -347,7 +349,7 @@ pub fn appendEscaped(out: *std.ArrayListUnmanaged(u8), s: []const u8) !void {
347349
348fn walkFieldAccesses(350fn walkFieldAccesses(
349 file_index: Walk.File.Index,351 file_index: Walk.File.Index,
350 out: *std.ArrayListUnmanaged(u8),352 out: *ArrayList(u8),
351 node: Ast.Node.Index,353 node: Ast.Node.Index,
352) Oom!void {354) Oom!void {
353 const ast = file_index.get_ast();355 const ast = file_index.get_ast();
...@@ -371,7 +373,7 @@ fn walkFieldAccesses(...@@ -371,7 +373,7 @@ fn walkFieldAccesses(
371373
372fn resolveIdentLink(374fn resolveIdentLink(
373 file_index: Walk.File.Index,375 file_index: Walk.File.Index,
374 out: *std.ArrayListUnmanaged(u8),376 out: *ArrayList(u8),
375 ident_token: Ast.TokenIndex,377 ident_token: Ast.TokenIndex,
376) Oom!void {378) Oom!void {
377 const decl_index = file_index.get().lookup_token(ident_token);379 const decl_index = file_index.get().lookup_token(ident_token);
...@@ -391,7 +393,7 @@ fn unindent(s: []const u8, indent: usize) []const u8 {...@@ -391,7 +393,7 @@ fn unindent(s: []const u8, indent: usize) []const u8 {
391 return s[indent_idx..];393 return s[indent_idx..];
392}394}
393395
394pub fn resolveDeclLink(decl_index: Decl.Index, out: *std.ArrayListUnmanaged(u8)) Oom!void {396pub fn resolveDeclLink(decl_index: Decl.Index, out: *ArrayList(u8)) Oom!void {
395 const decl = decl_index.get();397 const decl = decl_index.get();
396 switch (decl.categorize()) {398 switch (decl.categorize()) {
397 .alias => |alias_decl| try alias_decl.get().fqn(out),399 .alias => |alias_decl| try alias_decl.get().fqn(out),
lib/docs/wasm/main.zig+30-24
...@@ -5,6 +5,8 @@ const Ast = std.zig.Ast;...@@ -5,6 +5,8 @@ const Ast = std.zig.Ast;
5const Walk = @import("Walk");5const Walk = @import("Walk");
6const markdown = @import("markdown.zig");6const markdown = @import("markdown.zig");
7const Decl = Walk.Decl;7const Decl = Walk.Decl;
8const ArrayList = std.ArrayList;
9const Writer = std.Io.Writer;
810
9const fileSourceHtml = @import("html_render.zig").fileSourceHtml;11const fileSourceHtml = @import("html_render.zig").fileSourceHtml;
10const appendEscaped = @import("html_render.zig").appendEscaped;12const appendEscaped = @import("html_render.zig").appendEscaped;
...@@ -66,8 +68,8 @@ export fn unpack(tar_ptr: [*]u8, tar_len: usize) void {...@@ -66,8 +68,8 @@ export fn unpack(tar_ptr: [*]u8, tar_len: usize) void {
66 };68 };
67}69}
6870
69var query_string: std.ArrayListUnmanaged(u8) = .empty;71var query_string: ArrayList(u8) = .empty;
70var query_results: std.ArrayListUnmanaged(Decl.Index) = .empty;72var query_results: ArrayList(Decl.Index) = .empty;
7173
72/// Resizes the query string to be the correct length; returns the pointer to74/// Resizes the query string to be the correct length; returns the pointer to
73/// the query string.75/// the query string.
...@@ -99,11 +101,11 @@ fn query_exec_fallible(query: []const u8, ignore_case: bool) !void {...@@ -99,11 +101,11 @@ fn query_exec_fallible(query: []const u8, ignore_case: bool) !void {
99 segments: u16,101 segments: u16,
100 };102 };
101 const g = struct {103 const g = struct {
102 var full_path_search_text: std.ArrayListUnmanaged(u8) = .empty;104 var full_path_search_text: ArrayList(u8) = .empty;
103 var full_path_search_text_lower: std.ArrayListUnmanaged(u8) = .empty;105 var full_path_search_text_lower: ArrayList(u8) = .empty;
104 var doc_search_text: std.ArrayListUnmanaged(u8) = .empty;106 var doc_search_text: ArrayList(u8) = .empty;
105 /// Each element matches a corresponding query_results element.107 /// Each element matches a corresponding query_results element.
106 var scores: std.ArrayListUnmanaged(Score) = .empty;108 var scores: ArrayList(Score) = .empty;
107 };109 };
108110
109 // First element stores the size of the list.111 // First element stores the size of the list.
...@@ -234,7 +236,7 @@ const ErrorIdentifier = packed struct(u64) {...@@ -234,7 +236,7 @@ const ErrorIdentifier = packed struct(u64) {
234 return ast.tokenTag(token_index - 1) == .doc_comment;236 return ast.tokenTag(token_index - 1) == .doc_comment;
235 }237 }
236238
237 fn html(ei: ErrorIdentifier, base_decl: Decl.Index, out: *std.ArrayListUnmanaged(u8)) Oom!void {239 fn html(ei: ErrorIdentifier, base_decl: Decl.Index, out: *ArrayList(u8)) Oom!void {
238 const decl_index = ei.decl_index;240 const decl_index = ei.decl_index;
239 const ast = decl_index.get().file.get_ast();241 const ast = decl_index.get().file.get_ast();
240 const name = ast.tokenSlice(ei.token_index);242 const name = ast.tokenSlice(ei.token_index);
...@@ -260,7 +262,7 @@ const ErrorIdentifier = packed struct(u64) {...@@ -260,7 +262,7 @@ const ErrorIdentifier = packed struct(u64) {
260 }262 }
261};263};
262264
263var string_result: std.ArrayListUnmanaged(u8) = .empty;265var string_result: ArrayList(u8) = .empty;
264var error_set_result: std.StringArrayHashMapUnmanaged(ErrorIdentifier) = .empty;266var error_set_result: std.StringArrayHashMapUnmanaged(ErrorIdentifier) = .empty;
265267
266export fn decl_error_set(decl_index: Decl.Index) Slice(ErrorIdentifier) {268export fn decl_error_set(decl_index: Decl.Index) Slice(ErrorIdentifier) {
...@@ -411,7 +413,7 @@ fn decl_fields_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {...@@ -411,7 +413,7 @@ fn decl_fields_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {
411413
412fn ast_decl_fields_fallible(ast: *Ast, ast_index: Ast.Node.Index) ![]Ast.Node.Index {414fn ast_decl_fields_fallible(ast: *Ast, ast_index: Ast.Node.Index) ![]Ast.Node.Index {
413 const g = struct {415 const g = struct {
414 var result: std.ArrayListUnmanaged(Ast.Node.Index) = .empty;416 var result: ArrayList(Ast.Node.Index) = .empty;
415 };417 };
416 g.result.clearRetainingCapacity();418 g.result.clearRetainingCapacity();
417 var buf: [2]Ast.Node.Index = undefined;419 var buf: [2]Ast.Node.Index = undefined;
...@@ -429,7 +431,7 @@ fn ast_decl_fields_fallible(ast: *Ast, ast_index: Ast.Node.Index) ![]Ast.Node.In...@@ -429,7 +431,7 @@ fn ast_decl_fields_fallible(ast: *Ast, ast_index: Ast.Node.Index) ![]Ast.Node.In
429431
430fn decl_params_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {432fn decl_params_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {
431 const g = struct {433 const g = struct {
432 var result: std.ArrayListUnmanaged(Ast.Node.Index) = .empty;434 var result: ArrayList(Ast.Node.Index) = .empty;
433 };435 };
434 g.result.clearRetainingCapacity();436 g.result.clearRetainingCapacity();
435 const decl = decl_index.get();437 const decl = decl_index.get();
...@@ -460,7 +462,7 @@ export fn decl_param_html(decl_index: Decl.Index, param_node: Ast.Node.Index) St...@@ -460,7 +462,7 @@ export fn decl_param_html(decl_index: Decl.Index, param_node: Ast.Node.Index) St
460}462}
461463
462fn decl_field_html_fallible(464fn decl_field_html_fallible(
463 out: *std.ArrayListUnmanaged(u8),465 out: *ArrayList(u8),
464 decl_index: Decl.Index,466 decl_index: Decl.Index,
465 field_node: Ast.Node.Index,467 field_node: Ast.Node.Index,
466) !void {468) !void {
...@@ -480,7 +482,7 @@ fn decl_field_html_fallible(...@@ -480,7 +482,7 @@ fn decl_field_html_fallible(
480}482}
481483
482fn decl_param_html_fallible(484fn decl_param_html_fallible(
483 out: *std.ArrayListUnmanaged(u8),485 out: *ArrayList(u8),
484 decl_index: Decl.Index,486 decl_index: Decl.Index,
485 param_node: Ast.Node.Index,487 param_node: Ast.Node.Index,
486) !void {488) !void {
...@@ -649,7 +651,7 @@ export fn decl_docs_html(decl_index: Decl.Index, short: bool) String {...@@ -649,7 +651,7 @@ export fn decl_docs_html(decl_index: Decl.Index, short: bool) String {
649}651}
650652
651fn collect_docs(653fn collect_docs(
652 list: *std.ArrayListUnmanaged(u8),654 list: *ArrayList(u8),
653 ast: *const Ast,655 ast: *const Ast,
654 first_doc_comment: Ast.TokenIndex,656 first_doc_comment: Ast.TokenIndex,
655) Oom!void {657) Oom!void {
...@@ -667,7 +669,7 @@ fn collect_docs(...@@ -667,7 +669,7 @@ fn collect_docs(
667}669}
668670
669fn render_docs(671fn render_docs(
670 out: *std.ArrayListUnmanaged(u8),672 out: *ArrayList(u8),
671 decl_index: Decl.Index,673 decl_index: Decl.Index,
672 first_doc_comment: Ast.TokenIndex,674 first_doc_comment: Ast.TokenIndex,
673 short: bool,675 short: bool,
...@@ -691,11 +693,10 @@ fn render_docs(...@@ -691,11 +693,10 @@ fn render_docs(
691 defer parsed_doc.deinit(gpa);693 defer parsed_doc.deinit(gpa);
692694
693 const g = struct {695 const g = struct {
694 var link_buffer: std.ArrayListUnmanaged(u8) = .empty;696 var link_buffer: ArrayList(u8) = .empty;
695 };697 };
696698
697 const Writer = std.ArrayListUnmanaged(u8).Writer;699 const Renderer = markdown.Renderer(Decl.Index);
698 const Renderer = markdown.Renderer(Writer, Decl.Index);
699 const renderer: Renderer = .{700 const renderer: Renderer = .{
700 .context = decl_index,701 .context = decl_index,
701 .renderFn = struct {702 .renderFn = struct {
...@@ -703,8 +704,8 @@ fn render_docs(...@@ -703,8 +704,8 @@ fn render_docs(
703 r: Renderer,704 r: Renderer,
704 doc: markdown.Document,705 doc: markdown.Document,
705 node: markdown.Document.Node.Index,706 node: markdown.Document.Node.Index,
706 writer: Writer,707 writer: *Writer,
707 ) !void {708 ) Writer.Error!void {
708 const data = doc.nodes.items(.data)[@intFromEnum(node)];709 const data = doc.nodes.items(.data)[@intFromEnum(node)];
709 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {710 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {
710 .code_span => {711 .code_span => {
...@@ -712,7 +713,7 @@ fn render_docs(...@@ -712,7 +713,7 @@ fn render_docs(
712 const content = doc.string(data.text.content);713 const content = doc.string(data.text.content);
713 if (resolve_decl_path(r.context, content)) |resolved_decl_index| {714 if (resolve_decl_path(r.context, content)) |resolved_decl_index| {
714 g.link_buffer.clearRetainingCapacity();715 g.link_buffer.clearRetainingCapacity();
715 try resolveDeclLink(resolved_decl_index, &g.link_buffer);716 resolveDeclLink(resolved_decl_index, &g.link_buffer) catch return error.WriteFailed;
716717
717 try writer.writeAll("<a href=\"#");718 try writer.writeAll("<a href=\"#");
718 _ = missing_feature_url_escape;719 _ = missing_feature_url_escape;
...@@ -730,7 +731,12 @@ fn render_docs(...@@ -730,7 +731,12 @@ fn render_docs(
730 }731 }
731 }.render,732 }.render,
732 };733 };
733 try renderer.render(parsed_doc, out.writer(gpa));734
735 var allocating = Writer.Allocating.fromArrayList(gpa, out);
736 defer out.* = allocating.toArrayList();
737 renderer.render(parsed_doc, &allocating.writer) catch |err| switch (err) {
738 error.WriteFailed => return error.OutOfMemory,
739 };
734}740}
735741
736fn resolve_decl_path(decl_index: Decl.Index, path: []const u8) ?Decl.Index {742fn resolve_decl_path(decl_index: Decl.Index, path: []const u8) ?Decl.Index {
...@@ -827,7 +833,7 @@ export fn find_module_root(pkg: Walk.ModuleIndex) Decl.Index {...@@ -827,7 +833,7 @@ export fn find_module_root(pkg: Walk.ModuleIndex) Decl.Index {
827}833}
828834
829/// Set by `set_input_string`.835/// Set by `set_input_string`.
830var input_string: std.ArrayListUnmanaged(u8) = .empty;836var input_string: ArrayList(u8) = .empty;
831837
832export fn set_input_string(len: usize) [*]u8 {838export fn set_input_string(len: usize) [*]u8 {
833 input_string.resize(gpa, len) catch @panic("OOM");839 input_string.resize(gpa, len) catch @panic("OOM");
...@@ -849,7 +855,7 @@ export fn find_decl() Decl.Index {...@@ -849,7 +855,7 @@ export fn find_decl() Decl.Index {
849 if (result != .none) return result;855 if (result != .none) return result;
850856
851 const g = struct {857 const g = struct {
852 var match_fqn: std.ArrayListUnmanaged(u8) = .empty;858 var match_fqn: ArrayList(u8) = .empty;
853 };859 };
854 for (Walk.decls.items, 0..) |*decl, decl_index| {860 for (Walk.decls.items, 0..) |*decl, decl_index| {
855 g.match_fqn.clearRetainingCapacity();861 g.match_fqn.clearRetainingCapacity();
...@@ -905,7 +911,7 @@ export fn type_fn_members(parent: Decl.Index, include_private: bool) Slice(Decl....@@ -905,7 +911,7 @@ export fn type_fn_members(parent: Decl.Index, include_private: bool) Slice(Decl.
905911
906export fn namespace_members(parent: Decl.Index, include_private: bool) Slice(Decl.Index) {912export fn namespace_members(parent: Decl.Index, include_private: bool) Slice(Decl.Index) {
907 const g = struct {913 const g = struct {
908 var members: std.ArrayListUnmanaged(Decl.Index) = .empty;914 var members: ArrayList(Decl.Index) = .empty;
909 };915 };
910916
911 g.members.clearRetainingCapacity();917 g.members.clearRetainingCapacity();
lib/docs/wasm/markdown/renderer.zig+15-16
...@@ -2,25 +2,26 @@ const std = @import("std");...@@ -2,25 +2,26 @@ const std = @import("std");
2const Document = @import("Document.zig");2const Document = @import("Document.zig");
3const Node = Document.Node;3const Node = Document.Node;
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const Writer = std.Io.Writer;
56
6/// A Markdown document renderer.7/// A Markdown document renderer.
7///8///
8/// Each concrete `Renderer` type has a `renderDefault` function, with the9/// Each concrete `Renderer` type has a `renderDefault` function, with the
9/// intention that custom `renderFn` implementations can call `renderDefault`10/// intention that custom `renderFn` implementations can call `renderDefault`
10/// for node types for which they require no special rendering.11/// for node types for which they require no special rendering.
11pub fn Renderer(comptime Writer: type, comptime Context: type) type {12pub fn Renderer(comptime Context: type) type {
12 return struct {13 return struct {
13 renderFn: *const fn (14 renderFn: *const fn (
14 r: Self,15 r: Self,
15 doc: Document,16 doc: Document,
16 node: Node.Index,17 node: Node.Index,
17 writer: Writer,18 writer: *Writer,
18 ) Writer.Error!void = renderDefault,19 ) Writer.Error!void = renderDefault,
19 context: Context,20 context: Context,
2021
21 const Self = @This();22 const Self = @This();
2223
23 pub fn render(r: Self, doc: Document, writer: Writer) Writer.Error!void {24 pub fn render(r: Self, doc: Document, writer: *Writer) Writer.Error!void {
24 try r.renderFn(r, doc, .root, writer);25 try r.renderFn(r, doc, .root, writer);
25 }26 }
2627
...@@ -28,7 +29,7 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {...@@ -28,7 +29,7 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {
28 r: Self,29 r: Self,
29 doc: Document,30 doc: Document,
30 node: Node.Index,31 node: Node.Index,
31 writer: Writer,32 writer: *Writer,
32 ) Writer.Error!void {33 ) Writer.Error!void {
33 const data = doc.nodes.items(.data)[@intFromEnum(node)];34 const data = doc.nodes.items(.data)[@intFromEnum(node)];
34 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {35 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {
...@@ -188,8 +189,8 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {...@@ -188,8 +189,8 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {
188pub fn renderInlineNodeText(189pub fn renderInlineNodeText(
189 doc: Document,190 doc: Document,
190 node: Node.Index,191 node: Node.Index,
191 writer: anytype,192 writer: *Writer,
192) @TypeOf(writer).Error!void {193) Writer.Error!void {
193 const data = doc.nodes.items(.data)[@intFromEnum(node)];194 const data = doc.nodes.items(.data)[@intFromEnum(node)];
194 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {195 switch (doc.nodes.items(.tag)[@intFromEnum(node)]) {
195 .root,196 .root,
...@@ -234,14 +235,12 @@ pub fn fmtHtml(bytes: []const u8) std.fmt.Formatter([]const u8, formatHtml) {...@@ -234,14 +235,12 @@ pub fn fmtHtml(bytes: []const u8) std.fmt.Formatter([]const u8, formatHtml) {
234 return .{ .data = bytes };235 return .{ .data = bytes };
235}236}
236237
237fn formatHtml(bytes: []const u8, writer: *std.io.Writer) std.io.Writer.Error!void {238fn formatHtml(bytes: []const u8, w: *Writer) Writer.Error!void {
238 for (bytes) |b| {239 for (bytes) |b| switch (b) {
239 switch (b) {240 '<' => try w.writeAll("&lt;"),
240 '<' => try writer.writeAll("&lt;"),241 '>' => try w.writeAll("&gt;"),
241 '>' => try writer.writeAll("&gt;"),242 '&' => try w.writeAll("&amp;"),
242 '&' => try writer.writeAll("&amp;"),243 '"' => try w.writeAll("&quot;"),
243 '"' => try writer.writeAll("&quot;"),244 else => try w.writeByte(b),
244 else => try writer.writeByte(b),245 };
245 }
246 }
247}246}
lib/std/Build/Step/CheckObject.zig+25-27
...@@ -257,7 +257,7 @@ const Check = struct {...@@ -257,7 +257,7 @@ const Check = struct {
257 fn dumpSection(allocator: Allocator, name: [:0]const u8) Check {257 fn dumpSection(allocator: Allocator, name: [:0]const u8) Check {
258 var check = Check.create(allocator, .dump_section);258 var check = Check.create(allocator, .dump_section);
259 const off: u32 = @intCast(check.data.items.len);259 const off: u32 = @intCast(check.data.items.len);
260 check.data.writer().print("{s}\x00", .{name}) catch @panic("OOM");260 check.data.print("{s}\x00", .{name}) catch @panic("OOM");
261 check.payload = .{ .dump_section = off };261 check.payload = .{ .dump_section = off };
262 return check;262 return check;
263 }263 }
...@@ -1320,7 +1320,8 @@ const MachODumper = struct {...@@ -1320,7 +1320,8 @@ const MachODumper = struct {
1320 }1320 }
1321 bindings.deinit();1321 bindings.deinit();
1322 }1322 }
1323 try ctx.parseBindInfo(data, &bindings);1323 var data_reader: std.Io.Reader = .fixed(data);
1324 try ctx.parseBindInfo(&data_reader, &bindings);
1324 mem.sort(Binding, bindings.items, {}, Binding.lessThan);1325 mem.sort(Binding, bindings.items, {}, Binding.lessThan);
1325 for (bindings.items) |binding| {1326 for (bindings.items) |binding| {
1326 try writer.print("0x{x} [addend: {d}]", .{ binding.address, binding.addend });1327 try writer.print("0x{x} [addend: {d}]", .{ binding.address, binding.addend });
...@@ -1335,11 +1336,7 @@ const MachODumper = struct {...@@ -1335,11 +1336,7 @@ const MachODumper = struct {
1335 }1336 }
1336 }1337 }
13371338
1338 fn parseBindInfo(ctx: ObjectContext, data: []const u8, bindings: *std.array_list.Managed(Binding)) !void {1339 fn parseBindInfo(ctx: ObjectContext, reader: *std.Io.Reader, bindings: *std.array_list.Managed(Binding)) !void {
1339 var stream = std.io.fixedBufferStream(data);
1340 var creader = std.io.countingReader(stream.reader());
1341 const reader = creader.reader();
1342
1343 var seg_id: ?u8 = null;1340 var seg_id: ?u8 = null;
1344 var tag: Binding.Tag = .self;1341 var tag: Binding.Tag = .self;
1345 var ordinal: u16 = 0;1342 var ordinal: u16 = 0;
...@@ -1350,7 +1347,7 @@ const MachODumper = struct {...@@ -1350,7 +1347,7 @@ const MachODumper = struct {
1350 defer name_buf.deinit();1347 defer name_buf.deinit();
13511348
1352 while (true) {1349 while (true) {
1353 const byte = reader.readByte() catch break;1350 const byte = reader.takeByte() catch break;
1354 const opc = byte & macho.BIND_OPCODE_MASK;1351 const opc = byte & macho.BIND_OPCODE_MASK;
1355 const imm = byte & macho.BIND_IMMEDIATE_MASK;1352 const imm = byte & macho.BIND_IMMEDIATE_MASK;
1356 switch (opc) {1353 switch (opc) {
...@@ -1371,18 +1368,17 @@ const MachODumper = struct {...@@ -1371,18 +1368,17 @@ const MachODumper = struct {
1371 },1368 },
1372 macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => {1369 macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => {
1373 seg_id = imm;1370 seg_id = imm;
1374 offset = try std.leb.readUleb128(u64, reader);1371 offset = try reader.takeLeb128(u64);
1375 },1372 },
1376 macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => {1373 macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => {
1377 name_buf.clearRetainingCapacity();1374 name_buf.clearRetainingCapacity();
1378 try reader.readUntilDelimiterArrayList(&name_buf, 0, std.math.maxInt(u32));1375 try name_buf.appendSlice(try reader.takeDelimiterInclusive(0));
1379 try name_buf.append(0);
1380 },1376 },
1381 macho.BIND_OPCODE_SET_ADDEND_SLEB => {1377 macho.BIND_OPCODE_SET_ADDEND_SLEB => {
1382 addend = try std.leb.readIleb128(i64, reader);1378 addend = try reader.takeLeb128(i64);
1383 },1379 },
1384 macho.BIND_OPCODE_ADD_ADDR_ULEB => {1380 macho.BIND_OPCODE_ADD_ADDR_ULEB => {
1385 const x = try std.leb.readUleb128(u64, reader);1381 const x = try reader.takeLeb128(u64);
1386 offset = @intCast(@as(i64, @intCast(offset)) + @as(i64, @bitCast(x)));1382 offset = @intCast(@as(i64, @intCast(offset)) + @as(i64, @bitCast(x)));
1387 },1383 },
1388 macho.BIND_OPCODE_DO_BIND,1384 macho.BIND_OPCODE_DO_BIND,
...@@ -1397,14 +1393,14 @@ const MachODumper = struct {...@@ -1397,14 +1393,14 @@ const MachODumper = struct {
1397 switch (opc) {1393 switch (opc) {
1398 macho.BIND_OPCODE_DO_BIND => {},1394 macho.BIND_OPCODE_DO_BIND => {},
1399 macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB => {1395 macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB => {
1400 add_addr = try std.leb.readUleb128(u64, reader);1396 add_addr = try reader.takeLeb128(u64);
1401 },1397 },
1402 macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED => {1398 macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED => {
1403 add_addr = imm * @sizeOf(u64);1399 add_addr = imm * @sizeOf(u64);
1404 },1400 },
1405 macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB => {1401 macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB => {
1406 count = try std.leb.readUleb128(u64, reader);1402 count = try reader.takeLeb128(u64);
1407 skip = try std.leb.readUleb128(u64, reader);1403 skip = try reader.takeLeb128(u64);
1408 },1404 },
1409 else => unreachable,1405 else => unreachable,
1410 }1406 }
...@@ -1621,8 +1617,9 @@ const MachODumper = struct {...@@ -1621,8 +1617,9 @@ const MachODumper = struct {
1621 var ctx = ObjectContext{ .gpa = gpa, .data = bytes, .header = hdr };1617 var ctx = ObjectContext{ .gpa = gpa, .data = bytes, .header = hdr };
1622 try ctx.parse();1618 try ctx.parse();
16231619
1624 var output = std.array_list.Managed(u8).init(gpa);1620 var output: std.Io.Writer.Allocating = .init(gpa);
1625 const writer = output.writer();1621 defer output.deinit();
1622 const writer = &output.writer;
16261623
1627 switch (check.kind) {1624 switch (check.kind) {
1628 .headers => {1625 .headers => {
...@@ -1787,8 +1784,9 @@ const ElfDumper = struct {...@@ -1787,8 +1784,9 @@ const ElfDumper = struct {
1787 try ctx.objects.append(gpa, .{ .name = name, .off = stream.pos, .len = size });1784 try ctx.objects.append(gpa, .{ .name = name, .off = stream.pos, .len = size });
1788 }1785 }
17891786
1790 var output = std.array_list.Managed(u8).init(gpa);1787 var output: std.Io.Writer.Allocating = .init(gpa);
1791 const writer = output.writer();1788 defer output.deinit();
1789 const writer = &output.writer;
17921790
1793 switch (check.kind) {1791 switch (check.kind) {
1794 .archive_symtab => if (ctx.symtab.items.len > 0) {1792 .archive_symtab => if (ctx.symtab.items.len > 0) {
...@@ -1944,8 +1942,9 @@ const ElfDumper = struct {...@@ -1944,8 +1942,9 @@ const ElfDumper = struct {
1944 else => {},1942 else => {},
1945 };1943 };
19461944
1947 var output = std.array_list.Managed(u8).init(gpa);1945 var output: std.Io.Writer.Allocating = .init(gpa);
1948 const writer = output.writer();1946 defer output.deinit();
1947 const writer = &output.writer;
19491948
1950 switch (check.kind) {1949 switch (check.kind) {
1951 .headers => {1950 .headers => {
...@@ -2398,10 +2397,10 @@ const WasmDumper = struct {...@@ -2398,10 +2397,10 @@ const WasmDumper = struct {
2398 return error.UnsupportedWasmVersion;2397 return error.UnsupportedWasmVersion;
2399 }2398 }
24002399
2401 var output = std.array_list.Managed(u8).init(gpa);2400 var output: std.Io.Writer.Allocating = .init(gpa);
2402 defer output.deinit();2401 defer output.deinit();
2403 parseAndDumpInner(step, check, bytes, &fbs, &output) catch |err| switch (err) {2402 parseAndDumpInner(step, check, bytes, &fbs, &output.writer) catch |err| switch (err) {
2404 error.EndOfStream => try output.appendSlice("\n<UnexpectedEndOfStream>"),2403 error.EndOfStream => try output.writer.writeAll("\n<UnexpectedEndOfStream>"),
2405 else => |e| return e,2404 else => |e| return e,
2406 };2405 };
2407 return output.toOwnedSlice();2406 return output.toOwnedSlice();
...@@ -2412,10 +2411,9 @@ const WasmDumper = struct {...@@ -2412,10 +2411,9 @@ const WasmDumper = struct {
2412 check: Check,2411 check: Check,
2413 bytes: []const u8,2412 bytes: []const u8,
2414 fbs: *std.io.FixedBufferStream([]const u8),2413 fbs: *std.io.FixedBufferStream([]const u8),
2415 output: *std.array_list.Managed(u8),2414 writer: *std.Io.Writer,
2416 ) !void {2415 ) !void {
2417 const reader = fbs.reader();2416 const reader = fbs.reader();
2418 const writer = output.writer();
24192417
2420 switch (check.kind) {2418 switch (check.kind) {
2421 .headers => {2419 .headers => {
lib/std/Io.zig-163
...@@ -144,61 +144,6 @@ pub fn GenericReader(...@@ -144,61 +144,6 @@ pub fn GenericReader(
144 return @errorCast(self.any().readAllAlloc(allocator, max_size));144 return @errorCast(self.any().readAllAlloc(allocator, max_size));
145 }145 }
146146
147 pub inline fn readUntilDelimiterArrayList(
148 self: Self,
149 array_list: *std.array_list.Managed(u8),
150 delimiter: u8,
151 max_size: usize,
152 ) (NoEofError || Allocator.Error || error{StreamTooLong})!void {
153 return @errorCast(self.any().readUntilDelimiterArrayList(
154 array_list,
155 delimiter,
156 max_size,
157 ));
158 }
159
160 pub inline fn readUntilDelimiterAlloc(
161 self: Self,
162 allocator: Allocator,
163 delimiter: u8,
164 max_size: usize,
165 ) (NoEofError || Allocator.Error || error{StreamTooLong})![]u8 {
166 return @errorCast(self.any().readUntilDelimiterAlloc(
167 allocator,
168 delimiter,
169 max_size,
170 ));
171 }
172
173 pub inline fn readUntilDelimiter(
174 self: Self,
175 buf: []u8,
176 delimiter: u8,
177 ) (NoEofError || error{StreamTooLong})![]u8 {
178 return @errorCast(self.any().readUntilDelimiter(buf, delimiter));
179 }
180
181 pub inline fn readUntilDelimiterOrEofAlloc(
182 self: Self,
183 allocator: Allocator,
184 delimiter: u8,
185 max_size: usize,
186 ) (Error || Allocator.Error || error{StreamTooLong})!?[]u8 {
187 return @errorCast(self.any().readUntilDelimiterOrEofAlloc(
188 allocator,
189 delimiter,
190 max_size,
191 ));
192 }
193
194 pub inline fn readUntilDelimiterOrEof(
195 self: Self,
196 buf: []u8,
197 delimiter: u8,
198 ) (Error || error{StreamTooLong})!?[]u8 {
199 return @errorCast(self.any().readUntilDelimiterOrEof(buf, delimiter));
200 }
201
202 pub inline fn streamUntilDelimiter(147 pub inline fn streamUntilDelimiter(
203 self: Self,148 self: Self,
204 writer: anytype,149 writer: anytype,
...@@ -326,103 +271,8 @@ pub fn GenericReader(...@@ -326,103 +271,8 @@ pub fn GenericReader(
326 };271 };
327}272}
328273
329/// Deprecated in favor of `Writer`.
330pub fn GenericWriter(
331 comptime Context: type,
332 comptime WriteError: type,
333 comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize,
334) type {
335 return struct {
336 context: Context,
337
338 const Self = @This();
339 pub const Error = WriteError;
340
341 pub inline fn write(self: Self, bytes: []const u8) Error!usize {
342 return writeFn(self.context, bytes);
343 }
344
345 pub inline fn writeAll(self: Self, bytes: []const u8) Error!void {
346 return @errorCast(self.any().writeAll(bytes));
347 }
348
349 pub inline fn print(self: Self, comptime format: []const u8, args: anytype) Error!void {
350 return @errorCast(self.any().print(format, args));
351 }
352
353 pub inline fn writeByte(self: Self, byte: u8) Error!void {
354 return @errorCast(self.any().writeByte(byte));
355 }
356
357 pub inline fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void {
358 return @errorCast(self.any().writeByteNTimes(byte, n));
359 }
360
361 pub inline fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) Error!void {
362 return @errorCast(self.any().writeBytesNTimes(bytes, n));
363 }
364
365 pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) Error!void {
366 return @errorCast(self.any().writeInt(T, value, endian));
367 }
368
369 pub inline fn writeStruct(self: Self, value: anytype) Error!void {
370 return @errorCast(self.any().writeStruct(value));
371 }
372
373 pub inline fn writeStructEndian(self: Self, value: anytype, endian: std.builtin.Endian) Error!void {
374 return @errorCast(self.any().writeStructEndian(value, endian));
375 }
376
377 pub inline fn any(self: *const Self) AnyWriter {
378 return .{
379 .context = @ptrCast(&self.context),
380 .writeFn = typeErasedWriteFn,
381 };
382 }
383
384 fn typeErasedWriteFn(context: *const anyopaque, bytes: []const u8) anyerror!usize {
385 const ptr: *const Context = @ptrCast(@alignCast(context));
386 return writeFn(ptr.*, bytes);
387 }
388
389 /// Helper for bridging to the new `Writer` API while upgrading.
390 pub fn adaptToNewApi(self: *const Self, buffer: []u8) Adapter {
391 return .{
392 .derp_writer = self.*,
393 .new_interface = .{
394 .buffer = buffer,
395 .vtable = &.{ .drain = Adapter.drain },
396 },
397 };
398 }
399
400 pub const Adapter = struct {
401 derp_writer: Self,
402 new_interface: Writer,
403 err: ?Error = null,
404
405 fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
406 _ = splat;
407 const a: *@This() = @alignCast(@fieldParentPtr("new_interface", w));
408 const buffered = w.buffered();
409 if (buffered.len != 0) return w.consume(a.derp_writer.write(buffered) catch |err| {
410 a.err = err;
411 return error.WriteFailed;
412 });
413 return a.derp_writer.write(data[0]) catch |err| {
414 a.err = err;
415 return error.WriteFailed;
416 };
417 }
418 };
419 };
420}
421
422/// Deprecated in favor of `Reader`.274/// Deprecated in favor of `Reader`.
423pub const AnyReader = @import("Io/DeprecatedReader.zig");275pub const AnyReader = @import("Io/DeprecatedReader.zig");
424/// Deprecated in favor of `Writer`.
425pub const AnyWriter = @import("Io/DeprecatedWriter.zig");
426/// Deprecated in favor of `Reader`.276/// Deprecated in favor of `Reader`.
427pub const FixedBufferStream = @import("Io/fixed_buffer_stream.zig").FixedBufferStream;277pub const FixedBufferStream = @import("Io/fixed_buffer_stream.zig").FixedBufferStream;
428/// Deprecated in favor of `Reader`.278/// Deprecated in favor of `Reader`.
...@@ -434,19 +284,6 @@ pub const countingReader = @import("Io/counting_reader.zig").countingReader;...@@ -434,19 +284,6 @@ pub const countingReader = @import("Io/counting_reader.zig").countingReader;
434284
435pub const tty = @import("Io/tty.zig");285pub const tty = @import("Io/tty.zig");
436286
437/// Deprecated in favor of `Writer.Discarding`.
438pub const null_writer: NullWriter = .{ .context = {} };
439/// Deprecated in favor of `Writer.Discarding`.
440pub const NullWriter = GenericWriter(void, error{}, dummyWrite);
441fn dummyWrite(context: void, data: []const u8) error{}!usize {
442 _ = context;
443 return data.len;
444}
445
446test null_writer {
447 null_writer.writeAll("yay" ** 10) catch |err| switch (err) {};
448}
449
450pub fn poll(287pub fn poll(
451 gpa: Allocator,288 gpa: Allocator,
452 comptime StreamEnum: type,289 comptime StreamEnum: type,
lib/std/Io/DeprecatedReader.zig-98
...@@ -93,100 +93,6 @@ pub fn readAllAlloc(self: Self, allocator: mem.Allocator, max_size: usize) anyer...@@ -93,100 +93,6 @@ pub fn readAllAlloc(self: Self, allocator: mem.Allocator, max_size: usize) anyer
93 return try array_list.toOwnedSlice();93 return try array_list.toOwnedSlice();
94}94}
9595
96/// Deprecated: use `streamUntilDelimiter` with ArrayList's writer instead.
97/// Replaces the `std.array_list.Managed` contents by reading from the stream until `delimiter` is found.
98/// Does not include the delimiter in the result.
99/// If the `std.array_list.Managed` length would exceed `max_size`, `error.StreamTooLong` is returned and the
100/// `std.array_list.Managed` is populated with `max_size` bytes from the stream.
101pub fn readUntilDelimiterArrayList(
102 self: Self,
103 array_list: *std.array_list.Managed(u8),
104 delimiter: u8,
105 max_size: usize,
106) anyerror!void {
107 array_list.shrinkRetainingCapacity(0);
108 try self.streamUntilDelimiter(array_list.writer(), delimiter, max_size);
109}
110
111/// Deprecated: use `streamUntilDelimiter` with ArrayList's writer instead.
112/// Allocates enough memory to read until `delimiter`. If the allocated
113/// memory would be greater than `max_size`, returns `error.StreamTooLong`.
114/// Caller owns returned memory.
115/// If this function returns an error, the contents from the stream read so far are lost.
116pub fn readUntilDelimiterAlloc(
117 self: Self,
118 allocator: mem.Allocator,
119 delimiter: u8,
120 max_size: usize,
121) anyerror![]u8 {
122 var array_list = std.array_list.Managed(u8).init(allocator);
123 defer array_list.deinit();
124 try self.streamUntilDelimiter(array_list.writer(), delimiter, max_size);
125 return try array_list.toOwnedSlice();
126}
127
128/// Deprecated: use `streamUntilDelimiter` with FixedBufferStream's writer instead.
129/// Reads from the stream until specified byte is found. If the buffer is not
130/// large enough to hold the entire contents, `error.StreamTooLong` is returned.
131/// If end-of-stream is found, `error.EndOfStream` is returned.
132/// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
133/// delimiter byte is written to the output buffer but is not included
134/// in the returned slice.
135pub fn readUntilDelimiter(self: Self, buf: []u8, delimiter: u8) anyerror![]u8 {
136 var fbs = std.io.fixedBufferStream(buf);
137 try self.streamUntilDelimiter(fbs.writer(), delimiter, fbs.buffer.len);
138 const output = fbs.getWritten();
139 buf[output.len] = delimiter; // emulating old behaviour
140 return output;
141}
142
143/// Deprecated: use `streamUntilDelimiter` with ArrayList's (or any other's) writer instead.
144/// Allocates enough memory to read until `delimiter` or end-of-stream.
145/// If the allocated memory would be greater than `max_size`, returns
146/// `error.StreamTooLong`. If end-of-stream is found, returns the rest
147/// of the stream. If this function is called again after that, returns
148/// null.
149/// Caller owns returned memory.
150/// If this function returns an error, the contents from the stream read so far are lost.
151pub fn readUntilDelimiterOrEofAlloc(
152 self: Self,
153 allocator: mem.Allocator,
154 delimiter: u8,
155 max_size: usize,
156) anyerror!?[]u8 {
157 var array_list = std.array_list.Managed(u8).init(allocator);
158 defer array_list.deinit();
159 self.streamUntilDelimiter(array_list.writer(), delimiter, max_size) catch |err| switch (err) {
160 error.EndOfStream => if (array_list.items.len == 0) {
161 return null;
162 },
163 else => |e| return e,
164 };
165 return try array_list.toOwnedSlice();
166}
167
168/// Deprecated: use `streamUntilDelimiter` with FixedBufferStream's writer instead.
169/// Reads from the stream until specified byte is found. If the buffer is not
170/// large enough to hold the entire contents, `error.StreamTooLong` is returned.
171/// If end-of-stream is found, returns the rest of the stream. If this
172/// function is called again after that, returns null.
173/// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
174/// delimiter byte is written to the output buffer but is not included
175/// in the returned slice.
176pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) anyerror!?[]u8 {
177 var fbs = std.io.fixedBufferStream(buf);
178 self.streamUntilDelimiter(fbs.writer(), delimiter, fbs.buffer.len) catch |err| switch (err) {
179 error.EndOfStream => if (fbs.getWritten().len == 0) {
180 return null;
181 },
182
183 else => |e| return e,
184 };
185 const output = fbs.getWritten();
186 buf[output.len] = delimiter; // emulating old behaviour
187 return output;
188}
189
190/// Appends to the `writer` contents by reading from the stream until `delimiter` is found.96/// Appends to the `writer` contents by reading from the stream until `delimiter` is found.
191/// Does not write the delimiter itself.97/// Does not write the delimiter itself.
192/// If `optional_max_size` is not null and amount of written bytes exceeds `optional_max_size`,98/// If `optional_max_size` is not null and amount of written bytes exceeds `optional_max_size`,
...@@ -384,7 +290,3 @@ const mem = std.mem;...@@ -384,7 +290,3 @@ const mem = std.mem;
384const testing = std.testing;290const testing = std.testing;
385const native_endian = @import("builtin").target.cpu.arch.endian();291const native_endian = @import("builtin").target.cpu.arch.endian();
386const Alignment = std.mem.Alignment;292const Alignment = std.mem.Alignment;
387
388test {
389 _ = @import("Reader/test.zig");
390}
lib/std/Io/DeprecatedWriter.zig deleted-114
...@@ -1,114 +0,0 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4const native_endian = @import("builtin").target.cpu.arch.endian();
5
6context: *const anyopaque,
7writeFn: *const fn (context: *const anyopaque, bytes: []const u8) anyerror!usize,
8
9const Self = @This();
10pub const Error = anyerror;
11
12pub fn write(self: Self, bytes: []const u8) anyerror!usize {
13 return self.writeFn(self.context, bytes);
14}
15
16pub fn writeAll(self: Self, bytes: []const u8) anyerror!void {
17 var index: usize = 0;
18 while (index != bytes.len) {
19 index += try self.write(bytes[index..]);
20 }
21}
22
23pub fn print(self: Self, comptime format: []const u8, args: anytype) anyerror!void {
24 return std.fmt.format(self, format, args);
25}
26
27pub fn writeByte(self: Self, byte: u8) anyerror!void {
28 const array = [1]u8{byte};
29 return self.writeAll(&array);
30}
31
32pub fn writeByteNTimes(self: Self, byte: u8, n: usize) anyerror!void {
33 var bytes: [256]u8 = undefined;
34 @memset(bytes[0..], byte);
35
36 var remaining: usize = n;
37 while (remaining > 0) {
38 const to_write = @min(remaining, bytes.len);
39 try self.writeAll(bytes[0..to_write]);
40 remaining -= to_write;
41 }
42}
43
44pub fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) anyerror!void {
45 var i: usize = 0;
46 while (i < n) : (i += 1) {
47 try self.writeAll(bytes);
48 }
49}
50
51pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) anyerror!void {
52 var bytes: [@divExact(@typeInfo(T).int.bits, 8)]u8 = undefined;
53 mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian);
54 return self.writeAll(&bytes);
55}
56
57pub fn writeStruct(self: Self, value: anytype) anyerror!void {
58 // Only extern and packed structs have defined in-memory layout.
59 comptime assert(@typeInfo(@TypeOf(value)).@"struct".layout != .auto);
60 return self.writeAll(mem.asBytes(&value));
61}
62
63pub fn writeStructEndian(self: Self, value: anytype, endian: std.builtin.Endian) anyerror!void {
64 // TODO: make sure this value is not a reference type
65 if (native_endian == endian) {
66 return self.writeStruct(value);
67 } else {
68 var copy = value;
69 mem.byteSwapAllFields(@TypeOf(value), &copy);
70 return self.writeStruct(copy);
71 }
72}
73
74pub fn writeFile(self: Self, file: std.fs.File) anyerror!void {
75 // TODO: figure out how to adjust std lib abstractions so that this ends up
76 // doing sendfile or maybe even copy_file_range under the right conditions.
77 var buf: [4000]u8 = undefined;
78 while (true) {
79 const n = try file.readAll(&buf);
80 try self.writeAll(buf[0..n]);
81 if (n < buf.len) return;
82 }
83}
84
85/// Helper for bridging to the new `Writer` API while upgrading.
86pub fn adaptToNewApi(self: *const Self, buffer: []u8) Adapter {
87 return .{
88 .derp_writer = self.*,
89 .new_interface = .{
90 .buffer = buffer,
91 .vtable = &.{ .drain = Adapter.drain },
92 },
93 };
94}
95
96pub const Adapter = struct {
97 derp_writer: Self,
98 new_interface: std.io.Writer,
99 err: ?Error = null,
100
101 fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
102 _ = splat;
103 const a: *@This() = @alignCast(@fieldParentPtr("new_interface", w));
104 const buffered = w.buffered();
105 if (buffered.len != 0) return w.consume(a.derp_writer.write(buffered) catch |err| {
106 a.err = err;
107 return error.WriteFailed;
108 });
109 return a.derp_writer.write(data[0]) catch |err| {
110 a.err = err;
111 return error.WriteFailed;
112 };
113 }
114};
lib/std/Io/Reader.zig+48-5
...@@ -143,8 +143,8 @@ pub const failing: Reader = .{...@@ -143,8 +143,8 @@ pub const failing: Reader = .{
143143
144/// This is generally safe to `@constCast` because it has an empty buffer, so144/// This is generally safe to `@constCast` because it has an empty buffer, so
145/// there is not really a way to accidentally attempt mutation of these fields.145/// there is not really a way to accidentally attempt mutation of these fields.
146const ending_state: Reader = .fixed(&.{});146pub const ending_instance: Reader = .fixed(&.{});
147pub const ending: *Reader = @constCast(&ending_state);147pub const ending: *Reader = @constCast(&ending_instance);
148148
149pub fn limited(r: *Reader, limit: Limit, buffer: []u8) Limited {149pub fn limited(r: *Reader, limit: Limit, buffer: []u8) Limited {
150 return .init(r, limit, buffer);150 return .init(r, limit, buffer);
...@@ -784,7 +784,7 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {...@@ -784,7 +784,7 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
784}784}
785785
786/// Returns a slice of the next bytes of buffered data from the stream until786/// Returns a slice of the next bytes of buffered data from the stream until
787/// `delimiter` is found, advancing the seek position.787/// `delimiter` is found, advancing the seek position up to the delimiter.
788///788///
789/// Returned slice excludes the delimiter. End-of-stream is treated equivalent789/// Returned slice excludes the delimiter. End-of-stream is treated equivalent
790/// to a delimiter, unless it would result in a length 0 return value, in which790/// to a delimiter, unless it would result in a length 0 return value, in which
...@@ -814,6 +814,37 @@ pub fn takeDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {...@@ -814,6 +814,37 @@ pub fn takeDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
814 return result[0 .. result.len - 1];814 return result[0 .. result.len - 1];
815}815}
816816
817/// Returns a slice of the next bytes of buffered data from the stream until
818/// `delimiter` is found, advancing the seek position past the delimiter.
819///
820/// Returned slice excludes the delimiter. End-of-stream is treated equivalent
821/// to a delimiter, unless it would result in a length 0 return value, in which
822/// case `null` is returned instead.
823///
824/// If the delimiter is not found within a number of bytes matching the
825/// capacity of this `Reader`, `error.StreamTooLong` is returned. In
826/// such case, the stream state is unmodified as if this function was never
827/// called.
828///
829/// Invalidates previously returned values from `peek`.
830///
831/// See also:
832/// * `takeDelimiterInclusive`
833/// * `takeDelimiterExclusive`
834pub fn takeDelimiter(r: *Reader, delimiter: u8) error{ ReadFailed, StreamTooLong }!?[]u8 {
835 const result = r.peekDelimiterInclusive(delimiter) catch |err| switch (err) {
836 error.EndOfStream => {
837 const remaining = r.buffer[r.seek..r.end];
838 if (remaining.len == 0) return null;
839 r.toss(remaining.len);
840 return remaining;
841 },
842 else => |e| return e,
843 };
844 r.toss(result.len + 1);
845 return result[0 .. result.len - 1];
846}
847
817/// Returns a slice of the next bytes of buffered data from the stream until848/// Returns a slice of the next bytes of buffered data from the stream until
818/// `delimiter` is found, without advancing the seek position.849/// `delimiter` is found, without advancing the seek position.
819///850///
...@@ -846,6 +877,8 @@ pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {...@@ -846,6 +877,8 @@ pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
846/// Appends to `w` contents by reading from the stream until `delimiter` is877/// Appends to `w` contents by reading from the stream until `delimiter` is
847/// found. Does not write the delimiter itself.878/// found. Does not write the delimiter itself.
848///879///
880/// Does not discard the delimiter from the `Reader`.
881///
849/// Returns number of bytes streamed, which may be zero, or error.EndOfStream882/// Returns number of bytes streamed, which may be zero, or error.EndOfStream
850/// if the delimiter was not found.883/// if the delimiter was not found.
851///884///
...@@ -899,6 +932,8 @@ pub const StreamDelimiterLimitError = error{...@@ -899,6 +932,8 @@ pub const StreamDelimiterLimitError = error{
899/// Appends to `w` contents by reading from the stream until `delimiter` is found.932/// Appends to `w` contents by reading from the stream until `delimiter` is found.
900/// Does not write the delimiter itself.933/// Does not write the delimiter itself.
901///934///
935/// Does not discard the delimiter from the `Reader`.
936///
902/// Returns number of bytes streamed, which may be zero. End of stream can be937/// Returns number of bytes streamed, which may be zero. End of stream can be
903/// detected by checking if the next byte in the stream is the delimiter.938/// detected by checking if the next byte in the stream is the delimiter.
904///939///
...@@ -1128,7 +1163,11 @@ pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endia...@@ -1128,7 +1163,11 @@ pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endia
1128 .@"struct" => |info| switch (info.layout) {1163 .@"struct" => |info| switch (info.layout) {
1129 .auto => @compileError("ill-defined memory layout"),1164 .auto => @compileError("ill-defined memory layout"),
1130 .@"extern" => {1165 .@"extern" => {
1131 var res = (try r.takeStructPointer(T)).*;1166 // This code works around https://github.com/ziglang/zig/issues/25067
1167 // by avoiding a call to `peekStructPointer`.
1168 const struct_bytes = try r.takeArray(@sizeOf(T));
1169 var res: T = undefined;
1170 @memcpy(@as([]u8, @ptrCast(&res)), struct_bytes);
1132 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);1171 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
1133 return res;1172 return res;
1134 },1173 },
...@@ -1153,7 +1192,11 @@ pub inline fn peekStruct(r: *Reader, comptime T: type, endian: std.builtin.Endia...@@ -1153,7 +1192,11 @@ pub inline fn peekStruct(r: *Reader, comptime T: type, endian: std.builtin.Endia
1153 .@"struct" => |info| switch (info.layout) {1192 .@"struct" => |info| switch (info.layout) {
1154 .auto => @compileError("ill-defined memory layout"),1193 .auto => @compileError("ill-defined memory layout"),
1155 .@"extern" => {1194 .@"extern" => {
1156 var res = (try r.peekStructPointer(T)).*;1195 // This code works around https://github.com/ziglang/zig/issues/25067
1196 // by avoiding a call to `peekStructPointer`.
1197 const struct_bytes = try r.peekArray(@sizeOf(T));
1198 var res: T = undefined;
1199 @memcpy(@as([]u8, @ptrCast(&res)), struct_bytes);
1157 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);1200 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
1158 return res;1201 return res;
1159 },1202 },
lib/std/Io/Reader/test.zig deleted-351
...@@ -1,351 +0,0 @@
1const builtin = @import("builtin");
2const std = @import("../../std.zig");
3const testing = std.testing;
4
5test "Reader" {
6 var buf = "a\x02".*;
7 var fis = std.io.fixedBufferStream(&buf);
8 const reader = fis.reader();
9 try testing.expect((try reader.readByte()) == 'a');
10 try testing.expect((try reader.readEnum(enum(u8) {
11 a = 0,
12 b = 99,
13 c = 2,
14 d = 3,
15 }, builtin.cpu.arch.endian())) == .c);
16 try testing.expectError(error.EndOfStream, reader.readByte());
17}
18
19test "isBytes" {
20 var fis = std.io.fixedBufferStream("foobar");
21 const reader = fis.reader();
22 try testing.expectEqual(true, try reader.isBytes("foo"));
23 try testing.expectEqual(false, try reader.isBytes("qux"));
24}
25
26test "skipBytes" {
27 var fis = std.io.fixedBufferStream("foobar");
28 const reader = fis.reader();
29 try reader.skipBytes(3, .{});
30 try testing.expect(try reader.isBytes("bar"));
31 try reader.skipBytes(0, .{});
32 try testing.expectError(error.EndOfStream, reader.skipBytes(1, .{}));
33}
34
35test "readUntilDelimiterArrayList returns ArrayLists with bytes read until the delimiter, then EndOfStream" {
36 const a = std.testing.allocator;
37 var list = std.array_list.Managed(u8).init(a);
38 defer list.deinit();
39
40 var fis = std.io.fixedBufferStream("0000\n1234\n");
41 const reader = fis.reader();
42
43 try reader.readUntilDelimiterArrayList(&list, '\n', 5);
44 try std.testing.expectEqualStrings("0000", list.items);
45 try reader.readUntilDelimiterArrayList(&list, '\n', 5);
46 try std.testing.expectEqualStrings("1234", list.items);
47 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterArrayList(&list, '\n', 5));
48}
49
50test "readUntilDelimiterArrayList returns an empty ArrayList" {
51 const a = std.testing.allocator;
52 var list = std.array_list.Managed(u8).init(a);
53 defer list.deinit();
54
55 var fis = std.io.fixedBufferStream("\n");
56 const reader = fis.reader();
57
58 try reader.readUntilDelimiterArrayList(&list, '\n', 5);
59 try std.testing.expectEqualStrings("", list.items);
60}
61
62test "readUntilDelimiterArrayList returns StreamTooLong, then an ArrayList with bytes read until the delimiter" {
63 const a = std.testing.allocator;
64 var list = std.array_list.Managed(u8).init(a);
65 defer list.deinit();
66
67 var fis = std.io.fixedBufferStream("1234567\n");
68 const reader = fis.reader();
69
70 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterArrayList(&list, '\n', 5));
71 try std.testing.expectEqualStrings("12345", list.items);
72 try reader.readUntilDelimiterArrayList(&list, '\n', 5);
73 try std.testing.expectEqualStrings("67", list.items);
74}
75
76test "readUntilDelimiterArrayList returns EndOfStream" {
77 const a = std.testing.allocator;
78 var list = std.array_list.Managed(u8).init(a);
79 defer list.deinit();
80
81 var fis = std.io.fixedBufferStream("1234");
82 const reader = fis.reader();
83
84 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterArrayList(&list, '\n', 5));
85 try std.testing.expectEqualStrings("1234", list.items);
86}
87
88test "readUntilDelimiterAlloc returns ArrayLists with bytes read until the delimiter, then EndOfStream" {
89 const a = std.testing.allocator;
90
91 var fis = std.io.fixedBufferStream("0000\n1234\n");
92 const reader = fis.reader();
93
94 {
95 const result = try reader.readUntilDelimiterAlloc(a, '\n', 5);
96 defer a.free(result);
97 try std.testing.expectEqualStrings("0000", result);
98 }
99
100 {
101 const result = try reader.readUntilDelimiterAlloc(a, '\n', 5);
102 defer a.free(result);
103 try std.testing.expectEqualStrings("1234", result);
104 }
105
106 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterAlloc(a, '\n', 5));
107}
108
109test "readUntilDelimiterAlloc returns an empty ArrayList" {
110 const a = std.testing.allocator;
111
112 var fis = std.io.fixedBufferStream("\n");
113 const reader = fis.reader();
114
115 {
116 const result = try reader.readUntilDelimiterAlloc(a, '\n', 5);
117 defer a.free(result);
118 try std.testing.expectEqualStrings("", result);
119 }
120}
121
122test "readUntilDelimiterAlloc returns StreamTooLong, then an ArrayList with bytes read until the delimiter" {
123 const a = std.testing.allocator;
124
125 var fis = std.io.fixedBufferStream("1234567\n");
126 const reader = fis.reader();
127
128 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterAlloc(a, '\n', 5));
129
130 const result = try reader.readUntilDelimiterAlloc(a, '\n', 5);
131 defer a.free(result);
132 try std.testing.expectEqualStrings("67", result);
133}
134
135test "readUntilDelimiterAlloc returns EndOfStream" {
136 const a = std.testing.allocator;
137
138 var fis = std.io.fixedBufferStream("1234");
139 const reader = fis.reader();
140
141 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterAlloc(a, '\n', 5));
142}
143
144test "readUntilDelimiter returns bytes read until the delimiter" {
145 var buf: [5]u8 = undefined;
146 var fis = std.io.fixedBufferStream("0000\n1234\n");
147 const reader = fis.reader();
148 try std.testing.expectEqualStrings("0000", try reader.readUntilDelimiter(&buf, '\n'));
149 try std.testing.expectEqualStrings("1234", try reader.readUntilDelimiter(&buf, '\n'));
150}
151
152test "readUntilDelimiter returns an empty string" {
153 var buf: [5]u8 = undefined;
154 var fis = std.io.fixedBufferStream("\n");
155 const reader = fis.reader();
156 try std.testing.expectEqualStrings("", try reader.readUntilDelimiter(&buf, '\n'));
157}
158
159test "readUntilDelimiter returns StreamTooLong, then an empty string" {
160 var buf: [5]u8 = undefined;
161 var fis = std.io.fixedBufferStream("12345\n");
162 const reader = fis.reader();
163 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n'));
164 try std.testing.expectEqualStrings("", try reader.readUntilDelimiter(&buf, '\n'));
165}
166
167test "readUntilDelimiter returns StreamTooLong, then bytes read until the delimiter" {
168 var buf: [5]u8 = undefined;
169 var fis = std.io.fixedBufferStream("1234567\n");
170 const reader = fis.reader();
171 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n'));
172 try std.testing.expectEqualStrings("67", try reader.readUntilDelimiter(&buf, '\n'));
173}
174
175test "readUntilDelimiter returns EndOfStream" {
176 {
177 var buf: [5]u8 = undefined;
178 var fis = std.io.fixedBufferStream("");
179 const reader = fis.reader();
180 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n'));
181 }
182 {
183 var buf: [5]u8 = undefined;
184 var fis = std.io.fixedBufferStream("1234");
185 const reader = fis.reader();
186 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n'));
187 }
188}
189
190test "readUntilDelimiter returns bytes read until delimiter, then EndOfStream" {
191 var buf: [5]u8 = undefined;
192 var fis = std.io.fixedBufferStream("1234\n");
193 const reader = fis.reader();
194 try std.testing.expectEqualStrings("1234", try reader.readUntilDelimiter(&buf, '\n'));
195 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n'));
196}
197
198test "readUntilDelimiter returns StreamTooLong, then EndOfStream" {
199 var buf: [5]u8 = undefined;
200 var fis = std.io.fixedBufferStream("12345");
201 const reader = fis.reader();
202 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n'));
203 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n'));
204}
205
206test "readUntilDelimiter writes all bytes read to the output buffer" {
207 var buf: [5]u8 = undefined;
208 var fis = std.io.fixedBufferStream("0000\n12345");
209 const reader = fis.reader();
210 _ = try reader.readUntilDelimiter(&buf, '\n');
211 try std.testing.expectEqualStrings("0000\n", &buf);
212 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n'));
213 try std.testing.expectEqualStrings("12345", &buf);
214}
215
216test "readUntilDelimiterOrEofAlloc returns ArrayLists with bytes read until the delimiter, then EndOfStream" {
217 const a = std.testing.allocator;
218
219 var fis = std.io.fixedBufferStream("0000\n1234\n");
220 const reader = fis.reader();
221
222 {
223 const result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?;
224 defer a.free(result);
225 try std.testing.expectEqualStrings("0000", result);
226 }
227
228 {
229 const result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?;
230 defer a.free(result);
231 try std.testing.expectEqualStrings("1234", result);
232 }
233
234 try std.testing.expect((try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)) == null);
235}
236
237test "readUntilDelimiterOrEofAlloc returns an empty ArrayList" {
238 const a = std.testing.allocator;
239
240 var fis = std.io.fixedBufferStream("\n");
241 const reader = fis.reader();
242
243 {
244 const result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?;
245 defer a.free(result);
246 try std.testing.expectEqualStrings("", result);
247 }
248}
249
250test "readUntilDelimiterOrEofAlloc returns StreamTooLong, then an ArrayList with bytes read until the delimiter" {
251 const a = std.testing.allocator;
252
253 var fis = std.io.fixedBufferStream("1234567\n");
254 const reader = fis.reader();
255
256 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEofAlloc(a, '\n', 5));
257
258 const result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?;
259 defer a.free(result);
260 try std.testing.expectEqualStrings("67", result);
261}
262
263test "readUntilDelimiterOrEof returns bytes read until the delimiter" {
264 var buf: [5]u8 = undefined;
265 var fis = std.io.fixedBufferStream("0000\n1234\n");
266 const reader = fis.reader();
267 try std.testing.expectEqualStrings("0000", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
268 try std.testing.expectEqualStrings("1234", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
269}
270
271test "readUntilDelimiterOrEof returns an empty string" {
272 var buf: [5]u8 = undefined;
273 var fis = std.io.fixedBufferStream("\n");
274 const reader = fis.reader();
275 try std.testing.expectEqualStrings("", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
276}
277
278test "readUntilDelimiterOrEof returns StreamTooLong, then an empty string" {
279 var buf: [5]u8 = undefined;
280 var fis = std.io.fixedBufferStream("12345\n");
281 const reader = fis.reader();
282 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n'));
283 try std.testing.expectEqualStrings("", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
284}
285
286test "readUntilDelimiterOrEof returns StreamTooLong, then bytes read until the delimiter" {
287 var buf: [5]u8 = undefined;
288 var fis = std.io.fixedBufferStream("1234567\n");
289 const reader = fis.reader();
290 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n'));
291 try std.testing.expectEqualStrings("67", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
292}
293
294test "readUntilDelimiterOrEof returns null" {
295 var buf: [5]u8 = undefined;
296 var fis = std.io.fixedBufferStream("");
297 const reader = fis.reader();
298 try std.testing.expect((try reader.readUntilDelimiterOrEof(&buf, '\n')) == null);
299}
300
301test "readUntilDelimiterOrEof returns bytes read until delimiter, then null" {
302 var buf: [5]u8 = undefined;
303 var fis = std.io.fixedBufferStream("1234\n");
304 const reader = fis.reader();
305 try std.testing.expectEqualStrings("1234", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
306 try std.testing.expect((try reader.readUntilDelimiterOrEof(&buf, '\n')) == null);
307}
308
309test "readUntilDelimiterOrEof returns bytes read until end-of-stream" {
310 var buf: [5]u8 = undefined;
311 var fis = std.io.fixedBufferStream("1234");
312 const reader = fis.reader();
313 try std.testing.expectEqualStrings("1234", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
314}
315
316test "readUntilDelimiterOrEof returns StreamTooLong, then bytes read until end-of-stream" {
317 var buf: [5]u8 = undefined;
318 var fis = std.io.fixedBufferStream("1234567");
319 const reader = fis.reader();
320 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n'));
321 try std.testing.expectEqualStrings("67", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
322}
323
324test "readUntilDelimiterOrEof writes all bytes read to the output buffer" {
325 var buf: [5]u8 = undefined;
326 var fis = std.io.fixedBufferStream("0000\n12345");
327 const reader = fis.reader();
328 _ = try reader.readUntilDelimiterOrEof(&buf, '\n');
329 try std.testing.expectEqualStrings("0000\n", &buf);
330 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n'));
331 try std.testing.expectEqualStrings("12345", &buf);
332}
333
334test "streamUntilDelimiter writes all bytes without delimiter to the output" {
335 const input_string = "some_string_with_delimiter!";
336 var input_fbs = std.io.fixedBufferStream(input_string);
337 const reader = input_fbs.reader();
338
339 var output: [input_string.len]u8 = undefined;
340 var output_fbs = std.io.fixedBufferStream(&output);
341 const writer = output_fbs.writer();
342
343 try reader.streamUntilDelimiter(writer, '!', input_fbs.buffer.len);
344 try std.testing.expectEqualStrings("some_string_with_delimiter", output_fbs.getWritten());
345 try std.testing.expectError(error.EndOfStream, reader.streamUntilDelimiter(writer, '!', input_fbs.buffer.len));
346
347 input_fbs.reset();
348 output_fbs.reset();
349
350 try std.testing.expectError(error.StreamTooLong, reader.streamUntilDelimiter(writer, '!', 5));
351}
lib/std/Io/Writer.zig+29-5
...@@ -8,6 +8,7 @@ const Limit = std.Io.Limit;...@@ -8,6 +8,7 @@ const Limit = std.Io.Limit;
8const File = std.fs.File;8const File = std.fs.File;
9const testing = std.testing;9const testing = std.testing;
10const Allocator = std.mem.Allocator;10const Allocator = std.mem.Allocator;
11const ArrayList = std.ArrayList;
1112
12vtable: *const VTable,13vtable: *const VTable,
13/// If this has length zero, the writer is unbuffered, and `flush` is a no-op.14/// If this has length zero, the writer is unbuffered, and `flush` is a no-op.
...@@ -2374,6 +2375,29 @@ pub fn unreachableRebase(w: *Writer, preserve: usize, capacity: usize) Error!voi...@@ -2374,6 +2375,29 @@ pub fn unreachableRebase(w: *Writer, preserve: usize, capacity: usize) Error!voi
2374 unreachable;2375 unreachable;
2375}2376}
23762377
2378pub fn fromArrayList(array_list: *ArrayList(u8)) Writer {
2379 defer array_list.* = .empty;
2380 return .{
2381 .vtable = &.{
2382 .drain = fixedDrain,
2383 .flush = noopFlush,
2384 .rebase = failingRebase,
2385 },
2386 .buffer = array_list.allocatedSlice(),
2387 .end = array_list.items.len,
2388 };
2389}
2390
2391pub fn toArrayList(w: *Writer) ArrayList(u8) {
2392 const result: ArrayList(u8) = .{
2393 .items = w.buffer[0..w.end],
2394 .capacity = w.buffer.len,
2395 };
2396 w.buffer = &.{};
2397 w.end = 0;
2398 return result;
2399}
2400
2377/// Provides a `Writer` implementation based on calling `Hasher.update`, sending2401/// Provides a `Writer` implementation based on calling `Hasher.update`, sending
2378/// all data also to an underlying `Writer`.2402/// all data also to an underlying `Writer`.
2379///2403///
...@@ -2546,7 +2570,7 @@ pub const Allocating = struct {...@@ -2546,7 +2570,7 @@ pub const Allocating = struct {
2546 }2570 }
25472571
2548 /// Replaces `array_list` with empty, taking ownership of the memory.2572 /// Replaces `array_list` with empty, taking ownership of the memory.
2549 pub fn fromArrayList(allocator: Allocator, array_list: *std.ArrayListUnmanaged(u8)) Allocating {2573 pub fn fromArrayList(allocator: Allocator, array_list: *ArrayList(u8)) Allocating {
2550 defer array_list.* = .empty;2574 defer array_list.* = .empty;
2551 return .{2575 return .{
2552 .allocator = allocator,2576 .allocator = allocator,
...@@ -2572,9 +2596,9 @@ pub const Allocating = struct {...@@ -2572,9 +2596,9 @@ pub const Allocating = struct {
25722596
2573 /// Returns an array list that takes ownership of the allocated memory.2597 /// Returns an array list that takes ownership of the allocated memory.
2574 /// Resets the `Allocating` to an empty state.2598 /// Resets the `Allocating` to an empty state.
2575 pub fn toArrayList(a: *Allocating) std.ArrayListUnmanaged(u8) {2599 pub fn toArrayList(a: *Allocating) ArrayList(u8) {
2576 const w = &a.writer;2600 const w = &a.writer;
2577 const result: std.ArrayListUnmanaged(u8) = .{2601 const result: ArrayList(u8) = .{
2578 .items = w.buffer[0..w.end],2602 .items = w.buffer[0..w.end],
2579 .capacity = w.buffer.len,2603 .capacity = w.buffer.len,
2580 };2604 };
...@@ -2603,7 +2627,7 @@ pub const Allocating = struct {...@@ -2603,7 +2627,7 @@ pub const Allocating = struct {
26032627
2604 pub fn toOwnedSliceSentinel(a: *Allocating, comptime sentinel: u8) error{OutOfMemory}![:sentinel]u8 {2628 pub fn toOwnedSliceSentinel(a: *Allocating, comptime sentinel: u8) error{OutOfMemory}![:sentinel]u8 {
2605 const gpa = a.allocator;2629 const gpa = a.allocator;
2606 var list = toArrayList(a);2630 var list = @This().toArrayList(a);
2607 defer a.setArrayList(list);2631 defer a.setArrayList(list);
2608 return list.toOwnedSliceSentinel(gpa, sentinel);2632 return list.toOwnedSliceSentinel(gpa, sentinel);
2609 }2633 }
...@@ -2670,7 +2694,7 @@ pub const Allocating = struct {...@@ -2670,7 +2694,7 @@ pub const Allocating = struct {
2670 list.ensureUnusedCapacity(gpa, minimum_len) catch return error.WriteFailed;2694 list.ensureUnusedCapacity(gpa, minimum_len) catch return error.WriteFailed;
2671 }2695 }
26722696
2673 fn setArrayList(a: *Allocating, list: std.ArrayListUnmanaged(u8)) void {2697 fn setArrayList(a: *Allocating, list: ArrayList(u8)) void {
2674 a.writer.buffer = list.allocatedSlice();2698 a.writer.buffer = list.allocatedSlice();
2675 a.writer.end = list.items.len;2699 a.writer.end = list.items.len;
2676 }2700 }
lib/std/Io/fixed_buffer_stream.zig-69
...@@ -17,7 +17,6 @@ pub fn FixedBufferStream(comptime Buffer: type) type {...@@ -17,7 +17,6 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
17 pub const GetSeekPosError = error{};17 pub const GetSeekPosError = error{};
1818
19 pub const Reader = io.GenericReader(*Self, ReadError, read);19 pub const Reader = io.GenericReader(*Self, ReadError, read);
20 pub const Writer = io.GenericWriter(*Self, WriteError, write);
2120
22 const Self = @This();21 const Self = @This();
2322
...@@ -25,10 +24,6 @@ pub fn FixedBufferStream(comptime Buffer: type) type {...@@ -25,10 +24,6 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
25 return .{ .context = self };24 return .{ .context = self };
26 }25 }
2726
28 pub fn writer(self: *Self) Writer {
29 return .{ .context = self };
30 }
31
32 pub fn read(self: *Self, dest: []u8) ReadError!usize {27 pub fn read(self: *Self, dest: []u8) ReadError!usize {
33 const size = @min(dest.len, self.buffer.len - self.pos);28 const size = @min(dest.len, self.buffer.len - self.pos);
34 const end = self.pos + size;29 const end = self.pos + size;
...@@ -39,23 +34,6 @@ pub fn FixedBufferStream(comptime Buffer: type) type {...@@ -39,23 +34,6 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
39 return size;34 return size;
40 }35 }
4136
42 /// If the returned number of bytes written is less than requested, the
43 /// buffer is full. Returns `error.NoSpaceLeft` when no bytes would be written.
44 /// Note: `error.NoSpaceLeft` matches the corresponding error from
45 /// `std.fs.File.WriteError`.
46 pub fn write(self: *Self, bytes: []const u8) WriteError!usize {
47 if (bytes.len == 0) return 0;
48 if (self.pos >= self.buffer.len) return error.NoSpaceLeft;
49
50 const n = @min(self.buffer.len - self.pos, bytes.len);
51 @memcpy(self.buffer[self.pos..][0..n], bytes[0..n]);
52 self.pos += n;
53
54 if (n == 0) return error.NoSpaceLeft;
55
56 return n;
57 }
58
59 pub fn seekTo(self: *Self, pos: u64) SeekError!void {37 pub fn seekTo(self: *Self, pos: u64) SeekError!void {
60 self.pos = @min(std.math.lossyCast(usize, pos), self.buffer.len);38 self.pos = @min(std.math.lossyCast(usize, pos), self.buffer.len);
61 }39 }
...@@ -84,10 +62,6 @@ pub fn FixedBufferStream(comptime Buffer: type) type {...@@ -84,10 +62,6 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
84 return self.pos;62 return self.pos;
85 }63 }
8664
87 pub fn getWritten(self: Self) Buffer {
88 return self.buffer[0..self.pos];
89 }
90
91 pub fn reset(self: *Self) void {65 pub fn reset(self: *Self) void {
92 self.pos = 0;66 self.pos = 0;
93 }67 }
...@@ -117,49 +91,6 @@ fn Slice(comptime T: type) type {...@@ -117,49 +91,6 @@ fn Slice(comptime T: type) type {
117 }91 }
118}92}
11993
120test "output" {
121 var buf: [255]u8 = undefined;
122 var fbs = fixedBufferStream(&buf);
123 const stream = fbs.writer();
124
125 try stream.print("{s}{s}!", .{ "Hello", "World" });
126 try testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten());
127}
128
129test "output at comptime" {
130 comptime {
131 var buf: [255]u8 = undefined;
132 var fbs = fixedBufferStream(&buf);
133 const stream = fbs.writer();
134
135 try stream.print("{s}{s}!", .{ "Hello", "World" });
136 try testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten());
137 }
138}
139
140test "output 2" {
141 var buffer: [10]u8 = undefined;
142 var fbs = fixedBufferStream(&buffer);
143
144 try fbs.writer().writeAll("Hello");
145 try testing.expect(mem.eql(u8, fbs.getWritten(), "Hello"));
146
147 try fbs.writer().writeAll("world");
148 try testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
149
150 try testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("!"));
151 try testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
152
153 fbs.reset();
154 try testing.expect(fbs.getWritten().len == 0);
155
156 try testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("Hello world!"));
157 try testing.expect(mem.eql(u8, fbs.getWritten(), "Hello worl"));
158
159 try fbs.seekTo((try fbs.getEndPos()) + 1);
160 try testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("H"));
161}
162
163test "input" {94test "input" {
164 const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7 };95 const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7 };
165 var fbs = fixedBufferStream(&bytes);96 var fbs = fixedBufferStream(&bytes);
lib/std/Thread.zig+1-1
...@@ -167,7 +167,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {...@@ -167,7 +167,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
167 const file = try std.fs.cwd().openFile(path, .{ .mode = .write_only });167 const file = try std.fs.cwd().openFile(path, .{ .mode = .write_only });
168 defer file.close();168 defer file.close();
169169
170 try file.deprecatedWriter().writeAll(name);170 try file.writeAll(name);
171 return;171 return;
172 },172 },
173 .windows => {173 .windows => {
lib/std/array_list.zig-129
...@@ -336,39 +336,6 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type...@@ -336,39 +336,6 @@ pub fn AlignedManaged(comptime T: type, comptime alignment: ?mem.Alignment) type
336 try unmanaged.print(gpa, fmt, args);336 try unmanaged.print(gpa, fmt, args);
337 }337 }
338338
339 pub const Writer = if (T != u8) void else std.io.GenericWriter(*Self, Allocator.Error, appendWrite);
340
341 /// Initializes a Writer which will append to the list.
342 pub fn writer(self: *Self) Writer {
343 return .{ .context = self };
344 }
345
346 /// Same as `append` except it returns the number of bytes written, which is always the same
347 /// as `m.len`. The purpose of this function existing is to match `std.io.GenericWriter` API.
348 /// Invalidates element pointers if additional memory is needed.
349 fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize {
350 try self.appendSlice(m);
351 return m.len;
352 }
353
354 pub const FixedWriter = std.io.GenericWriter(*Self, Allocator.Error, appendWriteFixed);
355
356 /// Initializes a Writer which will append to the list but will return
357 /// `error.OutOfMemory` rather than increasing capacity.
358 pub fn fixedWriter(self: *Self) FixedWriter {
359 return .{ .context = self };
360 }
361
362 /// The purpose of this function existing is to match `std.io.GenericWriter` API.
363 fn appendWriteFixed(self: *Self, m: []const u8) error{OutOfMemory}!usize {
364 const available_capacity = self.capacity - self.items.len;
365 if (m.len > available_capacity)
366 return error.OutOfMemory;
367
368 self.appendSliceAssumeCapacity(m);
369 return m.len;
370 }
371
372 /// Append a value to the list `n` times.339 /// Append a value to the list `n` times.
373 /// Allocates more memory as necessary.340 /// Allocates more memory as necessary.
374 /// Invalidates element pointers if additional memory is needed.341 /// Invalidates element pointers if additional memory is needed.
...@@ -1083,48 +1050,6 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1083,48 +1050,6 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
1083 self.items.len += w.end;1050 self.items.len += w.end;
1084 }1051 }
10851052
1086 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
1087 pub const WriterContext = struct {
1088 self: *Self,
1089 allocator: Allocator,
1090 };
1091
1092 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
1093 pub const Writer = if (T != u8)
1094 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
1095 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
1096 else
1097 std.io.GenericWriter(WriterContext, Allocator.Error, appendWrite);
1098
1099 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
1100 pub fn writer(self: *Self, gpa: Allocator) Writer {
1101 return .{ .context = .{ .self = self, .allocator = gpa } };
1102 }
1103
1104 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
1105 fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize {
1106 try context.self.appendSlice(context.allocator, m);
1107 return m.len;
1108 }
1109
1110 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
1111 pub const FixedWriter = std.io.GenericWriter(*Self, Allocator.Error, appendWriteFixed);
1112
1113 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
1114 pub fn fixedWriter(self: *Self) FixedWriter {
1115 return .{ .context = self };
1116 }
1117
1118 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
1119 fn appendWriteFixed(self: *Self, m: []const u8) error{OutOfMemory}!usize {
1120 const available_capacity = self.capacity - self.items.len;
1121 if (m.len > available_capacity)
1122 return error.OutOfMemory;
1123
1124 self.appendSliceAssumeCapacity(m);
1125 return m.len;
1126 }
1127
1128 /// Append a value to the list `n` times.1053 /// Append a value to the list `n` times.
1129 /// Allocates more memory as necessary.1054 /// Allocates more memory as necessary.
1130 /// Invalidates element pointers if additional memory is needed.1055 /// Invalidates element pointers if additional memory is needed.
...@@ -2116,60 +2041,6 @@ test "Managed(T) of struct T" {...@@ -2116,60 +2041,6 @@ test "Managed(T) of struct T" {
2116 }2041 }
2117}2042}
21182043
2119test "Managed(u8) implements writer" {
2120 const a = testing.allocator;
2121
2122 {
2123 var buffer = Managed(u8).init(a);
2124 defer buffer.deinit();
2125
2126 const x: i32 = 42;
2127 const y: i32 = 1234;
2128 try buffer.writer().print("x: {}\ny: {}\n", .{ x, y });
2129
2130 try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items);
2131 }
2132 {
2133 var list = AlignedManaged(u8, .@"2").init(a);
2134 defer list.deinit();
2135
2136 const writer = list.writer();
2137 try writer.writeAll("a");
2138 try writer.writeAll("bc");
2139 try writer.writeAll("d");
2140 try writer.writeAll("efg");
2141
2142 try testing.expectEqualSlices(u8, list.items, "abcdefg");
2143 }
2144}
2145
2146test "ArrayList(u8) implements writer" {
2147 const a = testing.allocator;
2148
2149 {
2150 var buffer: ArrayList(u8) = .empty;
2151 defer buffer.deinit(a);
2152
2153 const x: i32 = 42;
2154 const y: i32 = 1234;
2155 try buffer.writer(a).print("x: {}\ny: {}\n", .{ x, y });
2156
2157 try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items);
2158 }
2159 {
2160 var list: Aligned(u8, .@"2") = .empty;
2161 defer list.deinit(a);
2162
2163 const writer = list.writer(a);
2164 try writer.writeAll("a");
2165 try writer.writeAll("bc");
2166 try writer.writeAll("d");
2167 try writer.writeAll("efg");
2168
2169 try testing.expectEqualSlices(u8, list.items, "abcdefg");
2170 }
2171}
2172
2173test "shrink still sets length when resizing is disabled" {2044test "shrink still sets length when resizing is disabled" {
2174 var failing_allocator = testing.FailingAllocator.init(testing.allocator, .{ .resize_fail_index = 0 });2045 var failing_allocator = testing.FailingAllocator.init(testing.allocator, .{ .resize_fail_index = 0 });
2175 const a = failing_allocator.allocator();2046 const a = failing_allocator.allocator();
lib/std/base64.zig+1-2
...@@ -108,8 +108,7 @@ pub const Base64Encoder = struct {...@@ -108,8 +108,7 @@ pub const Base64Encoder = struct {
108 }108 }
109 }109 }
110110
111 // dest must be compatible with std.io.GenericWriter's writeAll interface111 pub fn encodeWriter(encoder: *const Base64Encoder, dest: *std.Io.Writer, source: []const u8) !void {
112 pub fn encodeWriter(encoder: *const Base64Encoder, dest: anytype, source: []const u8) !void {
113 var chunker = window(u8, source, 3, 3);112 var chunker = window(u8, source, 3, 3);
114 while (chunker.next()) |chunk| {113 while (chunker.next()) |chunk| {
115 var temp: [5]u8 = undefined;114 var temp: [5]u8 = undefined;
lib/std/crypto/aegis.zig-12
...@@ -801,18 +801,6 @@ fn AegisMac(comptime T: type) type {...@@ -801,18 +801,6 @@ fn AegisMac(comptime T: type) type {
801 ctx.update(msg);801 ctx.update(msg);
802 ctx.final(out);802 ctx.final(out);
803 }803 }
804
805 pub const Error = error{};
806 pub const Writer = std.io.GenericWriter(*Mac, Error, write);
807
808 fn write(self: *Mac, bytes: []const u8) Error!usize {
809 self.update(bytes);
810 return bytes.len;
811 }
812
813 pub fn writer(self: *Mac) Writer {
814 return .{ .context = self };
815 }
816 };804 };
817}805}
818806
lib/std/crypto/blake2.zig-12
...@@ -185,18 +185,6 @@ pub fn Blake2s(comptime out_bits: usize) type {...@@ -185,18 +185,6 @@ pub fn Blake2s(comptime out_bits: usize) type {
185 r.* ^= v[i] ^ v[i + 8];185 r.* ^= v[i] ^ v[i + 8];
186 }186 }
187 }187 }
188
189 pub const Error = error{};
190 pub const Writer = std.io.GenericWriter(*Self, Error, write);
191
192 fn write(self: *Self, bytes: []const u8) Error!usize {
193 self.update(bytes);
194 return bytes.len;
195 }
196
197 pub fn writer(self: *Self) Writer {
198 return .{ .context = self };
199 }
200 };188 };
201}189}
202190
lib/std/crypto/blake3.zig-12
...@@ -474,18 +474,6 @@ pub const Blake3 = struct {...@@ -474,18 +474,6 @@ pub const Blake3 = struct {
474 }474 }
475 output.rootOutputBytes(out_slice);475 output.rootOutputBytes(out_slice);
476 }476 }
477
478 pub const Error = error{};
479 pub const Writer = std.io.GenericWriter(*Blake3, Error, write);
480
481 fn write(self: *Blake3, bytes: []const u8) Error!usize {
482 self.update(bytes);
483 return bytes.len;
484 }
485
486 pub fn writer(self: *Blake3) Writer {
487 return .{ .context = self };
488 }
489};477};
490478
491// Use named type declarations to workaround crash with anonymous structs (issue #4373).479// Use named type declarations to workaround crash with anonymous structs (issue #4373).
lib/std/crypto/codecs/asn1/der/ArrayListReverse.zig+6-11
...@@ -4,6 +4,12 @@...@@ -4,6 +4,12 @@
4//! Laid out in memory like:4//! Laid out in memory like:
5//! capacity |--------------------------|5//! capacity |--------------------------|
6//! data |-------------|6//! data |-------------|
7
8const std = @import("std");
9const Allocator = std.mem.Allocator;
10const assert = std.debug.assert;
11const testing = std.testing;
12
7data: []u8,13data: []u8,
8capacity: usize,14capacity: usize,
9allocator: Allocator,15allocator: Allocator,
...@@ -45,12 +51,6 @@ pub fn prependSlice(self: *ArrayListReverse, data: []const u8) Error!void {...@@ -45,12 +51,6 @@ pub fn prependSlice(self: *ArrayListReverse, data: []const u8) Error!void {
45 self.data.ptr = begin;51 self.data.ptr = begin;
46}52}
4753
48pub const Writer = std.io.GenericWriter(*ArrayListReverse, Error, prependSliceSize);
49/// Warning: This writer writes backwards. `fn print` will NOT work as expected.
50pub fn writer(self: *ArrayListReverse) Writer {
51 return .{ .context = self };
52}
53
54fn prependSliceSize(self: *ArrayListReverse, data: []const u8) Error!usize {54fn prependSliceSize(self: *ArrayListReverse, data: []const u8) Error!usize {
55 try self.prependSlice(data);55 try self.prependSlice(data);
56 return data.len;56 return data.len;
...@@ -77,11 +77,6 @@ pub fn toOwnedSlice(self: *ArrayListReverse) Error![]u8 {...@@ -77,11 +77,6 @@ pub fn toOwnedSlice(self: *ArrayListReverse) Error![]u8 {
77 return new_memory;77 return new_memory;
78}78}
7979
80const std = @import("std");
81const Allocator = std.mem.Allocator;
82const assert = std.debug.assert;
83const testing = std.testing;
84
85test ArrayListReverse {80test ArrayListReverse {
86 var b = ArrayListReverse.init(testing.allocator);81 var b = ArrayListReverse.init(testing.allocator);
87 defer b.deinit();82 defer b.deinit();
lib/std/crypto/ml_kem.zig+47-45
...@@ -1721,53 +1721,55 @@ test "Test happy flow" {...@@ -1721,53 +1721,55 @@ test "Test happy flow" {
17211721
1722// Code to test NIST Known Answer Tests (KAT), see PQCgenKAT.c.1722// Code to test NIST Known Answer Tests (KAT), see PQCgenKAT.c.
17231723
1724const sha2 = crypto.hash.sha2;1724test "NIST KAT test d00.Kyber512" {
17251725 try testNistKat(d00.Kyber512, "e9c2bd37133fcb40772f81559f14b1f58dccd1c816701be9ba6214d43baf4547");
1726test "NIST KAT test" {1726}
1727 inline for (.{
1728 .{ d00.Kyber512, "e9c2bd37133fcb40772f81559f14b1f58dccd1c816701be9ba6214d43baf4547" },
1729 .{ d00.Kyber1024, "89248f2f33f7f4f7051729111f3049c409a933ec904aedadf035f30fa5646cd5" },
1730 .{ d00.Kyber768, "a1e122cad3c24bc51622e4c242d8b8acbcd3f618fee4220400605ca8f9ea02c2" },
1731 }) |modeHash| {
1732 const mode = modeHash[0];
1733 var seed: [48]u8 = undefined;
1734 for (&seed, 0..) |*s, i| {
1735 s.* = @as(u8, @intCast(i));
1736 }
1737 var f = sha2.Sha256.init(.{});
1738 const fw = f.writer();
1739 var g = NistDRBG.init(seed);
1740 try std.fmt.format(fw, "# {s}\n\n", .{mode.name});
1741 for (0..100) |i| {
1742 g.fill(&seed);
1743 try std.fmt.format(fw, "count = {}\n", .{i});
1744 try std.fmt.format(fw, "seed = {X}\n", .{&seed});
1745 var g2 = NistDRBG.init(seed);
1746
1747 // This is not equivalent to g2.fill(kseed[:]). As the reference
1748 // implementation calls randombytes twice generating the keypair,
1749 // we have to do that as well.
1750 var kseed: [64]u8 = undefined;
1751 var eseed: [32]u8 = undefined;
1752 g2.fill(kseed[0..32]);
1753 g2.fill(kseed[32..64]);
1754 g2.fill(&eseed);
1755 const kp = try mode.KeyPair.generateDeterministic(kseed);
1756 const e = kp.public_key.encaps(eseed);
1757 const ss2 = try kp.secret_key.decaps(&e.ciphertext);
1758 try testing.expectEqual(ss2, e.shared_secret);
1759 try std.fmt.format(fw, "pk = {X}\n", .{&kp.public_key.toBytes()});
1760 try std.fmt.format(fw, "sk = {X}\n", .{&kp.secret_key.toBytes()});
1761 try std.fmt.format(fw, "ct = {X}\n", .{&e.ciphertext});
1762 try std.fmt.format(fw, "ss = {X}\n\n", .{&e.shared_secret});
1763 }
17641727
1765 var out: [32]u8 = undefined;1728test "NIST KAT test d00.Kyber1024" {
1766 f.final(&out);1729 try testNistKat(d00.Kyber1024, "89248f2f33f7f4f7051729111f3049c409a933ec904aedadf035f30fa5646cd5");
1767 var outHex: [64]u8 = undefined;1730}
1768 _ = try std.fmt.bufPrint(&outHex, "{x}", .{&out});1731
1769 try testing.expectEqual(outHex, modeHash[1].*);1732test "NIST KAT test d00.Kyber768" {
1733 try testNistKat(d00.Kyber768, "a1e122cad3c24bc51622e4c242d8b8acbcd3f618fee4220400605ca8f9ea02c2");
1734}
1735
1736fn testNistKat(mode: type, hash: []const u8) !void {
1737 var seed: [48]u8 = undefined;
1738 for (&seed, 0..) |*s, i| {
1739 s.* = @as(u8, @intCast(i));
1770 }1740 }
1741 var fw: std.Io.Writer.Hashing(crypto.hash.sha2.Sha256) = .init(&.{});
1742 var g = NistDRBG.init(seed);
1743 try fw.writer.print("# {s}\n\n", .{mode.name});
1744 for (0..100) |i| {
1745 g.fill(&seed);
1746 try fw.writer.print("count = {}\n", .{i});
1747 try fw.writer.print("seed = {X}\n", .{&seed});
1748 var g2 = NistDRBG.init(seed);
1749
1750 // This is not equivalent to g2.fill(kseed[:]). As the reference
1751 // implementation calls randombytes twice generating the keypair,
1752 // we have to do that as well.
1753 var kseed: [64]u8 = undefined;
1754 var eseed: [32]u8 = undefined;
1755 g2.fill(kseed[0..32]);
1756 g2.fill(kseed[32..64]);
1757 g2.fill(&eseed);
1758 const kp = try mode.KeyPair.generateDeterministic(kseed);
1759 const e = kp.public_key.encaps(eseed);
1760 const ss2 = try kp.secret_key.decaps(&e.ciphertext);
1761 try testing.expectEqual(ss2, e.shared_secret);
1762 try fw.writer.print("pk = {X}\n", .{&kp.public_key.toBytes()});
1763 try fw.writer.print("sk = {X}\n", .{&kp.secret_key.toBytes()});
1764 try fw.writer.print("ct = {X}\n", .{&e.ciphertext});
1765 try fw.writer.print("ss = {X}\n\n", .{&e.shared_secret});
1766 }
1767
1768 var out: [32]u8 = undefined;
1769 fw.hasher.final(&out);
1770 var outHex: [64]u8 = undefined;
1771 _ = try std.fmt.bufPrint(&outHex, "{x}", .{&out});
1772 try testing.expectEqualStrings(&outHex, hash);
1771}1773}
17721774
1773const NistDRBG = struct {1775const NistDRBG = struct {
lib/std/crypto/scrypt.zig+12-9
...@@ -304,31 +304,34 @@ const crypt_format = struct {...@@ -304,31 +304,34 @@ const crypt_format = struct {
304304
305 /// Serialize parameters into a string in modular crypt format.305 /// Serialize parameters into a string in modular crypt format.
306 pub fn serialize(params: anytype, str: []u8) EncodingError![]const u8 {306 pub fn serialize(params: anytype, str: []u8) EncodingError![]const u8 {
307 var buf = io.fixedBufferStream(str);307 var w: std.Io.Writer = .fixed(str);
308 try serializeTo(params, buf.writer());308 serializeTo(params, &w) catch |err| switch (err) {
309 return buf.getWritten();309 error.WriteFailed => return error.NoSpaceLeft,
310 else => |e| return e,
311 };
312 return w.buffered();
310 }313 }
311314
312 /// Compute the number of bytes required to serialize `params`315 /// Compute the number of bytes required to serialize `params`
313 pub fn calcSize(params: anytype) usize {316 pub fn calcSize(params: anytype) usize {
314 var trash: [128]u8 = undefined;317 var trash: [128]u8 = undefined;
315 var d: std.Io.Writer.Discarding = .init(&trash);318 var d: std.Io.Writer.Discarding = .init(&trash);
316 serializeTo(params, &d) catch unreachable;319 serializeTo(params, &d.writer) catch unreachable;
317 return @intCast(d.fullCount());320 return @intCast(d.fullCount());
318 }321 }
319322
320 fn serializeTo(params: anytype, out: anytype) !void {323 fn serializeTo(params: anytype, w: *std.Io.Writer) !void {
321 var header: [14]u8 = undefined;324 var header: [14]u8 = undefined;
322 header[0..3].* = prefix.*;325 header[0..3].* = prefix.*;
323 Codec.intEncode(header[3..4], params.ln);326 Codec.intEncode(header[3..4], params.ln);
324 Codec.intEncode(header[4..9], params.r);327 Codec.intEncode(header[4..9], params.r);
325 Codec.intEncode(header[9..14], params.p);328 Codec.intEncode(header[9..14], params.p);
326 try out.writeAll(&header);329 try w.writeAll(&header);
327 try out.writeAll(params.salt);330 try w.writeAll(params.salt);
328 try out.writeAll("$");331 try w.writeAll("$");
329 var buf: [@TypeOf(params.hash).max_encoded_length]u8 = undefined;332 var buf: [@TypeOf(params.hash).max_encoded_length]u8 = undefined;
330 const hash_str = try params.hash.toB64(&buf);333 const hash_str = try params.hash.toB64(&buf);
331 try out.writeAll(hash_str);334 try w.writeAll(hash_str);
332 }335 }
333336
334 /// Custom codec that maps 6 bits into 8 like regular Base64, but uses its own alphabet,337 /// Custom codec that maps 6 bits into 8 like regular Base64, but uses its own alphabet,
lib/std/crypto/sha2.zig-12
...@@ -373,18 +373,6 @@ fn Sha2x32(comptime iv: Iv32, digest_bits: comptime_int) type {...@@ -373,18 +373,6 @@ fn Sha2x32(comptime iv: Iv32, digest_bits: comptime_int) type {
373373
374 for (&d.s, v) |*dv, vv| dv.* +%= vv;374 for (&d.s, v) |*dv, vv| dv.* +%= vv;
375 }375 }
376
377 pub const Error = error{};
378 pub const Writer = std.io.GenericWriter(*Self, Error, write);
379
380 fn write(self: *Self, bytes: []const u8) Error!usize {
381 self.update(bytes);
382 return bytes.len;
383 }
384
385 pub fn writer(self: *Self) Writer {
386 return .{ .context = self };
387 }
388 };376 };
389}377}
390378
lib/std/crypto/sha3.zig-60
...@@ -80,18 +80,6 @@ pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime default_delim...@@ -80,18 +80,6 @@ pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime default_delim
80 self.st.pad();80 self.st.pad();
81 self.st.squeeze(out[0..]);81 self.st.squeeze(out[0..]);
82 }82 }
83
84 pub const Error = error{};
85 pub const Writer = std.io.GenericWriter(*Self, Error, write);
86
87 fn write(self: *Self, bytes: []const u8) Error!usize {
88 self.update(bytes);
89 return bytes.len;
90 }
91
92 pub fn writer(self: *Self) Writer {
93 return .{ .context = self };
94 }
95 };83 };
96}84}
9785
...@@ -191,18 +179,6 @@ fn ShakeLike(comptime security_level: u11, comptime default_delim: u8, comptime...@@ -191,18 +179,6 @@ fn ShakeLike(comptime security_level: u11, comptime default_delim: u8, comptime
191 pub fn fillBlock(self: *Self) void {179 pub fn fillBlock(self: *Self) void {
192 self.st.fillBlock();180 self.st.fillBlock();
193 }181 }
194
195 pub const Error = error{};
196 pub const Writer = std.io.GenericWriter(*Self, Error, write);
197
198 fn write(self: *Self, bytes: []const u8) Error!usize {
199 self.update(bytes);
200 return bytes.len;
201 }
202
203 pub fn writer(self: *Self) Writer {
204 return .{ .context = self };
205 }
206 };182 };
207}183}
208184
...@@ -284,18 +260,6 @@ fn CShakeLike(comptime security_level: u11, comptime default_delim: u8, comptime...@@ -284,18 +260,6 @@ fn CShakeLike(comptime security_level: u11, comptime default_delim: u8, comptime
284 pub fn fillBlock(self: *Self) void {260 pub fn fillBlock(self: *Self) void {
285 self.shaker.fillBlock();261 self.shaker.fillBlock();
286 }262 }
287
288 pub const Error = error{};
289 pub const Writer = std.io.GenericWriter(*Self, Error, write);
290
291 fn write(self: *Self, bytes: []const u8) Error!usize {
292 self.update(bytes);
293 return bytes.len;
294 }
295
296 pub fn writer(self: *Self) Writer {
297 return .{ .context = self };
298 }
299 };263 };
300}264}
301265
...@@ -390,18 +354,6 @@ fn KMacLike(comptime security_level: u11, comptime default_delim: u8, comptime r...@@ -390,18 +354,6 @@ fn KMacLike(comptime security_level: u11, comptime default_delim: u8, comptime r
390 ctx.update(msg);354 ctx.update(msg);
391 ctx.final(out);355 ctx.final(out);
392 }356 }
393
394 pub const Error = error{};
395 pub const Writer = std.io.GenericWriter(*Self, Error, write);
396
397 fn write(self: *Self, bytes: []const u8) Error!usize {
398 self.update(bytes);
399 return bytes.len;
400 }
401
402 pub fn writer(self: *Self) Writer {
403 return .{ .context = self };
404 }
405 };357 };
406}358}
407359
...@@ -482,18 +434,6 @@ fn TupleHashLike(comptime security_level: u11, comptime default_delim: u8, compt...@@ -482,18 +434,6 @@ fn TupleHashLike(comptime security_level: u11, comptime default_delim: u8, compt
482 }434 }
483 self.cshaker.squeeze(out);435 self.cshaker.squeeze(out);
484 }436 }
485
486 pub const Error = error{};
487 pub const Writer = std.io.GenericWriter(*Self, Error, write);
488
489 fn write(self: *Self, bytes: []const u8) Error!usize {
490 self.update(bytes);
491 return bytes.len;
492 }
493
494 pub fn writer(self: *Self) Writer {
495 return .{ .context = self };
496 }
497 };437 };
498}438}
499439
lib/std/crypto/siphash.zig-12
...@@ -238,18 +238,6 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)...@@ -238,18 +238,6 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
238 pub fn toInt(msg: []const u8, key: *const [key_length]u8) T {238 pub fn toInt(msg: []const u8, key: *const [key_length]u8) T {
239 return State.hash(msg, key);239 return State.hash(msg, key);
240 }240 }
241
242 pub const Error = error{};
243 pub const Writer = std.io.GenericWriter(*Self, Error, write);
244
245 fn write(self: *Self, bytes: []const u8) Error!usize {
246 self.update(bytes);
247 return bytes.len;
248 }
249
250 pub fn writer(self: *Self) Writer {
251 return .{ .context = self };
252 }
253 };241 };
254}242}
255243
lib/std/debug/Dwarf/expression.zig+101-100
...@@ -8,6 +8,8 @@ const OP = std.dwarf.OP;...@@ -8,6 +8,8 @@ const OP = std.dwarf.OP;
8const abi = std.debug.Dwarf.abi;8const abi = std.debug.Dwarf.abi;
9const mem = std.mem;9const mem = std.mem;
10const assert = std.debug.assert;10const assert = std.debug.assert;
11const testing = std.testing;
12const Writer = std.Io.Writer;
1113
12/// Expressions can be evaluated in different contexts, each requiring its own set of inputs.14/// Expressions can be evaluated in different contexts, each requiring its own set of inputs.
13/// Callers should specify all the fields relevant to their context. If a field is required15/// Callers should specify all the fields relevant to their context. If a field is required
...@@ -782,7 +784,7 @@ pub fn Builder(comptime options: Options) type {...@@ -782,7 +784,7 @@ pub fn Builder(comptime options: Options) type {
782784
783 return struct {785 return struct {
784 /// Zero-operand instructions786 /// Zero-operand instructions
785 pub fn writeOpcode(writer: anytype, comptime opcode: u8) !void {787 pub fn writeOpcode(writer: *Writer, comptime opcode: u8) !void {
786 if (options.call_frame_context and !comptime isOpcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;788 if (options.call_frame_context and !comptime isOpcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;
787 switch (opcode) {789 switch (opcode) {
788 OP.dup,790 OP.dup,
...@@ -823,14 +825,14 @@ pub fn Builder(comptime options: Options) type {...@@ -823,14 +825,14 @@ pub fn Builder(comptime options: Options) type {
823 }825 }
824826
825 // 2.5.1.1: Literal Encodings827 // 2.5.1.1: Literal Encodings
826 pub fn writeLiteral(writer: anytype, literal: u8) !void {828 pub fn writeLiteral(writer: *Writer, literal: u8) !void {
827 switch (literal) {829 switch (literal) {
828 0...31 => |n| try writer.writeByte(n + OP.lit0),830 0...31 => |n| try writer.writeByte(n + OP.lit0),
829 else => return error.InvalidLiteral,831 else => return error.InvalidLiteral,
830 }832 }
831 }833 }
832834
833 pub fn writeConst(writer: anytype, comptime T: type, value: T) !void {835 pub fn writeConst(writer: *Writer, comptime T: type, value: T) !void {
834 if (@typeInfo(T) != .int) @compileError("Constants must be integers");836 if (@typeInfo(T) != .int) @compileError("Constants must be integers");
835837
836 switch (T) {838 switch (T) {
...@@ -852,7 +854,7 @@ pub fn Builder(comptime options: Options) type {...@@ -852,7 +854,7 @@ pub fn Builder(comptime options: Options) type {
852 else => switch (@typeInfo(T).int.signedness) {854 else => switch (@typeInfo(T).int.signedness) {
853 .unsigned => {855 .unsigned => {
854 try writer.writeByte(OP.constu);856 try writer.writeByte(OP.constu);
855 try leb.writeUleb128(writer, value);857 try writer.writeUleb128(value);
856 },858 },
857 .signed => {859 .signed => {
858 try writer.writeByte(OP.consts);860 try writer.writeByte(OP.consts);
...@@ -862,105 +864,105 @@ pub fn Builder(comptime options: Options) type {...@@ -862,105 +864,105 @@ pub fn Builder(comptime options: Options) type {
862 }864 }
863 }865 }
864866
865 pub fn writeConstx(writer: anytype, debug_addr_offset: anytype) !void {867 pub fn writeConstx(writer: *Writer, debug_addr_offset: anytype) !void {
866 try writer.writeByte(OP.constx);868 try writer.writeByte(OP.constx);
867 try leb.writeUleb128(writer, debug_addr_offset);869 try writer.writeUleb128(debug_addr_offset);
868 }870 }
869871
870 pub fn writeConstType(writer: anytype, die_offset: anytype, value_bytes: []const u8) !void {872 pub fn writeConstType(writer: *Writer, die_offset: anytype, value_bytes: []const u8) !void {
871 if (options.call_frame_context) return error.InvalidCFAOpcode;873 if (options.call_frame_context) return error.InvalidCFAOpcode;
872 if (value_bytes.len > 0xff) return error.InvalidTypeLength;874 if (value_bytes.len > 0xff) return error.InvalidTypeLength;
873 try writer.writeByte(OP.const_type);875 try writer.writeByte(OP.const_type);
874 try leb.writeUleb128(writer, die_offset);876 try writer.writeUleb128(die_offset);
875 try writer.writeByte(@intCast(value_bytes.len));877 try writer.writeByte(@intCast(value_bytes.len));
876 try writer.writeAll(value_bytes);878 try writer.writeAll(value_bytes);
877 }879 }
878880
879 pub fn writeAddr(writer: anytype, value: addr_type) !void {881 pub fn writeAddr(writer: *Writer, value: addr_type) !void {
880 try writer.writeByte(OP.addr);882 try writer.writeByte(OP.addr);
881 try writer.writeInt(addr_type, value, options.endian);883 try writer.writeInt(addr_type, value, options.endian);
882 }884 }
883885
884 pub fn writeAddrx(writer: anytype, debug_addr_offset: anytype) !void {886 pub fn writeAddrx(writer: *Writer, debug_addr_offset: anytype) !void {
885 if (options.call_frame_context) return error.InvalidCFAOpcode;887 if (options.call_frame_context) return error.InvalidCFAOpcode;
886 try writer.writeByte(OP.addrx);888 try writer.writeByte(OP.addrx);
887 try leb.writeUleb128(writer, debug_addr_offset);889 try writer.writeUleb128(debug_addr_offset);
888 }890 }
889891
890 // 2.5.1.2: Register Values892 // 2.5.1.2: Register Values
891 pub fn writeFbreg(writer: anytype, offset: anytype) !void {893 pub fn writeFbreg(writer: *Writer, offset: anytype) !void {
892 try writer.writeByte(OP.fbreg);894 try writer.writeByte(OP.fbreg);
893 try leb.writeIleb128(writer, offset);895 try leb.writeIleb128(writer, offset);
894 }896 }
895897
896 pub fn writeBreg(writer: anytype, register: u8, offset: anytype) !void {898 pub fn writeBreg(writer: *Writer, register: u8, offset: anytype) !void {
897 if (register > 31) return error.InvalidRegister;899 if (register > 31) return error.InvalidRegister;
898 try writer.writeByte(OP.breg0 + register);900 try writer.writeByte(OP.breg0 + register);
899 try leb.writeIleb128(writer, offset);901 try leb.writeIleb128(writer, offset);
900 }902 }
901903
902 pub fn writeBregx(writer: anytype, register: anytype, offset: anytype) !void {904 pub fn writeBregx(writer: *Writer, register: anytype, offset: anytype) !void {
903 try writer.writeByte(OP.bregx);905 try writer.writeByte(OP.bregx);
904 try leb.writeUleb128(writer, register);906 try writer.writeUleb128(register);
905 try leb.writeIleb128(writer, offset);907 try leb.writeIleb128(writer, offset);
906 }908 }
907909
908 pub fn writeRegvalType(writer: anytype, register: anytype, offset: anytype) !void {910 pub fn writeRegvalType(writer: *Writer, register: anytype, offset: anytype) !void {
909 if (options.call_frame_context) return error.InvalidCFAOpcode;911 if (options.call_frame_context) return error.InvalidCFAOpcode;
910 try writer.writeByte(OP.regval_type);912 try writer.writeByte(OP.regval_type);
911 try leb.writeUleb128(writer, register);913 try writer.writeUleb128(register);
912 try leb.writeUleb128(writer, offset);914 try writer.writeUleb128(offset);
913 }915 }
914916
915 // 2.5.1.3: Stack Operations917 // 2.5.1.3: Stack Operations
916 pub fn writePick(writer: anytype, index: u8) !void {918 pub fn writePick(writer: *Writer, index: u8) !void {
917 try writer.writeByte(OP.pick);919 try writer.writeByte(OP.pick);
918 try writer.writeByte(index);920 try writer.writeByte(index);
919 }921 }
920922
921 pub fn writeDerefSize(writer: anytype, size: u8) !void {923 pub fn writeDerefSize(writer: *Writer, size: u8) !void {
922 try writer.writeByte(OP.deref_size);924 try writer.writeByte(OP.deref_size);
923 try writer.writeByte(size);925 try writer.writeByte(size);
924 }926 }
925927
926 pub fn writeXDerefSize(writer: anytype, size: u8) !void {928 pub fn writeXDerefSize(writer: *Writer, size: u8) !void {
927 try writer.writeByte(OP.xderef_size);929 try writer.writeByte(OP.xderef_size);
928 try writer.writeByte(size);930 try writer.writeByte(size);
929 }931 }
930932
931 pub fn writeDerefType(writer: anytype, size: u8, die_offset: anytype) !void {933 pub fn writeDerefType(writer: *Writer, size: u8, die_offset: anytype) !void {
932 if (options.call_frame_context) return error.InvalidCFAOpcode;934 if (options.call_frame_context) return error.InvalidCFAOpcode;
933 try writer.writeByte(OP.deref_type);935 try writer.writeByte(OP.deref_type);
934 try writer.writeByte(size);936 try writer.writeByte(size);
935 try leb.writeUleb128(writer, die_offset);937 try writer.writeUleb128(die_offset);
936 }938 }
937939
938 pub fn writeXDerefType(writer: anytype, size: u8, die_offset: anytype) !void {940 pub fn writeXDerefType(writer: *Writer, size: u8, die_offset: anytype) !void {
939 try writer.writeByte(OP.xderef_type);941 try writer.writeByte(OP.xderef_type);
940 try writer.writeByte(size);942 try writer.writeByte(size);
941 try leb.writeUleb128(writer, die_offset);943 try writer.writeUleb128(die_offset);
942 }944 }
943945
944 // 2.5.1.4: Arithmetic and Logical Operations946 // 2.5.1.4: Arithmetic and Logical Operations
945947
946 pub fn writePlusUconst(writer: anytype, uint_value: anytype) !void {948 pub fn writePlusUconst(writer: *Writer, uint_value: anytype) !void {
947 try writer.writeByte(OP.plus_uconst);949 try writer.writeByte(OP.plus_uconst);
948 try leb.writeUleb128(writer, uint_value);950 try writer.writeUleb128(uint_value);
949 }951 }
950952
951 // 2.5.1.5: Control Flow Operations953 // 2.5.1.5: Control Flow Operations
952954
953 pub fn writeSkip(writer: anytype, offset: i16) !void {955 pub fn writeSkip(writer: *Writer, offset: i16) !void {
954 try writer.writeByte(OP.skip);956 try writer.writeByte(OP.skip);
955 try writer.writeInt(i16, offset, options.endian);957 try writer.writeInt(i16, offset, options.endian);
956 }958 }
957959
958 pub fn writeBra(writer: anytype, offset: i16) !void {960 pub fn writeBra(writer: *Writer, offset: i16) !void {
959 try writer.writeByte(OP.bra);961 try writer.writeByte(OP.bra);
960 try writer.writeInt(i16, offset, options.endian);962 try writer.writeInt(i16, offset, options.endian);
961 }963 }
962964
963 pub fn writeCall(writer: anytype, comptime T: type, offset: T) !void {965 pub fn writeCall(writer: *Writer, comptime T: type, offset: T) !void {
964 if (options.call_frame_context) return error.InvalidCFAOpcode;966 if (options.call_frame_context) return error.InvalidCFAOpcode;
965 switch (T) {967 switch (T) {
966 u16 => try writer.writeByte(OP.call2),968 u16 => try writer.writeByte(OP.call2),
...@@ -971,45 +973,45 @@ pub fn Builder(comptime options: Options) type {...@@ -971,45 +973,45 @@ pub fn Builder(comptime options: Options) type {
971 try writer.writeInt(T, offset, options.endian);973 try writer.writeInt(T, offset, options.endian);
972 }974 }
973975
974 pub fn writeCallRef(writer: anytype, comptime is_64: bool, value: if (is_64) u64 else u32) !void {976 pub fn writeCallRef(writer: *Writer, comptime is_64: bool, value: if (is_64) u64 else u32) !void {
975 if (options.call_frame_context) return error.InvalidCFAOpcode;977 if (options.call_frame_context) return error.InvalidCFAOpcode;
976 try writer.writeByte(OP.call_ref);978 try writer.writeByte(OP.call_ref);
977 try writer.writeInt(if (is_64) u64 else u32, value, options.endian);979 try writer.writeInt(if (is_64) u64 else u32, value, options.endian);
978 }980 }
979981
980 pub fn writeConvert(writer: anytype, die_offset: anytype) !void {982 pub fn writeConvert(writer: *Writer, die_offset: anytype) !void {
981 if (options.call_frame_context) return error.InvalidCFAOpcode;983 if (options.call_frame_context) return error.InvalidCFAOpcode;
982 try writer.writeByte(OP.convert);984 try writer.writeByte(OP.convert);
983 try leb.writeUleb128(writer, die_offset);985 try writer.writeUleb128(die_offset);
984 }986 }
985987
986 pub fn writeReinterpret(writer: anytype, die_offset: anytype) !void {988 pub fn writeReinterpret(writer: *Writer, die_offset: anytype) !void {
987 if (options.call_frame_context) return error.InvalidCFAOpcode;989 if (options.call_frame_context) return error.InvalidCFAOpcode;
988 try writer.writeByte(OP.reinterpret);990 try writer.writeByte(OP.reinterpret);
989 try leb.writeUleb128(writer, die_offset);991 try writer.writeUleb128(die_offset);
990 }992 }
991993
992 // 2.5.1.7: Special Operations994 // 2.5.1.7: Special Operations
993995
994 pub fn writeEntryValue(writer: anytype, expression: []const u8) !void {996 pub fn writeEntryValue(writer: *Writer, expression: []const u8) !void {
995 try writer.writeByte(OP.entry_value);997 try writer.writeByte(OP.entry_value);
996 try leb.writeUleb128(writer, expression.len);998 try writer.writeUleb128(expression.len);
997 try writer.writeAll(expression);999 try writer.writeAll(expression);
998 }1000 }
9991001
1000 // 2.6: Location Descriptions1002 // 2.6: Location Descriptions
1001 pub fn writeReg(writer: anytype, register: u8) !void {1003 pub fn writeReg(writer: *Writer, register: u8) !void {
1002 try writer.writeByte(OP.reg0 + register);1004 try writer.writeByte(OP.reg0 + register);
1003 }1005 }
10041006
1005 pub fn writeRegx(writer: anytype, register: anytype) !void {1007 pub fn writeRegx(writer: *Writer, register: anytype) !void {
1006 try writer.writeByte(OP.regx);1008 try writer.writeByte(OP.regx);
1007 try leb.writeUleb128(writer, register);1009 try writer.writeUleb128(register);
1008 }1010 }
10091011
1010 pub fn writeImplicitValue(writer: anytype, value_bytes: []const u8) !void {1012 pub fn writeImplicitValue(writer: *Writer, value_bytes: []const u8) !void {
1011 try writer.writeByte(OP.implicit_value);1013 try writer.writeByte(OP.implicit_value);
1012 try leb.writeUleb128(writer, value_bytes.len);1014 try writer.writeUleb128(value_bytes.len);
1013 try writer.writeAll(value_bytes);1015 try writer.writeAll(value_bytes);
1014 }1016 }
1015 };1017 };
...@@ -1042,8 +1044,7 @@ fn isOpcodeRegisterLocation(opcode: u8) bool {...@@ -1042,8 +1044,7 @@ fn isOpcodeRegisterLocation(opcode: u8) bool {
1042 };1044 };
1043}1045}
10441046
1045const testing = std.testing;1047test "basics" {
1046test "DWARF expressions" {
1047 const allocator = std.testing.allocator;1048 const allocator = std.testing.allocator;
10481049
1049 const options = Options{};1050 const options = Options{};
...@@ -1052,10 +1053,10 @@ test "DWARF expressions" {...@@ -1052,10 +1053,10 @@ test "DWARF expressions" {
10521053
1053 const b = Builder(options);1054 const b = Builder(options);
10541055
1055 var program = std.array_list.Managed(u8).init(allocator);1056 var program: std.Io.Writer.Allocating = .init(allocator);
1056 defer program.deinit();1057 defer program.deinit();
10571058
1058 const writer = program.writer();1059 const writer = &program.writer;
10591060
1060 // Literals1061 // Literals
1061 {1062 {
...@@ -1064,7 +1065,7 @@ test "DWARF expressions" {...@@ -1064,7 +1065,7 @@ test "DWARF expressions" {
1064 try b.writeLiteral(writer, @intCast(i));1065 try b.writeLiteral(writer, @intCast(i));
1065 }1066 }
10661067
1067 _ = try stack_machine.run(program.items, allocator, context, 0);1068 _ = try stack_machine.run(program.written(), allocator, context, 0);
10681069
1069 for (0..32) |i| {1070 for (0..32) |i| {
1070 const expected = 31 - i;1071 const expected = 31 - i;
...@@ -1108,16 +1109,16 @@ test "DWARF expressions" {...@@ -1108,16 +1109,16 @@ test "DWARF expressions" {
1108 var mock_compile_unit: std.debug.Dwarf.CompileUnit = undefined;1109 var mock_compile_unit: std.debug.Dwarf.CompileUnit = undefined;
1109 mock_compile_unit.addr_base = 1;1110 mock_compile_unit.addr_base = 1;
11101111
1111 var mock_debug_addr = std.array_list.Managed(u8).init(allocator);1112 var mock_debug_addr: std.Io.Writer.Allocating = .init(allocator);
1112 defer mock_debug_addr.deinit();1113 defer mock_debug_addr.deinit();
11131114
1114 try mock_debug_addr.writer().writeInt(u16, 0, native_endian);1115 try mock_debug_addr.writer.writeInt(u16, 0, native_endian);
1115 try mock_debug_addr.writer().writeInt(usize, input[11], native_endian);1116 try mock_debug_addr.writer.writeInt(usize, input[11], native_endian);
1116 try mock_debug_addr.writer().writeInt(usize, input[12], native_endian);1117 try mock_debug_addr.writer.writeInt(usize, input[12], native_endian);
11171118
1118 const context = Context{1119 const context: Context = .{
1119 .compile_unit = &mock_compile_unit,1120 .compile_unit = &mock_compile_unit,
1120 .debug_addr = mock_debug_addr.items,1121 .debug_addr = mock_debug_addr.written(),
1121 };1122 };
11221123
1123 try b.writeConstx(writer, @as(usize, 1));1124 try b.writeConstx(writer, @as(usize, 1));
...@@ -1127,7 +1128,7 @@ test "DWARF expressions" {...@@ -1127,7 +1128,7 @@ test "DWARF expressions" {
1127 const type_bytes: []const u8 = &.{ 1, 2, 3, 4 };1128 const type_bytes: []const u8 = &.{ 1, 2, 3, 4 };
1128 try b.writeConstType(writer, die_offset, type_bytes);1129 try b.writeConstType(writer, die_offset, type_bytes);
11291130
1130 _ = try stack_machine.run(program.items, allocator, context, 0);1131 _ = try stack_machine.run(program.written(), allocator, context, 0);
11311132
1132 const const_type = stack_machine.stack.pop().?.const_type;1133 const const_type = stack_machine.stack.pop().?.const_type;
1133 try testing.expectEqual(die_offset, const_type.type_offset);1134 try testing.expectEqual(die_offset, const_type.type_offset);
...@@ -1185,7 +1186,7 @@ test "DWARF expressions" {...@@ -1185,7 +1186,7 @@ test "DWARF expressions" {
1185 try b.writeBregx(writer, abi.ipRegNum(native_arch).?, @as(usize, 300));1186 try b.writeBregx(writer, abi.ipRegNum(native_arch).?, @as(usize, 300));
1186 try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 400));1187 try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 400));
11871188
1188 _ = try stack_machine.run(program.items, allocator, context, 0);1189 _ = try stack_machine.run(program.written(), allocator, context, 0);
11891190
1190 const regval_type = stack_machine.stack.pop().?.regval_type;1191 const regval_type = stack_machine.stack.pop().?.regval_type;
1191 try testing.expectEqual(@as(usize, 400), regval_type.type_offset);1192 try testing.expectEqual(@as(usize, 400), regval_type.type_offset);
...@@ -1214,7 +1215,7 @@ test "DWARF expressions" {...@@ -1214,7 +1215,7 @@ test "DWARF expressions" {
1214 program.clearRetainingCapacity();1215 program.clearRetainingCapacity();
1215 try b.writeConst(writer, u8, 1);1216 try b.writeConst(writer, u8, 1);
1216 try b.writeOpcode(writer, OP.dup);1217 try b.writeOpcode(writer, OP.dup);
1217 _ = try stack_machine.run(program.items, allocator, context, null);1218 _ = try stack_machine.run(program.written(), allocator, context, null);
1218 try testing.expectEqual(@as(usize, 1), stack_machine.stack.pop().?.generic);1219 try testing.expectEqual(@as(usize, 1), stack_machine.stack.pop().?.generic);
1219 try testing.expectEqual(@as(usize, 1), stack_machine.stack.pop().?.generic);1220 try testing.expectEqual(@as(usize, 1), stack_machine.stack.pop().?.generic);
12201221
...@@ -1222,7 +1223,7 @@ test "DWARF expressions" {...@@ -1222,7 +1223,7 @@ test "DWARF expressions" {
1222 program.clearRetainingCapacity();1223 program.clearRetainingCapacity();
1223 try b.writeConst(writer, u8, 1);1224 try b.writeConst(writer, u8, 1);
1224 try b.writeOpcode(writer, OP.drop);1225 try b.writeOpcode(writer, OP.drop);
1225 _ = try stack_machine.run(program.items, allocator, context, null);1226 _ = try stack_machine.run(program.written(), allocator, context, null);
1226 try testing.expect(stack_machine.stack.pop() == null);1227 try testing.expect(stack_machine.stack.pop() == null);
12271228
1228 stack_machine.reset();1229 stack_machine.reset();
...@@ -1231,7 +1232,7 @@ test "DWARF expressions" {...@@ -1231,7 +1232,7 @@ test "DWARF expressions" {
1231 try b.writeConst(writer, u8, 5);1232 try b.writeConst(writer, u8, 5);
1232 try b.writeConst(writer, u8, 6);1233 try b.writeConst(writer, u8, 6);
1233 try b.writePick(writer, 2);1234 try b.writePick(writer, 2);
1234 _ = try stack_machine.run(program.items, allocator, context, null);1235 _ = try stack_machine.run(program.written(), allocator, context, null);
1235 try testing.expectEqual(@as(usize, 4), stack_machine.stack.pop().?.generic);1236 try testing.expectEqual(@as(usize, 4), stack_machine.stack.pop().?.generic);
12361237
1237 stack_machine.reset();1238 stack_machine.reset();
...@@ -1240,7 +1241,7 @@ test "DWARF expressions" {...@@ -1240,7 +1241,7 @@ test "DWARF expressions" {
1240 try b.writeConst(writer, u8, 5);1241 try b.writeConst(writer, u8, 5);
1241 try b.writeConst(writer, u8, 6);1242 try b.writeConst(writer, u8, 6);
1242 try b.writeOpcode(writer, OP.over);1243 try b.writeOpcode(writer, OP.over);
1243 _ = try stack_machine.run(program.items, allocator, context, null);1244 _ = try stack_machine.run(program.written(), allocator, context, null);
1244 try testing.expectEqual(@as(usize, 5), stack_machine.stack.pop().?.generic);1245 try testing.expectEqual(@as(usize, 5), stack_machine.stack.pop().?.generic);
12451246
1246 stack_machine.reset();1247 stack_machine.reset();
...@@ -1248,7 +1249,7 @@ test "DWARF expressions" {...@@ -1248,7 +1249,7 @@ test "DWARF expressions" {
1248 try b.writeConst(writer, u8, 5);1249 try b.writeConst(writer, u8, 5);
1249 try b.writeConst(writer, u8, 6);1250 try b.writeConst(writer, u8, 6);
1250 try b.writeOpcode(writer, OP.swap);1251 try b.writeOpcode(writer, OP.swap);
1251 _ = try stack_machine.run(program.items, allocator, context, null);1252 _ = try stack_machine.run(program.written(), allocator, context, null);
1252 try testing.expectEqual(@as(usize, 5), stack_machine.stack.pop().?.generic);1253 try testing.expectEqual(@as(usize, 5), stack_machine.stack.pop().?.generic);
1253 try testing.expectEqual(@as(usize, 6), stack_machine.stack.pop().?.generic);1254 try testing.expectEqual(@as(usize, 6), stack_machine.stack.pop().?.generic);
12541255
...@@ -1258,7 +1259,7 @@ test "DWARF expressions" {...@@ -1258,7 +1259,7 @@ test "DWARF expressions" {
1258 try b.writeConst(writer, u8, 5);1259 try b.writeConst(writer, u8, 5);
1259 try b.writeConst(writer, u8, 6);1260 try b.writeConst(writer, u8, 6);
1260 try b.writeOpcode(writer, OP.rot);1261 try b.writeOpcode(writer, OP.rot);
1261 _ = try stack_machine.run(program.items, allocator, context, null);1262 _ = try stack_machine.run(program.written(), allocator, context, null);
1262 try testing.expectEqual(@as(usize, 5), stack_machine.stack.pop().?.generic);1263 try testing.expectEqual(@as(usize, 5), stack_machine.stack.pop().?.generic);
1263 try testing.expectEqual(@as(usize, 4), stack_machine.stack.pop().?.generic);1264 try testing.expectEqual(@as(usize, 4), stack_machine.stack.pop().?.generic);
1264 try testing.expectEqual(@as(usize, 6), stack_machine.stack.pop().?.generic);1265 try testing.expectEqual(@as(usize, 6), stack_machine.stack.pop().?.generic);
...@@ -1269,7 +1270,7 @@ test "DWARF expressions" {...@@ -1269,7 +1270,7 @@ test "DWARF expressions" {
1269 program.clearRetainingCapacity();1270 program.clearRetainingCapacity();
1270 try b.writeAddr(writer, @intFromPtr(&deref_target));1271 try b.writeAddr(writer, @intFromPtr(&deref_target));
1271 try b.writeOpcode(writer, OP.deref);1272 try b.writeOpcode(writer, OP.deref);
1272 _ = try stack_machine.run(program.items, allocator, context, null);1273 _ = try stack_machine.run(program.written(), allocator, context, null);
1273 try testing.expectEqual(deref_target, stack_machine.stack.pop().?.generic);1274 try testing.expectEqual(deref_target, stack_machine.stack.pop().?.generic);
12741275
1275 stack_machine.reset();1276 stack_machine.reset();
...@@ -1277,14 +1278,14 @@ test "DWARF expressions" {...@@ -1277,14 +1278,14 @@ test "DWARF expressions" {
1277 try b.writeLiteral(writer, 0);1278 try b.writeLiteral(writer, 0);
1278 try b.writeAddr(writer, @intFromPtr(&deref_target));1279 try b.writeAddr(writer, @intFromPtr(&deref_target));
1279 try b.writeOpcode(writer, OP.xderef);1280 try b.writeOpcode(writer, OP.xderef);
1280 _ = try stack_machine.run(program.items, allocator, context, null);1281 _ = try stack_machine.run(program.written(), allocator, context, null);
1281 try testing.expectEqual(deref_target, stack_machine.stack.pop().?.generic);1282 try testing.expectEqual(deref_target, stack_machine.stack.pop().?.generic);
12821283
1283 stack_machine.reset();1284 stack_machine.reset();
1284 program.clearRetainingCapacity();1285 program.clearRetainingCapacity();
1285 try b.writeAddr(writer, @intFromPtr(&deref_target));1286 try b.writeAddr(writer, @intFromPtr(&deref_target));
1286 try b.writeDerefSize(writer, 1);1287 try b.writeDerefSize(writer, 1);
1287 _ = try stack_machine.run(program.items, allocator, context, null);1288 _ = try stack_machine.run(program.written(), allocator, context, null);
1288 try testing.expectEqual(@as(usize, @as(*const u8, @ptrCast(&deref_target)).*), stack_machine.stack.pop().?.generic);1289 try testing.expectEqual(@as(usize, @as(*const u8, @ptrCast(&deref_target)).*), stack_machine.stack.pop().?.generic);
12891290
1290 stack_machine.reset();1291 stack_machine.reset();
...@@ -1292,7 +1293,7 @@ test "DWARF expressions" {...@@ -1292,7 +1293,7 @@ test "DWARF expressions" {
1292 try b.writeLiteral(writer, 0);1293 try b.writeLiteral(writer, 0);
1293 try b.writeAddr(writer, @intFromPtr(&deref_target));1294 try b.writeAddr(writer, @intFromPtr(&deref_target));
1294 try b.writeXDerefSize(writer, 1);1295 try b.writeXDerefSize(writer, 1);
1295 _ = try stack_machine.run(program.items, allocator, context, null);1296 _ = try stack_machine.run(program.written(), allocator, context, null);
1296 try testing.expectEqual(@as(usize, @as(*const u8, @ptrCast(&deref_target)).*), stack_machine.stack.pop().?.generic);1297 try testing.expectEqual(@as(usize, @as(*const u8, @ptrCast(&deref_target)).*), stack_machine.stack.pop().?.generic);
12971298
1298 const type_offset: usize = @truncate(0xaabbaabb_aabbaabb);1299 const type_offset: usize = @truncate(0xaabbaabb_aabbaabb);
...@@ -1301,7 +1302,7 @@ test "DWARF expressions" {...@@ -1301,7 +1302,7 @@ test "DWARF expressions" {
1301 program.clearRetainingCapacity();1302 program.clearRetainingCapacity();
1302 try b.writeAddr(writer, @intFromPtr(&deref_target));1303 try b.writeAddr(writer, @intFromPtr(&deref_target));
1303 try b.writeDerefType(writer, 1, type_offset);1304 try b.writeDerefType(writer, 1, type_offset);
1304 _ = try stack_machine.run(program.items, allocator, context, null);1305 _ = try stack_machine.run(program.written(), allocator, context, null);
1305 const deref_type = stack_machine.stack.pop().?.regval_type;1306 const deref_type = stack_machine.stack.pop().?.regval_type;
1306 try testing.expectEqual(type_offset, deref_type.type_offset);1307 try testing.expectEqual(type_offset, deref_type.type_offset);
1307 try testing.expectEqual(@as(u8, 1), deref_type.type_size);1308 try testing.expectEqual(@as(u8, 1), deref_type.type_size);
...@@ -1312,7 +1313,7 @@ test "DWARF expressions" {...@@ -1312,7 +1313,7 @@ test "DWARF expressions" {
1312 try b.writeLiteral(writer, 0);1313 try b.writeLiteral(writer, 0);
1313 try b.writeAddr(writer, @intFromPtr(&deref_target));1314 try b.writeAddr(writer, @intFromPtr(&deref_target));
1314 try b.writeXDerefType(writer, 1, type_offset);1315 try b.writeXDerefType(writer, 1, type_offset);
1315 _ = try stack_machine.run(program.items, allocator, context, null);1316 _ = try stack_machine.run(program.written(), allocator, context, null);
1316 const xderef_type = stack_machine.stack.pop().?.regval_type;1317 const xderef_type = stack_machine.stack.pop().?.regval_type;
1317 try testing.expectEqual(type_offset, xderef_type.type_offset);1318 try testing.expectEqual(type_offset, xderef_type.type_offset);
1318 try testing.expectEqual(@as(u8, 1), xderef_type.type_size);1319 try testing.expectEqual(@as(u8, 1), xderef_type.type_size);
...@@ -1323,7 +1324,7 @@ test "DWARF expressions" {...@@ -1323,7 +1324,7 @@ test "DWARF expressions" {
1323 stack_machine.reset();1324 stack_machine.reset();
1324 program.clearRetainingCapacity();1325 program.clearRetainingCapacity();
1325 try b.writeOpcode(writer, OP.push_object_address);1326 try b.writeOpcode(writer, OP.push_object_address);
1326 _ = try stack_machine.run(program.items, allocator, context, null);1327 _ = try stack_machine.run(program.written(), allocator, context, null);
1327 try testing.expectEqual(@as(usize, @intFromPtr(context.object_address.?)), stack_machine.stack.pop().?.generic);1328 try testing.expectEqual(@as(usize, @intFromPtr(context.object_address.?)), stack_machine.stack.pop().?.generic);
13281329
1329 // TODO: Test OP.form_tls_address1330 // TODO: Test OP.form_tls_address
...@@ -1333,7 +1334,7 @@ test "DWARF expressions" {...@@ -1333,7 +1334,7 @@ test "DWARF expressions" {
1333 stack_machine.reset();1334 stack_machine.reset();
1334 program.clearRetainingCapacity();1335 program.clearRetainingCapacity();
1335 try b.writeOpcode(writer, OP.call_frame_cfa);1336 try b.writeOpcode(writer, OP.call_frame_cfa);
1336 _ = try stack_machine.run(program.items, allocator, context, null);1337 _ = try stack_machine.run(program.written(), allocator, context, null);
1337 try testing.expectEqual(context.cfa.?, stack_machine.stack.pop().?.generic);1338 try testing.expectEqual(context.cfa.?, stack_machine.stack.pop().?.generic);
1338 }1339 }
13391340
...@@ -1345,7 +1346,7 @@ test "DWARF expressions" {...@@ -1345,7 +1346,7 @@ test "DWARF expressions" {
1345 program.clearRetainingCapacity();1346 program.clearRetainingCapacity();
1346 try b.writeConst(writer, i16, -4096);1347 try b.writeConst(writer, i16, -4096);
1347 try b.writeOpcode(writer, OP.abs);1348 try b.writeOpcode(writer, OP.abs);
1348 _ = try stack_machine.run(program.items, allocator, context, null);1349 _ = try stack_machine.run(program.written(), allocator, context, null);
1349 try testing.expectEqual(@as(usize, 4096), stack_machine.stack.pop().?.generic);1350 try testing.expectEqual(@as(usize, 4096), stack_machine.stack.pop().?.generic);
13501351
1351 stack_machine.reset();1352 stack_machine.reset();
...@@ -1353,7 +1354,7 @@ test "DWARF expressions" {...@@ -1353,7 +1354,7 @@ test "DWARF expressions" {
1353 try b.writeConst(writer, u16, 0xff0f);1354 try b.writeConst(writer, u16, 0xff0f);
1354 try b.writeConst(writer, u16, 0xf0ff);1355 try b.writeConst(writer, u16, 0xf0ff);
1355 try b.writeOpcode(writer, OP.@"and");1356 try b.writeOpcode(writer, OP.@"and");
1356 _ = try stack_machine.run(program.items, allocator, context, null);1357 _ = try stack_machine.run(program.written(), allocator, context, null);
1357 try testing.expectEqual(@as(usize, 0xf00f), stack_machine.stack.pop().?.generic);1358 try testing.expectEqual(@as(usize, 0xf00f), stack_machine.stack.pop().?.generic);
13581359
1359 stack_machine.reset();1360 stack_machine.reset();
...@@ -1361,7 +1362,7 @@ test "DWARF expressions" {...@@ -1361,7 +1362,7 @@ test "DWARF expressions" {
1361 try b.writeConst(writer, i16, -404);1362 try b.writeConst(writer, i16, -404);
1362 try b.writeConst(writer, i16, 100);1363 try b.writeConst(writer, i16, 100);
1363 try b.writeOpcode(writer, OP.div);1364 try b.writeOpcode(writer, OP.div);
1364 _ = try stack_machine.run(program.items, allocator, context, null);1365 _ = try stack_machine.run(program.written(), allocator, context, null);
1365 try testing.expectEqual(@as(isize, -404 / 100), @as(isize, @bitCast(stack_machine.stack.pop().?.generic)));1366 try testing.expectEqual(@as(isize, -404 / 100), @as(isize, @bitCast(stack_machine.stack.pop().?.generic)));
13661367
1367 stack_machine.reset();1368 stack_machine.reset();
...@@ -1369,7 +1370,7 @@ test "DWARF expressions" {...@@ -1369,7 +1370,7 @@ test "DWARF expressions" {
1369 try b.writeConst(writer, u16, 200);1370 try b.writeConst(writer, u16, 200);
1370 try b.writeConst(writer, u16, 50);1371 try b.writeConst(writer, u16, 50);
1371 try b.writeOpcode(writer, OP.minus);1372 try b.writeOpcode(writer, OP.minus);
1372 _ = try stack_machine.run(program.items, allocator, context, null);1373 _ = try stack_machine.run(program.written(), allocator, context, null);
1373 try testing.expectEqual(@as(usize, 150), stack_machine.stack.pop().?.generic);1374 try testing.expectEqual(@as(usize, 150), stack_machine.stack.pop().?.generic);
13741375
1375 stack_machine.reset();1376 stack_machine.reset();
...@@ -1377,7 +1378,7 @@ test "DWARF expressions" {...@@ -1377,7 +1378,7 @@ test "DWARF expressions" {
1377 try b.writeConst(writer, u16, 123);1378 try b.writeConst(writer, u16, 123);
1378 try b.writeConst(writer, u16, 100);1379 try b.writeConst(writer, u16, 100);
1379 try b.writeOpcode(writer, OP.mod);1380 try b.writeOpcode(writer, OP.mod);
1380 _ = try stack_machine.run(program.items, allocator, context, null);1381 _ = try stack_machine.run(program.written(), allocator, context, null);
1381 try testing.expectEqual(@as(usize, 23), stack_machine.stack.pop().?.generic);1382 try testing.expectEqual(@as(usize, 23), stack_machine.stack.pop().?.generic);
13821383
1383 stack_machine.reset();1384 stack_machine.reset();
...@@ -1385,7 +1386,7 @@ test "DWARF expressions" {...@@ -1385,7 +1386,7 @@ test "DWARF expressions" {
1385 try b.writeConst(writer, u16, 0xff);1386 try b.writeConst(writer, u16, 0xff);
1386 try b.writeConst(writer, u16, 0xee);1387 try b.writeConst(writer, u16, 0xee);
1387 try b.writeOpcode(writer, OP.mul);1388 try b.writeOpcode(writer, OP.mul);
1388 _ = try stack_machine.run(program.items, allocator, context, null);1389 _ = try stack_machine.run(program.written(), allocator, context, null);
1389 try testing.expectEqual(@as(usize, 0xed12), stack_machine.stack.pop().?.generic);1390 try testing.expectEqual(@as(usize, 0xed12), stack_machine.stack.pop().?.generic);
13901391
1391 stack_machine.reset();1392 stack_machine.reset();
...@@ -1394,7 +1395,7 @@ test "DWARF expressions" {...@@ -1394,7 +1395,7 @@ test "DWARF expressions" {
1394 try b.writeOpcode(writer, OP.neg);1395 try b.writeOpcode(writer, OP.neg);
1395 try b.writeConst(writer, i16, -6);1396 try b.writeConst(writer, i16, -6);
1396 try b.writeOpcode(writer, OP.neg);1397 try b.writeOpcode(writer, OP.neg);
1397 _ = try stack_machine.run(program.items, allocator, context, null);1398 _ = try stack_machine.run(program.written(), allocator, context, null);
1398 try testing.expectEqual(@as(usize, 6), stack_machine.stack.pop().?.generic);1399 try testing.expectEqual(@as(usize, 6), stack_machine.stack.pop().?.generic);
1399 try testing.expectEqual(@as(isize, -5), @as(isize, @bitCast(stack_machine.stack.pop().?.generic)));1400 try testing.expectEqual(@as(isize, -5), @as(isize, @bitCast(stack_machine.stack.pop().?.generic)));
14001401
...@@ -1402,7 +1403,7 @@ test "DWARF expressions" {...@@ -1402,7 +1403,7 @@ test "DWARF expressions" {
1402 program.clearRetainingCapacity();1403 program.clearRetainingCapacity();
1403 try b.writeConst(writer, u16, 0xff0f);1404 try b.writeConst(writer, u16, 0xff0f);
1404 try b.writeOpcode(writer, OP.not);1405 try b.writeOpcode(writer, OP.not);
1405 _ = try stack_machine.run(program.items, allocator, context, null);1406 _ = try stack_machine.run(program.written(), allocator, context, null);
1406 try testing.expectEqual(~@as(usize, 0xff0f), stack_machine.stack.pop().?.generic);1407 try testing.expectEqual(~@as(usize, 0xff0f), stack_machine.stack.pop().?.generic);
14071408
1408 stack_machine.reset();1409 stack_machine.reset();
...@@ -1410,7 +1411,7 @@ test "DWARF expressions" {...@@ -1410,7 +1411,7 @@ test "DWARF expressions" {
1410 try b.writeConst(writer, u16, 0xff0f);1411 try b.writeConst(writer, u16, 0xff0f);
1411 try b.writeConst(writer, u16, 0xf0ff);1412 try b.writeConst(writer, u16, 0xf0ff);
1412 try b.writeOpcode(writer, OP.@"or");1413 try b.writeOpcode(writer, OP.@"or");
1413 _ = try stack_machine.run(program.items, allocator, context, null);1414 _ = try stack_machine.run(program.written(), allocator, context, null);
1414 try testing.expectEqual(@as(usize, 0xffff), stack_machine.stack.pop().?.generic);1415 try testing.expectEqual(@as(usize, 0xffff), stack_machine.stack.pop().?.generic);
14151416
1416 stack_machine.reset();1417 stack_machine.reset();
...@@ -1418,14 +1419,14 @@ test "DWARF expressions" {...@@ -1418,14 +1419,14 @@ test "DWARF expressions" {
1418 try b.writeConst(writer, i16, 402);1419 try b.writeConst(writer, i16, 402);
1419 try b.writeConst(writer, i16, 100);1420 try b.writeConst(writer, i16, 100);
1420 try b.writeOpcode(writer, OP.plus);1421 try b.writeOpcode(writer, OP.plus);
1421 _ = try stack_machine.run(program.items, allocator, context, null);1422 _ = try stack_machine.run(program.written(), allocator, context, null);
1422 try testing.expectEqual(@as(usize, 502), stack_machine.stack.pop().?.generic);1423 try testing.expectEqual(@as(usize, 502), stack_machine.stack.pop().?.generic);
14231424
1424 stack_machine.reset();1425 stack_machine.reset();
1425 program.clearRetainingCapacity();1426 program.clearRetainingCapacity();
1426 try b.writeConst(writer, u16, 4096);1427 try b.writeConst(writer, u16, 4096);
1427 try b.writePlusUconst(writer, @as(usize, 8192));1428 try b.writePlusUconst(writer, @as(usize, 8192));
1428 _ = try stack_machine.run(program.items, allocator, context, null);1429 _ = try stack_machine.run(program.written(), allocator, context, null);
1429 try testing.expectEqual(@as(usize, 4096 + 8192), stack_machine.stack.pop().?.generic);1430 try testing.expectEqual(@as(usize, 4096 + 8192), stack_machine.stack.pop().?.generic);
14301431
1431 stack_machine.reset();1432 stack_machine.reset();
...@@ -1433,7 +1434,7 @@ test "DWARF expressions" {...@@ -1433,7 +1434,7 @@ test "DWARF expressions" {
1433 try b.writeConst(writer, u16, 0xfff);1434 try b.writeConst(writer, u16, 0xfff);
1434 try b.writeConst(writer, u16, 1);1435 try b.writeConst(writer, u16, 1);
1435 try b.writeOpcode(writer, OP.shl);1436 try b.writeOpcode(writer, OP.shl);
1436 _ = try stack_machine.run(program.items, allocator, context, null);1437 _ = try stack_machine.run(program.written(), allocator, context, null);
1437 try testing.expectEqual(@as(usize, 0xfff << 1), stack_machine.stack.pop().?.generic);1438 try testing.expectEqual(@as(usize, 0xfff << 1), stack_machine.stack.pop().?.generic);
14381439
1439 stack_machine.reset();1440 stack_machine.reset();
...@@ -1441,7 +1442,7 @@ test "DWARF expressions" {...@@ -1441,7 +1442,7 @@ test "DWARF expressions" {
1441 try b.writeConst(writer, u16, 0xfff);1442 try b.writeConst(writer, u16, 0xfff);
1442 try b.writeConst(writer, u16, 1);1443 try b.writeConst(writer, u16, 1);
1443 try b.writeOpcode(writer, OP.shr);1444 try b.writeOpcode(writer, OP.shr);
1444 _ = try stack_machine.run(program.items, allocator, context, null);1445 _ = try stack_machine.run(program.written(), allocator, context, null);
1445 try testing.expectEqual(@as(usize, 0xfff >> 1), stack_machine.stack.pop().?.generic);1446 try testing.expectEqual(@as(usize, 0xfff >> 1), stack_machine.stack.pop().?.generic);
14461447
1447 stack_machine.reset();1448 stack_machine.reset();
...@@ -1449,7 +1450,7 @@ test "DWARF expressions" {...@@ -1449,7 +1450,7 @@ test "DWARF expressions" {
1449 try b.writeConst(writer, u16, 0xfff);1450 try b.writeConst(writer, u16, 0xfff);
1450 try b.writeConst(writer, u16, 1);1451 try b.writeConst(writer, u16, 1);
1451 try b.writeOpcode(writer, OP.shr);1452 try b.writeOpcode(writer, OP.shr);
1452 _ = try stack_machine.run(program.items, allocator, context, null);1453 _ = try stack_machine.run(program.written(), allocator, context, null);
1453 try testing.expectEqual(@as(usize, @bitCast(@as(isize, 0xfff) >> 1)), stack_machine.stack.pop().?.generic);1454 try testing.expectEqual(@as(usize, @bitCast(@as(isize, 0xfff) >> 1)), stack_machine.stack.pop().?.generic);
14541455
1455 stack_machine.reset();1456 stack_machine.reset();
...@@ -1457,7 +1458,7 @@ test "DWARF expressions" {...@@ -1457,7 +1458,7 @@ test "DWARF expressions" {
1457 try b.writeConst(writer, u16, 0xf0ff);1458 try b.writeConst(writer, u16, 0xf0ff);
1458 try b.writeConst(writer, u16, 0xff0f);1459 try b.writeConst(writer, u16, 0xff0f);
1459 try b.writeOpcode(writer, OP.xor);1460 try b.writeOpcode(writer, OP.xor);
1460 _ = try stack_machine.run(program.items, allocator, context, null);1461 _ = try stack_machine.run(program.written(), allocator, context, null);
1461 try testing.expectEqual(@as(usize, 0x0ff0), stack_machine.stack.pop().?.generic);1462 try testing.expectEqual(@as(usize, 0x0ff0), stack_machine.stack.pop().?.generic);
1462 }1463 }
14631464
...@@ -1486,7 +1487,7 @@ test "DWARF expressions" {...@@ -1486,7 +1487,7 @@ test "DWARF expressions" {
1486 try b.writeConst(writer, u16, 1);1487 try b.writeConst(writer, u16, 1);
1487 try b.writeConst(writer, u16, 0);1488 try b.writeConst(writer, u16, 0);
1488 try b.writeOpcode(writer, e[0]);1489 try b.writeOpcode(writer, e[0]);
1489 _ = try stack_machine.run(program.items, allocator, context, null);1490 _ = try stack_machine.run(program.written(), allocator, context, null);
1490 try testing.expectEqual(@as(usize, e[3]), stack_machine.stack.pop().?.generic);1491 try testing.expectEqual(@as(usize, e[3]), stack_machine.stack.pop().?.generic);
1491 try testing.expectEqual(@as(usize, e[2]), stack_machine.stack.pop().?.generic);1492 try testing.expectEqual(@as(usize, e[2]), stack_machine.stack.pop().?.generic);
1492 try testing.expectEqual(@as(usize, e[1]), stack_machine.stack.pop().?.generic);1493 try testing.expectEqual(@as(usize, e[1]), stack_machine.stack.pop().?.generic);
...@@ -1497,7 +1498,7 @@ test "DWARF expressions" {...@@ -1497,7 +1498,7 @@ test "DWARF expressions" {
1497 try b.writeLiteral(writer, 2);1498 try b.writeLiteral(writer, 2);
1498 try b.writeSkip(writer, 1);1499 try b.writeSkip(writer, 1);
1499 try b.writeLiteral(writer, 3);1500 try b.writeLiteral(writer, 3);
1500 _ = try stack_machine.run(program.items, allocator, context, null);1501 _ = try stack_machine.run(program.written(), allocator, context, null);
1501 try testing.expectEqual(@as(usize, 2), stack_machine.stack.pop().?.generic);1502 try testing.expectEqual(@as(usize, 2), stack_machine.stack.pop().?.generic);
15021503
1503 stack_machine.reset();1504 stack_machine.reset();
...@@ -1509,7 +1510,7 @@ test "DWARF expressions" {...@@ -1509,7 +1510,7 @@ test "DWARF expressions" {
1509 try b.writeBra(writer, 1);1510 try b.writeBra(writer, 1);
1510 try b.writeLiteral(writer, 4);1511 try b.writeLiteral(writer, 4);
1511 try b.writeLiteral(writer, 5);1512 try b.writeLiteral(writer, 5);
1512 _ = try stack_machine.run(program.items, allocator, context, null);1513 _ = try stack_machine.run(program.written(), allocator, context, null);
1513 try testing.expectEqual(@as(usize, 5), stack_machine.stack.pop().?.generic);1514 try testing.expectEqual(@as(usize, 5), stack_machine.stack.pop().?.generic);
1514 try testing.expectEqual(@as(usize, 4), stack_machine.stack.pop().?.generic);1515 try testing.expectEqual(@as(usize, 4), stack_machine.stack.pop().?.generic);
1515 try testing.expect(stack_machine.stack.pop() == null);1516 try testing.expect(stack_machine.stack.pop() == null);
...@@ -1535,7 +1536,7 @@ test "DWARF expressions" {...@@ -1535,7 +1536,7 @@ test "DWARF expressions" {
1535 program.clearRetainingCapacity();1536 program.clearRetainingCapacity();
1536 try b.writeConstType(writer, @as(usize, 0), &value_bytes);1537 try b.writeConstType(writer, @as(usize, 0), &value_bytes);
1537 try b.writeConvert(writer, @as(usize, 0));1538 try b.writeConvert(writer, @as(usize, 0));
1538 _ = try stack_machine.run(program.items, allocator, context, null);1539 _ = try stack_machine.run(program.written(), allocator, context, null);
1539 try testing.expectEqual(value, stack_machine.stack.pop().?.generic);1540 try testing.expectEqual(value, stack_machine.stack.pop().?.generic);
15401541
1541 // Reinterpret to generic type1542 // Reinterpret to generic type
...@@ -1543,7 +1544,7 @@ test "DWARF expressions" {...@@ -1543,7 +1544,7 @@ test "DWARF expressions" {
1543 program.clearRetainingCapacity();1544 program.clearRetainingCapacity();
1544 try b.writeConstType(writer, @as(usize, 0), &value_bytes);1545 try b.writeConstType(writer, @as(usize, 0), &value_bytes);
1545 try b.writeReinterpret(writer, @as(usize, 0));1546 try b.writeReinterpret(writer, @as(usize, 0));
1546 _ = try stack_machine.run(program.items, allocator, context, null);1547 _ = try stack_machine.run(program.written(), allocator, context, null);
1547 try testing.expectEqual(value, stack_machine.stack.pop().?.generic);1548 try testing.expectEqual(value, stack_machine.stack.pop().?.generic);
15481549
1549 // Reinterpret to new type1550 // Reinterpret to new type
...@@ -1553,7 +1554,7 @@ test "DWARF expressions" {...@@ -1553,7 +1554,7 @@ test "DWARF expressions" {
1553 program.clearRetainingCapacity();1554 program.clearRetainingCapacity();
1554 try b.writeConstType(writer, @as(usize, 0), &value_bytes);1555 try b.writeConstType(writer, @as(usize, 0), &value_bytes);
1555 try b.writeReinterpret(writer, die_offset);1556 try b.writeReinterpret(writer, die_offset);
1556 _ = try stack_machine.run(program.items, allocator, context, null);1557 _ = try stack_machine.run(program.written(), allocator, context, null);
1557 const const_type = stack_machine.stack.pop().?.const_type;1558 const const_type = stack_machine.stack.pop().?.const_type;
1558 try testing.expectEqual(die_offset, const_type.type_offset);1559 try testing.expectEqual(die_offset, const_type.type_offset);
15591560
...@@ -1561,7 +1562,7 @@ test "DWARF expressions" {...@@ -1561,7 +1562,7 @@ test "DWARF expressions" {
1561 program.clearRetainingCapacity();1562 program.clearRetainingCapacity();
1562 try b.writeLiteral(writer, 0);1563 try b.writeLiteral(writer, 0);
1563 try b.writeReinterpret(writer, die_offset);1564 try b.writeReinterpret(writer, die_offset);
1564 _ = try stack_machine.run(program.items, allocator, context, null);1565 _ = try stack_machine.run(program.written(), allocator, context, null);
1565 const regval_type = stack_machine.stack.pop().?.regval_type;1566 const regval_type = stack_machine.stack.pop().?.regval_type;
1566 try testing.expectEqual(die_offset, regval_type.type_offset);1567 try testing.expectEqual(die_offset, regval_type.type_offset);
1567 }1568 }
...@@ -1573,20 +1574,20 @@ test "DWARF expressions" {...@@ -1573,20 +1574,20 @@ test "DWARF expressions" {
1573 stack_machine.reset();1574 stack_machine.reset();
1574 program.clearRetainingCapacity();1575 program.clearRetainingCapacity();
1575 try b.writeOpcode(writer, OP.nop);1576 try b.writeOpcode(writer, OP.nop);
1576 _ = try stack_machine.run(program.items, allocator, context, null);1577 _ = try stack_machine.run(program.written(), allocator, context, null);
1577 try testing.expect(stack_machine.stack.pop() == null);1578 try testing.expect(stack_machine.stack.pop() == null);
15781579
1579 // Sub-expression1580 // Sub-expression
1580 {1581 {
1581 var sub_program = std.array_list.Managed(u8).init(allocator);1582 var sub_program: std.Io.Writer.Allocating = .init(allocator);
1582 defer sub_program.deinit();1583 defer sub_program.deinit();
1583 const sub_writer = sub_program.writer();1584 const sub_writer = &sub_program.writer;
1584 try b.writeLiteral(sub_writer, 3);1585 try b.writeLiteral(sub_writer, 3);
15851586
1586 stack_machine.reset();1587 stack_machine.reset();
1587 program.clearRetainingCapacity();1588 program.clearRetainingCapacity();
1588 try b.writeEntryValue(writer, sub_program.items);1589 try b.writeEntryValue(writer, sub_program.written());
1589 _ = try stack_machine.run(program.items, allocator, context, null);1590 _ = try stack_machine.run(program.written(), allocator, context, null);
1590 try testing.expectEqual(@as(usize, 3), stack_machine.stack.pop().?.generic);1591 try testing.expectEqual(@as(usize, 3), stack_machine.stack.pop().?.generic);
1591 }1592 }
15921593
...@@ -1605,15 +1606,15 @@ test "DWARF expressions" {...@@ -1605,15 +1606,15 @@ test "DWARF expressions" {
1605 if (abi.regBytes(&thread_context, 0, reg_context)) |reg_bytes| {1606 if (abi.regBytes(&thread_context, 0, reg_context)) |reg_bytes| {
1606 mem.writeInt(usize, reg_bytes[0..@sizeOf(usize)], 0xee, native_endian);1607 mem.writeInt(usize, reg_bytes[0..@sizeOf(usize)], 0xee, native_endian);
16071608
1608 var sub_program = std.array_list.Managed(u8).init(allocator);1609 var sub_program: std.Io.Writer.Allocating = .init(allocator);
1609 defer sub_program.deinit();1610 defer sub_program.deinit();
1610 const sub_writer = sub_program.writer();1611 const sub_writer = &sub_program.writer;
1611 try b.writeReg(sub_writer, 0);1612 try b.writeReg(sub_writer, 0);
16121613
1613 stack_machine.reset();1614 stack_machine.reset();
1614 program.clearRetainingCapacity();1615 program.clearRetainingCapacity();
1615 try b.writeEntryValue(writer, sub_program.items);1616 try b.writeEntryValue(writer, sub_program.written());
1616 _ = try stack_machine.run(program.items, allocator, context, null);1617 _ = try stack_machine.run(program.written(), allocator, context, null);
1617 try testing.expectEqual(@as(usize, 0xee), stack_machine.stack.pop().?.generic);1618 try testing.expectEqual(@as(usize, 0xee), stack_machine.stack.pop().?.generic);
1618 } else |err| {1619 } else |err| {
1619 switch (err) {1620 switch (err) {
lib/std/debug/Pdb.zig+185-158
...@@ -2,10 +2,11 @@ const std = @import("../std.zig");...@@ -2,10 +2,11 @@ const std = @import("../std.zig");
2const File = std.fs.File;2const File = std.fs.File;
3const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
4const pdb = std.pdb;4const pdb = std.pdb;
5const assert = std.debug.assert;
56
6const Pdb = @This();7const Pdb = @This();
78
8in_file: File,9file_reader: *File.Reader,
9msf: Msf,10msf: Msf,
10allocator: Allocator,11allocator: Allocator,
11string_table: ?*MsfStream,12string_table: ?*MsfStream,
...@@ -35,39 +36,38 @@ pub const Module = struct {...@@ -35,39 +36,38 @@ pub const Module = struct {
35 }36 }
36};37};
3738
38pub fn init(allocator: Allocator, path: []const u8) !Pdb {39pub fn init(gpa: Allocator, file_reader: *File.Reader) !Pdb {
39 const file = try std.fs.cwd().openFile(path, .{});
40 errdefer file.close();
41
42 return .{40 return .{
43 .in_file = file,41 .file_reader = file_reader,
44 .allocator = allocator,42 .allocator = gpa,
45 .string_table = null,43 .string_table = null,
46 .dbi = null,44 .dbi = null,
47 .msf = try Msf.init(allocator, file),45 .msf = try Msf.init(gpa, file_reader),
48 .modules = &[_]Module{},46 .modules = &.{},
49 .sect_contribs = &[_]pdb.SectionContribEntry{},47 .sect_contribs = &.{},
50 .guid = undefined,48 .guid = undefined,
51 .age = undefined,49 .age = undefined,
52 };50 };
53}51}
5452
55pub fn deinit(self: *Pdb) void {53pub fn deinit(self: *Pdb) void {
56 self.in_file.close();54 const gpa = self.allocator;
57 self.msf.deinit(self.allocator);55 self.msf.deinit(gpa);
58 for (self.modules) |*module| {56 for (self.modules) |*module| {
59 module.deinit(self.allocator);57 module.deinit(gpa);
60 }58 }
61 self.allocator.free(self.modules);59 gpa.free(self.modules);
62 self.allocator.free(self.sect_contribs);60 gpa.free(self.sect_contribs);
63}61}
6462
65pub fn parseDbiStream(self: *Pdb) !void {63pub fn parseDbiStream(self: *Pdb) !void {
66 var stream = self.getStream(pdb.StreamType.dbi) orelse64 var stream = self.getStream(pdb.StreamType.dbi) orelse
67 return error.InvalidDebugInfo;65 return error.InvalidDebugInfo;
68 const reader = stream.reader();
6966
70 const header = try reader.readStruct(std.pdb.DbiStreamHeader);67 const gpa = self.allocator;
68 const reader = &stream.interface;
69
70 const header = try reader.takeStruct(std.pdb.DbiStreamHeader, .little);
71 if (header.version_header != 19990903) // V70, only value observed by LLVM team71 if (header.version_header != 19990903) // V70, only value observed by LLVM team
72 return error.UnknownPDBVersion;72 return error.UnknownPDBVersion;
73 // if (header.Age != age)73 // if (header.Age != age)
...@@ -76,22 +76,28 @@ pub fn parseDbiStream(self: *Pdb) !void {...@@ -76,22 +76,28 @@ pub fn parseDbiStream(self: *Pdb) !void {
76 const mod_info_size = header.mod_info_size;76 const mod_info_size = header.mod_info_size;
77 const section_contrib_size = header.section_contribution_size;77 const section_contrib_size = header.section_contribution_size;
7878
79 var modules = std.array_list.Managed(Module).init(self.allocator);79 var modules = std.array_list.Managed(Module).init(gpa);
80 errdefer modules.deinit();80 errdefer modules.deinit();
8181
82 // Module Info Substream82 // Module Info Substream
83 var mod_info_offset: usize = 0;83 var mod_info_offset: usize = 0;
84 while (mod_info_offset != mod_info_size) {84 while (mod_info_offset != mod_info_size) {
85 const mod_info = try reader.readStruct(pdb.ModInfo);85 const mod_info = try reader.takeStruct(pdb.ModInfo, .little);
86 var this_record_len: usize = @sizeOf(pdb.ModInfo);86 var this_record_len: usize = @sizeOf(pdb.ModInfo);
8787
88 const module_name = try reader.readUntilDelimiterAlloc(self.allocator, 0, 1024);88 var module_name: std.Io.Writer.Allocating = .init(gpa);
89 errdefer self.allocator.free(module_name);89 defer module_name.deinit();
90 this_record_len += module_name.len + 1;90 this_record_len += try reader.streamDelimiterLimit(&module_name.writer, 0, .limited(1024));
91 assert(reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API
92 reader.toss(1);
93 this_record_len += 1;
9194
92 const obj_file_name = try reader.readUntilDelimiterAlloc(self.allocator, 0, 1024);95 var obj_file_name: std.Io.Writer.Allocating = .init(gpa);
93 errdefer self.allocator.free(obj_file_name);96 defer obj_file_name.deinit();
94 this_record_len += obj_file_name.len + 1;97 this_record_len += try reader.streamDelimiterLimit(&obj_file_name.writer, 0, .limited(1024));
98 assert(reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API
99 reader.toss(1);
100 this_record_len += 1;
95101
96 if (this_record_len % 4 != 0) {102 if (this_record_len % 4 != 0) {
97 const round_to_next_4 = (this_record_len | 0x3) + 1;103 const round_to_next_4 = (this_record_len | 0x3) + 1;
...@@ -100,10 +106,10 @@ pub fn parseDbiStream(self: *Pdb) !void {...@@ -100,10 +106,10 @@ pub fn parseDbiStream(self: *Pdb) !void {
100 this_record_len += march_forward_bytes;106 this_record_len += march_forward_bytes;
101 }107 }
102108
103 try modules.append(Module{109 try modules.append(.{
104 .mod_info = mod_info,110 .mod_info = mod_info,
105 .module_name = module_name,111 .module_name = try module_name.toOwnedSlice(),
106 .obj_file_name = obj_file_name,112 .obj_file_name = try obj_file_name.toOwnedSlice(),
107113
108 .populated = false,114 .populated = false,
109 .symbols = undefined,115 .symbols = undefined,
...@@ -117,21 +123,21 @@ pub fn parseDbiStream(self: *Pdb) !void {...@@ -117,21 +123,21 @@ pub fn parseDbiStream(self: *Pdb) !void {
117 }123 }
118124
119 // Section Contribution Substream125 // Section Contribution Substream
120 var sect_contribs = std.array_list.Managed(pdb.SectionContribEntry).init(self.allocator);126 var sect_contribs = std.array_list.Managed(pdb.SectionContribEntry).init(gpa);
121 errdefer sect_contribs.deinit();127 errdefer sect_contribs.deinit();
122128
123 var sect_cont_offset: usize = 0;129 var sect_cont_offset: usize = 0;
124 if (section_contrib_size != 0) {130 if (section_contrib_size != 0) {
125 const version = reader.readEnum(std.pdb.SectionContrSubstreamVersion, .little) catch |err| switch (err) {131 const version = reader.takeEnum(std.pdb.SectionContrSubstreamVersion, .little) catch |err| switch (err) {
126 error.InvalidValue => return error.InvalidDebugInfo,132 error.InvalidEnumTag, error.EndOfStream => return error.InvalidDebugInfo,
127 else => |e| return e,133 error.ReadFailed => return error.ReadFailed,
128 };134 };
129 _ = version;135 _ = version;
130 sect_cont_offset += @sizeOf(u32);136 sect_cont_offset += @sizeOf(u32);
131 }137 }
132 while (sect_cont_offset != section_contrib_size) {138 while (sect_cont_offset != section_contrib_size) {
133 const entry = try sect_contribs.addOne();139 const entry = try sect_contribs.addOne();
134 entry.* = try reader.readStruct(pdb.SectionContribEntry);140 entry.* = try reader.takeStruct(pdb.SectionContribEntry, .little);
135 sect_cont_offset += @sizeOf(pdb.SectionContribEntry);141 sect_cont_offset += @sizeOf(pdb.SectionContribEntry);
136142
137 if (sect_cont_offset > section_contrib_size)143 if (sect_cont_offset > section_contrib_size)
...@@ -143,29 +149,28 @@ pub fn parseDbiStream(self: *Pdb) !void {...@@ -143,29 +149,28 @@ pub fn parseDbiStream(self: *Pdb) !void {
143}149}
144150
145pub fn parseInfoStream(self: *Pdb) !void {151pub fn parseInfoStream(self: *Pdb) !void {
146 var stream = self.getStream(pdb.StreamType.pdb) orelse152 var stream = self.getStream(pdb.StreamType.pdb) orelse return error.InvalidDebugInfo;
147 return error.InvalidDebugInfo;153 const reader = &stream.interface;
148 const reader = stream.reader();
149154
150 // Parse the InfoStreamHeader.155 // Parse the InfoStreamHeader.
151 const version = try reader.readInt(u32, .little);156 const version = try reader.takeInt(u32, .little);
152 const signature = try reader.readInt(u32, .little);157 const signature = try reader.takeInt(u32, .little);
153 _ = signature;158 _ = signature;
154 const age = try reader.readInt(u32, .little);159 const age = try reader.takeInt(u32, .little);
155 const guid = try reader.readBytesNoEof(16);160 const guid = try reader.takeArray(16);
156161
157 if (version != 20000404) // VC70, only value observed by LLVM team162 if (version != 20000404) // VC70, only value observed by LLVM team
158 return error.UnknownPDBVersion;163 return error.UnknownPDBVersion;
159164
160 self.guid = guid;165 self.guid = guid.*;
161 self.age = age;166 self.age = age;
162167
168 const gpa = self.allocator;
169
163 // Find the string table.170 // Find the string table.
164 const string_table_index = str_tab_index: {171 const string_table_index = str_tab_index: {
165 const name_bytes_len = try reader.readInt(u32, .little);172 const name_bytes_len = try reader.takeInt(u32, .little);
166 const name_bytes = try self.allocator.alloc(u8, name_bytes_len);173 const name_bytes = try reader.readAlloc(gpa, name_bytes_len);
167 defer self.allocator.free(name_bytes);
168 try reader.readNoEof(name_bytes);
169174
170 const HashTableHeader = extern struct {175 const HashTableHeader = extern struct {
171 size: u32,176 size: u32,
...@@ -175,23 +180,23 @@ pub fn parseInfoStream(self: *Pdb) !void {...@@ -175,23 +180,23 @@ pub fn parseInfoStream(self: *Pdb) !void {
175 return cap * 2 / 3 + 1;180 return cap * 2 / 3 + 1;
176 }181 }
177 };182 };
178 const hash_tbl_hdr = try reader.readStruct(HashTableHeader);183 const hash_tbl_hdr = try reader.takeStruct(HashTableHeader, .little);
179 if (hash_tbl_hdr.capacity == 0)184 if (hash_tbl_hdr.capacity == 0)
180 return error.InvalidDebugInfo;185 return error.InvalidDebugInfo;
181186
182 if (hash_tbl_hdr.size > HashTableHeader.maxLoad(hash_tbl_hdr.capacity))187 if (hash_tbl_hdr.size > HashTableHeader.maxLoad(hash_tbl_hdr.capacity))
183 return error.InvalidDebugInfo;188 return error.InvalidDebugInfo;
184189
185 const present = try readSparseBitVector(&reader, self.allocator);190 const present = try readSparseBitVector(reader, gpa);
186 defer self.allocator.free(present);191 defer gpa.free(present);
187 if (present.len != hash_tbl_hdr.size)192 if (present.len != hash_tbl_hdr.size)
188 return error.InvalidDebugInfo;193 return error.InvalidDebugInfo;
189 const deleted = try readSparseBitVector(&reader, self.allocator);194 const deleted = try readSparseBitVector(reader, gpa);
190 defer self.allocator.free(deleted);195 defer gpa.free(deleted);
191196
192 for (present) |_| {197 for (present) |_| {
193 const name_offset = try reader.readInt(u32, .little);198 const name_offset = try reader.takeInt(u32, .little);
194 const name_index = try reader.readInt(u32, .little);199 const name_index = try reader.takeInt(u32, .little);
195 if (name_offset > name_bytes.len)200 if (name_offset > name_bytes.len)
196 return error.InvalidDebugInfo;201 return error.InvalidDebugInfo;
197 const name = std.mem.sliceTo(name_bytes[name_offset..], 0);202 const name = std.mem.sliceTo(name_bytes[name_offset..], 0);
...@@ -233,6 +238,7 @@ pub fn getSymbolName(self: *Pdb, module: *Module, address: u64) ?[]const u8 {...@@ -233,6 +238,7 @@ pub fn getSymbolName(self: *Pdb, module: *Module, address: u64) ?[]const u8 {
233pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.SourceLocation {238pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.SourceLocation {
234 std.debug.assert(module.populated);239 std.debug.assert(module.populated);
235 const subsect_info = module.subsect_info;240 const subsect_info = module.subsect_info;
241 const gpa = self.allocator;
236242
237 var sect_offset: usize = 0;243 var sect_offset: usize = 0;
238 var skip_len: usize = undefined;244 var skip_len: usize = undefined;
...@@ -287,7 +293,16 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S...@@ -287,7 +293,16 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S
287 const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&module.subsect_info[subsect_index]);293 const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&module.subsect_info[subsect_index]);
288 const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset;294 const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset;
289 try self.string_table.?.seekTo(strtab_offset);295 try self.string_table.?.seekTo(strtab_offset);
290 const source_file_name = try self.string_table.?.reader().readUntilDelimiterAlloc(self.allocator, 0, 1024);296 const source_file_name = s: {
297 const string_reader = &self.string_table.?.interface;
298 var source_file_name: std.Io.Writer.Allocating = .init(gpa);
299 defer source_file_name.deinit();
300 _ = try string_reader.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024));
301 assert(string_reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API
302 string_reader.toss(1);
303 break :s try source_file_name.toOwnedSlice();
304 };
305 errdefer gpa.free(source_file_name);
291306
292 const line_entry_idx = line_i - 1;307 const line_entry_idx = line_i - 1;
293308
...@@ -341,19 +356,16 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module {...@@ -341,19 +356,16 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module {
341356
342 const stream = self.getStreamById(mod.mod_info.module_sym_stream) orelse357 const stream = self.getStreamById(mod.mod_info.module_sym_stream) orelse
343 return error.MissingDebugInfo;358 return error.MissingDebugInfo;
344 const reader = stream.reader();359 const reader = &stream.interface;
345360
346 const signature = try reader.readInt(u32, .little);361 const signature = try reader.takeInt(u32, .little);
347 if (signature != 4)362 if (signature != 4)
348 return error.InvalidDebugInfo;363 return error.InvalidDebugInfo;
349364
350 mod.symbols = try self.allocator.alloc(u8, mod.mod_info.sym_byte_size - 4);365 const gpa = self.allocator;
351 errdefer self.allocator.free(mod.symbols);
352 try reader.readNoEof(mod.symbols);
353366
354 mod.subsect_info = try self.allocator.alloc(u8, mod.mod_info.c13_byte_size);367 mod.symbols = try reader.readAlloc(gpa, mod.mod_info.sym_byte_size - 4);
355 errdefer self.allocator.free(mod.subsect_info);368 mod.subsect_info = try reader.readAlloc(gpa, mod.mod_info.c13_byte_size);
356 try reader.readNoEof(mod.subsect_info);
357369
358 var sect_offset: usize = 0;370 var sect_offset: usize = 0;
359 var skip_len: usize = undefined;371 var skip_len: usize = undefined;
...@@ -379,8 +391,7 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module {...@@ -379,8 +391,7 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module {
379}391}
380392
381pub fn getStreamById(self: *Pdb, id: u32) ?*MsfStream {393pub fn getStreamById(self: *Pdb, id: u32) ?*MsfStream {
382 if (id >= self.msf.streams.len)394 if (id >= self.msf.streams.len) return null;
383 return null;
384 return &self.msf.streams[id];395 return &self.msf.streams[id];
385}396}
386397
...@@ -394,17 +405,14 @@ const Msf = struct {...@@ -394,17 +405,14 @@ const Msf = struct {
394 directory: MsfStream,405 directory: MsfStream,
395 streams: []MsfStream,406 streams: []MsfStream,
396407
397 fn init(allocator: Allocator, file: File) !Msf {408 fn init(gpa: Allocator, file_reader: *File.Reader) !Msf {
398 const in = file.deprecatedReader();409 const superblock = try file_reader.interface.takeStruct(pdb.SuperBlock, .little);
399
400 const superblock = try in.readStruct(pdb.SuperBlock);
401410
402 // Sanity checks
403 if (!std.mem.eql(u8, &superblock.file_magic, pdb.SuperBlock.expect_magic))411 if (!std.mem.eql(u8, &superblock.file_magic, pdb.SuperBlock.expect_magic))
404 return error.InvalidDebugInfo;412 return error.InvalidDebugInfo;
405 if (superblock.free_block_map_block != 1 and superblock.free_block_map_block != 2)413 if (superblock.free_block_map_block != 1 and superblock.free_block_map_block != 2)
406 return error.InvalidDebugInfo;414 return error.InvalidDebugInfo;
407 const file_len = try file.getEndPos();415 const file_len = try file_reader.getSize();
408 if (superblock.num_blocks * superblock.block_size != file_len)416 if (superblock.num_blocks * superblock.block_size != file_len)
409 return error.InvalidDebugInfo;417 return error.InvalidDebugInfo;
410 switch (superblock.block_size) {418 switch (superblock.block_size) {
...@@ -417,163 +425,182 @@ const Msf = struct {...@@ -417,163 +425,182 @@ const Msf = struct {
417 if (dir_block_count > superblock.block_size / @sizeOf(u32))425 if (dir_block_count > superblock.block_size / @sizeOf(u32))
418 return error.UnhandledBigDirectoryStream; // cf. BlockMapAddr comment.426 return error.UnhandledBigDirectoryStream; // cf. BlockMapAddr comment.
419427
420 try file.seekTo(superblock.block_size * superblock.block_map_addr);428 try file_reader.seekTo(superblock.block_size * superblock.block_map_addr);
421 const dir_blocks = try allocator.alloc(u32, dir_block_count);429 const dir_blocks = try gpa.alloc(u32, dir_block_count);
422 for (dir_blocks) |*b| {430 for (dir_blocks) |*b| {
423 b.* = try in.readInt(u32, .little);431 b.* = try file_reader.interface.takeInt(u32, .little);
424 }432 }
425 var directory = MsfStream.init(433 var directory_buffer: [64]u8 = undefined;
426 superblock.block_size,434 var directory = MsfStream.init(superblock.block_size, file_reader, dir_blocks, &directory_buffer);
427 file,
428 dir_blocks,
429 );
430435
431 const begin = directory.pos;436 const begin = directory.logicalPos();
432 const stream_count = try directory.reader().readInt(u32, .little);437 const stream_count = try directory.interface.takeInt(u32, .little);
433 const stream_sizes = try allocator.alloc(u32, stream_count);438 const stream_sizes = try gpa.alloc(u32, stream_count);
434 defer allocator.free(stream_sizes);439 defer gpa.free(stream_sizes);
435440
436 // Microsoft's implementation uses @as(u32, -1) for inexistent streams.441 // Microsoft's implementation uses @as(u32, -1) for inexistent streams.
437 // These streams are not used, but still participate in the file442 // These streams are not used, but still participate in the file
438 // and must be taken into account when resolving stream indices.443 // and must be taken into account when resolving stream indices.
439 const Nil = 0xFFFFFFFF;444 const nil_size = 0xFFFFFFFF;
440 for (stream_sizes) |*s| {445 for (stream_sizes) |*s| {
441 const size = try directory.reader().readInt(u32, .little);446 const size = try directory.interface.takeInt(u32, .little);
442 s.* = if (size == Nil) 0 else blockCountFromSize(size, superblock.block_size);447 s.* = if (size == nil_size) 0 else blockCountFromSize(size, superblock.block_size);
443 }448 }
444449
445 const streams = try allocator.alloc(MsfStream, stream_count);450 const streams = try gpa.alloc(MsfStream, stream_count);
451 errdefer gpa.free(streams);
452
446 for (streams, 0..) |*stream, i| {453 for (streams, 0..) |*stream, i| {
447 const size = stream_sizes[i];454 const size = stream_sizes[i];
448 if (size == 0) {455 if (size == 0) {
449 stream.* = MsfStream{456 stream.* = .empty;
450 .blocks = &[_]u32{},
451 };
452 } else {457 } else {
453 var blocks = try allocator.alloc(u32, size);458 const blocks = try gpa.alloc(u32, size);
454 var j: u32 = 0;459 errdefer gpa.free(blocks);
455 while (j < size) : (j += 1) {460 for (blocks) |*block| {
456 const block_id = try directory.reader().readInt(u32, .little);461 const block_id = try directory.interface.takeInt(u32, .little);
457 const n = (block_id % superblock.block_size);462 const n = (block_id % superblock.block_size);
458 // 0 is for pdb.SuperBlock, 1 and 2 for FPMs.463 // 0 is for pdb.SuperBlock, 1 and 2 for FPMs.
459 if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.block_size > file_len)464 if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.block_size > file_len)
460 return error.InvalidBlockIndex;465 return error.InvalidBlockIndex;
461 blocks[j] = block_id;466 block.* = block_id;
462 }467 }
463468 const buffer = try gpa.alloc(u8, 64);
464 stream.* = MsfStream.init(469 errdefer gpa.free(buffer);
465 superblock.block_size,470 stream.* = .init(superblock.block_size, file_reader, blocks, buffer);
466 file,
467 blocks,
468 );
469 }471 }
470 }472 }
471473
472 const end = directory.pos;474 const end = directory.logicalPos();
473 if (end - begin != superblock.num_directory_bytes)475 if (end - begin != superblock.num_directory_bytes)
474 return error.InvalidStreamDirectory;476 return error.InvalidStreamDirectory;
475477
476 return Msf{478 return .{
477 .directory = directory,479 .directory = directory,
478 .streams = streams,480 .streams = streams,
479 };481 };
480 }482 }
481483
482 fn deinit(self: *Msf, allocator: Allocator) void {484 fn deinit(self: *Msf, gpa: Allocator) void {
483 allocator.free(self.directory.blocks);485 gpa.free(self.directory.blocks);
484 for (self.streams) |*stream| {486 for (self.streams) |*stream| {
485 allocator.free(stream.blocks);487 gpa.free(stream.interface.buffer);
488 gpa.free(stream.blocks);
486 }489 }
487 allocator.free(self.streams);490 gpa.free(self.streams);
488 }491 }
489};492};
490493
491const MsfStream = struct {494const MsfStream = struct {
492 in_file: File = undefined,495 file_reader: *File.Reader,
493 pos: u64 = undefined,496 next_read_pos: u64,
494 blocks: []u32 = undefined,497 blocks: []u32,
495 block_size: u32 = undefined,498 block_size: u32,
496499 interface: std.Io.Reader,
497 pub const Error = @typeInfo(@typeInfo(@TypeOf(read)).@"fn".return_type.?).error_union.error_set;500 err: ?Error,
501
502 const Error = File.Reader.SeekError;
503
504 const empty: MsfStream = .{
505 .file_reader = undefined,
506 .next_read_pos = 0,
507 .blocks = &.{},
508 .block_size = undefined,
509 .interface = .ending_instance,
510 .err = null,
511 };
498512
499 fn init(block_size: u32, file: File, blocks: []u32) MsfStream {513 fn init(block_size: u32, file_reader: *File.Reader, blocks: []u32, buffer: []u8) MsfStream {
500 const stream = MsfStream{514 return .{
501 .in_file = file,515 .file_reader = file_reader,
502 .pos = 0,516 .next_read_pos = 0,
503 .blocks = blocks,517 .blocks = blocks,
504 .block_size = block_size,518 .block_size = block_size,
519 .interface = .{
520 .vtable = &.{ .stream = stream },
521 .buffer = buffer,
522 .seek = 0,
523 .end = 0,
524 },
525 .err = null,
505 };526 };
506
507 return stream;
508 }527 }
509528
510 fn read(self: *MsfStream, buffer: []u8) !usize {529 fn stream(r: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize {
511 var block_id = @as(usize, @intCast(self.pos / self.block_size));530 const ms: *MsfStream = @alignCast(@fieldParentPtr("interface", r));
512 if (block_id >= self.blocks.len) return 0; // End of Stream
513 var block = self.blocks[block_id];
514 var offset = self.pos % self.block_size;
515531
516 try self.in_file.seekTo(block * self.block_size + offset);532 var block_id: usize = @intCast(ms.next_read_pos / ms.block_size);
517 const in = self.in_file.deprecatedReader();533 if (block_id >= ms.blocks.len) return error.EndOfStream;
534 var block = ms.blocks[block_id];
535 var offset = ms.next_read_pos % ms.block_size;
518536
519 var size: usize = 0;537 ms.file_reader.seekTo(block * ms.block_size + offset) catch |err| {
520 var rem_buffer = buffer;538 ms.err = err;
521 while (size < buffer.len) {539 return error.ReadFailed;
522 const size_to_read = @min(self.block_size - offset, rem_buffer.len);540 };
523 size += try in.read(rem_buffer[0..size_to_read]);541
524 rem_buffer = buffer[size..];542 var remaining = @intFromEnum(limit);
525 offset += size_to_read;543 while (remaining != 0) {
544 const stream_len: usize = @min(remaining, ms.block_size - offset);
545 const n = try ms.file_reader.interface.stream(w, .limited(stream_len));
546 remaining -= n;
547 offset += n;
526548
527 // If we're at the end of a block, go to the next one.549 // If we're at the end of a block, go to the next one.
528 if (offset == self.block_size) {550 if (offset == ms.block_size) {
529 offset = 0;551 offset = 0;
530 block_id += 1;552 block_id += 1;
531 if (block_id >= self.blocks.len) break; // End of Stream553 if (block_id >= ms.blocks.len) break; // End of Stream
532 block = self.blocks[block_id];554 block = ms.blocks[block_id];
533 try self.in_file.seekTo(block * self.block_size);555 ms.file_reader.seekTo(block * ms.block_size) catch |err| {
556 ms.err = err;
557 return error.ReadFailed;
558 };
534 }559 }
535 }560 }
536561
537 self.pos += buffer.len;562 const total = @intFromEnum(limit) - remaining;
538 return buffer.len;563 ms.next_read_pos += total;
564 return total;
539 }565 }
540566
541 pub fn seekBy(self: *MsfStream, len: i64) !void {567 pub fn logicalPos(ms: *const MsfStream) u64 {
542 self.pos = @as(u64, @intCast(@as(i64, @intCast(self.pos)) + len));568 return ms.next_read_pos - ms.interface.bufferedLen();
543 if (self.pos >= self.blocks.len * self.block_size)
544 return error.EOF;
545 }569 }
546570
547 pub fn seekTo(self: *MsfStream, len: u64) !void {571 pub fn seekBy(ms: *MsfStream, len: i64) !void {
548 self.pos = len;572 ms.next_read_pos = @as(u64, @intCast(@as(i64, @intCast(ms.logicalPos())) + len));
549 if (self.pos >= self.blocks.len * self.block_size)573 if (ms.next_read_pos >= ms.blocks.len * ms.block_size) return error.EOF;
550 return error.EOF;574 ms.interface.tossBuffered();
551 }575 }
552576
553 fn getSize(self: *const MsfStream) u64 {577 pub fn seekTo(ms: *MsfStream, len: u64) !void {
554 return self.blocks.len * self.block_size;578 ms.next_read_pos = len;
579 if (ms.next_read_pos >= ms.blocks.len * ms.block_size) return error.EOF;
580 ms.interface.tossBuffered();
555 }581 }
556582
557 fn getFilePos(self: MsfStream) u64 {583 fn getSize(ms: *const MsfStream) u64 {
558 const block_id = self.pos / self.block_size;584 return ms.blocks.len * ms.block_size;
559 const block = self.blocks[block_id];
560 const offset = self.pos % self.block_size;
561
562 return block * self.block_size + offset;
563 }585 }
564586
565 pub fn reader(self: *MsfStream) std.io.GenericReader(*MsfStream, Error, read) {587 fn getFilePos(ms: *const MsfStream) u64 {
566 return .{ .context = self };588 const pos = ms.logicalPos();
589 const block_id = pos / ms.block_size;
590 const block = ms.blocks[block_id];
591 const offset = pos % ms.block_size;
592
593 return block * ms.block_size + offset;
567 }594 }
568};595};
569596
570fn readSparseBitVector(stream: anytype, allocator: Allocator) ![]u32 {597fn readSparseBitVector(reader: *std.Io.Reader, allocator: Allocator) ![]u32 {
571 const num_words = try stream.readInt(u32, .little);598 const num_words = try reader.takeInt(u32, .little);
572 var list = std.array_list.Managed(u32).init(allocator);599 var list = std.array_list.Managed(u32).init(allocator);
573 errdefer list.deinit();600 errdefer list.deinit();
574 var word_i: u32 = 0;601 var word_i: u32 = 0;
575 while (word_i != num_words) : (word_i += 1) {602 while (word_i != num_words) : (word_i += 1) {
576 const word = try stream.readInt(u32, .little);603 const word = try reader.takeInt(u32, .little);
577 var bit_i: u5 = 0;604 var bit_i: u5 = 0;
578 while (true) : (bit_i += 1) {605 while (true) : (bit_i += 1) {
579 if (word & (@as(u32, 1) << bit_i) != 0) {606 if (word & (@as(u32, 1) << bit_i) != 0) {
lib/std/debug/SelfInfo.zig+34-17
...@@ -713,22 +713,26 @@ pub const Module = switch (native_os) {...@@ -713,22 +713,26 @@ pub const Module = switch (native_os) {
713 },713 },
714 .uefi, .windows => struct {714 .uefi, .windows => struct {
715 base_address: usize,715 base_address: usize,
716 pdb: ?Pdb = null,716 pdb: ?Pdb,
717 dwarf: ?Dwarf = null,717 dwarf: ?Dwarf,
718 coff_image_base: u64,718 coff_image_base: u64,
719719
720 /// Only used if pdb is non-null720 /// Only used if pdb is non-null
721 coff_section_headers: []coff.SectionHeader,721 coff_section_headers: []coff.SectionHeader,
722722
723 pub fn deinit(self: *@This(), allocator: Allocator) void {723 pub fn deinit(self: *@This(), gpa: Allocator) void {
724 if (self.dwarf) |*dwarf| {724 if (self.dwarf) |*dwarf| {
725 dwarf.deinit(allocator);725 dwarf.deinit(gpa);
726 }726 }
727727
728 if (self.pdb) |*p| {728 if (self.pdb) |*p| {
729 gpa.free(p.file_reader.interface.buffer);
730 gpa.destroy(p.file_reader);
729 p.deinit();731 p.deinit();
730 allocator.free(self.coff_section_headers);732 gpa.free(self.coff_section_headers);
731 }733 }
734
735 self.* = undefined;
732 }736 }
733737
734 fn getSymbolFromPdb(self: *@This(), relocated_address: usize) !?std.debug.Symbol {738 fn getSymbolFromPdb(self: *@This(), relocated_address: usize) !?std.debug.Symbol {
...@@ -970,23 +974,25 @@ fn readMachODebugInfo(allocator: Allocator, macho_file: File) !Module {...@@ -970,23 +974,25 @@ fn readMachODebugInfo(allocator: Allocator, macho_file: File) !Module {
970 };974 };
971}975}
972976
973fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {977fn readCoffDebugInfo(gpa: Allocator, coff_obj: *coff.Coff) !Module {
974 nosuspend {978 nosuspend {
975 var di: Module = .{979 var di: Module = .{
976 .base_address = undefined,980 .base_address = undefined,
977 .coff_image_base = coff_obj.getImageBase(),981 .coff_image_base = coff_obj.getImageBase(),
978 .coff_section_headers = undefined,982 .coff_section_headers = undefined,
983 .pdb = null,
984 .dwarf = null,
979 };985 };
980986
981 if (coff_obj.getSectionByName(".debug_info")) |_| {987 if (coff_obj.getSectionByName(".debug_info")) |_| {
982 // This coff file has embedded DWARF debug info988 // This coff file has embedded DWARF debug info
983 var sections: Dwarf.SectionArray = Dwarf.null_section_array;989 var sections: Dwarf.SectionArray = Dwarf.null_section_array;
984 errdefer for (sections) |section| if (section) |s| if (s.owned) allocator.free(s.data);990 errdefer for (sections) |section| if (section) |s| if (s.owned) gpa.free(s.data);
985991
986 inline for (@typeInfo(Dwarf.Section.Id).@"enum".fields, 0..) |section, i| {992 inline for (@typeInfo(Dwarf.Section.Id).@"enum".fields, 0..) |section, i| {
987 sections[i] = if (coff_obj.getSectionByName("." ++ section.name)) |section_header| blk: {993 sections[i] = if (coff_obj.getSectionByName("." ++ section.name)) |section_header| blk: {
988 break :blk .{994 break :blk .{
989 .data = try coff_obj.getSectionDataAlloc(section_header, allocator),995 .data = try coff_obj.getSectionDataAlloc(section_header, gpa),
990 .virtual_address = section_header.virtual_address,996 .virtual_address = section_header.virtual_address,
991 .owned = true,997 .owned = true,
992 };998 };
...@@ -999,7 +1005,7 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {...@@ -999,7 +1005,7 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {
999 .is_macho = false,1005 .is_macho = false,
1000 };1006 };
10011007
1002 try Dwarf.open(&dwarf, allocator);1008 try Dwarf.open(&dwarf, gpa);
1003 di.dwarf = dwarf;1009 di.dwarf = dwarf;
1004 }1010 }
10051011
...@@ -1008,20 +1014,31 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {...@@ -1008,20 +1014,31 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {
1008 if (fs.path.isAbsolute(raw_path)) {1014 if (fs.path.isAbsolute(raw_path)) {
1009 break :blk raw_path;1015 break :blk raw_path;
1010 } else {1016 } else {
1011 const self_dir = try fs.selfExeDirPathAlloc(allocator);1017 const self_dir = try fs.selfExeDirPathAlloc(gpa);
1012 defer allocator.free(self_dir);1018 defer gpa.free(self_dir);
1013 break :blk try fs.path.join(allocator, &.{ self_dir, raw_path });1019 break :blk try fs.path.join(gpa, &.{ self_dir, raw_path });
1014 }1020 }
1015 };1021 };
1016 defer if (path.ptr != raw_path.ptr) allocator.free(path);1022 defer if (path.ptr != raw_path.ptr) gpa.free(path);
10171023
1018 di.pdb = Pdb.init(allocator, path) catch |err| switch (err) {1024 const pdb_file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {
1019 error.FileNotFound, error.IsDir => {1025 error.FileNotFound, error.IsDir => {
1020 if (di.dwarf == null) return error.MissingDebugInfo;1026 if (di.dwarf == null) return error.MissingDebugInfo;
1021 return di;1027 return di;
1022 },1028 },
1023 else => return err,1029 else => |e| return e,
1024 };1030 };
1031 errdefer pdb_file.close();
1032
1033 const pdb_file_reader_buffer = try gpa.alloc(u8, 4096);
1034 errdefer gpa.free(pdb_file_reader_buffer);
1035
1036 const pdb_file_reader = try gpa.create(File.Reader);
1037 errdefer gpa.destroy(pdb_file_reader);
1038
1039 pdb_file_reader.* = pdb_file.reader(pdb_file_reader_buffer);
1040
1041 di.pdb = try Pdb.init(gpa, pdb_file_reader);
1025 try di.pdb.?.parseInfoStream();1042 try di.pdb.?.parseInfoStream();
1026 try di.pdb.?.parseDbiStream();1043 try di.pdb.?.parseDbiStream();
10271044
...@@ -1029,8 +1046,8 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {...@@ -1029,8 +1046,8 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {
1029 return error.InvalidDebugInfo;1046 return error.InvalidDebugInfo;
10301047
1031 // Only used by the pdb path1048 // Only used by the pdb path
1032 di.coff_section_headers = try coff_obj.getSectionHeadersAlloc(allocator);1049 di.coff_section_headers = try coff_obj.getSectionHeadersAlloc(gpa);
1033 errdefer allocator.free(di.coff_section_headers);1050 errdefer gpa.free(di.coff_section_headers);
10341051
1035 return di;1052 return di;
1036 }1053 }
lib/std/fs/File.zig-8
...@@ -1097,14 +1097,6 @@ pub fn deprecatedReader(file: File) DeprecatedReader {...@@ -1097,14 +1097,6 @@ pub fn deprecatedReader(file: File) DeprecatedReader {
1097 return .{ .context = file };1097 return .{ .context = file };
1098}1098}
10991099
1100/// Deprecated in favor of `Writer`.
1101pub const DeprecatedWriter = io.GenericWriter(File, WriteError, write);
1102
1103/// Deprecated in favor of `Writer`.
1104pub fn deprecatedWriter(file: File) DeprecatedWriter {
1105 return .{ .context = file };
1106}
1107
1108/// Memoizes key information about a file handle such as:1100/// Memoizes key information about a file handle such as:
1109/// * The size from calling stat, or the error that occurred therein.1101/// * The size from calling stat, or the error that occurred therein.
1110/// * The current seek position.1102/// * The current seek position.
lib/std/json.zig+1-1
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
6//! The high-level `parseFromSlice` and `parseFromTokenSource` deserialize a JSON document into a Zig type.6//! The high-level `parseFromSlice` and `parseFromTokenSource` deserialize a JSON document into a Zig type.
7//! Parse into a dynamically-typed `Value` to load any JSON value for runtime inspection.7//! Parse into a dynamically-typed `Value` to load any JSON value for runtime inspection.
8//!8//!
9//! The low-level `writeStream` emits syntax-conformant JSON tokens to a `std.io.GenericWriter`.9//! The low-level `writeStream` emits syntax-conformant JSON tokens to a `std.Io.Writer`.
10//! The high-level `stringify` serializes a Zig or `Value` type into JSON.10//! The high-level `stringify` serializes a Zig or `Value` type into JSON.
1111
12const builtin = @import("builtin");12const builtin = @import("builtin");
lib/std/leb128.zig-103
...@@ -33,28 +33,6 @@ pub fn readUleb128(comptime T: type, reader: anytype) !T {...@@ -33,28 +33,6 @@ pub fn readUleb128(comptime T: type, reader: anytype) !T {
33 return @as(T, @truncate(value));33 return @as(T, @truncate(value));
34}34}
3535
36/// Write a single unsigned integer as unsigned LEB128 to the given writer.
37pub fn writeUleb128(writer: anytype, arg: anytype) !void {
38 const Arg = @TypeOf(arg);
39 const Int = switch (Arg) {
40 comptime_int => std.math.IntFittingRange(arg, arg),
41 else => Arg,
42 };
43 const Value = if (@typeInfo(Int).int.bits < 8) u8 else Int;
44 var value: Value = arg;
45
46 while (true) {
47 const byte: u8 = @truncate(value & 0x7f);
48 value >>= 7;
49 if (value == 0) {
50 try writer.writeByte(byte);
51 break;
52 } else {
53 try writer.writeByte(byte | 0x80);
54 }
55 }
56}
57
58/// Read a single signed LEB128 value from the given reader as type T,36/// Read a single signed LEB128 value from the given reader as type T,
59/// or error.Overflow if the value cannot fit.37/// or error.Overflow if the value cannot fit.
60pub fn readIleb128(comptime T: type, reader: anytype) !T {38pub fn readIleb128(comptime T: type, reader: anytype) !T {
...@@ -374,84 +352,3 @@ test "deserialize unsigned LEB128" {...@@ -374,84 +352,3 @@ test "deserialize unsigned LEB128" {
374 // Decode sequence of ULEB128 values352 // Decode sequence of ULEB128 values
375 try test_read_uleb128_seq(u64, 4, "\x81\x01\x3f\x80\x7f\x80\x80\x80\x00");353 try test_read_uleb128_seq(u64, 4, "\x81\x01\x3f\x80\x7f\x80\x80\x80\x00");
376}354}
377
378fn test_write_leb128(value: anytype) !void {
379 const T = @TypeOf(value);
380 const signedness = @typeInfo(T).int.signedness;
381 const t_signed = signedness == .signed;
382
383 const writeStream = if (t_signed) writeIleb128 else writeUleb128;
384 const readStream = if (t_signed) readIleb128 else readUleb128;
385
386 // decode to a larger bit size too, to ensure sign extension
387 // is working as expected
388 const larger_type_bits = ((@typeInfo(T).int.bits + 8) / 8) * 8;
389 const B = std.meta.Int(signedness, larger_type_bits);
390
391 const bytes_needed = bn: {
392 if (@typeInfo(T).int.bits <= 7) break :bn @as(u16, 1);
393
394 const unused_bits = if (value < 0) @clz(~value) else @clz(value);
395 const used_bits: u16 = (@typeInfo(T).int.bits - unused_bits) + @intFromBool(t_signed);
396 if (used_bits <= 7) break :bn @as(u16, 1);
397 break :bn ((used_bits + 6) / 7);
398 };
399
400 const max_groups = if (@typeInfo(T).int.bits == 0) 1 else (@typeInfo(T).int.bits + 6) / 7;
401
402 var buf: [max_groups]u8 = undefined;
403 var fbs = std.io.fixedBufferStream(&buf);
404
405 // stream write
406 try writeStream(fbs.writer(), value);
407 const w1_pos = fbs.pos;
408 try testing.expect(w1_pos == bytes_needed);
409
410 // stream read
411 fbs.pos = 0;
412 const sr = try readStream(T, fbs.reader());
413 try testing.expect(fbs.pos == w1_pos);
414 try testing.expect(sr == value);
415
416 // bigger type stream read
417 fbs.pos = 0;
418 const bsr = try readStream(B, fbs.reader());
419 try testing.expect(fbs.pos == w1_pos);
420 try testing.expect(bsr == value);
421}
422
423test "serialize unsigned LEB128" {
424 if (builtin.cpu.arch == .x86 and builtin.abi == .musl and builtin.link_mode == .dynamic) return error.SkipZigTest;
425
426 const max_bits = 18;
427
428 comptime var t = 0;
429 inline while (t <= max_bits) : (t += 1) {
430 const T = std.meta.Int(.unsigned, t);
431 const min = std.math.minInt(T);
432 const max = std.math.maxInt(T);
433 var i = @as(std.meta.Int(.unsigned, @typeInfo(T).int.bits + 1), min);
434
435 while (i <= max) : (i += 1) try test_write_leb128(@as(T, @intCast(i)));
436 }
437}
438
439test "serialize signed LEB128" {
440 if (builtin.cpu.arch == .x86 and builtin.abi == .musl and builtin.link_mode == .dynamic) return error.SkipZigTest;
441
442 // explicitly test i0 because starting `t` at 0
443 // will break the while loop
444 try test_write_leb128(@as(i0, 0));
445
446 const max_bits = 18;
447
448 comptime var t = 1;
449 inline while (t <= max_bits) : (t += 1) {
450 const T = std.meta.Int(.signed, t);
451 const min = std.math.minInt(T);
452 const max = std.math.maxInt(T);
453 var i = @as(std.meta.Int(.signed, @typeInfo(T).int.bits + 1), min);
454
455 while (i <= max) : (i += 1) try test_write_leb128(@as(T, @intCast(i)));
456 }
457}
lib/std/macho.zig-2
...@@ -1883,10 +1883,8 @@ pub const GenericBlob = extern struct {...@@ -1883,10 +1883,8 @@ pub const GenericBlob = extern struct {
1883pub const data_in_code_entry = extern struct {1883pub const data_in_code_entry = extern struct {
1884 /// From mach_header to start of data range.1884 /// From mach_header to start of data range.
1885 offset: u32,1885 offset: u32,
1886
1887 /// Number of bytes in data range.1886 /// Number of bytes in data range.
1888 length: u16,1887 length: u16,
1889
1890 /// A DICE_KIND value.1888 /// A DICE_KIND value.
1891 kind: u16,1889 kind: u16,
1892};1890};
lib/std/posix/test.zig+2-2
...@@ -683,11 +683,11 @@ test "mmap" {...@@ -683,11 +683,11 @@ test "mmap" {
683 const file = try tmp.dir.createFile(test_out_file, .{});683 const file = try tmp.dir.createFile(test_out_file, .{});
684 defer file.close();684 defer file.close();
685685
686 const stream = file.deprecatedWriter();686 var stream = file.writer(&.{});
687687
688 var i: u32 = 0;688 var i: u32 = 0;
689 while (i < alloc_size / @sizeOf(u32)) : (i += 1) {689 while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
690 try stream.writeInt(u32, i, .little);690 try stream.interface.writeInt(u32, i, .little);
691 }691 }
692 }692 }
693693
lib/std/tz.zig+45-44
...@@ -1,6 +1,12 @@...@@ -1,6 +1,12 @@
1const std = @import("std.zig");1//! The Time Zone Information Format (TZif)
2//! https://datatracker.ietf.org/doc/html/rfc8536
3
2const builtin = @import("builtin");4const builtin = @import("builtin");
35
6const std = @import("std.zig");
7const Reader = std.Io.Reader;
8const Allocator = std.mem.Allocator;
9
4pub const Transition = struct {10pub const Transition = struct {
5 ts: i64,11 ts: i64,
6 timetype: *Timetype,12 timetype: *Timetype,
...@@ -34,7 +40,7 @@ pub const Leapsecond = struct {...@@ -34,7 +40,7 @@ pub const Leapsecond = struct {
34};40};
3541
36pub const Tz = struct {42pub const Tz = struct {
37 allocator: std.mem.Allocator,43 allocator: Allocator,
38 transitions: []const Transition,44 transitions: []const Transition,
39 timetypes: []const Timetype,45 timetypes: []const Timetype,
40 leapseconds: []const Leapsecond,46 leapseconds: []const Leapsecond,
...@@ -54,34 +60,30 @@ pub const Tz = struct {...@@ -54,34 +60,30 @@ pub const Tz = struct {
54 },60 },
55 };61 };
5662
57 pub fn parse(allocator: std.mem.Allocator, reader: anytype) !Tz {63 pub fn parse(allocator: Allocator, reader: *Reader) !Tz {
58 var legacy_header = try reader.readStruct(Header);64 const legacy_header = try reader.takeStruct(Header, .big);
59 if (!std.mem.eql(u8, &legacy_header.magic, "TZif")) return error.BadHeader;65 if (!std.mem.eql(u8, &legacy_header.magic, "TZif")) return error.BadHeader;
60 if (legacy_header.version != 0 and legacy_header.version != '2' and legacy_header.version != '3') return error.BadVersion;66 if (legacy_header.version != 0 and legacy_header.version != '2' and legacy_header.version != '3')
6167 return error.BadVersion;
62 if (builtin.target.cpu.arch.endian() != std.builtin.Endian.big) {
63 std.mem.byteSwapAllFields(@TypeOf(legacy_header.counts), &legacy_header.counts);
64 }
6568
66 if (legacy_header.version == 0) {69 if (legacy_header.version == 0)
67 return parseBlock(allocator, reader, legacy_header, true);70 return parseBlock(allocator, reader, legacy_header, true);
68 } else {
69 // If the format is modern, just skip over the legacy data
70 const skipv = legacy_header.counts.timecnt * 5 + legacy_header.counts.typecnt * 6 + legacy_header.counts.charcnt + legacy_header.counts.leapcnt * 8 + legacy_header.counts.isstdcnt + legacy_header.counts.isutcnt;
71 try reader.skipBytes(skipv, .{});
72
73 var header = try reader.readStruct(Header);
74 if (!std.mem.eql(u8, &header.magic, "TZif")) return error.BadHeader;
75 if (header.version != '2' and header.version != '3') return error.BadVersion;
76 if (builtin.target.cpu.arch.endian() != std.builtin.Endian.big) {
77 std.mem.byteSwapAllFields(@TypeOf(header.counts), &header.counts);
78 }
7971
80 return parseBlock(allocator, reader, header, false);72 // If the format is modern, just skip over the legacy data
81 }73 const skip_n = legacy_header.counts.timecnt * 5 +
74 legacy_header.counts.typecnt * 6 +
75 legacy_header.counts.charcnt + legacy_header.counts.leapcnt * 8 +
76 legacy_header.counts.isstdcnt + legacy_header.counts.isutcnt;
77 try reader.discardAll(skip_n);
78
79 var header = try reader.takeStruct(Header, .big);
80 if (!std.mem.eql(u8, &header.magic, "TZif")) return error.BadHeader;
81 if (header.version != '2' and header.version != '3') return error.BadVersion;
82
83 return parseBlock(allocator, reader, header, false);
82 }84 }
8385
84 fn parseBlock(allocator: std.mem.Allocator, reader: anytype, header: Header, legacy: bool) !Tz {86 fn parseBlock(allocator: Allocator, reader: *Reader, header: Header, legacy: bool) !Tz {
85 if (header.counts.isstdcnt != 0 and header.counts.isstdcnt != header.counts.typecnt) return error.Malformed; // rfc8536: isstdcnt [...] MUST either be zero or equal to "typecnt"87 if (header.counts.isstdcnt != 0 and header.counts.isstdcnt != header.counts.typecnt) return error.Malformed; // rfc8536: isstdcnt [...] MUST either be zero or equal to "typecnt"
86 if (header.counts.isutcnt != 0 and header.counts.isutcnt != header.counts.typecnt) return error.Malformed; // rfc8536: isutcnt [...] MUST either be zero or equal to "typecnt"88 if (header.counts.isutcnt != 0 and header.counts.isutcnt != header.counts.typecnt) return error.Malformed; // rfc8536: isutcnt [...] MUST either be zero or equal to "typecnt"
87 if (header.counts.typecnt == 0) return error.Malformed; // rfc8536: typecnt [...] MUST NOT be zero89 if (header.counts.typecnt == 0) return error.Malformed; // rfc8536: typecnt [...] MUST NOT be zero
...@@ -98,12 +100,12 @@ pub const Tz = struct {...@@ -98,12 +100,12 @@ pub const Tz = struct {
98 // Parse transition types100 // Parse transition types
99 var i: usize = 0;101 var i: usize = 0;
100 while (i < header.counts.timecnt) : (i += 1) {102 while (i < header.counts.timecnt) : (i += 1) {
101 transitions[i].ts = if (legacy) try reader.readInt(i32, .big) else try reader.readInt(i64, .big);103 transitions[i].ts = if (legacy) try reader.takeInt(i32, .big) else try reader.takeInt(i64, .big);
102 }104 }
103105
104 i = 0;106 i = 0;
105 while (i < header.counts.timecnt) : (i += 1) {107 while (i < header.counts.timecnt) : (i += 1) {
106 const tt = try reader.readByte();108 const tt = try reader.takeByte();
107 if (tt >= timetypes.len) return error.Malformed; // rfc8536: Each type index MUST be in the range [0, "typecnt" - 1]109 if (tt >= timetypes.len) return error.Malformed; // rfc8536: Each type index MUST be in the range [0, "typecnt" - 1]
108 transitions[i].timetype = &timetypes[tt];110 transitions[i].timetype = &timetypes[tt];
109 }111 }
...@@ -111,11 +113,11 @@ pub const Tz = struct {...@@ -111,11 +113,11 @@ pub const Tz = struct {
111 // Parse time types113 // Parse time types
112 i = 0;114 i = 0;
113 while (i < header.counts.typecnt) : (i += 1) {115 while (i < header.counts.typecnt) : (i += 1) {
114 const offset = try reader.readInt(i32, .big);116 const offset = try reader.takeInt(i32, .big);
115 if (offset < -2147483648) return error.Malformed; // rfc8536: utoff [...] MUST NOT be -2**31117 if (offset < -2147483648) return error.Malformed; // rfc8536: utoff [...] MUST NOT be -2**31
116 const dst = try reader.readByte();118 const dst = try reader.takeByte();
117 if (dst != 0 and dst != 1) return error.Malformed; // rfc8536: (is)dst [...] The value MUST be 0 or 1.119 if (dst != 0 and dst != 1) return error.Malformed; // rfc8536: (is)dst [...] The value MUST be 0 or 1.
118 const idx = try reader.readByte();120 const idx = try reader.takeByte();
119 if (idx > header.counts.charcnt - 1) return error.Malformed; // rfc8536: (desig)idx [...] Each index MUST be in the range [0, "charcnt" - 1]121 if (idx > header.counts.charcnt - 1) return error.Malformed; // rfc8536: (desig)idx [...] Each index MUST be in the range [0, "charcnt" - 1]
120 timetypes[i] = .{122 timetypes[i] = .{
121 .offset = offset,123 .offset = offset,
...@@ -128,7 +130,7 @@ pub const Tz = struct {...@@ -128,7 +130,7 @@ pub const Tz = struct {
128 }130 }
129131
130 var designators_data: [256 + 6]u8 = undefined;132 var designators_data: [256 + 6]u8 = undefined;
131 try reader.readNoEof(designators_data[0..header.counts.charcnt]);133 try reader.readSliceAll(designators_data[0..header.counts.charcnt]);
132 const designators = designators_data[0..header.counts.charcnt];134 const designators = designators_data[0..header.counts.charcnt];
133 if (designators[designators.len - 1] != 0) return error.Malformed; // rfc8536: charcnt [...] includes the trailing NUL (0x00) octet135 if (designators[designators.len - 1] != 0) return error.Malformed; // rfc8536: charcnt [...] includes the trailing NUL (0x00) octet
134136
...@@ -144,12 +146,12 @@ pub const Tz = struct {...@@ -144,12 +146,12 @@ pub const Tz = struct {
144 // Parse leap seconds146 // Parse leap seconds
145 i = 0;147 i = 0;
146 while (i < header.counts.leapcnt) : (i += 1) {148 while (i < header.counts.leapcnt) : (i += 1) {
147 const occur: i64 = if (legacy) try reader.readInt(i32, .big) else try reader.readInt(i64, .big);149 const occur: i64 = if (legacy) try reader.takeInt(i32, .big) else try reader.takeInt(i64, .big);
148 if (occur < 0) return error.Malformed; // rfc8536: occur [...] MUST be nonnegative150 if (occur < 0) return error.Malformed; // rfc8536: occur [...] MUST be nonnegative
149 if (i > 0 and leapseconds[i - 1].occurrence + 2419199 > occur) return error.Malformed; // rfc8536: occur [...] each later value MUST be at least 2419199 greater than the previous value151 if (i > 0 and leapseconds[i - 1].occurrence + 2419199 > occur) return error.Malformed; // rfc8536: occur [...] each later value MUST be at least 2419199 greater than the previous value
150 if (occur > std.math.maxInt(i48)) return error.Malformed; // Unreasonably far into the future152 if (occur > std.math.maxInt(i48)) return error.Malformed; // Unreasonably far into the future
151153
152 const corr = try reader.readInt(i32, .big);154 const corr = try reader.takeInt(i32, .big);
153 if (i == 0 and corr != -1 and corr != 1) return error.Malformed; // rfc8536: The correction value in the first leap-second record, if present, MUST be either one (1) or minus one (-1)155 if (i == 0 and corr != -1 and corr != 1) return error.Malformed; // rfc8536: The correction value in the first leap-second record, if present, MUST be either one (1) or minus one (-1)
154 if (i > 0 and leapseconds[i - 1].correction != corr + 1 and leapseconds[i - 1].correction != corr - 1) return error.Malformed; // rfc8536: The correction values in adjacent leap-second records MUST differ by exactly one (1)156 if (i > 0 and leapseconds[i - 1].correction != corr + 1 and leapseconds[i - 1].correction != corr - 1) return error.Malformed; // rfc8536: The correction values in adjacent leap-second records MUST differ by exactly one (1)
155 if (corr > std.math.maxInt(i16)) return error.Malformed; // Unreasonably large correction157 if (corr > std.math.maxInt(i16)) return error.Malformed; // Unreasonably large correction
...@@ -163,7 +165,7 @@ pub const Tz = struct {...@@ -163,7 +165,7 @@ pub const Tz = struct {
163 // Parse standard/wall indicators165 // Parse standard/wall indicators
164 i = 0;166 i = 0;
165 while (i < header.counts.isstdcnt) : (i += 1) {167 while (i < header.counts.isstdcnt) : (i += 1) {
166 const stdtime = try reader.readByte();168 const stdtime = try reader.takeByte();
167 if (stdtime == 1) {169 if (stdtime == 1) {
168 timetypes[i].flags |= 0x02;170 timetypes[i].flags |= 0x02;
169 }171 }
...@@ -172,7 +174,7 @@ pub const Tz = struct {...@@ -172,7 +174,7 @@ pub const Tz = struct {
172 // Parse UT/local indicators174 // Parse UT/local indicators
173 i = 0;175 i = 0;
174 while (i < header.counts.isutcnt) : (i += 1) {176 while (i < header.counts.isutcnt) : (i += 1) {
175 const ut = try reader.readByte();177 const ut = try reader.takeByte();
176 if (ut == 1) {178 if (ut == 1) {
177 timetypes[i].flags |= 0x04;179 timetypes[i].flags |= 0x04;
178 if (!timetypes[i].standardTimeIndicator()) return error.Malformed; // rfc8536: standard/wall value MUST be one (1) if the UT/local value is one (1)180 if (!timetypes[i].standardTimeIndicator()) return error.Malformed; // rfc8536: standard/wall value MUST be one (1) if the UT/local value is one (1)
...@@ -182,9 +184,8 @@ pub const Tz = struct {...@@ -182,9 +184,8 @@ pub const Tz = struct {
182 // Footer184 // Footer
183 var footer: ?[]u8 = null;185 var footer: ?[]u8 = null;
184 if (!legacy) {186 if (!legacy) {
185 if ((try reader.readByte()) != '\n') return error.Malformed; // An rfc8536 footer must start with a newline187 if ((try reader.takeByte()) != '\n') return error.Malformed; // An rfc8536 footer must start with a newline
186 var footerdata_buf: [128]u8 = undefined;188 const footer_mem = reader.takeSentinel('\n') catch |err| switch (err) {
187 const footer_mem = reader.readUntilDelimiter(&footerdata_buf, '\n') catch |err| switch (err) {
188 error.StreamTooLong => return error.OverlargeFooter, // Read more than 128 bytes, much larger than any reasonable POSIX TZ string189 error.StreamTooLong => return error.OverlargeFooter, // Read more than 128 bytes, much larger than any reasonable POSIX TZ string
189 else => return err,190 else => return err,
190 };191 };
...@@ -194,7 +195,7 @@ pub const Tz = struct {...@@ -194,7 +195,7 @@ pub const Tz = struct {
194 }195 }
195 errdefer if (footer) |ft| allocator.free(ft);196 errdefer if (footer) |ft| allocator.free(ft);
196197
197 return Tz{198 return .{
198 .allocator = allocator,199 .allocator = allocator,
199 .transitions = transitions,200 .transitions = transitions,
200 .timetypes = timetypes,201 .timetypes = timetypes,
...@@ -215,9 +216,9 @@ pub const Tz = struct {...@@ -215,9 +216,9 @@ pub const Tz = struct {
215216
216test "slim" {217test "slim" {
217 const data = @embedFile("tz/asia_tokyo.tzif");218 const data = @embedFile("tz/asia_tokyo.tzif");
218 var in_stream = std.io.fixedBufferStream(data);219 var in_stream: Reader = .fixed(data);
219220
220 var tz = try std.Tz.parse(std.testing.allocator, in_stream.reader());221 var tz = try std.Tz.parse(std.testing.allocator, &in_stream);
221 defer tz.deinit();222 defer tz.deinit();
222223
223 try std.testing.expectEqual(tz.transitions.len, 9);224 try std.testing.expectEqual(tz.transitions.len, 9);
...@@ -228,9 +229,9 @@ test "slim" {...@@ -228,9 +229,9 @@ test "slim" {
228229
229test "fat" {230test "fat" {
230 const data = @embedFile("tz/antarctica_davis.tzif");231 const data = @embedFile("tz/antarctica_davis.tzif");
231 var in_stream = std.io.fixedBufferStream(data);232 var in_stream: Reader = .fixed(data);
232233
233 var tz = try std.Tz.parse(std.testing.allocator, in_stream.reader());234 var tz = try std.Tz.parse(std.testing.allocator, &in_stream);
234 defer tz.deinit();235 defer tz.deinit();
235236
236 try std.testing.expectEqual(tz.transitions.len, 8);237 try std.testing.expectEqual(tz.transitions.len, 8);
...@@ -241,9 +242,9 @@ test "fat" {...@@ -241,9 +242,9 @@ test "fat" {
241test "legacy" {242test "legacy" {
242 // Taken from Slackware 8.0, from 2001243 // Taken from Slackware 8.0, from 2001
243 const data = @embedFile("tz/europe_vatican.tzif");244 const data = @embedFile("tz/europe_vatican.tzif");
244 var in_stream = std.io.fixedBufferStream(data);245 var in_stream: Reader = .fixed(data);
245246
246 var tz = try std.Tz.parse(std.testing.allocator, in_stream.reader());247 var tz = try std.Tz.parse(std.testing.allocator, &in_stream);
247 defer tz.deinit();248 defer tz.deinit();
248249
249 try std.testing.expectEqual(tz.transitions.len, 170);250 try std.testing.expectEqual(tz.transitions.len, 170);
src/Compilation.zig+10-9
...@@ -5893,15 +5893,16 @@ fn buildGlibcCrtFile(comp: *Compilation, crt_file: glibc.CrtFile, prog_node: std...@@ -5893,15 +5893,16 @@ fn buildGlibcCrtFile(comp: *Compilation, crt_file: glibc.CrtFile, prog_node: std
58935893
5894fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {5894fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {
5895 defer comp.link_task_queue.finishPrelinkItem(comp);5895 defer comp.link_task_queue.finishPrelinkItem(comp);
5896 if (glibc.buildSharedObjects(comp, prog_node)) |_| {5896 glibc.buildSharedObjects(comp, prog_node) catch unreachable;
5897 // The job should no longer be queued up since it succeeded.5897 //if (glibc.buildSharedObjects(comp, prog_node)) |_| {
5898 comp.queued_jobs.glibc_shared_objects = false;5898 // // The job should no longer be queued up since it succeeded.
5899 } else |err| switch (err) {5899 // comp.queued_jobs.glibc_shared_objects = false;
5900 error.AlreadyReported => return,5900 //} else |err| switch (err) {
5901 else => comp.lockAndSetMiscFailure(.glibc_shared_objects, "unable to build glibc shared objects: {s}", .{5901 // error.AlreadyReported => return,
5902 @errorName(err),5902 // else => comp.lockAndSetMiscFailure(.glibc_shared_objects, "unable to build glibc shared objects: {s}", .{
5903 }),5903 // @errorName(err),
5904 }5904 // }),
5905 //}
5905}5906}
59065907
5907fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node: std.Progress.Node) void {5908fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node: std.Progress.Node) void {
src/IncrementalDebugServer.zig+4-4
...@@ -76,7 +76,9 @@ fn runThread(ids: *IncrementalDebugServer) void {...@@ -76,7 +76,9 @@ fn runThread(ids: *IncrementalDebugServer) void {
76 ids.mutex.lock();76 ids.mutex.lock();
77 }77 }
78 defer ids.mutex.unlock();78 defer ids.mutex.unlock();
79 handleCommand(ids.zcu, &text_out, cmd, arg) catch @panic("IncrementalDebugServer: out of memory");79 var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &text_out);
80 defer text_out = allocating.toArrayList();
81 handleCommand(ids.zcu, &allocating.writer, cmd, arg) catch @panic("IncrementalDebugServer: out of memory");
80 }82 }
81 text_out.append(gpa, '\n') catch @panic("IncrementalDebugServer: out of memory");83 text_out.append(gpa, '\n') catch @panic("IncrementalDebugServer: out of memory");
82 conn.stream.writeAll(text_out.items) catch @panic("IncrementalDebugServer: failed to write");84 conn.stream.writeAll(text_out.items) catch @panic("IncrementalDebugServer: failed to write");
...@@ -119,10 +121,8 @@ const help_str: []const u8 =...@@ -119,10 +121,8 @@ const help_str: []const u8 =
119 \\121 \\
120;122;
121123
122fn handleCommand(zcu: *Zcu, output: *std.ArrayListUnmanaged(u8), cmd_str: []const u8, arg_str: []const u8) Allocator.Error!void {124fn handleCommand(zcu: *Zcu, w: *std.Io.Writer, cmd_str: []const u8, arg_str: []const u8) error{ WriteFailed, OutOfMemory }!void {
123 const ip = &zcu.intern_pool;125 const ip = &zcu.intern_pool;
124 const gpa = zcu.gpa;
125 const w = output.writer(gpa);
126 if (std.mem.eql(u8, cmd_str, "help")) {126 if (std.mem.eql(u8, cmd_str, "help")) {
127 try w.writeAll(help_str);127 try w.writeAll(help_str);
128 } else if (std.mem.eql(u8, cmd_str, "summary")) {128 } else if (std.mem.eql(u8, cmd_str, "summary")) {
src/Package/Fetch.zig+5-5
...@@ -200,7 +200,7 @@ pub const JobQueue = struct {...@@ -200,7 +200,7 @@ pub const JobQueue = struct {
200200
201 const hash_slice = hash.toSlice();201 const hash_slice = hash.toSlice();
202202
203 try buf.writer().print(203 try buf.print(
204 \\ pub const {f} = struct {{204 \\ pub const {f} = struct {{
205 \\205 \\
206 , .{std.zig.fmtId(hash_slice)});206 , .{std.zig.fmtId(hash_slice)});
...@@ -226,13 +226,13 @@ pub const JobQueue = struct {...@@ -226,13 +226,13 @@ pub const JobQueue = struct {
226 }226 }
227 }227 }
228228
229 try buf.writer().print(229 try buf.print(
230 \\ pub const build_root = "{f}";230 \\ pub const build_root = "{f}";
231 \\231 \\
232 , .{std.fmt.alt(fetch.package_root, .formatEscapeString)});232 , .{std.fmt.alt(fetch.package_root, .formatEscapeString)});
233233
234 if (fetch.has_build_zig) {234 if (fetch.has_build_zig) {
235 try buf.writer().print(235 try buf.print(
236 \\ pub const build_zig = @import("{f}");236 \\ pub const build_zig = @import("{f}");
237 \\237 \\
238 , .{std.zig.fmtString(hash_slice)});238 , .{std.zig.fmtString(hash_slice)});
...@@ -245,7 +245,7 @@ pub const JobQueue = struct {...@@ -245,7 +245,7 @@ pub const JobQueue = struct {
245 );245 );
246 for (manifest.dependencies.keys(), manifest.dependencies.values()) |name, dep| {246 for (manifest.dependencies.keys(), manifest.dependencies.values()) |name, dep| {
247 const h = depDigest(fetch.package_root, jq.global_cache, dep) orelse continue;247 const h = depDigest(fetch.package_root, jq.global_cache, dep) orelse continue;
248 try buf.writer().print(248 try buf.print(
249 " .{{ \"{f}\", \"{f}\" }},\n",249 " .{{ \"{f}\", \"{f}\" }},\n",
250 .{ std.zig.fmtString(name), std.zig.fmtString(h.toSlice()) },250 .{ std.zig.fmtString(name), std.zig.fmtString(h.toSlice()) },
251 );251 );
...@@ -277,7 +277,7 @@ pub const JobQueue = struct {...@@ -277,7 +277,7 @@ pub const JobQueue = struct {
277277
278 for (root_manifest.dependencies.keys(), root_manifest.dependencies.values()) |name, dep| {278 for (root_manifest.dependencies.keys(), root_manifest.dependencies.values()) |name, dep| {
279 const h = depDigest(root_fetch.package_root, jq.global_cache, dep) orelse continue;279 const h = depDigest(root_fetch.package_root, jq.global_cache, dep) orelse continue;
280 try buf.writer().print(280 try buf.print(
281 " .{{ \"{f}\", \"{f}\" }},\n",281 " .{{ \"{f}\", \"{f}\" }},\n",
282 .{ std.zig.fmtString(name), std.zig.fmtString(h.toSlice()) },282 .{ std.zig.fmtString(name), std.zig.fmtString(h.toSlice()) },
283 );283 );
src/arch/riscv64/Emit.zig+1-1
...@@ -31,7 +31,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -31,7 +31,7 @@ pub fn emitMir(emit: *Emit) Error!void {
31 var lowered_relocs = lowered.relocs;31 var lowered_relocs = lowered.relocs;
32 for (lowered.insts, 0..) |lowered_inst, lowered_index| {32 for (lowered.insts, 0..) |lowered_inst, lowered_index| {
33 const start_offset: u32 = @intCast(emit.code.items.len);33 const start_offset: u32 = @intCast(emit.code.items.len);
34 try lowered_inst.encode(emit.code.writer(gpa));34 std.mem.writeInt(u32, try emit.code.addManyAsArray(gpa, 4), lowered_inst.toU32(), .little);
3535
36 while (lowered_relocs.len > 0 and36 while (lowered_relocs.len > 0 and
37 lowered_relocs[0].lowered_inst_index == lowered_index) : ({37 lowered_relocs[0].lowered_inst_index == lowered_index) : ({
src/arch/riscv64/encoding.zig+1-1
...@@ -518,7 +518,7 @@ pub const Instruction = union(Lir.Format) {...@@ -518,7 +518,7 @@ pub const Instruction = union(Lir.Format) {
518 };518 };
519 }519 }
520520
521 pub fn encode(inst: Instruction, writer: anytype) !void {521 pub fn encode(inst: Instruction, writer: *std.Io.Writer) !void {
522 try writer.writeInt(u32, inst.toU32(), .little);522 try writer.writeInt(u32, inst.toU32(), .little);
523 }523 }
524524
src/arch/wasm/Emit.zig+46-34
...@@ -3,7 +3,7 @@ const Emit = @This();...@@ -3,7 +3,7 @@ const Emit = @This();
3const std = @import("std");3const std = @import("std");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
6const leb = std.leb;6const ArrayList = std.ArrayList;
77
8const Wasm = link.File.Wasm;8const Wasm = link.File.Wasm;
9const Mir = @import("Mir.zig");9const Mir = @import("Mir.zig");
...@@ -15,7 +15,7 @@ const codegen = @import("../../codegen.zig");...@@ -15,7 +15,7 @@ const codegen = @import("../../codegen.zig");
15mir: Mir,15mir: Mir,
16wasm: *Wasm,16wasm: *Wasm,
17/// The binary representation that will be emitted by this module.17/// The binary representation that will be emitted by this module.
18code: *std.ArrayListUnmanaged(u8),18code: *ArrayList(u8),
1919
20pub const Error = error{20pub const Error = error{
21 OutOfMemory,21 OutOfMemory,
...@@ -85,7 +85,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -85,7 +85,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
85 if (is_obj) {85 if (is_obj) {
86 @panic("TODO");86 @panic("TODO");
87 } else {87 } else {
88 leb.writeUleb128(code.fixedWriter(), 1 + @intFromEnum(indirect_func_idx)) catch unreachable;88 writeUleb128(code, 1 + @intFromEnum(indirect_func_idx));
89 }89 }
90 inst += 1;90 inst += 1;
91 continue :loop tags[inst];91 continue :loop tags[inst];
...@@ -99,7 +99,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -99,7 +99,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
99 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));99 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));
100 // MIR is lowered during flush, so there is indeed only one thread at this time.100 // MIR is lowered during flush, so there is indeed only one thread at this time.
101 const errors_len = 1 + comp.zcu.?.intern_pool.global_error_set.getNamesFromMainThread().len;101 const errors_len = 1 + comp.zcu.?.intern_pool.global_error_set.getNamesFromMainThread().len;
102 leb.writeIleb128(code.fixedWriter(), errors_len) catch unreachable;102 writeSleb128(code, errors_len);
103103
104 inst += 1;104 inst += 1;
105 continue :loop tags[inst];105 continue :loop tags[inst];
...@@ -122,7 +122,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -122,7 +122,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
122 continue :loop tags[inst];122 continue :loop tags[inst];
123 } else {123 } else {
124 const addr: u32 = wasm.errorNameTableAddr();124 const addr: u32 = wasm.errorNameTableAddr();
125 leb.writeIleb128(code.fixedWriter(), addr) catch unreachable;125 writeSleb128(code, addr);
126126
127 inst += 1;127 inst += 1;
128 continue :loop tags[inst];128 continue :loop tags[inst];
...@@ -131,7 +131,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -131,7 +131,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
131 .br_if, .br, .memory_grow, .memory_size => {131 .br_if, .br, .memory_grow, .memory_size => {
132 try code.ensureUnusedCapacity(gpa, 11);132 try code.ensureUnusedCapacity(gpa, 11);
133 code.appendAssumeCapacity(@intFromEnum(tags[inst]));133 code.appendAssumeCapacity(@intFromEnum(tags[inst]));
134 leb.writeUleb128(code.fixedWriter(), datas[inst].label) catch unreachable;134 writeUleb128(code, datas[inst].label);
135135
136 inst += 1;136 inst += 1;
137 continue :loop tags[inst];137 continue :loop tags[inst];
...@@ -140,7 +140,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -140,7 +140,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
140 .local_get, .local_set, .local_tee => {140 .local_get, .local_set, .local_tee => {
141 try code.ensureUnusedCapacity(gpa, 11);141 try code.ensureUnusedCapacity(gpa, 11);
142 code.appendAssumeCapacity(@intFromEnum(tags[inst]));142 code.appendAssumeCapacity(@intFromEnum(tags[inst]));
143 leb.writeUleb128(code.fixedWriter(), datas[inst].local) catch unreachable;143 writeUleb128(code, datas[inst].local);
144144
145 inst += 1;145 inst += 1;
146 continue :loop tags[inst];146 continue :loop tags[inst];
...@@ -153,8 +153,8 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -153,8 +153,8 @@ pub fn lowerToCode(emit: *Emit) Error!void {
153 try code.ensureUnusedCapacity(gpa, 11 + 10 * labels.len);153 try code.ensureUnusedCapacity(gpa, 11 + 10 * labels.len);
154 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br_table));154 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br_table));
155 // -1 because default label is not part of length/depth.155 // -1 because default label is not part of length/depth.
156 leb.writeUleb128(code.fixedWriter(), extra.data.length - 1) catch unreachable;156 writeUleb128(code, extra.data.length - 1);
157 for (labels) |label| leb.writeUleb128(code.fixedWriter(), label) catch unreachable;157 for (labels) |label| writeUleb128(code, label);
158158
159 inst += 1;159 inst += 1;
160 continue :loop tags[inst];160 continue :loop tags[inst];
...@@ -199,9 +199,9 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -199,9 +199,9 @@ pub fn lowerToCode(emit: *Emit) Error!void {
199 code.appendNTimesAssumeCapacity(0, 5);199 code.appendNTimesAssumeCapacity(0, 5);
200 } else {200 } else {
201 const index: Wasm.Flush.FuncTypeIndex = .fromTypeIndex(func_ty_index, &wasm.flush_buffer);201 const index: Wasm.Flush.FuncTypeIndex = .fromTypeIndex(func_ty_index, &wasm.flush_buffer);
202 leb.writeUleb128(code.fixedWriter(), @intFromEnum(index)) catch unreachable;202 writeUleb128(code, @intFromEnum(index));
203 }203 }
204 leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // table index204 writeUleb128(code, @as(u32, 0)); // table index
205205
206 inst += 1;206 inst += 1;
207 continue :loop tags[inst];207 continue :loop tags[inst];
...@@ -263,7 +263,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -263,7 +263,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
263 code.appendNTimesAssumeCapacity(0, 5);263 code.appendNTimesAssumeCapacity(0, 5);
264 } else {264 } else {
265 const sp_global: Wasm.GlobalIndex = .stack_pointer;265 const sp_global: Wasm.GlobalIndex = .stack_pointer;
266 std.leb.writeUleb128(code.fixedWriter(), @intFromEnum(sp_global)) catch unreachable;266 writeUleb128(code, @intFromEnum(sp_global));
267 }267 }
268268
269 inst += 1;269 inst += 1;
...@@ -291,7 +291,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -291,7 +291,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
291 .i32_const => {291 .i32_const => {
292 try code.ensureUnusedCapacity(gpa, 6);292 try code.ensureUnusedCapacity(gpa, 6);
293 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));293 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));
294 leb.writeIleb128(code.fixedWriter(), datas[inst].imm32) catch unreachable;294 writeSleb128(code, datas[inst].imm32);
295295
296 inst += 1;296 inst += 1;
297 continue :loop tags[inst];297 continue :loop tags[inst];
...@@ -300,7 +300,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -300,7 +300,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
300 try code.ensureUnusedCapacity(gpa, 11);300 try code.ensureUnusedCapacity(gpa, 11);
301 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const));301 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const));
302 const int64: i64 = @bitCast(mir.extraData(Mir.Imm64, datas[inst].payload).data.toInt());302 const int64: i64 = @bitCast(mir.extraData(Mir.Imm64, datas[inst].payload).data.toInt());
303 leb.writeIleb128(code.fixedWriter(), int64) catch unreachable;303 writeSleb128(code, int64);
304304
305 inst += 1;305 inst += 1;
306 continue :loop tags[inst];306 continue :loop tags[inst];
...@@ -476,33 +476,33 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -476,33 +476,33 @@ pub fn lowerToCode(emit: *Emit) Error!void {
476 const extra_index = datas[inst].payload;476 const extra_index = datas[inst].payload;
477 const opcode = mir.extra[extra_index];477 const opcode = mir.extra[extra_index];
478 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.misc_prefix));478 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.misc_prefix));
479 leb.writeUleb128(code.fixedWriter(), opcode) catch unreachable;479 writeUleb128(code, opcode);
480 switch (@as(std.wasm.MiscOpcode, @enumFromInt(opcode))) {480 switch (@as(std.wasm.MiscOpcode, @enumFromInt(opcode))) {
481 // bulk-memory opcodes481 // bulk-memory opcodes
482 .data_drop => {482 .data_drop => {
483 const segment = mir.extra[extra_index + 1];483 const segment = mir.extra[extra_index + 1];
484 leb.writeUleb128(code.fixedWriter(), segment) catch unreachable;484 writeUleb128(code, segment);
485485
486 inst += 1;486 inst += 1;
487 continue :loop tags[inst];487 continue :loop tags[inst];
488 },488 },
489 .memory_init => {489 .memory_init => {
490 const segment = mir.extra[extra_index + 1];490 const segment = mir.extra[extra_index + 1];
491 leb.writeUleb128(code.fixedWriter(), segment) catch unreachable;491 writeUleb128(code, segment);
492 leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // memory index492 writeUleb128(code, @as(u32, 0)); // memory index
493493
494 inst += 1;494 inst += 1;
495 continue :loop tags[inst];495 continue :loop tags[inst];
496 },496 },
497 .memory_fill => {497 .memory_fill => {
498 leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // memory index498 writeUleb128(code, @as(u32, 0)); // memory index
499499
500 inst += 1;500 inst += 1;
501 continue :loop tags[inst];501 continue :loop tags[inst];
502 },502 },
503 .memory_copy => {503 .memory_copy => {
504 leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // dst memory index504 writeUleb128(code, @as(u32, 0)); // dst memory index
505 leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // src memory index505 writeUleb128(code, @as(u32, 0)); // src memory index
506506
507 inst += 1;507 inst += 1;
508 continue :loop tags[inst];508 continue :loop tags[inst];
...@@ -538,7 +538,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -538,7 +538,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
538 const extra_index = datas[inst].payload;538 const extra_index = datas[inst].payload;
539 const opcode = mir.extra[extra_index];539 const opcode = mir.extra[extra_index];
540 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.simd_prefix));540 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.simd_prefix));
541 leb.writeUleb128(code.fixedWriter(), opcode) catch unreachable;541 writeUleb128(code, opcode);
542 switch (@as(std.wasm.SimdOpcode, @enumFromInt(opcode))) {542 switch (@as(std.wasm.SimdOpcode, @enumFromInt(opcode))) {
543 .v128_store,543 .v128_store,
544 .v128_load,544 .v128_load,
...@@ -824,7 +824,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -824,7 +824,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
824 const extra_index = datas[inst].payload;824 const extra_index = datas[inst].payload;
825 const opcode = mir.extra[extra_index];825 const opcode = mir.extra[extra_index];
826 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));826 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));
827 leb.writeUleb128(code.fixedWriter(), opcode) catch unreachable;827 writeUleb128(code, opcode);
828 switch (@as(std.wasm.AtomicsOpcode, @enumFromInt(opcode))) {828 switch (@as(std.wasm.AtomicsOpcode, @enumFromInt(opcode))) {
829 .i32_atomic_load,829 .i32_atomic_load,
830 .i64_atomic_load,830 .i64_atomic_load,
...@@ -900,7 +900,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -900,7 +900,7 @@ pub fn lowerToCode(emit: *Emit) Error!void {
900 // Hard-codes memory index 0 since multi-memory proposal is900 // Hard-codes memory index 0 since multi-memory proposal is
901 // not yet accepted nor implemented.901 // not yet accepted nor implemented.
902 const memory_index: u32 = 0;902 const memory_index: u32 = 0;
903 leb.writeUleb128(code.fixedWriter(), memory_index) catch unreachable;903 writeUleb128(code, memory_index);
904 inst += 1;904 inst += 1;
905 continue :loop tags[inst];905 continue :loop tags[inst];
906 },906 },
...@@ -915,15 +915,15 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -915,15 +915,15 @@ pub fn lowerToCode(emit: *Emit) Error!void {
915}915}
916916
917/// Asserts 20 unused capacity.917/// Asserts 20 unused capacity.
918fn encodeMemArg(code: *std.ArrayListUnmanaged(u8), mem_arg: Mir.MemArg) void {918fn encodeMemArg(code: *ArrayList(u8), mem_arg: Mir.MemArg) void {
919 assert(code.unusedCapacitySlice().len >= 20);919 assert(code.unusedCapacitySlice().len >= 20);
920 // Wasm encodes alignment as power of 2, rather than natural alignment.920 // Wasm encodes alignment as power of 2, rather than natural alignment.
921 const encoded_alignment = @ctz(mem_arg.alignment);921 const encoded_alignment = @ctz(mem_arg.alignment);
922 leb.writeUleb128(code.fixedWriter(), encoded_alignment) catch unreachable;922 writeUleb128(code, encoded_alignment);
923 leb.writeUleb128(code.fixedWriter(), mem_arg.offset) catch unreachable;923 writeUleb128(code, mem_arg.offset);
924}924}
925925
926fn uavRefObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void {926fn uavRefObj(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void {
927 const comp = wasm.base.comp;927 const comp = wasm.base.comp;
928 const gpa = comp.gpa;928 const gpa = comp.gpa;
929 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;929 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
...@@ -940,7 +940,7 @@ fn uavRefObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.I...@@ -940,7 +940,7 @@ fn uavRefObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.I
940 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);940 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
941}941}
942942
943fn uavRefExe(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void {943fn uavRefExe(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void {
944 const comp = wasm.base.comp;944 const comp = wasm.base.comp;
945 const gpa = comp.gpa;945 const gpa = comp.gpa;
946 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;946 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
...@@ -949,10 +949,10 @@ fn uavRefExe(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.I...@@ -949,10 +949,10 @@ fn uavRefExe(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.I
949 code.appendAssumeCapacity(@intFromEnum(opcode));949 code.appendAssumeCapacity(@intFromEnum(opcode));
950950
951 const addr = wasm.uavAddr(value);951 const addr = wasm.uavAddr(value);
952 leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(@as(i64, addr) + offset))) catch unreachable;952 writeUleb128(code, @as(u32, @intCast(@as(i64, addr) + offset)));
953}953}
954954
955fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff, is_wasm32: bool) !void {955fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32: bool) !void {
956 const comp = wasm.base.comp;956 const comp = wasm.base.comp;
957 const zcu = comp.zcu.?;957 const zcu = comp.zcu.?;
958 const ip = &zcu.intern_pool;958 const ip = &zcu.intern_pool;
...@@ -975,10 +975,22 @@ fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff...@@ -975,10 +975,22 @@ fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff
975 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);975 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
976 } else {976 } else {
977 const addr = wasm.navAddr(data.nav_index);977 const addr = wasm.navAddr(data.nav_index);
978 leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(@as(i64, addr) + data.offset))) catch unreachable;978 writeUleb128(code, @as(u32, @intCast(@as(i64, addr) + data.offset)));
979 }979 }
980}980}
981981
982fn appendOutputFunctionIndex(code: *std.ArrayListUnmanaged(u8), i: Wasm.OutputFunctionIndex) void {982fn appendOutputFunctionIndex(code: *ArrayList(u8), i: Wasm.OutputFunctionIndex) void {
983 leb.writeUleb128(code.fixedWriter(), @intFromEnum(i)) catch unreachable;983 writeUleb128(code, @intFromEnum(i));
984}
985
986fn writeUleb128(code: *ArrayList(u8), arg: anytype) void {
987 var w: std.Io.Writer = .fixed(code.unusedCapacitySlice());
988 w.writeUleb128(arg) catch unreachable;
989 code.items.len += w.end;
990}
991
992fn writeSleb128(code: *ArrayList(u8), arg: anytype) void {
993 var w: std.Io.Writer = .fixed(code.unusedCapacitySlice());
994 w.writeSleb128(arg) catch unreachable;
995 code.items.len += w.end;
984}996}
src/arch/wasm/Mir.zig+22-17
...@@ -675,10 +675,13 @@ pub fn lower(mir: *const Mir, wasm: *Wasm, code: *std.ArrayListUnmanaged(u8)) st...@@ -675,10 +675,13 @@ pub fn lower(mir: *const Mir, wasm: *Wasm, code: *std.ArrayListUnmanaged(u8)) st
675 // Write the locals in the prologue of the function body.675 // Write the locals in the prologue of the function body.
676 try code.ensureUnusedCapacity(gpa, 5 + mir.locals.len * 6 + 38);676 try code.ensureUnusedCapacity(gpa, 5 + mir.locals.len * 6 + 38);
677677
678 std.leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(mir.locals.len))) catch unreachable;678 var w: std.Io.Writer = .fixed(code.unusedCapacitySlice());
679
680 w.writeLeb128(@as(u32, @intCast(mir.locals.len))) catch unreachable;
681
679 for (mir.locals) |local| {682 for (mir.locals) |local| {
680 std.leb.writeUleb128(code.fixedWriter(), @as(u32, 1)) catch unreachable;683 w.writeLeb128(@as(u32, 1)) catch unreachable;
681 code.appendAssumeCapacity(@intFromEnum(local));684 w.writeByte(@intFromEnum(local)) catch unreachable;
682 }685 }
683686
684 // Stack management section of function prologue.687 // Stack management section of function prologue.
...@@ -686,33 +689,35 @@ pub fn lower(mir: *const Mir, wasm: *Wasm, code: *std.ArrayListUnmanaged(u8)) st...@@ -686,33 +689,35 @@ pub fn lower(mir: *const Mir, wasm: *Wasm, code: *std.ArrayListUnmanaged(u8)) st
686 if (stack_alignment.toByteUnits()) |align_bytes| {689 if (stack_alignment.toByteUnits()) |align_bytes| {
687 const sp_global: Wasm.GlobalIndex = .stack_pointer;690 const sp_global: Wasm.GlobalIndex = .stack_pointer;
688 // load stack pointer691 // load stack pointer
689 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_get));692 w.writeByte(@intFromEnum(std.wasm.Opcode.global_get)) catch unreachable;
690 std.leb.writeUleb128(code.fixedWriter(), @intFromEnum(sp_global)) catch unreachable;693 w.writeUleb128(@intFromEnum(sp_global)) catch unreachable;
691 // store stack pointer so we can restore it when we return from the function694 // store stack pointer so we can restore it when we return from the function
692 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_tee));695 w.writeByte(@intFromEnum(std.wasm.Opcode.local_tee)) catch unreachable;
693 leb.writeUleb128(code.fixedWriter(), mir.prologue.sp_local) catch unreachable;696 w.writeUleb128(mir.prologue.sp_local) catch unreachable;
694 // get the total stack size697 // get the total stack size
695 const aligned_stack: i32 = @intCast(stack_alignment.forward(mir.prologue.stack_size));698 const aligned_stack: i32 = @intCast(stack_alignment.forward(mir.prologue.stack_size));
696 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));699 w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)) catch unreachable;
697 leb.writeIleb128(code.fixedWriter(), aligned_stack) catch unreachable;700 w.writeSleb128(aligned_stack) catch unreachable;
698 // subtract it from the current stack pointer701 // subtract it from the current stack pointer
699 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_sub));702 w.writeByte(@intFromEnum(std.wasm.Opcode.i32_sub)) catch unreachable;
700 // Get negative stack alignment703 // Get negative stack alignment
701 const neg_stack_align = @as(i32, @intCast(align_bytes)) * -1;704 const neg_stack_align = @as(i32, @intCast(align_bytes)) * -1;
702 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));705 w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)) catch unreachable;
703 leb.writeIleb128(code.fixedWriter(), neg_stack_align) catch unreachable;706 w.writeSleb128(neg_stack_align) catch unreachable;
704 // Bitwise-and the value to get the new stack pointer to ensure the707 // Bitwise-and the value to get the new stack pointer to ensure the
705 // pointers are aligned with the abi alignment.708 // pointers are aligned with the abi alignment.
706 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_and));709 w.writeByte(@intFromEnum(std.wasm.Opcode.i32_and)) catch unreachable;
707 // The bottom will be used to calculate all stack pointer offsets.710 // The bottom will be used to calculate all stack pointer offsets.
708 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_tee));711 w.writeByte(@intFromEnum(std.wasm.Opcode.local_tee)) catch unreachable;
709 leb.writeUleb128(code.fixedWriter(), mir.prologue.bottom_stack_local) catch unreachable;712 w.writeUleb128(mir.prologue.bottom_stack_local) catch unreachable;
710 // Store the current stack pointer value into the global stack pointer so other function calls will713 // Store the current stack pointer value into the global stack pointer so other function calls will
711 // start from this value instead and not overwrite the current stack.714 // start from this value instead and not overwrite the current stack.
712 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_set));715 w.writeByte(@intFromEnum(std.wasm.Opcode.global_set)) catch unreachable;
713 std.leb.writeUleb128(code.fixedWriter(), @intFromEnum(sp_global)) catch unreachable;716 w.writeUleb128(@intFromEnum(sp_global)) catch unreachable;
714 }717 }
715718
719 code.items.len += w.end;
720
716 var emit: Emit = .{721 var emit: Emit = .{
717 .mir = mir.*,722 .mir = mir.*,
718 .wasm = wasm,723 .wasm = wasm,
src/codegen.zig+13-12
...@@ -6,6 +6,7 @@ const link = @import("link.zig");...@@ -6,6 +6,7 @@ const link = @import("link.zig");
6const log = std.log.scoped(.codegen);6const log = std.log.scoped(.codegen);
7const mem = std.mem;7const mem = std.mem;
8const math = std.math;8const math = std.math;
9const ArrayList = std.ArrayList;
9const target_util = @import("target.zig");10const target_util = @import("target.zig");
10const trace = @import("tracy.zig").trace;11const trace = @import("tracy.zig").trace;
1112
...@@ -179,7 +180,7 @@ pub fn emitFunction(...@@ -179,7 +180,7 @@ pub fn emitFunction(
179 src_loc: Zcu.LazySrcLoc,180 src_loc: Zcu.LazySrcLoc,
180 func_index: InternPool.Index,181 func_index: InternPool.Index,
181 any_mir: *const AnyMir,182 any_mir: *const AnyMir,
182 code: *std.ArrayListUnmanaged(u8),183 code: *ArrayList(u8),
183 debug_output: link.File.DebugInfoOutput,184 debug_output: link.File.DebugInfoOutput,
184) CodeGenError!void {185) CodeGenError!void {
185 const zcu = pt.zcu;186 const zcu = pt.zcu;
...@@ -204,7 +205,7 @@ pub fn generateLazyFunction(...@@ -204,7 +205,7 @@ pub fn generateLazyFunction(
204 pt: Zcu.PerThread,205 pt: Zcu.PerThread,
205 src_loc: Zcu.LazySrcLoc,206 src_loc: Zcu.LazySrcLoc,
206 lazy_sym: link.File.LazySymbol,207 lazy_sym: link.File.LazySymbol,
207 code: *std.ArrayListUnmanaged(u8),208 code: *ArrayList(u8),
208 debug_output: link.File.DebugInfoOutput,209 debug_output: link.File.DebugInfoOutput,
209) CodeGenError!void {210) CodeGenError!void {
210 const zcu = pt.zcu;211 const zcu = pt.zcu;
...@@ -236,7 +237,7 @@ pub fn generateLazySymbol(...@@ -236,7 +237,7 @@ pub fn generateLazySymbol(
236 lazy_sym: link.File.LazySymbol,237 lazy_sym: link.File.LazySymbol,
237 // TODO don't use an "out" parameter like this; put it in the result instead238 // TODO don't use an "out" parameter like this; put it in the result instead
238 alignment: *Alignment,239 alignment: *Alignment,
239 code: *std.ArrayListUnmanaged(u8),240 code: *ArrayList(u8),
240 debug_output: link.File.DebugInfoOutput,241 debug_output: link.File.DebugInfoOutput,
241 reloc_parent: link.File.RelocInfo.Parent,242 reloc_parent: link.File.RelocInfo.Parent,
242) CodeGenError!void {243) CodeGenError!void {
...@@ -311,7 +312,7 @@ pub fn generateSymbol(...@@ -311,7 +312,7 @@ pub fn generateSymbol(
311 pt: Zcu.PerThread,312 pt: Zcu.PerThread,
312 src_loc: Zcu.LazySrcLoc,313 src_loc: Zcu.LazySrcLoc,
313 val: Value,314 val: Value,
314 code: *std.ArrayListUnmanaged(u8),315 code: *ArrayList(u8),
315 reloc_parent: link.File.RelocInfo.Parent,316 reloc_parent: link.File.RelocInfo.Parent,
316) GenerateSymbolError!void {317) GenerateSymbolError!void {
317 const tracy = trace(@src());318 const tracy = trace(@src());
...@@ -379,7 +380,7 @@ pub fn generateSymbol(...@@ -379,7 +380,7 @@ pub fn generateSymbol(
379 },380 },
380 .err => |err| {381 .err => |err| {
381 const int = try pt.getErrorValue(err.name);382 const int = try pt.getErrorValue(err.name);
382 try code.writer(gpa).writeInt(u16, @intCast(int), endian);383 mem.writeInt(u16, try code.addManyAsArray(gpa, 2), @intCast(int), endian);
383 },384 },
384 .error_union => |error_union| {385 .error_union => |error_union| {
385 const payload_ty = ty.errorUnionPayload(zcu);386 const payload_ty = ty.errorUnionPayload(zcu);
...@@ -389,7 +390,7 @@ pub fn generateSymbol(...@@ -389,7 +390,7 @@ pub fn generateSymbol(
389 };390 };
390391
391 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {392 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
392 try code.writer(gpa).writeInt(u16, err_val, endian);393 mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian);
393 return;394 return;
394 }395 }
395396
...@@ -399,7 +400,7 @@ pub fn generateSymbol(...@@ -399,7 +400,7 @@ pub fn generateSymbol(
399400
400 // error value first when its type is larger than the error union's payload401 // error value first when its type is larger than the error union's payload
401 if (error_align.order(payload_align) == .gt) {402 if (error_align.order(payload_align) == .gt) {
402 try code.writer(gpa).writeInt(u16, err_val, endian);403 mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian);
403 }404 }
404405
405 // emit payload part of the error union406 // emit payload part of the error union
...@@ -421,7 +422,7 @@ pub fn generateSymbol(...@@ -421,7 +422,7 @@ pub fn generateSymbol(
421 // Payload size is larger than error set, so emit our error set last422 // Payload size is larger than error set, so emit our error set last
422 if (error_align.compare(.lte, payload_align)) {423 if (error_align.compare(.lte, payload_align)) {
423 const begin = code.items.len;424 const begin = code.items.len;
424 try code.writer(gpa).writeInt(u16, err_val, endian);425 mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian);
425 const unpadded_end = code.items.len - begin;426 const unpadded_end = code.items.len - begin;
426 const padded_end = abi_align.forward(unpadded_end);427 const padded_end = abi_align.forward(unpadded_end);
427 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;428 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;
...@@ -476,7 +477,7 @@ pub fn generateSymbol(...@@ -476,7 +477,7 @@ pub fn generateSymbol(
476 }));477 }));
477 try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent);478 try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent);
478 }479 }
479 try code.writer(gpa).writeByte(@intFromBool(payload_val != null));480 try code.append(gpa, @intFromBool(payload_val != null));
480 try code.appendNTimes(gpa, 0, padding);481 try code.appendNTimes(gpa, 0, padding);
481 }482 }
482 },483 },
...@@ -721,7 +722,7 @@ fn lowerPtr(...@@ -721,7 +722,7 @@ fn lowerPtr(
721 pt: Zcu.PerThread,722 pt: Zcu.PerThread,
722 src_loc: Zcu.LazySrcLoc,723 src_loc: Zcu.LazySrcLoc,
723 ptr_val: InternPool.Index,724 ptr_val: InternPool.Index,
724 code: *std.ArrayListUnmanaged(u8),725 code: *ArrayList(u8),
725 reloc_parent: link.File.RelocInfo.Parent,726 reloc_parent: link.File.RelocInfo.Parent,
726 prev_offset: u64,727 prev_offset: u64,
727) GenerateSymbolError!void {728) GenerateSymbolError!void {
...@@ -774,7 +775,7 @@ fn lowerUavRef(...@@ -774,7 +775,7 @@ fn lowerUavRef(
774 pt: Zcu.PerThread,775 pt: Zcu.PerThread,
775 src_loc: Zcu.LazySrcLoc,776 src_loc: Zcu.LazySrcLoc,
776 uav: InternPool.Key.Ptr.BaseAddr.Uav,777 uav: InternPool.Key.Ptr.BaseAddr.Uav,
777 code: *std.ArrayListUnmanaged(u8),778 code: *ArrayList(u8),
778 reloc_parent: link.File.RelocInfo.Parent,779 reloc_parent: link.File.RelocInfo.Parent,
779 offset: u64,780 offset: u64,
780) GenerateSymbolError!void {781) GenerateSymbolError!void {
...@@ -834,7 +835,7 @@ fn lowerNavRef(...@@ -834,7 +835,7 @@ fn lowerNavRef(
834 lf: *link.File,835 lf: *link.File,
835 pt: Zcu.PerThread,836 pt: Zcu.PerThread,
836 nav_index: InternPool.Nav.Index,837 nav_index: InternPool.Nav.Index,
837 code: *std.ArrayListUnmanaged(u8),838 code: *ArrayList(u8),
838 reloc_parent: link.File.RelocInfo.Parent,839 reloc_parent: link.File.RelocInfo.Parent,
839 offset: u64,840 offset: u64,
840) GenerateSymbolError!void {841) GenerateSymbolError!void {
src/libs/freebsd.zig+42-39
...@@ -512,7 +512,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -512,7 +512,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
512 {512 {
513 var map_contents = std.array_list.Managed(u8).init(arena);513 var map_contents = std.array_list.Managed(u8).init(arena);
514 for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| {514 for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| {
515 try map_contents.writer().print("FBSD_{d}.{d} {{ }};\n", .{ ver.major, ver.minor });515 try map_contents.print("FBSD_{d}.{d} {{ }};\n", .{ ver.major, ver.minor });
516 }516 }
517 try o_directory.handle.writeFile(.{ .sub_path = all_map_basename, .data = map_contents.items });517 try o_directory.handle.writeFile(.{ .sub_path = all_map_basename, .data = map_contents.items });
518 map_contents.deinit();518 map_contents.deinit();
...@@ -524,20 +524,17 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -524,20 +524,17 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
524 for (libs, 0..) |lib, lib_i| {524 for (libs, 0..) |lib, lib_i| {
525 stubs_asm.shrinkRetainingCapacity(0);525 stubs_asm.shrinkRetainingCapacity(0);
526526
527 const stubs_writer = stubs_asm.writer();527 try stubs_asm.appendSlice(".text\n");
528
529 try stubs_writer.writeAll(".text\n");
530528
531 var sym_i: usize = 0;529 var sym_i: usize = 0;
532 var sym_name_buf = std.array_list.Managed(u8).init(arena);530 var sym_name_buf: std.Io.Writer.Allocating = .init(arena);
533 var opt_symbol_name: ?[]const u8 = null;531 var opt_symbol_name: ?[]const u8 = null;
534 var versions = try std.DynamicBitSetUnmanaged.initEmpty(arena, metadata.all_versions.len);532 var versions = try std.DynamicBitSetUnmanaged.initEmpty(arena, metadata.all_versions.len);
535 var weak_linkages = try std.DynamicBitSetUnmanaged.initEmpty(arena, metadata.all_versions.len);533 var weak_linkages = try std.DynamicBitSetUnmanaged.initEmpty(arena, metadata.all_versions.len);
536534
537 var inc_fbs = std.io.fixedBufferStream(metadata.inclusions);535 var inc_reader: std.Io.Reader = .fixed(metadata.inclusions);
538 var inc_reader = inc_fbs.reader();
539536
540 const fn_inclusions_len = try inc_reader.readInt(u16, .little);537 const fn_inclusions_len = try inc_reader.takeInt(u16, .little);
541538
542 // Pick the default symbol version:539 // Pick the default symbol version:
543 // - If there are no versions, don't emit it540 // - If there are no versions, don't emit it
...@@ -550,19 +547,21 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -550,19 +547,21 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
550 while (sym_i < fn_inclusions_len) : (sym_i += 1) {547 while (sym_i < fn_inclusions_len) : (sym_i += 1) {
551 const sym_name = opt_symbol_name orelse n: {548 const sym_name = opt_symbol_name orelse n: {
552 sym_name_buf.clearRetainingCapacity();549 sym_name_buf.clearRetainingCapacity();
553 try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null);550 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0);
551 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API
552 inc_reader.toss(1);
554553
555 opt_symbol_name = sym_name_buf.items;554 opt_symbol_name = sym_name_buf.written();
556 versions.unsetAll();555 versions.unsetAll();
557 weak_linkages.unsetAll();556 weak_linkages.unsetAll();
558 chosen_def_ver_index = 255;557 chosen_def_ver_index = 255;
559 chosen_unversioned_ver_index = 255;558 chosen_unversioned_ver_index = 255;
560559
561 break :n sym_name_buf.items;560 break :n sym_name_buf.written();
562 };561 };
563 {562 {
564 const targets = try std.leb.readUleb128(u64, inc_reader);563 const targets = try inc_reader.takeLeb128(u64);
565 var lib_index = try inc_reader.readByte();564 var lib_index = try inc_reader.takeByte();
566565
567 const is_unversioned = (lib_index & (1 << 5)) != 0;566 const is_unversioned = (lib_index & (1 << 5)) != 0;
568 const is_weak = (lib_index & (1 << 6)) != 0;567 const is_weak = (lib_index & (1 << 6)) != 0;
...@@ -576,7 +575,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -576,7 +575,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
576 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);575 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);
577576
578 while (true) {577 while (true) {
579 const byte = try inc_reader.readByte();578 const byte = try inc_reader.takeByte();
580 const last = (byte & 0b1000_0000) != 0;579 const last = (byte & 0b1000_0000) != 0;
581 const ver_i = @as(u7, @truncate(byte));580 const ver_i = @as(u7, @truncate(byte));
582 if (ok_lib_and_target and ver_i <= target_ver_index) {581 if (ok_lib_and_target and ver_i <= target_ver_index) {
...@@ -608,7 +607,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -608,7 +607,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
608 // .globl _Exit607 // .globl _Exit
609 // .type _Exit, %function608 // .type _Exit, %function
610 // _Exit: .long 0609 // _Exit: .long 0
611 try stubs_writer.print(610 try stubs_asm.print(
612 \\.balign {d}611 \\.balign {d}
613 \\.{s} {s}612 \\.{s} {s}
614 \\.type {s}, %function613 \\.type {s}, %function
...@@ -640,7 +639,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -640,7 +639,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
640 .{ sym_name, ver.major, ver.minor },639 .{ sym_name, ver.major, ver.minor },
641 );640 );
642641
643 try stubs_writer.print(642 try stubs_asm.print(
644 \\.balign {d}643 \\.balign {d}
645 \\.{s} {s}644 \\.{s} {s}
646 \\.type {s}, %function645 \\.type {s}, %function
...@@ -665,14 +664,14 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -665,14 +664,14 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
665 }664 }
666 }665 }
667666
668 try stubs_writer.writeAll(".data\n");667 try stubs_asm.appendSlice(".data\n");
669668
670 // FreeBSD's `libc.so.7` contains strong references to `__progname` and `environ` which are669 // FreeBSD's `libc.so.7` contains strong references to `__progname` and `environ` which are
671 // defined in the statically-linked startup code. Those references cause the linker to put670 // defined in the statically-linked startup code. Those references cause the linker to put
672 // the symbols in the dynamic symbol table. We need to create dummy references to them here671 // the symbols in the dynamic symbol table. We need to create dummy references to them here
673 // to get the same effect.672 // to get the same effect.
674 if (std.mem.eql(u8, lib.name, "c")) {673 if (std.mem.eql(u8, lib.name, "c")) {
675 try stubs_writer.print(674 try stubs_asm.print(
676 \\.balign {d}675 \\.balign {d}
677 \\.globl __progname676 \\.globl __progname
678 \\.globl environ677 \\.globl environ
...@@ -686,7 +685,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -686,7 +685,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
686 });685 });
687 }686 }
688687
689 const obj_inclusions_len = try inc_reader.readInt(u16, .little);688 const obj_inclusions_len = try inc_reader.takeInt(u16, .little);
690689
691 var sizes = try arena.alloc(u16, metadata.all_versions.len);690 var sizes = try arena.alloc(u16, metadata.all_versions.len);
692691
...@@ -696,21 +695,23 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -696,21 +695,23 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
696 while (sym_i < obj_inclusions_len) : (sym_i += 1) {695 while (sym_i < obj_inclusions_len) : (sym_i += 1) {
697 const sym_name = opt_symbol_name orelse n: {696 const sym_name = opt_symbol_name orelse n: {
698 sym_name_buf.clearRetainingCapacity();697 sym_name_buf.clearRetainingCapacity();
699 try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null);698 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0);
699 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API
700 inc_reader.toss(1);
700701
701 opt_symbol_name = sym_name_buf.items;702 opt_symbol_name = sym_name_buf.written();
702 versions.unsetAll();703 versions.unsetAll();
703 weak_linkages.unsetAll();704 weak_linkages.unsetAll();
704 chosen_def_ver_index = 255;705 chosen_def_ver_index = 255;
705 chosen_unversioned_ver_index = 255;706 chosen_unversioned_ver_index = 255;
706707
707 break :n sym_name_buf.items;708 break :n sym_name_buf.written();
708 };709 };
709710
710 {711 {
711 const targets = try std.leb.readUleb128(u64, inc_reader);712 const targets = try inc_reader.takeLeb128(u64);
712 const size = try std.leb.readUleb128(u16, inc_reader);713 const size = try inc_reader.takeLeb128(u16);
713 var lib_index = try inc_reader.readByte();714 var lib_index = try inc_reader.takeByte();
714715
715 const is_unversioned = (lib_index & (1 << 5)) != 0;716 const is_unversioned = (lib_index & (1 << 5)) != 0;
716 const is_weak = (lib_index & (1 << 6)) != 0;717 const is_weak = (lib_index & (1 << 6)) != 0;
...@@ -724,7 +725,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -724,7 +725,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
724 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);725 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);
725726
726 while (true) {727 while (true) {
727 const byte = try inc_reader.readByte();728 const byte = try inc_reader.takeByte();
728 const last = (byte & 0b1000_0000) != 0;729 const last = (byte & 0b1000_0000) != 0;
729 const ver_i = @as(u7, @truncate(byte));730 const ver_i = @as(u7, @truncate(byte));
730 if (ok_lib_and_target and ver_i <= target_ver_index) {731 if (ok_lib_and_target and ver_i <= target_ver_index) {
...@@ -758,7 +759,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -758,7 +759,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
758 // .type malloc_conf, %object759 // .type malloc_conf, %object
759 // .size malloc_conf, 4760 // .size malloc_conf, 4
760 // malloc_conf: .fill 4, 1, 0761 // malloc_conf: .fill 4, 1, 0
761 try stubs_writer.print(762 try stubs_asm.print(
762 \\.balign {d}763 \\.balign {d}
763 \\.{s} {s}764 \\.{s} {s}
764 \\.type {s}, %object765 \\.type {s}, %object
...@@ -794,7 +795,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -794,7 +795,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
794 .{ sym_name, ver.major, ver.minor },795 .{ sym_name, ver.major, ver.minor },
795 );796 );
796797
797 try stubs_asm.writer().print(798 try stubs_asm.print(
798 \\.balign {d}799 \\.balign {d}
799 \\.{s} {s}800 \\.{s} {s}
800 \\.type {s}, %object801 \\.type {s}, %object
...@@ -822,9 +823,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -822,9 +823,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
822 }823 }
823 }824 }
824825
825 try stubs_writer.writeAll(".tdata\n");826 try stubs_asm.appendSlice(".tdata\n");
826827
827 const tls_inclusions_len = try inc_reader.readInt(u16, .little);828 const tls_inclusions_len = try inc_reader.takeInt(u16, .little);
828829
829 sym_i = 0;830 sym_i = 0;
830 opt_symbol_name = null;831 opt_symbol_name = null;
...@@ -832,21 +833,23 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -832,21 +833,23 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
832 while (sym_i < tls_inclusions_len) : (sym_i += 1) {833 while (sym_i < tls_inclusions_len) : (sym_i += 1) {
833 const sym_name = opt_symbol_name orelse n: {834 const sym_name = opt_symbol_name orelse n: {
834 sym_name_buf.clearRetainingCapacity();835 sym_name_buf.clearRetainingCapacity();
835 try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null);836 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0);
837 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API
838 inc_reader.toss(1);
836839
837 opt_symbol_name = sym_name_buf.items;840 opt_symbol_name = sym_name_buf.written();
838 versions.unsetAll();841 versions.unsetAll();
839 weak_linkages.unsetAll();842 weak_linkages.unsetAll();
840 chosen_def_ver_index = 255;843 chosen_def_ver_index = 255;
841 chosen_unversioned_ver_index = 255;844 chosen_unversioned_ver_index = 255;
842845
843 break :n sym_name_buf.items;846 break :n sym_name_buf.written();
844 };847 };
845848
846 {849 {
847 const targets = try std.leb.readUleb128(u64, inc_reader);850 const targets = try inc_reader.takeLeb128(u64);
848 const size = try std.leb.readUleb128(u16, inc_reader);851 const size = try inc_reader.takeLeb128(u16);
849 var lib_index = try inc_reader.readByte();852 var lib_index = try inc_reader.takeByte();
850853
851 const is_unversioned = (lib_index & (1 << 5)) != 0;854 const is_unversioned = (lib_index & (1 << 5)) != 0;
852 const is_weak = (lib_index & (1 << 6)) != 0;855 const is_weak = (lib_index & (1 << 6)) != 0;
...@@ -860,7 +863,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -860,7 +863,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
860 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);863 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);
861864
862 while (true) {865 while (true) {
863 const byte = try inc_reader.readByte();866 const byte = try inc_reader.takeByte();
864 const last = (byte & 0b1000_0000) != 0;867 const last = (byte & 0b1000_0000) != 0;
865 const ver_i = @as(u7, @truncate(byte));868 const ver_i = @as(u7, @truncate(byte));
866 if (ok_lib_and_target and ver_i <= target_ver_index) {869 if (ok_lib_and_target and ver_i <= target_ver_index) {
...@@ -894,7 +897,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -894,7 +897,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
894 // .type _ThreadRuneLocale, %object897 // .type _ThreadRuneLocale, %object
895 // .size _ThreadRuneLocale, 4898 // .size _ThreadRuneLocale, 4
896 // _ThreadRuneLocale: .fill 4, 1, 0899 // _ThreadRuneLocale: .fill 4, 1, 0
897 try stubs_writer.print(900 try stubs_asm.print(
898 \\.balign {d}901 \\.balign {d}
899 \\.{s} {s}902 \\.{s} {s}
900 \\.type {s}, %tls_object903 \\.type {s}, %tls_object
...@@ -930,7 +933,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -930,7 +933,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
930 .{ sym_name, ver.major, ver.minor },933 .{ sym_name, ver.major, ver.minor },
931 );934 );
932935
933 try stubs_writer.print(936 try stubs_asm.print(
934 \\.balign {d}937 \\.balign {d}
935 \\.{s} {s}938 \\.{s} {s}
936 \\.type {s}, %tls_object939 \\.type {s}, %tls_object
src/libs/glibc.zig+28-25
...@@ -752,9 +752,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -752,9 +752,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
752 var map_contents = std.array_list.Managed(u8).init(arena);752 var map_contents = std.array_list.Managed(u8).init(arena);
753 for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| {753 for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| {
754 if (ver.patch == 0) {754 if (ver.patch == 0) {
755 try map_contents.writer().print("GLIBC_{d}.{d} {{ }};\n", .{ ver.major, ver.minor });755 try map_contents.print("GLIBC_{d}.{d} {{ }};\n", .{ ver.major, ver.minor });
756 } else {756 } else {
757 try map_contents.writer().print("GLIBC_{d}.{d}.{d} {{ }};\n", .{ ver.major, ver.minor, ver.patch });757 try map_contents.print("GLIBC_{d}.{d}.{d} {{ }};\n", .{ ver.major, ver.minor, ver.patch });
758 }758 }
759 }759 }
760 try o_directory.handle.writeFile(.{ .sub_path = all_map_basename, .data = map_contents.items });760 try o_directory.handle.writeFile(.{ .sub_path = all_map_basename, .data = map_contents.items });
...@@ -773,7 +773,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -773,7 +773,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
773 try stubs_asm.appendSlice(".text\n");773 try stubs_asm.appendSlice(".text\n");
774774
775 var sym_i: usize = 0;775 var sym_i: usize = 0;
776 var sym_name_buf = std.array_list.Managed(u8).init(arena);776 var sym_name_buf: std.Io.Writer.Allocating = .init(arena);
777 var opt_symbol_name: ?[]const u8 = null;777 var opt_symbol_name: ?[]const u8 = null;
778 var versions_buffer: [32]u8 = undefined;778 var versions_buffer: [32]u8 = undefined;
779 var versions_len: usize = undefined;779 var versions_len: usize = undefined;
...@@ -794,24 +794,25 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -794,24 +794,25 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
794 // twice, which causes a "duplicate symbol" assembler error.794 // twice, which causes a "duplicate symbol" assembler error.
795 var versions_written = std.AutoArrayHashMap(Version, void).init(arena);795 var versions_written = std.AutoArrayHashMap(Version, void).init(arena);
796796
797 var inc_fbs = std.io.fixedBufferStream(metadata.inclusions);797 var inc_reader: std.Io.Reader = .fixed(metadata.inclusions);
798 var inc_reader = inc_fbs.reader();
799798
800 const fn_inclusions_len = try inc_reader.readInt(u16, .little);799 const fn_inclusions_len = try inc_reader.takeInt(u16, .little);
801800
802 while (sym_i < fn_inclusions_len) : (sym_i += 1) {801 while (sym_i < fn_inclusions_len) : (sym_i += 1) {
803 const sym_name = opt_symbol_name orelse n: {802 const sym_name = opt_symbol_name orelse n: {
804 sym_name_buf.clearRetainingCapacity();803 sym_name_buf.clearRetainingCapacity();
805 try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null);804 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0);
805 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API
806 inc_reader.toss(1);
806807
807 opt_symbol_name = sym_name_buf.items;808 opt_symbol_name = sym_name_buf.written();
808 versions_buffer = undefined;809 versions_buffer = undefined;
809 versions_len = 0;810 versions_len = 0;
810811
811 break :n sym_name_buf.items;812 break :n sym_name_buf.written();
812 };813 };
813 const targets = try std.leb.readUleb128(u64, inc_reader);814 const targets = try inc_reader.takeLeb128(u64);
814 var lib_index = try inc_reader.readByte();815 var lib_index = try inc_reader.takeByte();
815816
816 const is_terminal = (lib_index & (1 << 7)) != 0;817 const is_terminal = (lib_index & (1 << 7)) != 0;
817 if (is_terminal) {818 if (is_terminal) {
...@@ -825,7 +826,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -825,7 +826,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
825 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);826 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);
826827
827 while (true) {828 while (true) {
828 const byte = try inc_reader.readByte();829 const byte = try inc_reader.takeByte();
829 const last = (byte & 0b1000_0000) != 0;830 const last = (byte & 0b1000_0000) != 0;
830 const ver_i = @as(u7, @truncate(byte));831 const ver_i = @as(u7, @truncate(byte));
831 if (ok_lib_and_target and ver_i <= target_ver_index) {832 if (ok_lib_and_target and ver_i <= target_ver_index) {
...@@ -880,7 +881,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -880,7 +881,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
880 "{s}_{d}_{d}",881 "{s}_{d}_{d}",
881 .{ sym_name, ver.major, ver.minor },882 .{ sym_name, ver.major, ver.minor },
882 );883 );
883 try stubs_asm.writer().print(884 try stubs_asm.print(
884 \\.balign {d}885 \\.balign {d}
885 \\.globl {s}886 \\.globl {s}
886 \\.type {s}, %function887 \\.type {s}, %function
...@@ -905,7 +906,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -905,7 +906,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
905 "{s}_{d}_{d}_{d}",906 "{s}_{d}_{d}_{d}",
906 .{ sym_name, ver.major, ver.minor, ver.patch },907 .{ sym_name, ver.major, ver.minor, ver.patch },
907 );908 );
908 try stubs_asm.writer().print(909 try stubs_asm.print(
909 \\.balign {d}910 \\.balign {d}
910 \\.globl {s}911 \\.globl {s}
911 \\.type {s}, %function912 \\.type {s}, %function
...@@ -950,7 +951,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -950,7 +951,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
950 // versions where the symbol didn't exist. We only care about modern glibc versions, so use951 // versions where the symbol didn't exist. We only care about modern glibc versions, so use
951 // a strong reference.952 // a strong reference.
952 if (std.mem.eql(u8, lib.name, "c")) {953 if (std.mem.eql(u8, lib.name, "c")) {
953 try stubs_asm.writer().print(954 try stubs_asm.print(
954 \\.balign {d}955 \\.balign {d}
955 \\.globl _IO_stdin_used956 \\.globl _IO_stdin_used
956 \\{s} _IO_stdin_used957 \\{s} _IO_stdin_used
...@@ -963,7 +964,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -963,7 +964,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
963964
964 try stubs_asm.appendSlice(".data\n");965 try stubs_asm.appendSlice(".data\n");
965966
966 const obj_inclusions_len = try inc_reader.readInt(u16, .little);967 const obj_inclusions_len = try inc_reader.takeInt(u16, .little);
967968
968 var sizes = try arena.alloc(u16, metadata.all_versions.len);969 var sizes = try arena.alloc(u16, metadata.all_versions.len);
969970
...@@ -974,17 +975,19 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -974,17 +975,19 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
974 while (sym_i < obj_inclusions_len) : (sym_i += 1) {975 while (sym_i < obj_inclusions_len) : (sym_i += 1) {
975 const sym_name = opt_symbol_name orelse n: {976 const sym_name = opt_symbol_name orelse n: {
976 sym_name_buf.clearRetainingCapacity();977 sym_name_buf.clearRetainingCapacity();
977 try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null);978 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0);
979 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API
980 inc_reader.toss(1);
978981
979 opt_symbol_name = sym_name_buf.items;982 opt_symbol_name = sym_name_buf.written();
980 versions_buffer = undefined;983 versions_buffer = undefined;
981 versions_len = 0;984 versions_len = 0;
982985
983 break :n sym_name_buf.items;986 break :n sym_name_buf.written();
984 };987 };
985 const targets = try std.leb.readUleb128(u64, inc_reader);988 const targets = try inc_reader.takeLeb128(u64);
986 const size = try std.leb.readUleb128(u16, inc_reader);989 const size = try inc_reader.takeLeb128(u16);
987 var lib_index = try inc_reader.readByte();990 var lib_index = try inc_reader.takeByte();
988991
989 const is_terminal = (lib_index & (1 << 7)) != 0;992 const is_terminal = (lib_index & (1 << 7)) != 0;
990 if (is_terminal) {993 if (is_terminal) {
...@@ -998,7 +1001,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -998,7 +1001,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
998 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);1001 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);
9991002
1000 while (true) {1003 while (true) {
1001 const byte = try inc_reader.readByte();1004 const byte = try inc_reader.takeByte();
1002 const last = (byte & 0b1000_0000) != 0;1005 const last = (byte & 0b1000_0000) != 0;
1003 const ver_i = @as(u7, @truncate(byte));1006 const ver_i = @as(u7, @truncate(byte));
1004 if (ok_lib_and_target and ver_i <= target_ver_index) {1007 if (ok_lib_and_target and ver_i <= target_ver_index) {
...@@ -1055,7 +1058,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -1055,7 +1058,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
1055 "{s}_{d}_{d}",1058 "{s}_{d}_{d}",
1056 .{ sym_name, ver.major, ver.minor },1059 .{ sym_name, ver.major, ver.minor },
1057 );1060 );
1058 try stubs_asm.writer().print(1061 try stubs_asm.print(
1059 \\.balign {d}1062 \\.balign {d}
1060 \\.globl {s}1063 \\.globl {s}
1061 \\.type {s}, %object1064 \\.type {s}, %object
...@@ -1083,7 +1086,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -1083,7 +1086,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
1083 "{s}_{d}_{d}_{d}",1086 "{s}_{d}_{d}_{d}",
1084 .{ sym_name, ver.major, ver.minor, ver.patch },1087 .{ sym_name, ver.major, ver.minor, ver.patch },
1085 );1088 );
1086 try stubs_asm.writer().print(1089 try stubs_asm.print(
1087 \\.balign {d}1090 \\.balign {d}
1088 \\.globl {s}1091 \\.globl {s}
1089 \\.type {s}, %object1092 \\.type {s}, %object
src/libs/mingw.zig+12-10
...@@ -304,9 +304,8 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -304,9 +304,8 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
304 const include_dir = try comp.dirs.zig_lib.join(arena, &.{ "libc", "mingw", "def-include" });304 const include_dir = try comp.dirs.zig_lib.join(arena, &.{ "libc", "mingw", "def-include" });
305305
306 if (comp.verbose_cc) print: {306 if (comp.verbose_cc) print: {
307 std.debug.lockStdErr();307 var stderr = std.debug.lockStderrWriter(&.{});
308 defer std.debug.unlockStdErr();308 defer std.debug.unlockStderrWriter();
309 const stderr = std.fs.File.stderr().deprecatedWriter();
310 nosuspend stderr.print("def file: {s}\n", .{def_file_path}) catch break :print;309 nosuspend stderr.print("def file: {s}\n", .{def_file_path}) catch break :print;
311 nosuspend stderr.print("include dir: {s}\n", .{include_dir}) catch break :print;310 nosuspend stderr.print("include dir: {s}\n", .{include_dir}) catch break :print;
312 nosuspend stderr.print("output path: {s}\n", .{def_final_path}) catch break :print;311 nosuspend stderr.print("output path: {s}\n", .{def_final_path}) catch break :print;
...@@ -335,7 +334,10 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -335,7 +334,10 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
335 // new scope to ensure definition file is written before passing the path to WriteImportLibrary334 // new scope to ensure definition file is written before passing the path to WriteImportLibrary
336 const def_final_file = try o_dir.createFile(final_def_basename, .{ .truncate = true });335 const def_final_file = try o_dir.createFile(final_def_basename, .{ .truncate = true });
337 defer def_final_file.close();336 defer def_final_file.close();
338 try pp.prettyPrintTokens(def_final_file.deprecatedWriter(), .result_only);337 var buffer: [1024]u8 = undefined;
338 var def_final_file_writer = def_final_file.writer(&buffer);
339 try pp.prettyPrintTokens(&def_final_file_writer.interface, .result_only);
340 try def_final_file_writer.interface.flush();
339 }341 }
340342
341 const lib_final_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });343 const lib_final_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });
...@@ -410,9 +412,9 @@ fn findDef(...@@ -410,9 +412,9 @@ fn findDef(
410 // Try the archtecture-specific path first.412 // Try the archtecture-specific path first.
411 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def";413 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def";
412 if (zig_lib_directory.path) |p| {414 if (zig_lib_directory.path) |p| {
413 try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_path, lib_name });415 try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_path, lib_name });
414 } else {416 } else {
415 try override_path.writer().print(fmt_path, .{ lib_path, lib_name });417 try override_path.print(fmt_path, .{ lib_path, lib_name });
416 }418 }
417 if (std.fs.cwd().access(override_path.items, .{})) |_| {419 if (std.fs.cwd().access(override_path.items, .{})) |_| {
418 return override_path.toOwnedSlice();420 return override_path.toOwnedSlice();
...@@ -427,9 +429,9 @@ fn findDef(...@@ -427,9 +429,9 @@ fn findDef(
427 override_path.shrinkRetainingCapacity(0);429 override_path.shrinkRetainingCapacity(0);
428 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def";430 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def";
429 if (zig_lib_directory.path) |p| {431 if (zig_lib_directory.path) |p| {
430 try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_name });432 try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_name });
431 } else {433 } else {
432 try override_path.writer().print(fmt_path, .{lib_name});434 try override_path.print(fmt_path, .{lib_name});
433 }435 }
434 if (std.fs.cwd().access(override_path.items, .{})) |_| {436 if (std.fs.cwd().access(override_path.items, .{})) |_| {
435 return override_path.toOwnedSlice();437 return override_path.toOwnedSlice();
...@@ -444,9 +446,9 @@ fn findDef(...@@ -444,9 +446,9 @@ fn findDef(
444 override_path.shrinkRetainingCapacity(0);446 override_path.shrinkRetainingCapacity(0);
445 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in";447 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in";
446 if (zig_lib_directory.path) |p| {448 if (zig_lib_directory.path) |p| {
447 try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_name });449 try override_path.print("{s}" ++ s ++ fmt_path, .{ p, lib_name });
448 } else {450 } else {
449 try override_path.writer().print(fmt_path, .{lib_name});451 try override_path.print(fmt_path, .{lib_name});
450 }452 }
451 if (std.fs.cwd().access(override_path.items, .{})) |_| {453 if (std.fs.cwd().access(override_path.items, .{})) |_| {
452 return override_path.toOwnedSlice();454 return override_path.toOwnedSlice();
src/libs/musl.zig+3-3
...@@ -140,21 +140,21 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro...@@ -140,21 +140,21 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
140 if (!is_arch_specific) {140 if (!is_arch_specific) {
141 // Look for an arch specific override.141 // Look for an arch specific override.
142 override_path.shrinkRetainingCapacity(0);142 override_path.shrinkRetainingCapacity(0);
143 try override_path.writer().print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.s", .{143 try override_path.print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.s", .{
144 dirname, arch_name, noextbasename,144 dirname, arch_name, noextbasename,
145 });145 });
146 if (source_table.contains(override_path.items))146 if (source_table.contains(override_path.items))
147 continue;147 continue;
148148
149 override_path.shrinkRetainingCapacity(0);149 override_path.shrinkRetainingCapacity(0);
150 try override_path.writer().print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.S", .{150 try override_path.print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.S", .{
151 dirname, arch_name, noextbasename,151 dirname, arch_name, noextbasename,
152 });152 });
153 if (source_table.contains(override_path.items))153 if (source_table.contains(override_path.items))
154 continue;154 continue;
155155
156 override_path.shrinkRetainingCapacity(0);156 override_path.shrinkRetainingCapacity(0);
157 try override_path.writer().print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.c", .{157 try override_path.print("{s}" ++ s ++ "{s}" ++ s ++ "{s}.c", .{
158 dirname, arch_name, noextbasename,158 dirname, arch_name, noextbasename,
159 });159 });
160 if (source_table.contains(override_path.items))160 if (source_table.contains(override_path.items))
src/libs/netbsd.zig+25-24
...@@ -460,18 +460,15 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -460,18 +460,15 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
460 for (libs, 0..) |lib, lib_i| {460 for (libs, 0..) |lib, lib_i| {
461 stubs_asm.shrinkRetainingCapacity(0);461 stubs_asm.shrinkRetainingCapacity(0);
462462
463 const stubs_writer = stubs_asm.writer();463 try stubs_asm.appendSlice(".text\n");
464
465 try stubs_writer.writeAll(".text\n");
466464
467 var sym_i: usize = 0;465 var sym_i: usize = 0;
468 var sym_name_buf = std.array_list.Managed(u8).init(arena);466 var sym_name_buf: std.Io.Writer.Allocating = .init(arena);
469 var opt_symbol_name: ?[]const u8 = null;467 var opt_symbol_name: ?[]const u8 = null;
470468
471 var inc_fbs = std.io.fixedBufferStream(metadata.inclusions);469 var inc_reader: std.Io.Reader = .fixed(metadata.inclusions);
472 var inc_reader = inc_fbs.reader();
473470
474 const fn_inclusions_len = try inc_reader.readInt(u16, .little);471 const fn_inclusions_len = try inc_reader.takeInt(u16, .little);
475472
476 var chosen_ver_index: usize = 255;473 var chosen_ver_index: usize = 255;
477 var chosen_is_weak: bool = undefined;474 var chosen_is_weak: bool = undefined;
...@@ -479,17 +476,19 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -479,17 +476,19 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
479 while (sym_i < fn_inclusions_len) : (sym_i += 1) {476 while (sym_i < fn_inclusions_len) : (sym_i += 1) {
480 const sym_name = opt_symbol_name orelse n: {477 const sym_name = opt_symbol_name orelse n: {
481 sym_name_buf.clearRetainingCapacity();478 sym_name_buf.clearRetainingCapacity();
482 try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null);479 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0);
480 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API
481 inc_reader.toss(1);
483482
484 opt_symbol_name = sym_name_buf.items;483 opt_symbol_name = sym_name_buf.written();
485 chosen_ver_index = 255;484 chosen_ver_index = 255;
486485
487 break :n sym_name_buf.items;486 break :n sym_name_buf.written();
488 };487 };
489488
490 {489 {
491 const targets = try std.leb.readUleb128(u64, inc_reader);490 const targets = try inc_reader.takeLeb128(u64);
492 var lib_index = try inc_reader.readByte();491 var lib_index = try inc_reader.takeByte();
493492
494 const is_weak = (lib_index & (1 << 6)) != 0;493 const is_weak = (lib_index & (1 << 6)) != 0;
495 const is_terminal = (lib_index & (1 << 7)) != 0;494 const is_terminal = (lib_index & (1 << 7)) != 0;
...@@ -502,7 +501,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -502,7 +501,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
502 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);501 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);
503502
504 while (true) {503 while (true) {
505 const byte = try inc_reader.readByte();504 const byte = try inc_reader.takeByte();
506 const last = (byte & 0b1000_0000) != 0;505 const last = (byte & 0b1000_0000) != 0;
507 const ver_i = @as(u7, @truncate(byte));506 const ver_i = @as(u7, @truncate(byte));
508 if (ok_lib_and_target and ver_i <= target_ver_index and507 if (ok_lib_and_target and ver_i <= target_ver_index and
...@@ -525,7 +524,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -525,7 +524,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
525 // .globl _Exit524 // .globl _Exit
526 // .type _Exit, %function525 // .type _Exit, %function
527 // _Exit: .long 0526 // _Exit: .long 0
528 try stubs_writer.print(527 try stubs_asm.print(
529 \\.balign {d}528 \\.balign {d}
530 \\.{s} {s}529 \\.{s} {s}
531 \\.type {s}, %function530 \\.type {s}, %function
...@@ -542,9 +541,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -542,9 +541,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
542 }541 }
543 }542 }
544543
545 try stubs_writer.writeAll(".data\n");544 try stubs_asm.appendSlice(".data\n");
546545
547 const obj_inclusions_len = try inc_reader.readInt(u16, .little);546 const obj_inclusions_len = try inc_reader.takeInt(u16, .little);
548547
549 sym_i = 0;548 sym_i = 0;
550 opt_symbol_name = null;549 opt_symbol_name = null;
...@@ -554,18 +553,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -554,18 +553,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
554 while (sym_i < obj_inclusions_len) : (sym_i += 1) {553 while (sym_i < obj_inclusions_len) : (sym_i += 1) {
555 const sym_name = opt_symbol_name orelse n: {554 const sym_name = opt_symbol_name orelse n: {
556 sym_name_buf.clearRetainingCapacity();555 sym_name_buf.clearRetainingCapacity();
557 try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null);556 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0);
557 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API
558 inc_reader.toss(1);
558559
559 opt_symbol_name = sym_name_buf.items;560 opt_symbol_name = sym_name_buf.written();
560 chosen_ver_index = 255;561 chosen_ver_index = 255;
561562
562 break :n sym_name_buf.items;563 break :n sym_name_buf.written();
563 };564 };
564565
565 {566 {
566 const targets = try std.leb.readUleb128(u64, inc_reader);567 const targets = try inc_reader.takeLeb128(u64);
567 const size = try std.leb.readUleb128(u16, inc_reader);568 const size = try inc_reader.takeLeb128(u16);
568 var lib_index = try inc_reader.readByte();569 var lib_index = try inc_reader.takeByte();
569570
570 const is_weak = (lib_index & (1 << 6)) != 0;571 const is_weak = (lib_index & (1 << 6)) != 0;
571 const is_terminal = (lib_index & (1 << 7)) != 0;572 const is_terminal = (lib_index & (1 << 7)) != 0;
...@@ -578,7 +579,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -578,7 +579,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
578 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);579 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);
579580
580 while (true) {581 while (true) {
581 const byte = try inc_reader.readByte();582 const byte = try inc_reader.takeByte();
582 const last = (byte & 0b1000_0000) != 0;583 const last = (byte & 0b1000_0000) != 0;
583 const ver_i = @as(u7, @truncate(byte));584 const ver_i = @as(u7, @truncate(byte));
584 if (ok_lib_and_target and ver_i <= target_ver_index and585 if (ok_lib_and_target and ver_i <= target_ver_index and
...@@ -603,7 +604,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -603,7 +604,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
603 // .type malloc_conf, %object604 // .type malloc_conf, %object
604 // .size malloc_conf, 4605 // .size malloc_conf, 4
605 // malloc_conf: .fill 4, 1, 0606 // malloc_conf: .fill 4, 1, 0
606 try stubs_writer.print(607 try stubs_asm.print(
607 \\.balign {d}608 \\.balign {d}
608 \\.{s} {s}609 \\.{s} {s}
609 \\.type {s}, %object610 \\.type {s}, %object
src/link.zig+4-4
...@@ -1976,7 +1976,7 @@ fn resolveLibInput(...@@ -1976,7 +1976,7 @@ fn resolveLibInput(
1976 .root_dir = lib_directory,1976 .root_dir = lib_directory,
1977 .sub_path = try std.fmt.allocPrint(arena, "lib{s}.tbd", .{lib_name}),1977 .sub_path = try std.fmt.allocPrint(arena, "lib{s}.tbd", .{lib_name}),
1978 };1978 };
1979 try checked_paths.writer(gpa).print("\n {f}", .{test_path});1979 try checked_paths.print(gpa, "\n {f}", .{test_path});
1980 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {1980 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
1981 error.FileNotFound => break :tbd,1981 error.FileNotFound => break :tbd,
1982 else => |e| fatal("unable to search for tbd library '{f}': {s}", .{ test_path, @errorName(e) }),1982 else => |e| fatal("unable to search for tbd library '{f}': {s}", .{ test_path, @errorName(e) }),
...@@ -1995,7 +1995,7 @@ fn resolveLibInput(...@@ -1995,7 +1995,7 @@ fn resolveLibInput(
1995 },1995 },
1996 }),1996 }),
1997 };1997 };
1998 try checked_paths.writer(gpa).print("\n {f}", .{test_path});1998 try checked_paths.print(gpa, "\n {f}", .{test_path});
1999 switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{1999 switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{
2000 .path = test_path,2000 .path = test_path,
2001 .query = name_query.query,2001 .query = name_query.query,
...@@ -2012,7 +2012,7 @@ fn resolveLibInput(...@@ -2012,7 +2012,7 @@ fn resolveLibInput(
2012 .root_dir = lib_directory,2012 .root_dir = lib_directory,
2013 .sub_path = try std.fmt.allocPrint(arena, "lib{s}.so", .{lib_name}),2013 .sub_path = try std.fmt.allocPrint(arena, "lib{s}.so", .{lib_name}),
2014 };2014 };
2015 try checked_paths.writer(gpa).print("\n {f}", .{test_path});2015 try checked_paths.print(gpa, "\n {f}", .{test_path});
2016 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {2016 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
2017 error.FileNotFound => break :so,2017 error.FileNotFound => break :so,
2018 else => |e| fatal("unable to search for so library '{f}': {s}", .{2018 else => |e| fatal("unable to search for so library '{f}': {s}", .{
...@@ -2030,7 +2030,7 @@ fn resolveLibInput(...@@ -2030,7 +2030,7 @@ fn resolveLibInput(
2030 .root_dir = lib_directory,2030 .root_dir = lib_directory,
2031 .sub_path = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}),2031 .sub_path = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}),
2032 };2032 };
2033 try checked_paths.writer(gpa).print("\n {f}", .{test_path});2033 try checked_paths.print(gpa, "\n {f}", .{test_path});
2034 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {2034 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
2035 error.FileNotFound => break :mingw,2035 error.FileNotFound => break :mingw,
2036 else => |e| fatal("unable to search for static library '{f}': {s}", .{ test_path, @errorName(e) }),2036 else => |e| fatal("unable to search for static library '{f}': {s}", .{ test_path, @errorName(e) }),
src/link/Coff.zig+4-4
...@@ -2179,13 +2179,13 @@ fn writeDataDirectoriesHeaders(coff: *Coff) !void {...@@ -2179,13 +2179,13 @@ fn writeDataDirectoriesHeaders(coff: *Coff) !void {
2179fn writeHeader(coff: *Coff) !void {2179fn writeHeader(coff: *Coff) !void {
2180 const target = &coff.base.comp.root_mod.resolved_target.result;2180 const target = &coff.base.comp.root_mod.resolved_target.result;
2181 const gpa = coff.base.comp.gpa;2181 const gpa = coff.base.comp.gpa;
2182 var buffer = std.array_list.Managed(u8).init(gpa);2182 var buffer: std.Io.Writer.Allocating = .init(gpa);
2183 defer buffer.deinit();2183 defer buffer.deinit();
2184 const writer = buffer.writer();2184 const writer = &buffer.writer;
21852185
2186 try buffer.ensureTotalCapacity(coff.getSizeOfHeaders());2186 try buffer.ensureTotalCapacity(coff.getSizeOfHeaders());
2187 writer.writeAll(&msdos_stub) catch unreachable;2187 writer.writeAll(&msdos_stub) catch unreachable;
2188 mem.writeInt(u32, buffer.items[0x3c..][0..4], msdos_stub.len, .little);2188 mem.writeInt(u32, buffer.writer.buffer[0x3c..][0..4], msdos_stub.len, .little);
21892189
2190 writer.writeAll("PE\x00\x00") catch unreachable;2190 writer.writeAll("PE\x00\x00") catch unreachable;
2191 var flags = coff_util.CoffHeaderFlags{2191 var flags = coff_util.CoffHeaderFlags{
...@@ -2313,7 +2313,7 @@ fn writeHeader(coff: *Coff) !void {...@@ -2313,7 +2313,7 @@ fn writeHeader(coff: *Coff) !void {
2313 },2313 },
2314 }2314 }
23152315
2316 try coff.pwriteAll(buffer.items, 0);2316 try coff.pwriteAll(buffer.written(), 0);
2317}2317}
23182318
2319pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {2319pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
src/link/Elf.zig+34-38
...@@ -811,10 +811,6 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {...@@ -811,10 +811,6 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
811811
812 if (self.base.gc_sections) {812 if (self.base.gc_sections) {
813 try gc.gcAtoms(self);813 try gc.gcAtoms(self);
814
815 if (self.base.print_gc_sections) {
816 try gc.dumpPrunedAtoms(self);
817 }
818 }814 }
819815
820 self.checkDuplicates() catch |err| switch (err) {816 self.checkDuplicates() catch |err| switch (err) {
...@@ -3005,7 +3001,7 @@ fn writeAtoms(self: *Elf) !void {...@@ -3005,7 +3001,7 @@ fn writeAtoms(self: *Elf) !void {
3005 undefs.deinit();3001 undefs.deinit();
3006 }3002 }
30073003
3008 var buffer = std.array_list.Managed(u8).init(gpa);3004 var buffer: std.Io.Writer.Allocating = .init(gpa);
3009 defer buffer.deinit();3005 defer buffer.deinit();
30103006
3011 const slice = self.sections.slice();3007 const slice = self.sections.slice();
...@@ -3032,9 +3028,9 @@ fn writeAtoms(self: *Elf) !void {...@@ -3032,9 +3028,9 @@ fn writeAtoms(self: *Elf) !void {
3032 try buffer.ensureUnusedCapacity(thunk_size);3028 try buffer.ensureUnusedCapacity(thunk_size);
3033 const shdr = slice.items(.shdr)[th.output_section_index];3029 const shdr = slice.items(.shdr)[th.output_section_index];
3034 const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset;3030 const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset;
3035 try th.write(self, buffer.writer());3031 try th.write(self, &buffer.writer);
3036 assert(buffer.items.len == thunk_size);3032 assert(buffer.written().len == thunk_size);
3037 try self.pwriteAll(buffer.items, offset);3033 try self.pwriteAll(buffer.written(), offset);
3038 buffer.clearRetainingCapacity();3034 buffer.clearRetainingCapacity();
3039 }3035 }
3040 }3036 }
...@@ -3166,26 +3162,26 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3166,26 +3162,26 @@ fn writeSyntheticSections(self: *Elf) !void {
31663162
3167 if (self.section_indexes.verneed) |shndx| {3163 if (self.section_indexes.verneed) |shndx| {
3168 const shdr = slice.items(.shdr)[shndx];3164 const shdr = slice.items(.shdr)[shndx];
3169 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.verneed.size());3165 var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.verneed.size());
3170 defer buffer.deinit();3166 defer buffer.deinit();
3171 try self.verneed.write(buffer.writer());3167 try self.verneed.write(&buffer.writer);
3172 try self.pwriteAll(buffer.items, shdr.sh_offset);3168 try self.pwriteAll(buffer.written(), shdr.sh_offset);
3173 }3169 }
31743170
3175 if (self.section_indexes.dynamic) |shndx| {3171 if (self.section_indexes.dynamic) |shndx| {
3176 const shdr = slice.items(.shdr)[shndx];3172 const shdr = slice.items(.shdr)[shndx];
3177 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.dynamic.size(self));3173 var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.dynamic.size(self));
3178 defer buffer.deinit();3174 defer buffer.deinit();
3179 try self.dynamic.write(self, buffer.writer());3175 try self.dynamic.write(self, &buffer.writer);
3180 try self.pwriteAll(buffer.items, shdr.sh_offset);3176 try self.pwriteAll(buffer.written(), shdr.sh_offset);
3181 }3177 }
31823178
3183 if (self.section_indexes.dynsymtab) |shndx| {3179 if (self.section_indexes.dynsymtab) |shndx| {
3184 const shdr = slice.items(.shdr)[shndx];3180 const shdr = slice.items(.shdr)[shndx];
3185 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.dynsym.size());3181 var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.dynsym.size());
3186 defer buffer.deinit();3182 defer buffer.deinit();
3187 try self.dynsym.write(self, buffer.writer());3183 try self.dynsym.write(self, &buffer.writer);
3188 try self.pwriteAll(buffer.items, shdr.sh_offset);3184 try self.pwriteAll(buffer.written(), shdr.sh_offset);
3189 }3185 }
31903186
3191 if (self.section_indexes.dynstrtab) |shndx| {3187 if (self.section_indexes.dynstrtab) |shndx| {
...@@ -3201,28 +3197,28 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3201,28 +3197,28 @@ fn writeSyntheticSections(self: *Elf) !void {
3201 };3197 };
3202 const shdr = slice.items(.shdr)[shndx];3198 const shdr = slice.items(.shdr)[shndx];
3203 const sh_size = try self.cast(usize, shdr.sh_size);3199 const sh_size = try self.cast(usize, shdr.sh_size);
3204 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, @intCast(sh_size - existing_size));3200 var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, @intCast(sh_size - existing_size));
3205 defer buffer.deinit();3201 defer buffer.deinit();
3206 try eh_frame.writeEhFrame(self, buffer.writer());3202 try eh_frame.writeEhFrame(self, &buffer.writer);
3207 assert(buffer.items.len == sh_size - existing_size);3203 assert(buffer.written().len == sh_size - existing_size);
3208 try self.pwriteAll(buffer.items, shdr.sh_offset + existing_size);3204 try self.pwriteAll(buffer.written(), shdr.sh_offset + existing_size);
3209 }3205 }
32103206
3211 if (self.section_indexes.eh_frame_hdr) |shndx| {3207 if (self.section_indexes.eh_frame_hdr) |shndx| {
3212 const shdr = slice.items(.shdr)[shndx];3208 const shdr = slice.items(.shdr)[shndx];
3213 const sh_size = try self.cast(usize, shdr.sh_size);3209 const sh_size = try self.cast(usize, shdr.sh_size);
3214 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, sh_size);3210 var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, sh_size);
3215 defer buffer.deinit();3211 defer buffer.deinit();
3216 try eh_frame.writeEhFrameHdr(self, buffer.writer());3212 try eh_frame.writeEhFrameHdr(self, &buffer.writer);
3217 try self.pwriteAll(buffer.items, shdr.sh_offset);3213 try self.pwriteAll(buffer.written(), shdr.sh_offset);
3218 }3214 }
32193215
3220 if (self.section_indexes.got) |index| {3216 if (self.section_indexes.got) |index| {
3221 const shdr = slice.items(.shdr)[index];3217 const shdr = slice.items(.shdr)[index];
3222 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.got.size(self));3218 var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.got.size(self));
3223 defer buffer.deinit();3219 defer buffer.deinit();
3224 try self.got.write(self, buffer.writer());3220 try self.got.write(self, &buffer.writer);
3225 try self.pwriteAll(buffer.items, shdr.sh_offset);3221 try self.pwriteAll(buffer.written(), shdr.sh_offset);
3226 }3222 }
32273223
3228 if (self.section_indexes.rela_dyn) |shndx| {3224 if (self.section_indexes.rela_dyn) |shndx| {
...@@ -3235,26 +3231,26 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3235,26 +3231,26 @@ fn writeSyntheticSections(self: *Elf) !void {
32353231
3236 if (self.section_indexes.plt) |shndx| {3232 if (self.section_indexes.plt) |shndx| {
3237 const shdr = slice.items(.shdr)[shndx];3233 const shdr = slice.items(.shdr)[shndx];
3238 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.plt.size(self));3234 var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.plt.size(self));
3239 defer buffer.deinit();3235 defer buffer.deinit();
3240 try self.plt.write(self, buffer.writer());3236 try self.plt.write(self, &buffer.writer);
3241 try self.pwriteAll(buffer.items, shdr.sh_offset);3237 try self.pwriteAll(buffer.written(), shdr.sh_offset);
3242 }3238 }
32433239
3244 if (self.section_indexes.got_plt) |shndx| {3240 if (self.section_indexes.got_plt) |shndx| {
3245 const shdr = slice.items(.shdr)[shndx];3241 const shdr = slice.items(.shdr)[shndx];
3246 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.got_plt.size(self));3242 var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.got_plt.size(self));
3247 defer buffer.deinit();3243 defer buffer.deinit();
3248 try self.got_plt.write(self, buffer.writer());3244 try self.got_plt.write(self, &buffer.writer);
3249 try self.pwriteAll(buffer.items, shdr.sh_offset);3245 try self.pwriteAll(buffer.written(), shdr.sh_offset);
3250 }3246 }
32513247
3252 if (self.section_indexes.plt_got) |shndx| {3248 if (self.section_indexes.plt_got) |shndx| {
3253 const shdr = slice.items(.shdr)[shndx];3249 const shdr = slice.items(.shdr)[shndx];
3254 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.plt_got.size(self));3250 var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.plt_got.size(self));
3255 defer buffer.deinit();3251 defer buffer.deinit();
3256 try self.plt_got.write(self, buffer.writer());3252 try self.plt_got.write(self, &buffer.writer);
3257 try self.pwriteAll(buffer.items, shdr.sh_offset);3253 try self.pwriteAll(buffer.written(), shdr.sh_offset);
3258 }3254 }
32593255
3260 if (self.section_indexes.rela_plt) |shndx| {3256 if (self.section_indexes.rela_plt) |shndx| {
...@@ -3757,7 +3753,7 @@ pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 {...@@ -3757,7 +3753,7 @@ pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 {
3757 const gpa = self.base.comp.gpa;3753 const gpa = self.base.comp.gpa;
3758 const off = @as(u32, @intCast(self.shstrtab.items.len));3754 const off = @as(u32, @intCast(self.shstrtab.items.len));
3759 try self.shstrtab.ensureUnusedCapacity(gpa, name.len + 1);3755 try self.shstrtab.ensureUnusedCapacity(gpa, name.len + 1);
3760 self.shstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable;3756 self.shstrtab.print(gpa, "{s}\x00", .{name}) catch unreachable;
3761 return off;3757 return off;
3762}3758}
37633759
...@@ -3770,7 +3766,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {...@@ -3770,7 +3766,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
3770 const gpa = self.base.comp.gpa;3766 const gpa = self.base.comp.gpa;
3771 const off = @as(u32, @intCast(self.dynstrtab.items.len));3767 const off = @as(u32, @intCast(self.dynstrtab.items.len));
3772 try self.dynstrtab.ensureUnusedCapacity(gpa, name.len + 1);3768 try self.dynstrtab.ensureUnusedCapacity(gpa, name.len + 1);
3773 self.dynstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable;3769 self.dynstrtab.print(gpa, "{s}\x00", .{name}) catch unreachable;
3774 return off;3770 return off;
3775}3771}
37763772
src/link/Elf/Archive.zig+4-5
...@@ -123,8 +123,7 @@ pub fn setArHdr(opts: struct {...@@ -123,8 +123,7 @@ pub fn setArHdr(opts: struct {
123 @memcpy(&hdr.ar_fmag, elf.ARFMAG);123 @memcpy(&hdr.ar_fmag, elf.ARFMAG);
124124
125 {125 {
126 var stream = std.io.fixedBufferStream(&hdr.ar_name);126 var writer: std.Io.Writer = .fixed(&hdr.ar_name);
127 const writer = stream.writer();
128 switch (opts.name) {127 switch (opts.name) {
129 .symtab => writer.print("{s}", .{elf.SYM64NAME}) catch unreachable,128 .symtab => writer.print("{s}", .{elf.SYM64NAME}) catch unreachable,
130 .strtab => writer.print("//", .{}) catch unreachable,129 .strtab => writer.print("//", .{}) catch unreachable,
...@@ -133,8 +132,8 @@ pub fn setArHdr(opts: struct {...@@ -133,8 +132,8 @@ pub fn setArHdr(opts: struct {
133 }132 }
134 }133 }
135 {134 {
136 var stream = std.io.fixedBufferStream(&hdr.ar_size);135 var writer: std.Io.Writer = .fixed(&hdr.ar_size);
137 stream.writer().print("{d}", .{opts.size}) catch unreachable;136 writer.print("{d}", .{opts.size}) catch unreachable;
138 }137 }
139138
140 return hdr;139 return hdr;
...@@ -246,7 +245,7 @@ pub const ArStrtab = struct {...@@ -246,7 +245,7 @@ pub const ArStrtab = struct {
246245
247 pub fn insert(ar: *ArStrtab, allocator: Allocator, name: []const u8) error{OutOfMemory}!u32 {246 pub fn insert(ar: *ArStrtab, allocator: Allocator, name: []const u8) error{OutOfMemory}!u32 {
248 const off = @as(u32, @intCast(ar.buffer.items.len));247 const off = @as(u32, @intCast(ar.buffer.items.len));
249 try ar.buffer.writer(allocator).print("{s}/{c}", .{ name, strtab_delimiter });248 try ar.buffer.print(allocator, "{s}/{c}", .{ name, strtab_delimiter });
250 return off;249 return off;
251 }250 }
252251
src/link/Elf/Atom.zig+113-142
...@@ -621,7 +621,6 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi...@@ -621,7 +621,6 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
621621
622 const cpu_arch = elf_file.getTarget().cpu.arch;622 const cpu_arch = elf_file.getTarget().cpu.arch;
623 const file_ptr = self.file(elf_file).?;623 const file_ptr = self.file(elf_file).?;
624 var stream = std.io.fixedBufferStream(code);
625624
626 const rels = self.relocs(elf_file);625 const rels = self.relocs(elf_file);
627 var it = RelocsIterator{ .relocs = rels };626 var it = RelocsIterator{ .relocs = rels };
...@@ -661,20 +660,16 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi...@@ -661,20 +660,16 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
661 target.name(elf_file),660 target.name(elf_file),
662 });661 });
663662
664 try stream.seekTo(r_offset);
665
666 const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP };663 const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP };
667664
668 switch (cpu_arch) {665 switch (cpu_arch) {
669 .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {666 .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code) catch |err| switch (err) {
670 error.RelocFailure,667 error.RelocFailure,
671 error.RelaxFailure,668 error.RelaxFailure,
672 error.InvalidInstruction,
673 error.CannotEncode,
674 => has_reloc_errors = true,669 => has_reloc_errors = true,
675 else => |e| return e,670 else => |e| return e,
676 },671 },
677 .aarch64, .aarch64_be => aarch64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {672 .aarch64, .aarch64_be => aarch64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code) catch |err| switch (err) {
678 error.RelocFailure,673 error.RelocFailure,
679 error.RelaxFailure,674 error.RelaxFailure,
680 error.UnexpectedRemainder,675 error.UnexpectedRemainder,
...@@ -682,7 +677,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi...@@ -682,7 +677,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
682 => has_reloc_errors = true,677 => has_reloc_errors = true,
683 else => |e| return e,678 else => |e| return e,
684 },679 },
685 .riscv64, .riscv64be => riscv.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {680 .riscv64, .riscv64be => riscv.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code) catch |err| switch (err) {
686 error.RelocFailure,681 error.RelocFailure,
687 error.RelaxFailure,682 error.RelaxFailure,
688 => has_reloc_errors = true,683 => has_reloc_errors = true,
...@@ -701,7 +696,8 @@ fn resolveDynAbsReloc(...@@ -701,7 +696,8 @@ fn resolveDynAbsReloc(
701 rel: elf.Elf64_Rela,696 rel: elf.Elf64_Rela,
702 action: RelocAction,697 action: RelocAction,
703 elf_file: *Elf,698 elf_file: *Elf,
704 writer: anytype,699 code: []u8,
700 r_offset: usize,
705) !void {701) !void {
706 const comp = elf_file.base.comp;702 const comp = elf_file.base.comp;
707 const gpa = comp.gpa;703 const gpa = comp.gpa;
...@@ -726,7 +722,7 @@ fn resolveDynAbsReloc(...@@ -726,7 +722,7 @@ fn resolveDynAbsReloc(
726 .copyrel,722 .copyrel,
727 .cplt,723 .cplt,
728 .none,724 .none,
729 => try writer.writeInt(i64, S + A, .little),725 => mem.writeInt(i64, code[r_offset..][0..8], S + A, .little),
730726
731 .dyn_copyrel => {727 .dyn_copyrel => {
732 if (is_writeable or elf_file.z_nocopyreloc) {728 if (is_writeable or elf_file.z_nocopyreloc) {
...@@ -737,9 +733,9 @@ fn resolveDynAbsReloc(...@@ -737,9 +733,9 @@ fn resolveDynAbsReloc(
737 .addend = A,733 .addend = A,
738 .target = target,734 .target = target,
739 });735 });
740 try applyDynamicReloc(A, elf_file, writer);736 applyDynamicReloc(A, code, r_offset);
741 } else {737 } else {
742 try writer.writeInt(i64, S + A, .little);738 mem.writeInt(i64, code[r_offset..][0..8], S + A, .little);
743 }739 }
744 },740 },
745741
...@@ -752,9 +748,9 @@ fn resolveDynAbsReloc(...@@ -752,9 +748,9 @@ fn resolveDynAbsReloc(
752 .addend = A,748 .addend = A,
753 .target = target,749 .target = target,
754 });750 });
755 try applyDynamicReloc(A, elf_file, writer);751 applyDynamicReloc(A, code, r_offset);
756 } else {752 } else {
757 try writer.writeInt(i64, S + A, .little);753 mem.writeInt(i64, code[r_offset..][0..8], S + A, .little);
758 }754 }
759 },755 },
760756
...@@ -766,7 +762,7 @@ fn resolveDynAbsReloc(...@@ -766,7 +762,7 @@ fn resolveDynAbsReloc(
766 .addend = A,762 .addend = A,
767 .target = target,763 .target = target,
768 });764 });
769 try applyDynamicReloc(A, elf_file, writer);765 applyDynamicReloc(A, code, r_offset);
770 },766 },
771767
772 .baserel => {768 .baserel => {
...@@ -776,7 +772,7 @@ fn resolveDynAbsReloc(...@@ -776,7 +772,7 @@ fn resolveDynAbsReloc(
776 .addend = S + A,772 .addend = S + A,
777 .target = target,773 .target = target,
778 });774 });
779 try applyDynamicReloc(S + A, elf_file, writer);775 applyDynamicReloc(S + A, code, r_offset);
780 },776 },
781777
782 .ifunc => {778 .ifunc => {
...@@ -787,16 +783,13 @@ fn resolveDynAbsReloc(...@@ -787,16 +783,13 @@ fn resolveDynAbsReloc(
787 .addend = S_ + A,783 .addend = S_ + A,
788 .target = target,784 .target = target,
789 });785 });
790 try applyDynamicReloc(S_ + A, elf_file, writer);786 applyDynamicReloc(S_ + A, code, r_offset);
791 },787 },
792 }788 }
793}789}
794790
795fn applyDynamicReloc(value: i64, elf_file: *Elf, writer: anytype) !void {791fn applyDynamicReloc(value: i64, code: []u8, r_offset: usize) void {
796 _ = elf_file;792 mem.writeInt(i64, code[r_offset..][0..8], value, .little);
797 // if (elf_file.options.apply_dynamic_relocs) {
798 try writer.writeInt(i64, value, .little);
799 // }
800}793}
801794
802pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void {795pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void {
...@@ -804,7 +797,6 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any...@@ -804,7 +797,6 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
804797
805 const cpu_arch = elf_file.getTarget().cpu.arch;798 const cpu_arch = elf_file.getTarget().cpu.arch;
806 const file_ptr = self.file(elf_file).?;799 const file_ptr = self.file(elf_file).?;
807 var stream = std.io.fixedBufferStream(code);
808800
809 const rels = self.relocs(elf_file);801 const rels = self.relocs(elf_file);
810 var has_reloc_errors = false;802 var has_reloc_errors = false;
...@@ -863,18 +855,16 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any...@@ -863,18 +855,16 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
863 target.name(elf_file),855 target.name(elf_file),
864 });856 });
865857
866 try stream.seekTo(r_offset);
867
868 switch (cpu_arch) {858 switch (cpu_arch) {
869 .x86_64 => x86_64.resolveRelocNonAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {859 .x86_64 => x86_64.resolveRelocNonAlloc(self, elf_file, rel, target, args, code[r_offset..]) catch |err| switch (err) {
870 error.RelocFailure => has_reloc_errors = true,860 error.RelocFailure => has_reloc_errors = true,
871 else => |e| return e,861 else => |e| return e,
872 },862 },
873 .aarch64, .aarch64_be => aarch64.resolveRelocNonAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {863 .aarch64, .aarch64_be => aarch64.resolveRelocNonAlloc(self, elf_file, rel, target, args, code[r_offset..]) catch |err| switch (err) {
874 error.RelocFailure => has_reloc_errors = true,864 error.RelocFailure => has_reloc_errors = true,
875 else => |e| return e,865 else => |e| return e,
876 },866 },
877 .riscv64, .riscv64be => riscv.resolveRelocNonAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {867 .riscv64, .riscv64be => riscv.resolveRelocNonAlloc(self, elf_file, rel, target, args, code[r_offset..]) catch |err| switch (err) {
878 error.RelocFailure => has_reloc_errors = true,868 error.RelocFailure => has_reloc_errors = true,
879 else => |e| return e,869 else => |e| return e,
880 },870 },
...@@ -915,7 +905,7 @@ const Format = struct {...@@ -915,7 +905,7 @@ const Format = struct {
915 atom: Atom,905 atom: Atom,
916 elf_file: *Elf,906 elf_file: *Elf,
917907
918 fn default(f: Format, w: *std.io.Writer) std.io.Writer.Error!void {908 fn default(f: Format, w: *Writer) Writer.Error!void {
919 const atom = f.atom;909 const atom = f.atom;
920 const elf_file = f.elf_file;910 const elf_file = f.elf_file;
921 try w.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x}) : prev({f}) : next({f})", .{911 try w.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x}) : prev({f}) : next({f})", .{
...@@ -1068,16 +1058,13 @@ const x86_64 = struct {...@@ -1068,16 +1058,13 @@ const x86_64 = struct {
1068 args: ResolveArgs,1058 args: ResolveArgs,
1069 it: *RelocsIterator,1059 it: *RelocsIterator,
1070 code: []u8,1060 code: []u8,
1071 stream: anytype,1061 ) !void {
1072 ) (error{ InvalidInstruction, CannotEncode } || RelocError)!void {
1073 dev.check(.x86_64_backend);1062 dev.check(.x86_64_backend);
1074 const t = &elf_file.base.comp.root_mod.resolved_target.result;1063 const t = &elf_file.base.comp.root_mod.resolved_target.result;
1075 const diags = &elf_file.base.comp.link_diags;1064 const diags = &elf_file.base.comp.link_diags;
1076 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());1065 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
1077 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;1066 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
10781067
1079 const cwriter = stream.writer();
1080
1081 const P, const A, const S, const GOT, const G, const TP, const DTP = args;1068 const P, const A, const S, const GOT, const G, const TP, const DTP = args;
10821069
1083 switch (r_type) {1070 switch (r_type) {
...@@ -1089,58 +1076,60 @@ const x86_64 = struct {...@@ -1089,58 +1076,60 @@ const x86_64 = struct {
1089 rel,1076 rel,
1090 dynAbsRelocAction(target, elf_file),1077 dynAbsRelocAction(target, elf_file),
1091 elf_file,1078 elf_file,
1092 cwriter,1079 code,
1080 r_offset,
1093 );1081 );
1094 },1082 },
10951083
1096 .PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),1084 .PLT32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S + A - P)), .little),
1097 .PC32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),1085 .PC32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S + A - P)), .little),
10981086
1099 .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),1087 .GOTPCREL => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(G + GOT + A - P)), .little),
1100 .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),1088 .GOTPC32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(GOT + A - P)), .little),
1101 .GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little),1089 .GOTPC64 => mem.writeInt(i64, code[r_offset..][0..8], GOT + A - P, .little),
11021090
1103 .GOTPCRELX => {1091 .GOTPCRELX => {
1104 if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {1092 if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
1105 x86_64.relaxGotpcrelx(code[r_offset - 2 ..], t) catch break :blk;1093 x86_64.relaxGotpcrelx(code[r_offset - 2 ..], t) catch break :blk;
1106 try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);1094 mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S + A - P)), .little);
1107 return;1095 return;
1108 }1096 }
1109 try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);1097 mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(G + GOT + A - P)), .little);
1110 },1098 },
11111099
1112 .REX_GOTPCRELX => {1100 .REX_GOTPCRELX => {
1113 if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {1101 if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
1114 x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..], t) catch break :blk;1102 x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..], t) catch break :blk;
1115 try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);1103 mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S + A - P)), .little);
1116 return;1104 return;
1117 }1105 }
1118 try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);1106 mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(G + GOT + A - P)), .little);
1119 },1107 },
11201108
1121 .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),1109 .@"32" => mem.writeInt(u32, code[r_offset..][0..4], @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
1122 .@"32S" => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little),1110 .@"32S" => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @truncate(S + A)), .little),
11231111
1124 .TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little),1112 .TPOFF32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @truncate(S + A - TP)), .little),
1125 .TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little),1113 .TPOFF64 => mem.writeInt(i64, code[r_offset..][0..8], S + A - TP, .little),
11261114
1127 .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little),1115 .DTPOFF32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @truncate(S + A - DTP)), .little),
1128 .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little),1116 .DTPOFF64 => mem.writeInt(i64, code[r_offset..][0..8], S + A - DTP, .little),
11291117
1130 .TLSGD => {1118 .TLSGD => {
1131 if (target.flags.has_tlsgd) {1119 if (target.flags.has_tlsgd) {
1132 const S_ = target.tlsGdAddress(elf_file);1120 const S_ = target.tlsGdAddress(elf_file);
1133 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1121 mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S_ + A - P)), .little);
1134 } else if (target.flags.has_gottp) {1122 } else if (target.flags.has_gottp) {
1135 const S_ = target.gotTpAddress(elf_file);1123 const S_ = target.gotTpAddress(elf_file);
1136 try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, stream);1124 try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, code, r_offset);
1137 } else {1125 } else {
1138 try x86_64.relaxTlsGdToLe(1126 try x86_64.relaxTlsGdToLe(
1139 atom,1127 atom,
1140 &.{ rel, it.next().? },1128 &.{ rel, it.next().? },
1141 @as(i32, @intCast(S - TP)),1129 @as(i32, @intCast(S - TP)),
1142 elf_file,1130 elf_file,
1143 stream,1131 code,
1132 r_offset,
1144 );1133 );
1145 }1134 }
1146 },1135 },
...@@ -1149,14 +1138,15 @@ const x86_64 = struct {...@@ -1149,14 +1138,15 @@ const x86_64 = struct {
1149 if (elf_file.got.tlsld_index) |entry_index| {1138 if (elf_file.got.tlsld_index) |entry_index| {
1150 const tlsld_entry = elf_file.got.entries.items[entry_index];1139 const tlsld_entry = elf_file.got.entries.items[entry_index];
1151 const S_ = tlsld_entry.address(elf_file);1140 const S_ = tlsld_entry.address(elf_file);
1152 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1141 mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S_ + A - P)), .little);
1153 } else {1142 } else {
1154 try x86_64.relaxTlsLdToLe(1143 try x86_64.relaxTlsLdToLe(
1155 atom,1144 atom,
1156 &.{ rel, it.next().? },1145 &.{ rel, it.next().? },
1157 @as(i32, @intCast(TP - elf_file.tlsAddress())),1146 @as(i32, @intCast(TP - elf_file.tlsAddress())),
1158 elf_file,1147 elf_file,
1159 stream,1148 code,
1149 r_offset,
1160 );1150 );
1161 }1151 }
1162 },1152 },
...@@ -1164,7 +1154,7 @@ const x86_64 = struct {...@@ -1164,7 +1154,7 @@ const x86_64 = struct {
1164 .GOTPC32_TLSDESC => {1154 .GOTPC32_TLSDESC => {
1165 if (target.flags.has_tlsdesc) {1155 if (target.flags.has_tlsdesc) {
1166 const S_ = target.tlsDescAddress(elf_file);1156 const S_ = target.tlsDescAddress(elf_file);
1167 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1157 mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S_ + A - P)), .little);
1168 } else {1158 } else {
1169 x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..], t) catch {1159 x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..], t) catch {
1170 var err = try diags.addErrorWithNotes(1);1160 var err = try diags.addErrorWithNotes(1);
...@@ -1176,26 +1166,26 @@ const x86_64 = struct {...@@ -1176,26 +1166,26 @@ const x86_64 = struct {
1176 });1166 });
1177 return error.RelaxFailure;1167 return error.RelaxFailure;
1178 };1168 };
1179 try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);1169 mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S - TP)), .little);
1180 }1170 }
1181 },1171 },
11821172
1183 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {1173 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
1184 // call -> nop1174 // call -> nop
1185 try cwriter.writeAll(&.{ 0x66, 0x90 });1175 code[r_offset..][0..2].* = .{ 0x66, 0x90 };
1186 },1176 },
11871177
1188 .GOTTPOFF => {1178 .GOTTPOFF => {
1189 if (target.flags.has_gottp) {1179 if (target.flags.has_gottp) {
1190 const S_ = target.gotTpAddress(elf_file);1180 const S_ = target.gotTpAddress(elf_file);
1191 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1181 mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S_ + A - P)), .little);
1192 } else {1182 } else {
1193 x86_64.relaxGotTpOff(code[r_offset - 3 ..], t);1183 x86_64.relaxGotTpOff(code[r_offset - 3 ..], t);
1194 try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);1184 mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S - TP)), .little);
1195 }1185 }
1196 },1186 },
11971187
1198 .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + A)), .little),1188 .GOT32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(G + A)), .little),
11991189
1200 else => try atom.reportUnhandledRelocError(rel, elf_file),1190 else => try atom.reportUnhandledRelocError(rel, elf_file),
1201 }1191 }
...@@ -1207,45 +1197,42 @@ const x86_64 = struct {...@@ -1207,45 +1197,42 @@ const x86_64 = struct {
1207 rel: elf.Elf64_Rela,1197 rel: elf.Elf64_Rela,
1208 target: *const Symbol,1198 target: *const Symbol,
1209 args: ResolveArgs,1199 args: ResolveArgs,
1210 it: *RelocsIterator,
1211 code: []u8,1200 code: []u8,
1212 stream: anytype,
1213 ) !void {1201 ) !void {
1214 dev.check(.x86_64_backend);1202 dev.check(.x86_64_backend);
1215 _ = code;
1216 _ = it;
1217 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());1203 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
1218 const cwriter = stream.writer();
12191204
1220 _, const A, const S, const GOT, _, _, const DTP = args;1205 _, const A, const S, const GOT, _, _, const DTP = args;
12211206
1207 var writer: Writer = .fixed(code);
1208
1222 switch (r_type) {1209 switch (r_type) {
1223 .NONE => unreachable,1210 .NONE => unreachable,
1224 .@"8" => try cwriter.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little),1211 .@"8" => try writer.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little),
1225 .@"16" => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little),1212 .@"16" => try writer.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little),
1226 .@"32" => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little),1213 .@"32" => try writer.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little),
1227 .@"32S" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),1214 .@"32S" => try writer.writeInt(i32, @as(i32, @intCast(S + A)), .little),
1228 .@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value|1215 .@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
1229 try cwriter.writeInt(u64, value, .little)1216 try writer.writeInt(u64, value, .little)
1230 else1217 else
1231 try cwriter.writeInt(i64, S + A, .little),1218 try writer.writeInt(i64, S + A, .little),
1232 .DTPOFF32 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|1219 .DTPOFF32 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
1233 try cwriter.writeInt(u64, value, .little)1220 try writer.writeInt(u64, value, .little)
1234 else1221 else
1235 try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little),1222 try writer.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little),
1236 .DTPOFF64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|1223 .DTPOFF64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
1237 try cwriter.writeInt(u64, value, .little)1224 try writer.writeInt(u64, value, .little)
1238 else1225 else
1239 try cwriter.writeInt(i64, S + A - DTP, .little),1226 try writer.writeInt(i64, S + A - DTP, .little),
1240 .GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little),1227 .GOTOFF64 => try writer.writeInt(i64, S + A - GOT, .little),
1241 .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little),1228 .GOTPC64 => try writer.writeInt(i64, GOT + A, .little),
1242 .SIZE32 => {1229 .SIZE32 => {
1243 const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));1230 const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));
1244 try cwriter.writeInt(u32, @bitCast(@as(i32, @intCast(size + A))), .little);1231 try writer.writeInt(u32, @bitCast(@as(i32, @intCast(size + A))), .little);
1245 },1232 },
1246 .SIZE64 => {1233 .SIZE64 => {
1247 const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));1234 const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));
1248 try cwriter.writeInt(i64, @intCast(size + A), .little);1235 try writer.writeInt(i64, @intCast(size + A), .little);
1249 },1236 },
1250 else => try atom.reportUnhandledRelocError(rel, elf_file),1237 else => try atom.reportUnhandledRelocError(rel, elf_file),
1251 }1238 }
...@@ -1288,12 +1275,12 @@ const x86_64 = struct {...@@ -1288,12 +1275,12 @@ const x86_64 = struct {
1288 rels: []const elf.Elf64_Rela,1275 rels: []const elf.Elf64_Rela,
1289 value: i32,1276 value: i32,
1290 elf_file: *Elf,1277 elf_file: *Elf,
1291 stream: anytype,1278 code: []u8,
1279 r_offset: usize,
1292 ) !void {1280 ) !void {
1293 dev.check(.x86_64_backend);1281 dev.check(.x86_64_backend);
1294 assert(rels.len == 2);1282 assert(rels.len == 2);
1295 const diags = &elf_file.base.comp.link_diags;1283 const diags = &elf_file.base.comp.link_diags;
1296 const writer = stream.writer();
1297 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());1284 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
1298 switch (rel) {1285 switch (rel) {
1299 .PC32,1286 .PC32,
...@@ -1304,8 +1291,7 @@ const x86_64 = struct {...@@ -1304,8 +1291,7 @@ const x86_64 = struct {
1304 0x48, 0x03, 0x05, 0, 0, 0, 0, // add foo@gottpoff(%rip), %rax1291 0x48, 0x03, 0x05, 0, 0, 0, 0, // add foo@gottpoff(%rip), %rax
1305 };1292 };
1306 std.mem.writeInt(i32, insts[12..][0..4], value - 12, .little);1293 std.mem.writeInt(i32, insts[12..][0..4], value - 12, .little);
1307 try stream.seekBy(-4);1294 @memcpy(code[r_offset - 4 ..][0..insts.len], &insts);
1308 try writer.writeAll(&insts);
1309 },1295 },
13101296
1311 else => {1297 else => {
...@@ -1329,12 +1315,12 @@ const x86_64 = struct {...@@ -1329,12 +1315,12 @@ const x86_64 = struct {
1329 rels: []const elf.Elf64_Rela,1315 rels: []const elf.Elf64_Rela,
1330 value: i32,1316 value: i32,
1331 elf_file: *Elf,1317 elf_file: *Elf,
1332 stream: anytype,1318 code: []u8,
1319 r_offset: usize,
1333 ) !void {1320 ) !void {
1334 dev.check(.x86_64_backend);1321 dev.check(.x86_64_backend);
1335 assert(rels.len == 2);1322 assert(rels.len == 2);
1336 const diags = &elf_file.base.comp.link_diags;1323 const diags = &elf_file.base.comp.link_diags;
1337 const writer = stream.writer();
1338 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());1324 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
1339 switch (rel) {1325 switch (rel) {
1340 .PC32,1326 .PC32,
...@@ -1346,8 +1332,7 @@ const x86_64 = struct {...@@ -1346,8 +1332,7 @@ const x86_64 = struct {
1346 0x48, 0x2d, 0, 0, 0, 0, // sub $tls_size, %rax1332 0x48, 0x2d, 0, 0, 0, 0, // sub $tls_size, %rax
1347 };1333 };
1348 std.mem.writeInt(i32, insts[8..][0..4], value, .little);1334 std.mem.writeInt(i32, insts[8..][0..4], value, .little);
1349 try stream.seekBy(-3);1335 @memcpy(code[r_offset - 3 ..][0..insts.len], &insts);
1350 try writer.writeAll(&insts);
1351 },1336 },
13521337
1353 .GOTPCREL,1338 .GOTPCREL,
...@@ -1360,8 +1345,7 @@ const x86_64 = struct {...@@ -1360,8 +1345,7 @@ const x86_64 = struct {
1360 0x90, // nop1345 0x90, // nop
1361 };1346 };
1362 std.mem.writeInt(i32, insts[8..][0..4], value, .little);1347 std.mem.writeInt(i32, insts[8..][0..4], value, .little);
1363 try stream.seekBy(-3);1348 @memcpy(code[r_offset - 3 ..][0..insts.len], &insts);
1364 try writer.writeAll(&insts);
1365 },1349 },
13661350
1367 else => {1351 else => {
...@@ -1390,7 +1374,7 @@ const x86_64 = struct {...@@ -1390,7 +1374,7 @@ const x86_64 = struct {
1390 // TODO: hack to force imm32s in the assembler1374 // TODO: hack to force imm32s in the assembler
1391 .{ .imm = .s(-129) },1375 .{ .imm = .s(-129) },
1392 }, t) catch return false;1376 }, t) catch return false;
1393 var trash: std.io.Writer.Discarding = .init(&.{});1377 var trash: Writer.Discarding = .init(&.{});
1394 inst.encode(&trash.writer, .{}) catch return false;1378 inst.encode(&trash.writer, .{}) catch return false;
1395 return true;1379 return true;
1396 },1380 },
...@@ -1437,12 +1421,12 @@ const x86_64 = struct {...@@ -1437,12 +1421,12 @@ const x86_64 = struct {
1437 rels: []const elf.Elf64_Rela,1421 rels: []const elf.Elf64_Rela,
1438 value: i32,1422 value: i32,
1439 elf_file: *Elf,1423 elf_file: *Elf,
1440 stream: anytype,1424 code: []u8,
1425 r_offset: usize,
1441 ) !void {1426 ) !void {
1442 dev.check(.x86_64_backend);1427 dev.check(.x86_64_backend);
1443 assert(rels.len == 2);1428 assert(rels.len == 2);
1444 const diags = &elf_file.base.comp.link_diags;1429 const diags = &elf_file.base.comp.link_diags;
1445 const writer = stream.writer();
1446 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());1430 const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
1447 switch (rel) {1431 switch (rel) {
1448 .PC32,1432 .PC32,
...@@ -1455,8 +1439,7 @@ const x86_64 = struct {...@@ -1455,8 +1439,7 @@ const x86_64 = struct {
1455 0x48, 0x81, 0xc0, 0, 0, 0, 0, // add $tp_offset, %rax1439 0x48, 0x81, 0xc0, 0, 0, 0, 0, // add $tp_offset, %rax
1456 };1440 };
1457 std.mem.writeInt(i32, insts[12..][0..4], value, .little);1441 std.mem.writeInt(i32, insts[12..][0..4], value, .little);
1458 try stream.seekBy(-4);1442 @memcpy(code[r_offset - 4 ..][0..insts.len], &insts);
1459 try writer.writeAll(&insts);
1460 relocs_log.debug(" relaxing {f} and {f}", .{1443 relocs_log.debug(" relaxing {f} and {f}", .{
1461 relocation.fmtRelocType(rels[0].r_type(), .x86_64),1444 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
1462 relocation.fmtRelocType(rels[1].r_type(), .x86_64),1445 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
...@@ -1486,8 +1469,8 @@ const x86_64 = struct {...@@ -1486,8 +1469,8 @@ const x86_64 = struct {
1486 }1469 }
14871470
1488 fn encode(insts: []const Instruction, code: []u8) !void {1471 fn encode(insts: []const Instruction, code: []u8) !void {
1489 var stream: std.io.Writer = .fixed(code);1472 var writer: Writer = .fixed(code);
1490 for (insts) |inst| try inst.encode(&stream, .{});1473 for (insts) |inst| try inst.encode(&writer, .{});
1491 }1474 }
14921475
1493 const bits = @import("../../arch/x86_64/bits.zig");1476 const bits = @import("../../arch/x86_64/bits.zig");
...@@ -1592,14 +1575,12 @@ const aarch64 = struct {...@@ -1592,14 +1575,12 @@ const aarch64 = struct {
1592 args: ResolveArgs,1575 args: ResolveArgs,
1593 it: *RelocsIterator,1576 it: *RelocsIterator,
1594 code_buffer: []u8,1577 code_buffer: []u8,
1595 stream: anytype,
1596 ) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void {1578 ) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void {
1597 _ = it;1579 _ = it;
15981580
1599 const diags = &elf_file.base.comp.link_diags;1581 const diags = &elf_file.base.comp.link_diags;
1600 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());1582 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
1601 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;1583 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
1602 const cwriter = stream.writer();
1603 const code = code_buffer[r_offset..][0..4];1584 const code = code_buffer[r_offset..][0..4];
1604 const file_ptr = atom.file(elf_file).?;1585 const file_ptr = atom.file(elf_file).?;
16051586
...@@ -1614,7 +1595,8 @@ const aarch64 = struct {...@@ -1614,7 +1595,8 @@ const aarch64 = struct {
1614 rel,1595 rel,
1615 dynAbsRelocAction(target, elf_file),1596 dynAbsRelocAction(target, elf_file),
1616 elf_file,1597 elf_file,
1617 cwriter,1598 code_buffer,
1599 r_offset,
1618 );1600 );
1619 },1601 },
16201602
...@@ -1782,25 +1764,20 @@ const aarch64 = struct {...@@ -1782,25 +1764,20 @@ const aarch64 = struct {
1782 rel: elf.Elf64_Rela,1764 rel: elf.Elf64_Rela,
1783 target: *const Symbol,1765 target: *const Symbol,
1784 args: ResolveArgs,1766 args: ResolveArgs,
1785 it: *RelocsIterator,
1786 code: []u8,1767 code: []u8,
1787 stream: anytype,
1788 ) !void {1768 ) !void {
1789 _ = it;
1790 _ = code;
1791
1792 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());1769 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
1793 const cwriter = stream.writer();
17941770
1795 _, const A, const S, _, _, _, _ = args;1771 _, const A, const S, _, _, _, _ = args;
17961772
1773 var writer: Writer = .fixed(code);
1797 switch (r_type) {1774 switch (r_type) {
1798 .NONE => unreachable,1775 .NONE => unreachable,
1799 .ABS32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),1776 .ABS32 => try writer.writeInt(i32, @as(i32, @intCast(S + A)), .little),
1800 .ABS64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|1777 .ABS64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
1801 try cwriter.writeInt(u64, value, .little)1778 try writer.writeInt(u64, value, .little)
1802 else1779 else
1803 try cwriter.writeInt(i64, S + A, .little),1780 try writer.writeInt(i64, S + A, .little),
1804 else => try atom.reportUnhandledRelocError(rel, elf_file),1781 else => try atom.reportUnhandledRelocError(rel, elf_file),
1805 }1782 }
1806 }1783 }
...@@ -1861,12 +1838,10 @@ const riscv = struct {...@@ -1861,12 +1838,10 @@ const riscv = struct {
1861 args: ResolveArgs,1838 args: ResolveArgs,
1862 it: *RelocsIterator,1839 it: *RelocsIterator,
1863 code: []u8,1840 code: []u8,
1864 stream: anytype,
1865 ) !void {1841 ) !void {
1866 const diags = &elf_file.base.comp.link_diags;1842 const diags = &elf_file.base.comp.link_diags;
1867 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());1843 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
1868 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;1844 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
1869 const cwriter = stream.writer();
18701845
1871 const P, const A, const S, const GOT, const G, const TP, const DTP = args;1846 const P, const A, const S, const GOT, const G, const TP, const DTP = args;
1872 _ = TP;1847 _ = TP;
...@@ -1875,7 +1850,7 @@ const riscv = struct {...@@ -1875,7 +1850,7 @@ const riscv = struct {
1875 switch (r_type) {1850 switch (r_type) {
1876 .NONE => unreachable,1851 .NONE => unreachable,
18771852
1878 .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),1853 .@"32" => mem.writeInt(u32, code[r_offset..][0..4], @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
18791854
1880 .@"64" => {1855 .@"64" => {
1881 try atom.resolveDynAbsReloc(1856 try atom.resolveDynAbsReloc(
...@@ -1883,7 +1858,8 @@ const riscv = struct {...@@ -1883,7 +1858,8 @@ const riscv = struct {
1883 rel,1858 rel,
1884 dynAbsRelocAction(target, elf_file),1859 dynAbsRelocAction(target, elf_file),
1885 elf_file,1860 elf_file,
1886 cwriter,1861 code,
1862 r_offset,
1887 );1863 );
1888 },1864 },
18891865
...@@ -1997,15 +1973,9 @@ const riscv = struct {...@@ -1997,15 +1973,9 @@ const riscv = struct {
1997 rel: elf.Elf64_Rela,1973 rel: elf.Elf64_Rela,
1998 target: *const Symbol,1974 target: *const Symbol,
1999 args: ResolveArgs,1975 args: ResolveArgs,
2000 it: *RelocsIterator,
2001 code: []u8,1976 code: []u8,
2002 stream: anytype,
2003 ) !void {1977 ) !void {
2004 _ = it;
2005
2006 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());1978 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
2007 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
2008 const cwriter = stream.writer();
20091979
2010 _, const A, const S, const GOT, _, _, const DTP = args;1980 _, const A, const S, const GOT, _, _, const DTP = args;
2011 _ = GOT;1981 _ = GOT;
...@@ -2014,30 +1984,29 @@ const riscv = struct {...@@ -2014,30 +1984,29 @@ const riscv = struct {
2014 switch (r_type) {1984 switch (r_type) {
2015 .NONE => unreachable,1985 .NONE => unreachable,
20161986
2017 .@"32" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),1987 .@"32" => mem.writeInt(i32, code[0..4], @intCast(S + A), .little),
2018 .@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value|1988 .@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
2019 try cwriter.writeInt(u64, value, .little)1989 mem.writeInt(u64, code[0..8], value, .little)
2020 else1990 else
2021 try cwriter.writeInt(i64, S + A, .little),1991 mem.writeInt(i64, code[0..8], S + A, .little),
20221992 .ADD8 => riscv_util.writeAddend(i8, .add, code[0..1], S + A),
2023 .ADD8 => riscv_util.writeAddend(i8, .add, code[r_offset..][0..1], S + A),1993 .SUB8 => riscv_util.writeAddend(i8, .sub, code[0..1], S + A),
2024 .SUB8 => riscv_util.writeAddend(i8, .sub, code[r_offset..][0..1], S + A),1994 .ADD16 => riscv_util.writeAddend(i16, .add, code[0..2], S + A),
2025 .ADD16 => riscv_util.writeAddend(i16, .add, code[r_offset..][0..2], S + A),1995 .SUB16 => riscv_util.writeAddend(i16, .sub, code[0..2], S + A),
2026 .SUB16 => riscv_util.writeAddend(i16, .sub, code[r_offset..][0..2], S + A),1996 .ADD32 => riscv_util.writeAddend(i32, .add, code[0..4], S + A),
2027 .ADD32 => riscv_util.writeAddend(i32, .add, code[r_offset..][0..4], S + A),1997 .SUB32 => riscv_util.writeAddend(i32, .sub, code[0..4], S + A),
2028 .SUB32 => riscv_util.writeAddend(i32, .sub, code[r_offset..][0..4], S + A),1998 .ADD64 => riscv_util.writeAddend(i64, .add, code[0..8], S + A),
2029 .ADD64 => riscv_util.writeAddend(i64, .add, code[r_offset..][0..8], S + A),1999 .SUB64 => riscv_util.writeAddend(i64, .sub, code[0..8], S + A),
2030 .SUB64 => riscv_util.writeAddend(i64, .sub, code[r_offset..][0..8], S + A),2000
20312001 .SET8 => mem.writeInt(i8, code[0..1], @as(i8, @truncate(S + A)), .little),
2032 .SET8 => mem.writeInt(i8, code[r_offset..][0..1], @as(i8, @truncate(S + A)), .little),2002 .SET16 => mem.writeInt(i16, code[0..2], @as(i16, @truncate(S + A)), .little),
2033 .SET16 => mem.writeInt(i16, code[r_offset..][0..2], @as(i16, @truncate(S + A)), .little),2003 .SET32 => mem.writeInt(i32, code[0..4], @as(i32, @truncate(S + A)), .little),
2034 .SET32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @truncate(S + A)), .little),2004
20352005 .SET6 => riscv_util.writeSetSub6(.set, code[0..1], S + A),
2036 .SET6 => riscv_util.writeSetSub6(.set, code[r_offset..][0..1], S + A),2006 .SUB6 => riscv_util.writeSetSub6(.sub, code[0..1], S + A),
2037 .SUB6 => riscv_util.writeSetSub6(.sub, code[r_offset..][0..1], S + A),2007
20382008 .SET_ULEB128 => riscv_util.writeSetUleb(code, S + A),
2039 .SET_ULEB128 => try riscv_util.writeSetSubUleb(.set, stream, S + A),2009 .SUB_ULEB128 => riscv_util.writeSubUleb(code, S - A),
2040 .SUB_ULEB128 => try riscv_util.writeSetSubUleb(.sub, stream, S - A),
20412010
2042 else => try atom.reportUnhandledRelocError(rel, elf_file),2011 else => try atom.reportUnhandledRelocError(rel, elf_file),
2043 }2012 }
...@@ -2108,14 +2077,16 @@ pub const Extra = struct {...@@ -2108,14 +2077,16 @@ pub const Extra = struct {
2108const std = @import("std");2077const std = @import("std");
2109const assert = std.debug.assert;2078const assert = std.debug.assert;
2110const elf = std.elf;2079const elf = std.elf;
2111const eh_frame = @import("eh_frame.zig");
2112const log = std.log.scoped(.link);2080const log = std.log.scoped(.link);
2113const math = std.math;2081const math = std.math;
2114const mem = std.mem;2082const mem = std.mem;
2115const relocs_log = std.log.scoped(.link_relocs);2083const relocs_log = std.log.scoped(.link_relocs);
2084const Allocator = mem.Allocator;
2085const Writer = std.Io.Writer;
2086
2087const eh_frame = @import("eh_frame.zig");
2116const relocation = @import("relocation.zig");2088const relocation = @import("relocation.zig");
21172089
2118const Allocator = mem.Allocator;
2119const Atom = @This();2090const Atom = @This();
2120const Elf = @import("../Elf.zig");2091const Elf = @import("../Elf.zig");
2121const Fde = eh_frame.Fde;2092const Fde = eh_frame.Fde;
src/link/Elf/AtomList.zig+4-5
...@@ -89,7 +89,7 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void {...@@ -89,7 +89,7 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
89 list.dirty = false;89 list.dirty = false;
90}90}
9191
92pub fn write(list: AtomList, buffer: *std.array_list.Managed(u8), undefs: anytype, elf_file: *Elf) !void {92pub fn write(list: AtomList, buffer: *std.Io.Writer.Allocating, undefs: anytype, elf_file: *Elf) !void {
93 const gpa = elf_file.base.comp.gpa;93 const gpa = elf_file.base.comp.gpa;
94 const osec = elf_file.sections.items(.shdr)[list.output_section_index];94 const osec = elf_file.sections.items(.shdr)[list.output_section_index];
95 assert(osec.sh_type != elf.SHT_NOBITS);95 assert(osec.sh_type != elf.SHT_NOBITS);
...@@ -98,8 +98,7 @@ pub fn write(list: AtomList, buffer: *std.array_list.Managed(u8), undefs: anytyp...@@ -98,8 +98,7 @@ pub fn write(list: AtomList, buffer: *std.array_list.Managed(u8), undefs: anytyp
98 log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)});98 log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)});
9999
100 const list_size = math.cast(usize, list.size) orelse return error.Overflow;100 const list_size = math.cast(usize, list.size) orelse return error.Overflow;
101 try buffer.ensureUnusedCapacity(list_size);101 try buffer.writer.splatByteAll(0, list_size);
102 buffer.appendNTimesAssumeCapacity(0, list_size);
103102
104 for (list.atoms.keys()) |ref| {103 for (list.atoms.keys()) |ref| {
105 const atom_ptr = elf_file.atom(ref).?;104 const atom_ptr = elf_file.atom(ref).?;
...@@ -113,7 +112,7 @@ pub fn write(list: AtomList, buffer: *std.array_list.Managed(u8), undefs: anytyp...@@ -113,7 +112,7 @@ pub fn write(list: AtomList, buffer: *std.array_list.Managed(u8), undefs: anytyp
113 const object = atom_ptr.file(elf_file).?.object;112 const object = atom_ptr.file(elf_file).?.object;
114 const code = try object.codeDecompressAlloc(elf_file, ref.index);113 const code = try object.codeDecompressAlloc(elf_file, ref.index);
115 defer gpa.free(code);114 defer gpa.free(code);
116 const out_code = buffer.items[off..][0..size];115 const out_code = buffer.written()[off..][0..size];
117 @memcpy(out_code, code);116 @memcpy(out_code, code);
118117
119 if (osec.sh_flags & elf.SHF_ALLOC == 0)118 if (osec.sh_flags & elf.SHF_ALLOC == 0)
...@@ -122,7 +121,7 @@ pub fn write(list: AtomList, buffer: *std.array_list.Managed(u8), undefs: anytyp...@@ -122,7 +121,7 @@ pub fn write(list: AtomList, buffer: *std.array_list.Managed(u8), undefs: anytyp
122 try atom_ptr.resolveRelocsAlloc(elf_file, out_code);121 try atom_ptr.resolveRelocsAlloc(elf_file, out_code);
123 }122 }
124123
125 try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file));124 try elf_file.base.file.?.pwriteAll(buffer.written(), list.offset(elf_file));
126 buffer.clearRetainingCapacity();125 buffer.clearRetainingCapacity();
127}126}
128127
src/link/Elf/Object.zig+1-1
...@@ -952,7 +952,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -952,7 +952,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
952 const is_tls = sym.type(elf_file) == elf.STT_TLS;952 const is_tls = sym.type(elf_file) == elf.STT_TLS;
953 const name = if (is_tls) ".tls_common" else ".common";953 const name = if (is_tls) ".tls_common" else ".common";
954 const name_offset = @as(u32, @intCast(self.strtab.items.len));954 const name_offset = @as(u32, @intCast(self.strtab.items.len));
955 try self.strtab.writer(gpa).print("{s}\x00", .{name});955 try self.strtab.print(gpa, "{s}\x00", .{name});
956956
957 var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE;957 var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE;
958 if (is_tls) sh_flags |= elf.SHF_TLS;958 if (is_tls) sh_flags |= elf.SHF_TLS;
src/link/Elf/gc.zig-16
...@@ -162,22 +162,6 @@ fn prune(elf_file: *Elf) void {...@@ -162,22 +162,6 @@ fn prune(elf_file: *Elf) void {
162 }162 }
163}163}
164164
165pub fn dumpPrunedAtoms(elf_file: *Elf) !void {
166 const stderr = std.fs.File.stderr().deprecatedWriter();
167 for (elf_file.objects.items) |index| {
168 const file = elf_file.file(index).?;
169 for (file.atoms()) |atom_index| {
170 const atom = file.atom(atom_index) orelse continue;
171 if (!atom.alive)
172 // TODO should we simply print to stderr?
173 try stderr.print("link: removing unused section '{s}' in file '{f}'\n", .{
174 atom.name(elf_file),
175 atom.file(elf_file).?.fmtPath(),
176 });
177 }
178 }
179}
180
181const Level = struct {165const Level = struct {
182 value: usize = 0,166 value: usize = 0,
183167
src/link/Elf/relocatable.zig+24-21
...@@ -100,32 +100,33 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {...@@ -100,32 +100,33 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
100 state_log.debug("ar_strtab\n{f}\n", .{ar_strtab});100 state_log.debug("ar_strtab\n{f}\n", .{ar_strtab});
101 }101 }
102102
103 var buffer = std.array_list.Managed(u8).init(gpa);103 const buffer = try gpa.alloc(u8, total_size);
104 defer buffer.deinit();104 defer gpa.free(buffer);
105 try buffer.ensureTotalCapacityPrecise(total_size);105
106 var writer: std.Io.Writer = .fixed(buffer);
106107
107 // Write magic108 // Write magic
108 try buffer.writer().writeAll(elf.ARMAG);109 try writer.writeAll(elf.ARMAG);
109110
110 // Write symtab111 // Write symtab
111 try ar_symtab.write(.p64, elf_file, buffer.writer());112 try ar_symtab.write(.p64, elf_file, &writer);
112113
113 // Write strtab114 // Write strtab
114 if (ar_strtab.size() > 0) {115 if (ar_strtab.size() > 0) {
115 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);116 if (!mem.isAligned(writer.end, 2)) try writer.writeByte(0);
116 try ar_strtab.write(buffer.writer());117 try ar_strtab.write(&writer);
117 }118 }
118119
119 // Write object files120 // Write object files
120 for (files.items) |index| {121 for (files.items) |index| {
121 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);122 if (!mem.isAligned(writer.end, 2)) try writer.writeByte(0);
122 try elf_file.file(index).?.writeAr(elf_file, buffer.writer());123 try elf_file.file(index).?.writeAr(elf_file, &writer);
123 }124 }
124125
125 assert(buffer.items.len == total_size);126 assert(writer.buffered().len == total_size);
126127
127 try elf_file.base.file.?.setEndPos(total_size);128 try elf_file.base.file.?.setEndPos(total_size);
128 try elf_file.base.file.?.pwriteAll(buffer.items, 0);129 try elf_file.base.file.?.pwriteAll(writer.buffered(), 0);
129130
130 if (diags.hasErrors()) return error.LinkFailure;131 if (diags.hasErrors()) return error.LinkFailure;
131}132}
...@@ -407,15 +408,16 @@ fn writeSyntheticSections(elf_file: *Elf) !void {...@@ -407,15 +408,16 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
407 };408 };
408 const shdr = slice.items(.shdr)[shndx];409 const shdr = slice.items(.shdr)[shndx];
409 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;410 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
410 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, @intCast(sh_size - existing_size));411 const buffer = try gpa.alloc(u8, @intCast(sh_size - existing_size));
411 defer buffer.deinit();412 defer gpa.free(buffer);
412 try eh_frame.writeEhFrameRelocatable(elf_file, buffer.writer());413 var writer: std.Io.Writer = .fixed(buffer);
414 try eh_frame.writeEhFrameRelocatable(elf_file, &writer);
413 log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{415 log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{
414 shdr.sh_offset + existing_size,416 shdr.sh_offset + existing_size,
415 shdr.sh_offset + sh_size,417 shdr.sh_offset + sh_size,
416 });418 });
417 assert(buffer.items.len == sh_size - existing_size);419 assert(writer.buffered().len == sh_size - existing_size);
418 try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset + existing_size);420 try elf_file.base.file.?.pwriteAll(writer.buffered(), shdr.sh_offset + existing_size);
419 }421 }
420 if (elf_file.section_indexes.eh_frame_rela) |shndx| {422 if (elf_file.section_indexes.eh_frame_rela) |shndx| {
421 const shdr = slice.items(.shdr)[shndx];423 const shdr = slice.items(.shdr)[shndx];
...@@ -446,15 +448,16 @@ fn writeGroups(elf_file: *Elf) !void {...@@ -446,15 +448,16 @@ fn writeGroups(elf_file: *Elf) !void {
446 for (elf_file.group_sections.items) |cgs| {448 for (elf_file.group_sections.items) |cgs| {
447 const shdr = elf_file.sections.items(.shdr)[cgs.shndx];449 const shdr = elf_file.sections.items(.shdr)[cgs.shndx];
448 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;450 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
449 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, sh_size);451 const buffer = try gpa.alloc(u8, sh_size);
450 defer buffer.deinit();452 defer gpa.free(buffer);
451 try cgs.write(elf_file, buffer.writer());453 var writer: std.Io.Writer = .fixed(buffer);
452 assert(buffer.items.len == sh_size);454 try cgs.write(elf_file, &writer);
455 assert(writer.buffered().len == sh_size);
453 log.debug("writing group from 0x{x} to 0x{x}", .{456 log.debug("writing group from 0x{x} to 0x{x}", .{
454 shdr.sh_offset,457 shdr.sh_offset,
455 shdr.sh_offset + shdr.sh_size,458 shdr.sh_offset + shdr.sh_size,
456 });459 });
457 try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);460 try elf_file.base.file.?.pwriteAll(writer.buffered(), shdr.sh_offset);
458 }461 }
459}462}
460463
src/link/Elf/synthetic_sections.zig+53-51
...@@ -94,134 +94,134 @@ pub const DynamicSection = struct {...@@ -94,134 +94,134 @@ pub const DynamicSection = struct {
94 return nentries * @sizeOf(elf.Elf64_Dyn);94 return nentries * @sizeOf(elf.Elf64_Dyn);
95 }95 }
9696
97 pub fn write(dt: DynamicSection, elf_file: *Elf, writer: anytype) !void {97 pub fn write(dt: DynamicSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
98 const shdrs = elf_file.sections.items(.shdr);98 const shdrs = elf_file.sections.items(.shdr);
9999
100 // NEEDED100 // NEEDED
101 for (dt.needed.items) |off| {101 for (dt.needed.items) |off| {
102 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NEEDED, .d_val = off });102 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_NEEDED, .d_val = off }), .little);
103 }103 }
104104
105 if (dt.soname) |off| {105 if (dt.soname) |off| {
106 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SONAME, .d_val = off });106 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_SONAME, .d_val = off }), .little);
107 }107 }
108108
109 // RUNPATH109 // RUNPATH
110 // TODO add option in Options to revert to old RPATH tag110 // TODO add option in Options to revert to old RPATH tag
111 if (dt.rpath > 0) {111 if (dt.rpath > 0) {
112 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RUNPATH, .d_val = dt.rpath });112 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_RUNPATH, .d_val = dt.rpath }), .little);
113 }113 }
114114
115 // INIT115 // INIT
116 if (elf_file.sectionByName(".init")) |shndx| {116 if (elf_file.sectionByName(".init")) |shndx| {
117 const addr = shdrs[shndx].sh_addr;117 const addr = shdrs[shndx].sh_addr;
118 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT, .d_val = addr });118 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_INIT, .d_val = addr }), .little);
119 }119 }
120120
121 // FINI121 // FINI
122 if (elf_file.sectionByName(".fini")) |shndx| {122 if (elf_file.sectionByName(".fini")) |shndx| {
123 const addr = shdrs[shndx].sh_addr;123 const addr = shdrs[shndx].sh_addr;
124 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI, .d_val = addr });124 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FINI, .d_val = addr }), .little);
125 }125 }
126126
127 // INIT_ARRAY127 // INIT_ARRAY
128 if (elf_file.sectionByName(".init_array")) |shndx| {128 if (elf_file.sectionByName(".init_array")) |shndx| {
129 const shdr = shdrs[shndx];129 const shdr = shdrs[shndx];
130 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAY, .d_val = shdr.sh_addr });130 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_INIT_ARRAY, .d_val = shdr.sh_addr }), .little);
131 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAYSZ, .d_val = shdr.sh_size });131 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_INIT_ARRAYSZ, .d_val = shdr.sh_size }), .little);
132 }132 }
133133
134 // FINI_ARRAY134 // FINI_ARRAY
135 if (elf_file.sectionByName(".fini_array")) |shndx| {135 if (elf_file.sectionByName(".fini_array")) |shndx| {
136 const shdr = shdrs[shndx];136 const shdr = shdrs[shndx];
137 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAY, .d_val = shdr.sh_addr });137 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FINI_ARRAY, .d_val = shdr.sh_addr }), .little);
138 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAYSZ, .d_val = shdr.sh_size });138 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FINI_ARRAYSZ, .d_val = shdr.sh_size }), .little);
139 }139 }
140140
141 // RELA141 // RELA
142 if (elf_file.section_indexes.rela_dyn) |shndx| {142 if (elf_file.section_indexes.rela_dyn) |shndx| {
143 const shdr = shdrs[shndx];143 const shdr = shdrs[shndx];
144 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELA, .d_val = shdr.sh_addr });144 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_RELA, .d_val = shdr.sh_addr }), .little);
145 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELASZ, .d_val = shdr.sh_size });145 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_RELASZ, .d_val = shdr.sh_size }), .little);
146 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELAENT, .d_val = shdr.sh_entsize });146 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_RELAENT, .d_val = shdr.sh_entsize }), .little);
147 }147 }
148148
149 // JMPREL149 // JMPREL
150 if (elf_file.section_indexes.rela_plt) |shndx| {150 if (elf_file.section_indexes.rela_plt) |shndx| {
151 const shdr = shdrs[shndx];151 const shdr = shdrs[shndx];
152 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_JMPREL, .d_val = shdr.sh_addr });152 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_JMPREL, .d_val = shdr.sh_addr }), .little);
153 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTRELSZ, .d_val = shdr.sh_size });153 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_PLTRELSZ, .d_val = shdr.sh_size }), .little);
154 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTREL, .d_val = elf.DT_RELA });154 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_PLTREL, .d_val = elf.DT_RELA }), .little);
155 }155 }
156156
157 // PLTGOT157 // PLTGOT
158 if (elf_file.section_indexes.got_plt) |shndx| {158 if (elf_file.section_indexes.got_plt) |shndx| {
159 const addr = shdrs[shndx].sh_addr;159 const addr = shdrs[shndx].sh_addr;
160 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTGOT, .d_val = addr });160 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_PLTGOT, .d_val = addr }), .little);
161 }161 }
162162
163 {163 {
164 assert(elf_file.section_indexes.hash != null);164 assert(elf_file.section_indexes.hash != null);
165 const addr = shdrs[elf_file.section_indexes.hash.?].sh_addr;165 const addr = shdrs[elf_file.section_indexes.hash.?].sh_addr;
166 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_HASH, .d_val = addr });166 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_HASH, .d_val = addr }), .little);
167 }167 }
168168
169 if (elf_file.section_indexes.gnu_hash) |shndx| {169 if (elf_file.section_indexes.gnu_hash) |shndx| {
170 const addr = shdrs[shndx].sh_addr;170 const addr = shdrs[shndx].sh_addr;
171 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_GNU_HASH, .d_val = addr });171 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_GNU_HASH, .d_val = addr }), .little);
172 }172 }
173173
174 // TEXTREL174 // TEXTREL
175 if (elf_file.has_text_reloc) {175 if (elf_file.has_text_reloc) {
176 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_TEXTREL, .d_val = 0 });176 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_TEXTREL, .d_val = 0 }), .little);
177 }177 }
178178
179 // SYMTAB + SYMENT179 // SYMTAB + SYMENT
180 {180 {
181 assert(elf_file.section_indexes.dynsymtab != null);181 assert(elf_file.section_indexes.dynsymtab != null);
182 const shdr = shdrs[elf_file.section_indexes.dynsymtab.?];182 const shdr = shdrs[elf_file.section_indexes.dynsymtab.?];
183 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMTAB, .d_val = shdr.sh_addr });183 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_SYMTAB, .d_val = shdr.sh_addr }), .little);
184 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMENT, .d_val = shdr.sh_entsize });184 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_SYMENT, .d_val = shdr.sh_entsize }), .little);
185 }185 }
186186
187 // STRTAB + STRSZ187 // STRTAB + STRSZ
188 {188 {
189 assert(elf_file.section_indexes.dynstrtab != null);189 assert(elf_file.section_indexes.dynstrtab != null);
190 const shdr = shdrs[elf_file.section_indexes.dynstrtab.?];190 const shdr = shdrs[elf_file.section_indexes.dynstrtab.?];
191 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRTAB, .d_val = shdr.sh_addr });191 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_STRTAB, .d_val = shdr.sh_addr }), .little);
192 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRSZ, .d_val = shdr.sh_size });192 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_STRSZ, .d_val = shdr.sh_size }), .little);
193 }193 }
194194
195 // VERSYM195 // VERSYM
196 if (elf_file.section_indexes.versym) |shndx| {196 if (elf_file.section_indexes.versym) |shndx| {
197 const addr = shdrs[shndx].sh_addr;197 const addr = shdrs[shndx].sh_addr;
198 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERSYM, .d_val = addr });198 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_VERSYM, .d_val = addr }), .little);
199 }199 }
200200
201 // VERNEED + VERNEEDNUM201 // VERNEED + VERNEEDNUM
202 if (elf_file.section_indexes.verneed) |shndx| {202 if (elf_file.section_indexes.verneed) |shndx| {
203 const addr = shdrs[shndx].sh_addr;203 const addr = shdrs[shndx].sh_addr;
204 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERNEED, .d_val = addr });204 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_VERNEED, .d_val = addr }), .little);
205 try writer.writeStruct(elf.Elf64_Dyn{205 try writer.writeStruct(@as(elf.Elf64_Dyn, .{
206 .d_tag = elf.DT_VERNEEDNUM,206 .d_tag = elf.DT_VERNEEDNUM,
207 .d_val = elf_file.verneed.verneed.items.len,207 .d_val = elf_file.verneed.verneed.items.len,
208 });208 }), .little);
209 }209 }
210210
211 // FLAGS211 // FLAGS
212 if (dt.getFlags(elf_file)) |flags| {212 if (dt.getFlags(elf_file)) |flags| {
213 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS, .d_val = flags });213 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FLAGS, .d_val = flags }), .little);
214 }214 }
215 // FLAGS_1215 // FLAGS_1
216 if (dt.getFlags1(elf_file)) |flags_1| {216 if (dt.getFlags1(elf_file)) |flags_1| {
217 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS_1, .d_val = flags_1 });217 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FLAGS_1, .d_val = flags_1 }), .little);
218 }218 }
219219
220 // DEBUG220 // DEBUG
221 if (!elf_file.isEffectivelyDynLib()) try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_DEBUG, .d_val = 0 });221 if (!elf_file.isEffectivelyDynLib()) try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_DEBUG, .d_val = 0 }), .little);
222222
223 // NULL223 // NULL
224 try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NULL, .d_val = 0 });224 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_NULL, .d_val = 0 }), .little);
225 }225 }
226};226};
227227
...@@ -360,7 +360,7 @@ pub const GotSection = struct {...@@ -360,7 +360,7 @@ pub const GotSection = struct {
360 return s;360 return s;
361 }361 }
362362
363 pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void {363 pub fn write(got: GotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
364 const comp = elf_file.base.comp;364 const comp = elf_file.base.comp;
365 const is_dyn_lib = elf_file.isEffectivelyDynLib();365 const is_dyn_lib = elf_file.isEffectivelyDynLib();
366 const apply_relocs = true; // TODO add user option for this366 const apply_relocs = true; // TODO add user option for this
...@@ -666,7 +666,7 @@ pub const PltSection = struct {...@@ -666,7 +666,7 @@ pub const PltSection = struct {
666 };666 };
667 }667 }
668668
669 pub fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void {669 pub fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
670 const cpu_arch = elf_file.getTarget().cpu.arch;670 const cpu_arch = elf_file.getTarget().cpu.arch;
671 switch (cpu_arch) {671 switch (cpu_arch) {
672 .x86_64 => try x86_64.write(plt, elf_file, writer),672 .x86_64 => try x86_64.write(plt, elf_file, writer),
...@@ -763,7 +763,7 @@ pub const PltSection = struct {...@@ -763,7 +763,7 @@ pub const PltSection = struct {
763 }763 }
764764
765 const x86_64 = struct {765 const x86_64 = struct {
766 fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void {766 fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
767 const shdrs = elf_file.sections.items(.shdr);767 const shdrs = elf_file.sections.items(.shdr);
768 const plt_addr = shdrs[elf_file.section_indexes.plt.?].sh_addr;768 const plt_addr = shdrs[elf_file.section_indexes.plt.?].sh_addr;
769 const got_plt_addr = shdrs[elf_file.section_indexes.got_plt.?].sh_addr;769 const got_plt_addr = shdrs[elf_file.section_indexes.got_plt.?].sh_addr;
...@@ -778,7 +778,7 @@ pub const PltSection = struct {...@@ -778,7 +778,7 @@ pub const PltSection = struct {
778 disp = @as(i64, @intCast(got_plt_addr + 16)) - @as(i64, @intCast(plt_addr + 14)) - 4;778 disp = @as(i64, @intCast(got_plt_addr + 16)) - @as(i64, @intCast(plt_addr + 14)) - 4;
779 mem.writeInt(i32, preamble[14..][0..4], @as(i32, @intCast(disp)), .little);779 mem.writeInt(i32, preamble[14..][0..4], @as(i32, @intCast(disp)), .little);
780 try writer.writeAll(&preamble);780 try writer.writeAll(&preamble);
781 try writer.writeByteNTimes(0xcc, preambleSize(.x86_64) - preamble.len);781 try writer.splatByteAll(0xcc, preambleSize(.x86_64) - preamble.len);
782782
783 for (plt.symbols.items, 0..) |ref, i| {783 for (plt.symbols.items, 0..) |ref, i| {
784 const sym = elf_file.symbol(ref).?;784 const sym = elf_file.symbol(ref).?;
...@@ -798,7 +798,7 @@ pub const PltSection = struct {...@@ -798,7 +798,7 @@ pub const PltSection = struct {
798 };798 };
799799
800 const aarch64 = struct {800 const aarch64 = struct {
801 fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void {801 fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
802 {802 {
803 const shdrs = elf_file.sections.items(.shdr);803 const shdrs = elf_file.sections.items(.shdr);
804 const plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.plt.?].sh_addr);804 const plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.plt.?].sh_addr);
...@@ -853,7 +853,7 @@ pub const GotPltSection = struct {...@@ -853,7 +853,7 @@ pub const GotPltSection = struct {
853 return preamble_size + elf_file.plt.symbols.items.len * 8;853 return preamble_size + elf_file.plt.symbols.items.len * 8;
854 }854 }
855855
856 pub fn write(got_plt: GotPltSection, elf_file: *Elf, writer: anytype) !void {856 pub fn write(got_plt: GotPltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
857 _ = got_plt;857 _ = got_plt;
858 {858 {
859 // [0]: _DYNAMIC859 // [0]: _DYNAMIC
...@@ -904,7 +904,7 @@ pub const PltGotSection = struct {...@@ -904,7 +904,7 @@ pub const PltGotSection = struct {
904 };904 };
905 }905 }
906906
907 pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {907 pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
908 const cpu_arch = elf_file.getTarget().cpu.arch;908 const cpu_arch = elf_file.getTarget().cpu.arch;
909 switch (cpu_arch) {909 switch (cpu_arch) {
910 .x86_64 => try x86_64.write(plt_got, elf_file, writer),910 .x86_64 => try x86_64.write(plt_got, elf_file, writer),
...@@ -940,7 +940,7 @@ pub const PltGotSection = struct {...@@ -940,7 +940,7 @@ pub const PltGotSection = struct {
940 }940 }
941941
942 const x86_64 = struct {942 const x86_64 = struct {
943 pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {943 pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
944 for (plt_got.symbols.items) |ref| {944 for (plt_got.symbols.items) |ref| {
945 const sym = elf_file.symbol(ref).?;945 const sym = elf_file.symbol(ref).?;
946 const target_addr = sym.gotAddress(elf_file);946 const target_addr = sym.gotAddress(elf_file);
...@@ -958,7 +958,7 @@ pub const PltGotSection = struct {...@@ -958,7 +958,7 @@ pub const PltGotSection = struct {
958 };958 };
959959
960 const aarch64 = struct {960 const aarch64 = struct {
961 fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {961 fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
962 for (plt_got.symbols.items) |ref| {962 for (plt_got.symbols.items) |ref| {
963 const sym = elf_file.symbol(ref).?;963 const sym = elf_file.symbol(ref).?;
964 const target_addr = sym.gotAddress(elf_file);964 const target_addr = sym.gotAddress(elf_file);
...@@ -1133,14 +1133,14 @@ pub const DynsymSection = struct {...@@ -1133,14 +1133,14 @@ pub const DynsymSection = struct {
1133 return @as(u32, @intCast(dynsym.entries.items.len + 1));1133 return @as(u32, @intCast(dynsym.entries.items.len + 1));
1134 }1134 }
11351135
1136 pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: anytype) !void {1136 pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
1137 try writer.writeStruct(Elf.null_sym);1137 try writer.writeStruct(Elf.null_sym, .little);
1138 for (dynsym.entries.items) |entry| {1138 for (dynsym.entries.items) |entry| {
1139 const sym = elf_file.symbol(entry.ref).?;1139 const sym = elf_file.symbol(entry.ref).?;
1140 var out_sym: elf.Elf64_Sym = Elf.null_sym;1140 var out_sym: elf.Elf64_Sym = Elf.null_sym;
1141 sym.setOutputSym(elf_file, &out_sym);1141 sym.setOutputSym(elf_file, &out_sym);
1142 out_sym.st_name = entry.off;1142 out_sym.st_name = entry.off;
1143 try writer.writeStruct(out_sym);1143 try writer.writeStruct(out_sym, .little);
1144 }1144 }
1145 }1145 }
1146};1146};
...@@ -1175,10 +1175,12 @@ pub const HashSection = struct {...@@ -1175,10 +1175,12 @@ pub const HashSection = struct {
1175 }1175 }
11761176
1177 try hs.buffer.ensureTotalCapacityPrecise(gpa, (2 + nsyms * 2) * 4);1177 try hs.buffer.ensureTotalCapacityPrecise(gpa, (2 + nsyms * 2) * 4);
1178 hs.buffer.writer(gpa).writeInt(u32, @as(u32, @intCast(nsyms)), .little) catch unreachable;1178 var w: std.Io.Writer = .fixed(hs.buffer.unusedCapacitySlice());
1179 hs.buffer.writer(gpa).writeInt(u32, @as(u32, @intCast(nsyms)), .little) catch unreachable;1179 w.writeInt(u32, @as(u32, @intCast(nsyms)), .little) catch unreachable;
1180 hs.buffer.writer(gpa).writeAll(mem.sliceAsBytes(buckets)) catch unreachable;1180 w.writeInt(u32, @as(u32, @intCast(nsyms)), .little) catch unreachable;
1181 hs.buffer.writer(gpa).writeAll(mem.sliceAsBytes(chains)) catch unreachable;1181 w.writeAll(@ptrCast(buckets)) catch unreachable;
1182 w.writeAll(@ptrCast(chains)) catch unreachable;
1183 hs.buffer.items.len += w.end;
1182 }1184 }
11831185
1184 pub inline fn size(hs: HashSection) usize {1186 pub inline fn size(hs: HashSection) usize {
...@@ -1439,7 +1441,7 @@ pub const VerneedSection = struct {...@@ -1439,7 +1441,7 @@ pub const VerneedSection = struct {
1439 return vern.verneed.items.len * @sizeOf(elf.Elf64_Verneed) + vern.vernaux.items.len * @sizeOf(elf.Vernaux);1441 return vern.verneed.items.len * @sizeOf(elf.Elf64_Verneed) + vern.vernaux.items.len * @sizeOf(elf.Vernaux);
1440 }1442 }
14411443
1442 pub fn write(vern: VerneedSection, writer: anytype) !void {1444 pub fn write(vern: VerneedSection, writer: *std.Io.Writer) !void {
1443 try writer.writeAll(mem.sliceAsBytes(vern.verneed.items));1445 try writer.writeAll(mem.sliceAsBytes(vern.verneed.items));
1444 try writer.writeAll(mem.sliceAsBytes(vern.vernaux.items));1446 try writer.writeAll(mem.sliceAsBytes(vern.vernaux.items));
1445 }1447 }
...@@ -1467,7 +1469,7 @@ pub const GroupSection = struct {...@@ -1467,7 +1469,7 @@ pub const GroupSection = struct {
1467 return (members.len + 1) * @sizeOf(u32);1469 return (members.len + 1) * @sizeOf(u32);
1468 }1470 }
14691471
1470 pub fn write(cgs: GroupSection, elf_file: *Elf, writer: anytype) !void {1472 pub fn write(cgs: GroupSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
1471 const cg = cgs.group(elf_file);1473 const cg = cgs.group(elf_file);
1472 const object = cg.file(elf_file).object;1474 const object = cg.file(elf_file).object;
1473 const members = cg.members(elf_file);1475 const members = cg.members(elf_file);
...@@ -1495,7 +1497,7 @@ pub const GroupSection = struct {...@@ -1495,7 +1497,7 @@ pub const GroupSection = struct {
1495 }1497 }
1496};1498};
14971499
1498fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void {1500fn writeInt(value: anytype, elf_file: *Elf, writer: *std.Io.Writer) !void {
1499 const entry_size = elf_file.archPtrWidthBytes();1501 const entry_size = elf_file.archPtrWidthBytes();
1500 const target = elf_file.getTarget();1502 const target = elf_file.getTarget();
1501 const endian = target.cpu.arch.endian();1503 const endian = target.cpu.arch.endian();
src/link/MachO.zig+71-65
...@@ -589,7 +589,7 @@ pub fn flush(...@@ -589,7 +589,7 @@ pub fn flush(
589 );589 );
590590
591 const ncmds, const sizeofcmds, const uuid_cmd_offset = self.writeLoadCommands() catch |err| switch (err) {591 const ncmds, const sizeofcmds, const uuid_cmd_offset = self.writeLoadCommands() catch |err| switch (err) {
592 error.NoSpaceLeft => unreachable,592 error.WriteFailed => unreachable,
593 error.OutOfMemory => return error.OutOfMemory,593 error.OutOfMemory => return error.OutOfMemory,
594 error.LinkFailure => return error.LinkFailure,594 error.LinkFailure => return error.LinkFailure,
595 };595 };
...@@ -1074,7 +1074,7 @@ fn accessLibPath(...@@ -1074,7 +1074,7 @@ fn accessLibPath(
10741074
1075 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1075 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1076 test_path.clearRetainingCapacity();1076 test_path.clearRetainingCapacity();
1077 try test_path.writer().print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });1077 try test_path.print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
1078 try checked_paths.append(try arena.dupe(u8, test_path.items));1078 try checked_paths.append(try arena.dupe(u8, test_path.items));
1079 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {1079 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
1080 error.FileNotFound => continue,1080 error.FileNotFound => continue,
...@@ -1097,7 +1097,7 @@ fn accessFrameworkPath(...@@ -1097,7 +1097,7 @@ fn accessFrameworkPath(
10971097
1098 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1098 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1099 test_path.clearRetainingCapacity();1099 test_path.clearRetainingCapacity();
1100 try test_path.writer().print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{1100 try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
1101 search_dir,1101 search_dir,
1102 name,1102 name,
1103 name,1103 name,
...@@ -1178,9 +1178,9 @@ fn parseDependentDylibs(self: *MachO) !void {...@@ -1178,9 +1178,9 @@ fn parseDependentDylibs(self: *MachO) !void {
1178 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1178 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1179 test_path.clearRetainingCapacity();1179 test_path.clearRetainingCapacity();
1180 if (self.base.comp.sysroot) |root| {1180 if (self.base.comp.sysroot) |root| {
1181 try test_path.writer().print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });1181 try test_path.print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
1182 } else {1182 } else {
1183 try test_path.writer().print("{s}{s}", .{ path, ext });1183 try test_path.print("{s}{s}", .{ path, ext });
1184 }1184 }
1185 try checked_paths.append(try arena.dupe(u8, test_path.items));1185 try checked_paths.append(try arena.dupe(u8, test_path.items));
1186 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {1186 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
...@@ -2528,8 +2528,8 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {...@@ -2528,8 +2528,8 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
2528 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {2528 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {
2529 const off = try macho_file.cast(usize, th.value);2529 const off = try macho_file.cast(usize, th.value);
2530 const size = th.size();2530 const size = th.size();
2531 var stream = std.io.fixedBufferStream(buffer[off..][0..size]);2531 var stream: Writer = .fixed(buffer[off..][0..size]);
2532 try th.write(macho_file, stream.writer());2532 try th.write(macho_file, &stream);
2533 }2533 }
2534 }.doWork;2534 }.doWork;
2535 const out = self.sections.items(.out)[thunk.out_n_sect].items;2535 const out = self.sections.items(.out)[thunk.out_n_sect].items;
...@@ -2556,15 +2556,15 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {...@@ -2556,15 +2556,15 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {
25562556
2557 const doWork = struct {2557 const doWork = struct {
2558 fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {2558 fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {
2559 var stream = std.io.fixedBufferStream(buffer);2559 var stream: Writer = .fixed(buffer);
2560 switch (tag) {2560 switch (tag) {
2561 .eh_frame => eh_frame.write(macho_file, buffer),2561 .eh_frame => eh_frame.write(macho_file, buffer),
2562 .unwind_info => try macho_file.unwind_info.write(macho_file, buffer),2562 .unwind_info => try macho_file.unwind_info.write(macho_file, buffer),
2563 .got => try macho_file.got.write(macho_file, stream.writer()),2563 .got => try macho_file.got.write(macho_file, &stream),
2564 .stubs => try macho_file.stubs.write(macho_file, stream.writer()),2564 .stubs => try macho_file.stubs.write(macho_file, &stream),
2565 .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, stream.writer()),2565 .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, &stream),
2566 .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, stream.writer()),2566 .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, &stream),
2567 .objc_stubs => try macho_file.objc_stubs.write(macho_file, stream.writer()),2567 .objc_stubs => try macho_file.objc_stubs.write(macho_file, &stream),
2568 }2568 }
2569 }2569 }
2570 }.doWork;2570 }.doWork;
...@@ -2605,8 +2605,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {...@@ -2605,8 +2605,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {
2605 try macho_file.lazy_bind_section.updateSize(macho_file);2605 try macho_file.lazy_bind_section.updateSize(macho_file);
2606 const sect_id = macho_file.stubs_helper_sect_index.?;2606 const sect_id = macho_file.stubs_helper_sect_index.?;
2607 const out = &macho_file.sections.items(.out)[sect_id];2607 const out = &macho_file.sections.items(.out)[sect_id];
2608 var stream = std.io.fixedBufferStream(out.items);2608 var stream: Writer = .fixed(out.items);
2609 try macho_file.stubs_helper.write(macho_file, stream.writer());2609 try macho_file.stubs_helper.write(macho_file, &stream);
2610 }2610 }
2611 }.doWork;2611 }.doWork;
2612 doWork(self) catch |err|2612 doWork(self) catch |err|
...@@ -2669,18 +2669,17 @@ fn writeDyldInfo(self: *MachO) !void {...@@ -2669,18 +2669,17 @@ fn writeDyldInfo(self: *MachO) !void {
2669 defer gpa.free(buffer);2669 defer gpa.free(buffer);
2670 @memset(buffer, 0);2670 @memset(buffer, 0);
26712671
2672 var stream = std.io.fixedBufferStream(buffer);2672 var writer: Writer = .fixed(buffer);
2673 const writer = stream.writer();2673
26742674 try self.rebase_section.write(&writer);
2675 try self.rebase_section.write(writer);2675 writer.end = @intCast(cmd.bind_off - base_off);
2676 try stream.seekTo(cmd.bind_off - base_off);2676 try self.bind_section.write(&writer);
2677 try self.bind_section.write(writer);2677 writer.end = @intCast(cmd.weak_bind_off - base_off);
2678 try stream.seekTo(cmd.weak_bind_off - base_off);2678 try self.weak_bind_section.write(&writer);
2679 try self.weak_bind_section.write(writer);2679 writer.end = @intCast(cmd.lazy_bind_off - base_off);
2680 try stream.seekTo(cmd.lazy_bind_off - base_off);2680 try self.lazy_bind_section.write(&writer);
2681 try self.lazy_bind_section.write(writer);2681 writer.end = @intCast(cmd.export_off - base_off);
2682 try stream.seekTo(cmd.export_off - base_off);2682 try self.export_trie.write(&writer);
2683 try self.export_trie.write(writer);
2684 try self.pwriteAll(buffer, cmd.rebase_off);2683 try self.pwriteAll(buffer, cmd.rebase_off);
2685}2684}
26862685
...@@ -2689,10 +2688,10 @@ pub fn writeDataInCode(self: *MachO) !void {...@@ -2689,10 +2688,10 @@ pub fn writeDataInCode(self: *MachO) !void {
2689 defer tracy.end();2688 defer tracy.end();
2690 const gpa = self.base.comp.gpa;2689 const gpa = self.base.comp.gpa;
2691 const cmd = self.data_in_code_cmd;2690 const cmd = self.data_in_code_cmd;
2692 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.data_in_code.size());2691 var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.data_in_code.size());
2693 defer buffer.deinit();2692 defer buffer.deinit();
2694 try self.data_in_code.write(self, buffer.writer());2693 self.data_in_code.write(self, &buffer.writer) catch return error.OutOfMemory;
2695 try self.pwriteAll(buffer.items, cmd.dataoff);2694 try self.pwriteAll(buffer.written(), cmd.dataoff);
2696}2695}
26972696
2698fn writeIndsymtab(self: *MachO) !void {2697fn writeIndsymtab(self: *MachO) !void {
...@@ -2701,10 +2700,11 @@ fn writeIndsymtab(self: *MachO) !void {...@@ -2701,10 +2700,11 @@ fn writeIndsymtab(self: *MachO) !void {
2701 const gpa = self.base.comp.gpa;2700 const gpa = self.base.comp.gpa;
2702 const cmd = self.dysymtab_cmd;2701 const cmd = self.dysymtab_cmd;
2703 const needed_size = cmd.nindirectsyms * @sizeOf(u32);2702 const needed_size = cmd.nindirectsyms * @sizeOf(u32);
2704 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, needed_size);2703 const buffer = try gpa.alloc(u8, needed_size);
2705 defer buffer.deinit();2704 defer gpa.free(buffer);
2706 try self.indsymtab.write(self, buffer.writer());2705 var writer: Writer = .fixed(buffer);
2707 try self.pwriteAll(buffer.items, cmd.indirectsymoff);2706 try self.indsymtab.write(self, &writer);
2707 try self.pwriteAll(buffer, cmd.indirectsymoff);
2708}2708}
27092709
2710pub fn writeSymtabToFile(self: *MachO) !void {2710pub fn writeSymtabToFile(self: *MachO) !void {
...@@ -2821,8 +2821,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2821,8 +2821,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2821 const buffer = try gpa.alloc(u8, needed_size);2821 const buffer = try gpa.alloc(u8, needed_size);
2822 defer gpa.free(buffer);2822 defer gpa.free(buffer);
28232823
2824 var stream = std.io.fixedBufferStream(buffer);2824 var writer: Writer = .fixed(buffer);
2825 const writer = stream.writer();
28262825
2827 var ncmds: usize = 0;2826 var ncmds: usize = 0;
28282827
...@@ -2831,26 +2830,26 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2831,26 +2830,26 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2831 const slice = self.sections.slice();2830 const slice = self.sections.slice();
2832 var sect_id: usize = 0;2831 var sect_id: usize = 0;
2833 for (self.segments.items) |seg| {2832 for (self.segments.items) |seg| {
2834 try writer.writeStruct(seg);2833 try writer.writeStruct(seg, .little);
2835 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {2834 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
2836 try writer.writeStruct(header);2835 try writer.writeStruct(header, .little);
2837 }2836 }
2838 sect_id += seg.nsects;2837 sect_id += seg.nsects;
2839 }2838 }
2840 ncmds += self.segments.items.len;2839 ncmds += self.segments.items.len;
2841 }2840 }
28422841
2843 try writer.writeStruct(self.dyld_info_cmd);2842 try writer.writeStruct(self.dyld_info_cmd, .little);
2844 ncmds += 1;2843 ncmds += 1;
2845 try writer.writeStruct(self.function_starts_cmd);2844 try writer.writeStruct(self.function_starts_cmd, .little);
2846 ncmds += 1;2845 ncmds += 1;
2847 try writer.writeStruct(self.data_in_code_cmd);2846 try writer.writeStruct(self.data_in_code_cmd, .little);
2848 ncmds += 1;2847 ncmds += 1;
2849 try writer.writeStruct(self.symtab_cmd);2848 try writer.writeStruct(self.symtab_cmd, .little);
2850 ncmds += 1;2849 ncmds += 1;
2851 try writer.writeStruct(self.dysymtab_cmd);2850 try writer.writeStruct(self.dysymtab_cmd, .little);
2852 ncmds += 1;2851 ncmds += 1;
2853 try load_commands.writeDylinkerLC(writer);2852 try load_commands.writeDylinkerLC(&writer);
2854 ncmds += 1;2853 ncmds += 1;
28552854
2856 if (self.getInternalObject()) |obj| {2855 if (self.getInternalObject()) |obj| {
...@@ -2861,44 +2860,44 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2861,44 +2860,44 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2861 02860 0
2862 else2861 else
2863 @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));2862 @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));
2864 try writer.writeStruct(macho.entry_point_command{2863 try writer.writeStruct(@as(macho.entry_point_command, .{
2865 .entryoff = entryoff,2864 .entryoff = entryoff,
2866 .stacksize = self.base.stack_size,2865 .stacksize = self.base.stack_size,
2867 });2866 }), .little);
2868 ncmds += 1;2867 ncmds += 1;
2869 }2868 }
2870 }2869 }
28712870
2872 if (self.base.isDynLib()) {2871 if (self.base.isDynLib()) {
2873 try load_commands.writeDylibIdLC(self, writer);2872 try load_commands.writeDylibIdLC(self, &writer);
2874 ncmds += 1;2873 ncmds += 1;
2875 }2874 }
28762875
2877 for (self.rpath_list) |rpath| {2876 for (self.rpath_list) |rpath| {
2878 try load_commands.writeRpathLC(rpath, writer);2877 try load_commands.writeRpathLC(rpath, &writer);
2879 ncmds += 1;2878 ncmds += 1;
2880 }2879 }
2881 if (comp.config.any_sanitize_thread) {2880 if (comp.config.any_sanitize_thread) {
2882 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);2881 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
2883 defer gpa.free(path);2882 defer gpa.free(path);
2884 const rpath = std.fs.path.dirname(path) orelse ".";2883 const rpath = std.fs.path.dirname(path) orelse ".";
2885 try load_commands.writeRpathLC(rpath, writer);2884 try load_commands.writeRpathLC(rpath, &writer);
2886 ncmds += 1;2885 ncmds += 1;
2887 }2886 }
28882887
2889 try writer.writeStruct(macho.source_version_command{ .version = 0 });2888 try writer.writeStruct(@as(macho.source_version_command, .{ .version = 0 }), .little);
2890 ncmds += 1;2889 ncmds += 1;
28912890
2892 if (self.platform.isBuildVersionCompatible()) {2891 if (self.platform.isBuildVersionCompatible()) {
2893 try load_commands.writeBuildVersionLC(self.platform, self.sdk_version, writer);2892 try load_commands.writeBuildVersionLC(self.platform, self.sdk_version, &writer);
2894 ncmds += 1;2893 ncmds += 1;
2895 } else {2894 } else {
2896 try load_commands.writeVersionMinLC(self.platform, self.sdk_version, writer);2895 try load_commands.writeVersionMinLC(self.platform, self.sdk_version, &writer);
2897 ncmds += 1;2896 ncmds += 1;
2898 }2897 }
28992898
2900 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + stream.pos;2899 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + writer.end;
2901 try writer.writeStruct(self.uuid_cmd);2900 try writer.writeStruct(self.uuid_cmd, .little);
2902 ncmds += 1;2901 ncmds += 1;
29032902
2904 for (self.dylibs.items) |index| {2903 for (self.dylibs.items) |index| {
...@@ -2916,16 +2915,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2916,16 +2915,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2916 .timestamp = dylib_id.timestamp,2915 .timestamp = dylib_id.timestamp,
2917 .current_version = dylib_id.current_version,2916 .current_version = dylib_id.current_version,
2918 .compatibility_version = dylib_id.compatibility_version,2917 .compatibility_version = dylib_id.compatibility_version,
2919 }, writer);2918 }, &writer);
2920 ncmds += 1;2919 ncmds += 1;
2921 }2920 }
29222921
2923 if (self.requiresCodeSig()) {2922 if (self.requiresCodeSig()) {
2924 try writer.writeStruct(self.codesig_cmd);2923 try writer.writeStruct(self.codesig_cmd, .little);
2925 ncmds += 1;2924 ncmds += 1;
2926 }2925 }
29272926
2928 assert(stream.pos == needed_size);2927 assert(writer.end == needed_size);
29292928
2930 try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64));2929 try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
29312930
...@@ -3014,25 +3013,32 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {...@@ -3014,25 +3013,32 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
3014pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {3013pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {
3015 const seg = self.getTextSegment();3014 const seg = self.getTextSegment();
3016 const offset = self.codesig_cmd.dataoff;3015 const offset = self.codesig_cmd.dataoff;
3016 const gpa = self.base.comp.gpa;
30173017
3018 var buffer = std.array_list.Managed(u8).init(self.base.comp.gpa);3018 var buffer: std.Io.Writer.Allocating = .init(gpa);
3019 defer buffer.deinit();3019 defer buffer.deinit();
3020 try buffer.ensureTotalCapacityPrecise(code_sig.size());3020 // The writeAdhocSignature function internally changes code_sig.size()
3021 try code_sig.writeAdhocSignature(self, .{3021 // during the execution.
3022 try buffer.ensureUnusedCapacity(code_sig.size());
3023
3024 code_sig.writeAdhocSignature(self, .{
3022 .file = self.base.file.?,3025 .file = self.base.file.?,
3023 .exec_seg_base = seg.fileoff,3026 .exec_seg_base = seg.fileoff,
3024 .exec_seg_limit = seg.filesize,3027 .exec_seg_limit = seg.filesize,
3025 .file_size = offset,3028 .file_size = offset,
3026 .dylib = self.base.isDynLib(),3029 .dylib = self.base.isDynLib(),
3027 }, buffer.writer());3030 }, &buffer.writer) catch |err| switch (err) {
3028 assert(buffer.items.len == code_sig.size());3031 error.WriteFailed => return error.OutOfMemory,
3032 else => |e| return e,
3033 };
3034 assert(buffer.written().len == code_sig.size());
30293035
3030 log.debug("writing code signature from 0x{x} to 0x{x}", .{3036 log.debug("writing code signature from 0x{x} to 0x{x}", .{
3031 offset,3037 offset,
3032 offset + buffer.items.len,3038 offset + buffer.written().len,
3033 });3039 });
30343040
3035 try self.pwriteAll(buffer.items, offset);3041 try self.pwriteAll(buffer.written(), offset);
3036}3042}
30373043
3038pub fn updateFunc(3044pub fn updateFunc(
...@@ -5372,7 +5378,7 @@ const macho = std.macho;...@@ -5372,7 +5378,7 @@ const macho = std.macho;
5372const math = std.math;5378const math = std.math;
5373const mem = std.mem;5379const mem = std.mem;
5374const meta = std.meta;5380const meta = std.meta;
5375const Writer = std.io.Writer;5381const Writer = std.Io.Writer;
53765382
5377const aarch64 = codegen.aarch64.encoding;5383const aarch64 = codegen.aarch64.encoding;
5378const bind = @import("MachO/dyld_info/bind.zig");5384const bind = @import("MachO/dyld_info/bind.zig");
src/link/MachO/Archive.zig+18-38
...@@ -81,34 +81,20 @@ pub fn writeHeader(...@@ -81,34 +81,20 @@ pub fn writeHeader(
81 object_name: []const u8,81 object_name: []const u8,
82 object_size: usize,82 object_size: usize,
83 format: Format,83 format: Format,
84 writer: anytype,84 writer: *Writer,
85) !void {85) !void {
86 var hdr: ar_hdr = .{86 var hdr: ar_hdr = .{};
87 .ar_name = undefined,
88 .ar_date = undefined,
89 .ar_uid = undefined,
90 .ar_gid = undefined,
91 .ar_mode = undefined,
92 .ar_size = undefined,
93 .ar_fmag = undefined,
94 };
95 @memset(mem.asBytes(&hdr), 0x20);
96 inline for (@typeInfo(ar_hdr).@"struct".fields) |field| {
97 var stream = std.io.fixedBufferStream(&@field(hdr, field.name));
98 stream.writer().print("0", .{}) catch unreachable;
99 }
100 @memcpy(&hdr.ar_fmag, ARFMAG);
10187
102 const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format));88 const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format));
103 const total_object_size = object_size + object_name_len;89 const total_object_size = object_size + object_name_len;
10490
105 {91 {
106 var stream = std.io.fixedBufferStream(&hdr.ar_name);92 var stream: Writer = .fixed(&hdr.ar_name);
107 stream.writer().print("#1/{d}", .{object_name_len}) catch unreachable;93 stream.print("#1/{d}", .{object_name_len}) catch unreachable;
108 }94 }
109 {95 {
110 var stream = std.io.fixedBufferStream(&hdr.ar_size);96 var stream: Writer = .fixed(&hdr.ar_size);
111 stream.writer().print("{d}", .{total_object_size}) catch unreachable;97 stream.print("{d}", .{total_object_size}) catch unreachable;
112 }98 }
11399
114 try writer.writeAll(mem.asBytes(&hdr));100 try writer.writeAll(mem.asBytes(&hdr));
...@@ -116,7 +102,7 @@ pub fn writeHeader(...@@ -116,7 +102,7 @@ pub fn writeHeader(
116102
117 const padding = object_name_len - object_name.len - 1;103 const padding = object_name_len - object_name.len - 1;
118 if (padding > 0) {104 if (padding > 0) {
119 try writer.writeByteNTimes(0, padding);105 try writer.splatByteAll(0, padding);
120 }106 }
121}107}
122108
...@@ -138,25 +124,19 @@ pub const SYMDEF64_SORTED = "__.SYMDEF_64 SORTED";...@@ -138,25 +124,19 @@ pub const SYMDEF64_SORTED = "__.SYMDEF_64 SORTED";
138124
139pub const ar_hdr = extern struct {125pub const ar_hdr = extern struct {
140 /// Member file name, sometimes / terminated.126 /// Member file name, sometimes / terminated.
141 ar_name: [16]u8,127 ar_name: [16]u8 = "0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20".*,
142
143 /// File date, decimal seconds since Epoch.128 /// File date, decimal seconds since Epoch.
144 ar_date: [12]u8,129 ar_date: [12]u8 = "0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20".*,
145
146 /// User ID, in ASCII format.130 /// User ID, in ASCII format.
147 ar_uid: [6]u8,131 ar_uid: [6]u8 = "0\x20\x20\x20\x20\x20".*,
148
149 /// Group ID, in ASCII format.132 /// Group ID, in ASCII format.
150 ar_gid: [6]u8,133 ar_gid: [6]u8 = "0\x20\x20\x20\x20\x20".*,
151
152 /// File mode, in ASCII octal.134 /// File mode, in ASCII octal.
153 ar_mode: [8]u8,135 ar_mode: [8]u8 = "0\x20\x20\x20\x20\x20\x20\x20".*,
154
155 /// File size, in ASCII decimal.136 /// File size, in ASCII decimal.
156 ar_size: [10]u8,137 ar_size: [10]u8 = "0\x20\x20\x20\x20\x20\x20\x20\x20\x20".*,
157
158 /// Always contains ARFMAG.138 /// Always contains ARFMAG.
159 ar_fmag: [2]u8,139 ar_fmag: [2]u8 = ARFMAG.*,
160140
161 fn date(self: ar_hdr) !u64 {141 fn date(self: ar_hdr) !u64 {
162 const value = mem.trimEnd(u8, &self.ar_date, &[_]u8{@as(u8, 0x20)});142 const value = mem.trimEnd(u8, &self.ar_date, &[_]u8{@as(u8, 0x20)});
...@@ -201,7 +181,7 @@ pub const ArSymtab = struct {...@@ -201,7 +181,7 @@ pub const ArSymtab = struct {
201 return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);181 return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
202 }182 }
203183
204 pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: anytype) !void {184 pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: *Writer) !void {
205 const ptr_width = ptrWidth(format);185 const ptr_width = ptrWidth(format);
206 // Header186 // Header
207 try writeHeader(SYMDEF, ar.size(format), format, writer);187 try writeHeader(SYMDEF, ar.size(format), format, writer);
...@@ -226,7 +206,7 @@ pub const ArSymtab = struct {...@@ -226,7 +206,7 @@ pub const ArSymtab = struct {
226 // Strtab206 // Strtab
227 try writer.writeAll(ar.strtab.buffer.items);207 try writer.writeAll(ar.strtab.buffer.items);
228 if (padding > 0) {208 if (padding > 0) {
229 try writer.writeByteNTimes(0, padding);209 try writer.splatByteAll(0, padding);
230 }210 }
231 }211 }
232212
...@@ -275,7 +255,7 @@ pub fn ptrWidth(format: Format) usize {...@@ -275,7 +255,7 @@ pub fn ptrWidth(format: Format) usize {
275 };255 };
276}256}
277257
278pub fn writeInt(format: Format, value: u64, writer: anytype) !void {258pub fn writeInt(format: Format, value: u64, writer: *Writer) !void {
279 switch (format) {259 switch (format) {
280 .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),260 .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
281 .p64 => try writer.writeInt(u64, value, .little),261 .p64 => try writer.writeInt(u64, value, .little),
...@@ -299,7 +279,7 @@ const mem = std.mem;...@@ -299,7 +279,7 @@ const mem = std.mem;
299const std = @import("std");279const std = @import("std");
300const Allocator = std.mem.Allocator;280const Allocator = std.mem.Allocator;
301const Path = std.Build.Cache.Path;281const Path = std.Build.Cache.Path;
302const Writer = std.io.Writer;282const Writer = std.Io.Writer;
303283
304const Archive = @This();284const Archive = @This();
305const File = @import("file.zig").File;285const File = @import("file.zig").File;
src/link/MachO/Atom.zig+7-6
...@@ -581,19 +581,19 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {...@@ -581,19 +581,19 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
581 relocs_log.debug("{x}: {s}", .{ self.value, name });581 relocs_log.debug("{x}: {s}", .{ self.value, name });
582582
583 var has_error = false;583 var has_error = false;
584 var stream = std.io.fixedBufferStream(buffer);584 var stream: Writer = .fixed(buffer);
585 var i: usize = 0;585 var i: usize = 0;
586 while (i < relocs.len) : (i += 1) {586 while (i < relocs.len) : (i += 1) {
587 const rel = relocs[i];587 const rel = relocs[i];
588 const rel_offset = rel.offset - self.off;588 const rel_offset: usize = @intCast(rel.offset - self.off);
589 const subtractor = if (rel.meta.has_subtractor) relocs[i - 1] else null;589 const subtractor = if (rel.meta.has_subtractor) relocs[i - 1] else null;
590590
591 if (rel.tag == .@"extern") {591 if (rel.tag == .@"extern") {
592 if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;592 if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;
593 }593 }
594594
595 try stream.seekTo(rel_offset);595 stream.end = rel_offset;
596 self.resolveRelocInner(rel, subtractor, buffer, macho_file, stream.writer()) catch |err| {596 self.resolveRelocInner(rel, subtractor, buffer, macho_file, &stream) catch |err| {
597 switch (err) {597 switch (err) {
598 error.RelaxFail => {598 error.RelaxFail => {
599 const target = switch (rel.tag) {599 const target = switch (rel.tag) {
...@@ -630,6 +630,7 @@ const ResolveError = error{...@@ -630,6 +630,7 @@ const ResolveError = error{
630 UnexpectedRemainder,630 UnexpectedRemainder,
631 Overflow,631 Overflow,
632 OutOfMemory,632 OutOfMemory,
633 WriteFailed,
633};634};
634635
635fn resolveRelocInner(636fn resolveRelocInner(
...@@ -638,7 +639,7 @@ fn resolveRelocInner(...@@ -638,7 +639,7 @@ fn resolveRelocInner(
638 subtractor: ?Relocation,639 subtractor: ?Relocation,
639 code: []u8,640 code: []u8,
640 macho_file: *MachO,641 macho_file: *MachO,
641 writer: anytype,642 writer: *Writer,
642) ResolveError!void {643) ResolveError!void {
643 const t = &macho_file.base.comp.root_mod.resolved_target.result;644 const t = &macho_file.base.comp.root_mod.resolved_target.result;
644 const cpu_arch = t.cpu.arch;645 const cpu_arch = t.cpu.arch;
...@@ -1147,7 +1148,7 @@ const math = std.math;...@@ -1147,7 +1148,7 @@ const math = std.math;
1147const mem = std.mem;1148const mem = std.mem;
1148const log = std.log.scoped(.link);1149const log = std.log.scoped(.link);
1149const relocs_log = std.log.scoped(.link_relocs);1150const relocs_log = std.log.scoped(.link_relocs);
1150const Writer = std.io.Writer;1151const Writer = std.Io.Writer;
1151const Allocator = mem.Allocator;1152const Allocator = mem.Allocator;
1152const AtomicBool = std.atomic.Value(bool);1153const AtomicBool = std.atomic.Value(bool);
11531154
src/link/MachO/CodeSignature.zig+9-9
...@@ -263,7 +263,7 @@ pub fn writeAdhocSignature(...@@ -263,7 +263,7 @@ pub fn writeAdhocSignature(
263 self: *CodeSignature,263 self: *CodeSignature,
264 macho_file: *MachO,264 macho_file: *MachO,
265 opts: WriteOpts,265 opts: WriteOpts,
266 writer: anytype,266 writer: *std.Io.Writer,
267) !void {267) !void {
268 const tracy = trace(@src());268 const tracy = trace(@src());
269 defer tracy.end();269 defer tracy.end();
...@@ -304,10 +304,10 @@ pub fn writeAdhocSignature(...@@ -304,10 +304,10 @@ pub fn writeAdhocSignature(
304 var hash: [hash_size]u8 = undefined;304 var hash: [hash_size]u8 = undefined;
305305
306 if (self.requirements) |*req| {306 if (self.requirements) |*req| {
307 var buf = std.array_list.Managed(u8).init(allocator);307 var a: std.Io.Writer.Allocating = .init(allocator);
308 defer buf.deinit();308 defer a.deinit();
309 try req.write(buf.writer());309 try req.write(&a.writer);
310 Sha256.hash(buf.items, &hash, .{});310 Sha256.hash(a.written(), &hash, .{});
311 self.code_directory.addSpecialHash(req.slotType(), hash);311 self.code_directory.addSpecialHash(req.slotType(), hash);
312312
313 try blobs.append(.{ .requirements = req });313 try blobs.append(.{ .requirements = req });
...@@ -316,10 +316,10 @@ pub fn writeAdhocSignature(...@@ -316,10 +316,10 @@ pub fn writeAdhocSignature(
316 }316 }
317317
318 if (self.entitlements) |*ents| {318 if (self.entitlements) |*ents| {
319 var buf = std.array_list.Managed(u8).init(allocator);319 var a: std.Io.Writer.Allocating = .init(allocator);
320 defer buf.deinit();320 defer a.deinit();
321 try ents.write(buf.writer());321 try ents.write(&a.writer);
322 Sha256.hash(buf.items, &hash, .{});322 Sha256.hash(a.written(), &hash, .{});
323 self.code_directory.addSpecialHash(ents.slotType(), hash);323 self.code_directory.addSpecialHash(ents.slotType(), hash);
324324
325 try blobs.append(.{ .entitlements = ents });325 try blobs.append(.{ .entitlements = ents });
src/link/MachO/DebugSymbols.zig+9-10
...@@ -273,14 +273,13 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -273,14 +273,13 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
273 const buffer = try gpa.alloc(u8, needed_size);273 const buffer = try gpa.alloc(u8, needed_size);
274 defer gpa.free(buffer);274 defer gpa.free(buffer);
275275
276 var stream = std.io.fixedBufferStream(buffer);276 var writer: Writer = .fixed(buffer);
277 const writer = stream.writer();
278277
279 var ncmds: usize = 0;278 var ncmds: usize = 0;
280279
281 // UUID comes first presumably to speed up lookup by the consumer like lldb.280 // UUID comes first presumably to speed up lookup by the consumer like lldb.
282 @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);281 @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);
283 try writer.writeStruct(self.uuid_cmd);282 try writer.writeStruct(self.uuid_cmd, .little);
284 ncmds += 1;283 ncmds += 1;
285284
286 // Segment and section load commands285 // Segment and section load commands
...@@ -293,11 +292,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -293,11 +292,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
293 var out_seg = seg;292 var out_seg = seg;
294 out_seg.fileoff = 0;293 out_seg.fileoff = 0;
295 out_seg.filesize = 0;294 out_seg.filesize = 0;
296 try writer.writeStruct(out_seg);295 try writer.writeStruct(out_seg, .little);
297 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {296 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
298 var out_header = header;297 var out_header = header;
299 out_header.offset = 0;298 out_header.offset = 0;
300 try writer.writeStruct(out_header);299 try writer.writeStruct(out_header, .little);
301 }300 }
302 sect_id += seg.nsects;301 sect_id += seg.nsects;
303 }302 }
...@@ -306,19 +305,19 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -306,19 +305,19 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
306 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.305 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
307 sect_id = 0;306 sect_id = 0;
308 for (self.segments.items) |seg| {307 for (self.segments.items) |seg| {
309 try writer.writeStruct(seg);308 try writer.writeStruct(seg, .little);
310 for (self.sections.items[sect_id..][0..seg.nsects]) |header| {309 for (self.sections.items[sect_id..][0..seg.nsects]) |header| {
311 try writer.writeStruct(header);310 try writer.writeStruct(header, .little);
312 }311 }
313 sect_id += seg.nsects;312 sect_id += seg.nsects;
314 }313 }
315 ncmds += self.segments.items.len;314 ncmds += self.segments.items.len;
316 }315 }
317316
318 try writer.writeStruct(self.symtab_cmd);317 try writer.writeStruct(self.symtab_cmd, .little);
319 ncmds += 1;318 ncmds += 1;
320319
321 assert(stream.pos == needed_size);320 assert(writer.end == needed_size);
322321
323 try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));322 try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
324323
...@@ -460,7 +459,7 @@ const math = std.math;...@@ -460,7 +459,7 @@ const math = std.math;
460const mem = std.mem;459const mem = std.mem;
461const padToIdeal = MachO.padToIdeal;460const padToIdeal = MachO.padToIdeal;
462const trace = @import("../../tracy.zig").trace;461const trace = @import("../../tracy.zig").trace;
463const Writer = std.io.Writer;462const Writer = std.Io.Writer;
464463
465const Allocator = mem.Allocator;464const Allocator = mem.Allocator;
466const MachO = @import("../MachO.zig");465const MachO = @import("../MachO.zig");
src/link/MachO/InternalObject.zig+1-1
...@@ -261,7 +261,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil...@@ -261,7 +261,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
261261
262 sect.offset = @intCast(self.objc_methnames.items.len);262 sect.offset = @intCast(self.objc_methnames.items.len);
263 try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1);263 try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1);
264 self.objc_methnames.writer(gpa).print("{s}\x00", .{methname}) catch unreachable;264 self.objc_methnames.print(gpa, "{s}\x00", .{methname}) catch unreachable;
265265
266 const name_str = try self.addString(gpa, "ltmp");266 const name_str = try self.addString(gpa, "ltmp");
267 const sym_index = try self.addSymbol(gpa);267 const sym_index = try self.addSymbol(gpa);
src/link/MachO/UnwindInfo.zig+23-24
...@@ -293,8 +293,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -293,8 +293,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
293 const seg = macho_file.getTextSegment();293 const seg = macho_file.getTextSegment();
294 const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];294 const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];
295295
296 var stream = std.io.fixedBufferStream(buffer);296 var writer: Writer = .fixed(buffer);
297 const writer = stream.writer();
298297
299 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);298 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);
300 const common_encodings_count: u32 = info.common_encodings_count;299 const common_encodings_count: u32 = info.common_encodings_count;
...@@ -303,14 +302,14 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -303,14 +302,14 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
303 const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);302 const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);
304 const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1));303 const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1));
305304
306 try writer.writeStruct(macho.unwind_info_section_header{305 try writer.writeStruct(@as(macho.unwind_info_section_header, .{
307 .commonEncodingsArraySectionOffset = common_encodings_offset,306 .commonEncodingsArraySectionOffset = common_encodings_offset,
308 .commonEncodingsArrayCount = common_encodings_count,307 .commonEncodingsArrayCount = common_encodings_count,
309 .personalityArraySectionOffset = personalities_offset,308 .personalityArraySectionOffset = personalities_offset,
310 .personalityArrayCount = personalities_count,309 .personalityArrayCount = personalities_count,
311 .indexSectionOffset = indexes_offset,310 .indexSectionOffset = indexes_offset,
312 .indexCount = indexes_count,311 .indexCount = indexes_count,
313 });312 }), .little);
314313
315 try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));314 try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));
316315
...@@ -325,42 +324,42 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -325,42 +324,42 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
325 for (info.pages.items, 0..) |page, i| {324 for (info.pages.items, 0..) |page, i| {
326 assert(page.count > 0);325 assert(page.count > 0);
327 const rec = info.records.items[page.start].getUnwindRecord(macho_file);326 const rec = info.records.items[page.start].getUnwindRecord(macho_file);
328 try writer.writeStruct(macho.unwind_info_section_header_index_entry{327 try writer.writeStruct(@as(macho.unwind_info_section_header_index_entry, .{
329 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),328 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
330 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),329 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),
331 .lsdaIndexArraySectionOffset = lsda_base_offset +330 .lsdaIndexArraySectionOffset = lsda_base_offset +
332 info.lsdas_lookup.items[page.start] * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),331 info.lsdas_lookup.items[page.start] * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),
333 });332 }), .little);
334 }333 }
335334
336 const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);335 const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);
337 const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));336 const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));
338 try writer.writeStruct(macho.unwind_info_section_header_index_entry{337 try writer.writeStruct(@as(macho.unwind_info_section_header_index_entry, .{
339 .functionOffset = sentinel_address,338 .functionOffset = sentinel_address,
340 .secondLevelPagesSectionOffset = 0,339 .secondLevelPagesSectionOffset = 0,
341 .lsdaIndexArraySectionOffset = lsda_base_offset +340 .lsdaIndexArraySectionOffset = lsda_base_offset +
342 @as(u32, @intCast(info.lsdas.items.len)) * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),341 @as(u32, @intCast(info.lsdas.items.len)) * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),
343 });342 }), .little);
344343
345 for (info.lsdas.items) |index| {344 for (info.lsdas.items) |index| {
346 const rec = info.records.items[index].getUnwindRecord(macho_file);345 const rec = info.records.items[index].getUnwindRecord(macho_file);
347 try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{346 try writer.writeStruct(@as(macho.unwind_info_section_header_lsda_index_entry, .{
348 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),347 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
349 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),348 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),
350 });349 }), .little);
351 }350 }
352351
353 for (info.pages.items) |page| {352 for (info.pages.items) |page| {
354 const start = stream.pos;353 const start = writer.end;
355 try page.write(info, macho_file, writer);354 try page.write(info, macho_file, &writer);
356 const nwritten = stream.pos - start;355 const nwritten = writer.end - start;
357 if (nwritten < second_level_page_bytes) {356 if (nwritten < second_level_page_bytes) {
358 const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;357 const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;
359 try writer.writeByteNTimes(0, padding);358 try writer.splatByteAll(0, padding);
360 }359 }
361 }360 }
362361
363 @memset(buffer[stream.pos..], 0);362 @memset(buffer[writer.end..], 0);
364}363}
365364
366fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {365fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {
...@@ -611,33 +610,33 @@ const Page = struct {...@@ -611,33 +610,33 @@ const Page = struct {
611 } };610 } };
612 }611 }
613612
614 fn write(page: Page, info: UnwindInfo, macho_file: *MachO, writer: anytype) !void {613 fn write(page: Page, info: UnwindInfo, macho_file: *MachO, writer: *Writer) !void {
615 const seg = macho_file.getTextSegment();614 const seg = macho_file.getTextSegment();
616615
617 switch (page.kind) {616 switch (page.kind) {
618 .regular => {617 .regular => {
619 try writer.writeStruct(macho.unwind_info_regular_second_level_page_header{618 try writer.writeStruct(@as(macho.unwind_info_regular_second_level_page_header, .{
620 .entryPageOffset = @sizeOf(macho.unwind_info_regular_second_level_page_header),619 .entryPageOffset = @sizeOf(macho.unwind_info_regular_second_level_page_header),
621 .entryCount = page.count,620 .entryCount = page.count,
622 });621 }), .little);
623622
624 for (info.records.items[page.start..][0..page.count]) |ref| {623 for (info.records.items[page.start..][0..page.count]) |ref| {
625 const rec = ref.getUnwindRecord(macho_file);624 const rec = ref.getUnwindRecord(macho_file);
626 try writer.writeStruct(macho.unwind_info_regular_second_level_entry{625 try writer.writeStruct(@as(macho.unwind_info_regular_second_level_entry, .{
627 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),626 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
628 .encoding = rec.enc.enc,627 .encoding = rec.enc.enc,
629 });628 }), .little);
630 }629 }
631 },630 },
632 .compressed => {631 .compressed => {
633 const entry_offset = @sizeOf(macho.unwind_info_compressed_second_level_page_header) +632 const entry_offset = @sizeOf(macho.unwind_info_compressed_second_level_page_header) +
634 @as(u16, @intCast(page.page_encodings_count)) * @sizeOf(u32);633 @as(u16, @intCast(page.page_encodings_count)) * @sizeOf(u32);
635 try writer.writeStruct(macho.unwind_info_compressed_second_level_page_header{634 try writer.writeStruct(@as(macho.unwind_info_compressed_second_level_page_header, .{
636 .entryPageOffset = entry_offset,635 .entryPageOffset = entry_offset,
637 .entryCount = page.count,636 .entryCount = page.count,
638 .encodingsPageOffset = @sizeOf(macho.unwind_info_compressed_second_level_page_header),637 .encodingsPageOffset = @sizeOf(macho.unwind_info_compressed_second_level_page_header),
639 .encodingsCount = page.page_encodings_count,638 .encodingsCount = page.page_encodings_count,
640 });639 }), .little);
641640
642 for (page.page_encodings[0..page.page_encodings_count]) |enc| {641 for (page.page_encodings[0..page.page_encodings_count]) |enc| {
643 try writer.writeInt(u32, enc.enc, .little);642 try writer.writeInt(u32, enc.enc, .little);
...@@ -656,7 +655,7 @@ const Page = struct {...@@ -656,7 +655,7 @@ const Page = struct {
656 .funcOffset = @as(u24, @intCast(rec.getAtomAddress(macho_file) - first_rec.getAtomAddress(macho_file))),655 .funcOffset = @as(u24, @intCast(rec.getAtomAddress(macho_file) - first_rec.getAtomAddress(macho_file))),
657 .encodingIndex = @as(u8, @intCast(enc_index)),656 .encodingIndex = @as(u8, @intCast(enc_index)),
658 };657 };
659 try writer.writeStruct(compressed);658 try writer.writeStruct(compressed, .little);
660 }659 }
661 },660 },
662 }661 }
...@@ -673,7 +672,7 @@ const macho = std.macho;...@@ -673,7 +672,7 @@ const macho = std.macho;
673const math = std.math;672const math = std.math;
674const mem = std.mem;673const mem = std.mem;
675const trace = @import("../../tracy.zig").trace;674const trace = @import("../../tracy.zig").trace;
676const Writer = std.io.Writer;675const Writer = std.Io.Writer;
677676
678const Allocator = mem.Allocator;677const Allocator = mem.Allocator;
679const Atom = @import("Atom.zig");678const Atom = @import("Atom.zig");
src/link/MachO/dyld_info/Rebase.zig+10-9
...@@ -110,12 +110,14 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {...@@ -110,12 +110,14 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
110fn finalize(rebase: *Rebase, gpa: Allocator) !void {110fn finalize(rebase: *Rebase, gpa: Allocator) !void {
111 if (rebase.entries.items.len == 0) return;111 if (rebase.entries.items.len == 0) return;
112112
113 const writer = rebase.buffer.writer(gpa);
114
115 log.debug("rebase opcodes", .{});113 log.debug("rebase opcodes", .{});
116114
117 std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);115 std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);
118116
117 var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &rebase.buffer);
118 defer rebase.buffer = allocating.toArrayList();
119 const writer = &allocating.writer;
120
119 try setTypePointer(writer);121 try setTypePointer(writer);
120122
121 var start: usize = 0;123 var start: usize = 0;
...@@ -226,13 +228,13 @@ fn setTypePointer(writer: anytype) !void {...@@ -226,13 +228,13 @@ fn setTypePointer(writer: anytype) !void {
226fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {228fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
227 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });229 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });
228 try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));230 try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
229 try std.leb.writeUleb128(writer, offset);231 try writer.writeUleb128(offset);
230}232}
231233
232fn rebaseAddAddr(addr: u64, writer: anytype) !void {234fn rebaseAddAddr(addr: u64, writer: anytype) !void {
233 log.debug(">>> rebase with add: {x}", .{addr});235 log.debug(">>> rebase with add: {x}", .{addr});
234 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);236 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
235 try std.leb.writeUleb128(writer, addr);237 try writer.writeUleb128(addr);
236}238}
237239
238fn rebaseTimes(count: usize, writer: anytype) !void {240fn rebaseTimes(count: usize, writer: anytype) !void {
...@@ -241,15 +243,15 @@ fn rebaseTimes(count: usize, writer: anytype) !void {...@@ -241,15 +243,15 @@ fn rebaseTimes(count: usize, writer: anytype) !void {
241 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count)));243 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count)));
242 } else {244 } else {
243 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);245 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
244 try std.leb.writeUleb128(writer, count);246 try writer.writeUleb128(count);
245 }247 }
246}248}
247249
248fn rebaseTimesSkip(count: usize, skip: u64, writer: anytype) !void {250fn rebaseTimesSkip(count: usize, skip: u64, writer: anytype) !void {
249 log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, skip });251 log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, skip });
250 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);252 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
251 try std.leb.writeUleb128(writer, count);253 try writer.writeUleb128(count);
252 try std.leb.writeUleb128(writer, skip);254 try writer.writeUleb128(skip);
253}255}
254256
255fn addAddr(addr: u64, writer: anytype) !void {257fn addAddr(addr: u64, writer: anytype) !void {
...@@ -262,7 +264,7 @@ fn addAddr(addr: u64, writer: anytype) !void {...@@ -262,7 +264,7 @@ fn addAddr(addr: u64, writer: anytype) !void {
262 }264 }
263 }265 }
264 try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);266 try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);
265 try std.leb.writeUleb128(writer, addr);267 try writer.writeUleb128(addr);
266}268}
267269
268fn done(writer: anytype) !void {270fn done(writer: anytype) !void {
...@@ -649,7 +651,6 @@ test "rebase - composite" {...@@ -649,7 +651,6 @@ test "rebase - composite" {
649651
650const std = @import("std");652const std = @import("std");
651const assert = std.debug.assert;653const assert = std.debug.assert;
652const leb = std.leb;
653const log = std.log.scoped(.link_dyld_info);654const log = std.log.scoped(.link_dyld_info);
654const macho = std.macho;655const macho = std.macho;
655const mem = std.mem;656const mem = std.mem;
src/link/MachO/dyld_info/Trie.zig+16-12
...@@ -170,8 +170,13 @@ fn finalize(self: *Trie, allocator: Allocator) !void {...@@ -170,8 +170,13 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
170 }170 }
171171
172 try self.buffer.ensureTotalCapacityPrecise(allocator, size);172 try self.buffer.ensureTotalCapacityPrecise(allocator, size);
173
174 var allocating: std.Io.Writer.Allocating = .fromArrayList(allocator, &self.buffer);
175 defer self.buffer = allocating.toArrayList();
176 const writer = &allocating.writer;
177
173 for (ordered_nodes.items) |node_index| {178 for (ordered_nodes.items) |node_index| {
174 try self.writeNode(node_index, self.buffer.writer(allocator));179 try self.writeNode(node_index, writer);
175 }180 }
176}181}
177182
...@@ -232,7 +237,7 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {...@@ -232,7 +237,7 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {
232 self.buffer.deinit(allocator);237 self.buffer.deinit(allocator);
233}238}
234239
235pub fn write(self: Trie, writer: anytype) !void {240pub fn write(self: Trie, writer: *std.Io.Writer) !void {
236 if (self.buffer.items.len == 0) return;241 if (self.buffer.items.len == 0) return;
237 try writer.writeAll(self.buffer.items);242 try writer.writeAll(self.buffer.items);
238}243}
...@@ -243,7 +248,7 @@ pub fn write(self: Trie, writer: anytype) !void {...@@ -243,7 +248,7 @@ pub fn write(self: Trie, writer: anytype) !void {
243/// iterate over `Trie.ordered_nodes` and call this method on each node.248/// iterate over `Trie.ordered_nodes` and call this method on each node.
244/// This is one of the requirements of the MachO.249/// This is one of the requirements of the MachO.
245/// Panics if `finalize` was not called before calling this method.250/// Panics if `finalize` was not called before calling this method.
246fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {251fn writeNode(self: *Trie, node_index: Node.Index, writer: *std.Io.Writer) !void {
247 const slice = self.nodes.slice();252 const slice = self.nodes.slice();
248 const edges = slice.items(.edges)[node_index];253 const edges = slice.items(.edges)[node_index];
249 const is_terminal = slice.items(.is_terminal)[node_index];254 const is_terminal = slice.items(.is_terminal)[node_index];
...@@ -253,21 +258,21 @@ fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {...@@ -253,21 +258,21 @@ fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {
253 if (is_terminal) {258 if (is_terminal) {
254 // Terminal node info: encode export flags and vmaddr offset of this symbol.259 // Terminal node info: encode export flags and vmaddr offset of this symbol.
255 var info_buf: [@sizeOf(u64) * 2]u8 = undefined;260 var info_buf: [@sizeOf(u64) * 2]u8 = undefined;
256 var info_stream = std.io.fixedBufferStream(&info_buf);261 var info_stream: std.Io.Writer = .fixed(&info_buf);
257 // TODO Implement for special flags.262 // TODO Implement for special flags.
258 assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and263 assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
259 export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);264 export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);
260 try leb.writeUleb128(info_stream.writer(), export_flags);265 try info_stream.writeUleb128(export_flags);
261 try leb.writeUleb128(info_stream.writer(), vmaddr_offset);266 try info_stream.writeUleb128(vmaddr_offset);
262267
263 // Encode the size of the terminal node info.268 // Encode the size of the terminal node info.
264 var size_buf: [@sizeOf(u64)]u8 = undefined;269 var size_buf: [@sizeOf(u64)]u8 = undefined;
265 var size_stream = std.io.fixedBufferStream(&size_buf);270 var size_stream: std.Io.Writer = .fixed(&size_buf);
266 try leb.writeUleb128(size_stream.writer(), info_stream.pos);271 try size_stream.writeUleb128(info_stream.end);
267272
268 // Now, write them to the output stream.273 // Now, write them to the output stream.
269 try writer.writeAll(size_buf[0..size_stream.pos]);274 try writer.writeAll(size_buf[0..size_stream.end]);
270 try writer.writeAll(info_buf[0..info_stream.pos]);275 try writer.writeAll(info_buf[0..info_stream.end]);
271 } else {276 } else {
272 // Non-terminal node is delimited by 0 byte.277 // Non-terminal node is delimited by 0 byte.
273 try writer.writeByte(0);278 try writer.writeByte(0);
...@@ -280,7 +285,7 @@ fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {...@@ -280,7 +285,7 @@ fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {
280 // Write edge label and offset to next node in trie.285 // Write edge label and offset to next node in trie.
281 try writer.writeAll(edge.label);286 try writer.writeAll(edge.label);
282 try writer.writeByte(0);287 try writer.writeByte(0);
283 try leb.writeUleb128(writer, slice.items(.trie_offset)[edge.node]);288 try writer.writeUleb128(slice.items(.trie_offset)[edge.node]);
284 }289 }
285}290}
286291
...@@ -414,7 +419,6 @@ test "ordering bug" {...@@ -414,7 +419,6 @@ test "ordering bug" {
414}419}
415420
416const assert = std.debug.assert;421const assert = std.debug.assert;
417const leb = std.leb;
418const log = std.log.scoped(.macho);422const log = std.log.scoped(.macho);
419const macho = std.macho;423const macho = std.macho;
420const mem = std.mem;424const mem = std.mem;
src/link/MachO/dyld_info/bind.zig+32-28
...@@ -132,12 +132,14 @@ pub const Bind = struct {...@@ -132,12 +132,14 @@ pub const Bind = struct {
132 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {132 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
133 if (self.entries.items.len == 0) return;133 if (self.entries.items.len == 0) return;
134134
135 const writer = self.buffer.writer(gpa);
136
137 log.debug("bind opcodes", .{});135 log.debug("bind opcodes", .{});
138136
139 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);137 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
140138
139 var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &self.buffer);
140 defer self.buffer = allocating.toArrayList();
141 const writer = &allocating.writer;
142
141 var start: usize = 0;143 var start: usize = 0;
142 var seg_id: ?u8 = null;144 var seg_id: ?u8 = null;
143 for (self.entries.items, 0..) |entry, i| {145 for (self.entries.items, 0..) |entry, i| {
...@@ -151,7 +153,7 @@ pub const Bind = struct {...@@ -151,7 +153,7 @@ pub const Bind = struct {
151 try done(writer);153 try done(writer);
152 }154 }
153155
154 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {156 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: *std.Io.Writer) !void {
155 if (entries.len == 0) return;157 if (entries.len == 0) return;
156158
157 const seg_id = entries[0].segment_id;159 const seg_id = entries[0].segment_id;
...@@ -263,7 +265,7 @@ pub const Bind = struct {...@@ -263,7 +265,7 @@ pub const Bind = struct {
263 }265 }
264 }266 }
265267
266 pub fn write(self: Self, writer: anytype) !void {268 pub fn write(self: Self, writer: *std.Io.Writer) !void {
267 try writer.writeAll(self.buffer.items);269 try writer.writeAll(self.buffer.items);
268 }270 }
269};271};
...@@ -385,12 +387,14 @@ pub const WeakBind = struct {...@@ -385,12 +387,14 @@ pub const WeakBind = struct {
385 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {387 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
386 if (self.entries.items.len == 0) return;388 if (self.entries.items.len == 0) return;
387389
388 const writer = self.buffer.writer(gpa);
389
390 log.debug("weak bind opcodes", .{});390 log.debug("weak bind opcodes", .{});
391391
392 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);392 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
393393
394 var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &self.buffer);
395 defer self.buffer = allocating.toArrayList();
396 const writer = &allocating.writer;
397
394 var start: usize = 0;398 var start: usize = 0;
395 var seg_id: ?u8 = null;399 var seg_id: ?u8 = null;
396 for (self.entries.items, 0..) |entry, i| {400 for (self.entries.items, 0..) |entry, i| {
...@@ -404,7 +408,7 @@ pub const WeakBind = struct {...@@ -404,7 +408,7 @@ pub const WeakBind = struct {
404 try done(writer);408 try done(writer);
405 }409 }
406410
407 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {411 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: *std.Io.Writer) !void {
408 if (entries.len == 0) return;412 if (entries.len == 0) return;
409413
410 const seg_id = entries[0].segment_id;414 const seg_id = entries[0].segment_id;
...@@ -505,7 +509,7 @@ pub const WeakBind = struct {...@@ -505,7 +509,7 @@ pub const WeakBind = struct {
505 }509 }
506 }510 }
507511
508 pub fn write(self: Self, writer: anytype) !void {512 pub fn write(self: Self, writer: *std.Io.Writer) !void {
509 try writer.writeAll(self.buffer.items);513 try writer.writeAll(self.buffer.items);
510 }514 }
511};515};
...@@ -555,8 +559,6 @@ pub const LazyBind = struct {...@@ -555,8 +559,6 @@ pub const LazyBind = struct {
555 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {559 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
556 try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);560 try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);
557561
558 const writer = self.buffer.writer(gpa);
559
560 log.debug("lazy bind opcodes", .{});562 log.debug("lazy bind opcodes", .{});
561563
562 var addend: i64 = 0;564 var addend: i64 = 0;
...@@ -578,6 +580,9 @@ pub const LazyBind = struct {...@@ -578,6 +580,9 @@ pub const LazyBind = struct {
578 break :ord macho.BIND_SPECIAL_DYLIB_SELF;580 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
579 };581 };
580582
583 var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &self.buffer);
584 defer self.buffer = allocating.toArrayList();
585 const writer = &allocating.writer;
581 try setSegmentOffset(entry.segment_id, entry.offset, writer);586 try setSegmentOffset(entry.segment_id, entry.offset, writer);
582 try setSymbol(name, flags, writer);587 try setSymbol(name, flags, writer);
583 try setDylibOrdinal(ordinal, writer);588 try setDylibOrdinal(ordinal, writer);
...@@ -592,30 +597,30 @@ pub const LazyBind = struct {...@@ -592,30 +597,30 @@ pub const LazyBind = struct {
592 }597 }
593 }598 }
594599
595 pub fn write(self: Self, writer: anytype) !void {600 pub fn write(self: Self, writer: *std.Io.Writer) !void {
596 try writer.writeAll(self.buffer.items);601 try writer.writeAll(self.buffer.items);
597 }602 }
598};603};
599604
600fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {605fn setSegmentOffset(segment_id: u8, offset: u64, writer: *std.Io.Writer) !void {
601 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });606 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });
602 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));607 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
603 try std.leb.writeUleb128(writer, offset);608 try writer.writeUleb128(offset);
604}609}
605610
606fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void {611fn setSymbol(name: []const u8, flags: u8, writer: *std.Io.Writer) !void {
607 log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });612 log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });
608 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | @as(u4, @truncate(flags)));613 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | @as(u4, @truncate(flags)));
609 try writer.writeAll(name);614 try writer.writeAll(name);
610 try writer.writeByte(0);615 try writer.writeByte(0);
611}616}
612617
613fn setTypePointer(writer: anytype) !void {618fn setTypePointer(writer: *std.Io.Writer) !void {
614 log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER});619 log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER});
615 try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.BIND_TYPE_POINTER)));620 try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.BIND_TYPE_POINTER)));
616}621}
617622
618fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {623fn setDylibOrdinal(ordinal: i16, writer: *std.Io.Writer) !void {
619 if (ordinal <= 0) {624 if (ordinal <= 0) {
620 switch (ordinal) {625 switch (ordinal) {
621 macho.BIND_SPECIAL_DYLIB_SELF,626 macho.BIND_SPECIAL_DYLIB_SELF,
...@@ -634,23 +639,23 @@ fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {...@@ -634,23 +639,23 @@ fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {
634 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @as(u4, @truncate(cast)));639 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @as(u4, @truncate(cast)));
635 } else {640 } else {
636 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);641 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
637 try std.leb.writeUleb128(writer, cast);642 try writer.writeUleb128(cast);
638 }643 }
639 }644 }
640}645}
641646
642fn setAddend(addend: i64, writer: anytype) !void {647fn setAddend(addend: i64, writer: *std.Io.Writer) !void {
643 log.debug(">>> set addend: {x}", .{addend});648 log.debug(">>> set addend: {x}", .{addend});
644 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);649 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
645 try std.leb.writeIleb128(writer, addend);650 try std.leb.writeIleb128(writer, addend);
646}651}
647652
648fn doBind(writer: anytype) !void {653fn doBind(writer: *std.Io.Writer) !void {
649 log.debug(">>> bind", .{});654 log.debug(">>> bind", .{});
650 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);655 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
651}656}
652657
653fn doBindAddAddr(addr: u64, writer: anytype) !void {658fn doBindAddAddr(addr: u64, writer: *std.Io.Writer) !void {
654 log.debug(">>> bind with add: {x}", .{addr});659 log.debug(">>> bind with add: {x}", .{addr});
655 if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {660 if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {
656 const imm = @divExact(addr, @sizeOf(u64));661 const imm = @divExact(addr, @sizeOf(u64));
...@@ -662,29 +667,28 @@ fn doBindAddAddr(addr: u64, writer: anytype) !void {...@@ -662,29 +667,28 @@ fn doBindAddAddr(addr: u64, writer: anytype) !void {
662 }667 }
663 }668 }
664 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);669 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
665 try std.leb.writeUleb128(writer, addr);670 try writer.writeUleb128(addr);
666}671}
667672
668fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void {673fn doBindTimesSkip(count: usize, skip: u64, writer: *std.Io.Writer) !void {
669 log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });674 log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });
670 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);675 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
671 try std.leb.writeUleb128(writer, count);676 try writer.writeUleb128(count);
672 try std.leb.writeUleb128(writer, skip);677 try writer.writeUleb128(skip);
673}678}
674679
675fn addAddr(addr: u64, writer: anytype) !void {680fn addAddr(addr: u64, writer: *std.Io.Writer) !void {
676 log.debug(">>> add: {x}", .{addr});681 log.debug(">>> add: {x}", .{addr});
677 try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);682 try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
678 try std.leb.writeUleb128(writer, addr);683 try writer.writeUleb128(addr);
679}684}
680685
681fn done(writer: anytype) !void {686fn done(writer: *std.Io.Writer) !void {
682 log.debug(">>> done", .{});687 log.debug(">>> done", .{});
683 try writer.writeByte(macho.BIND_OPCODE_DONE);688 try writer.writeByte(macho.BIND_OPCODE_DONE);
684}689}
685690
686const assert = std.debug.assert;691const assert = std.debug.assert;
687const leb = std.leb;
688const log = std.log.scoped(.link_dyld_info);692const log = std.log.scoped(.link_dyld_info);
689const macho = std.macho;693const macho = std.macho;
690const mem = std.mem;694const mem = std.mem;
src/link/MachO/load_commands.zig+19-19
...@@ -3,9 +3,9 @@ const assert = std.debug.assert;...@@ -3,9 +3,9 @@ const assert = std.debug.assert;
3const log = std.log.scoped(.link);3const log = std.log.scoped(.link);
4const macho = std.macho;4const macho = std.macho;
5const mem = std.mem;5const mem = std.mem;
6const Writer = std.io.Writer;6const Writer = std.Io.Writer;
7const Allocator = std.mem.Allocator;
78
8const Allocator = mem.Allocator;
9const DebugSymbols = @import("DebugSymbols.zig");9const DebugSymbols = @import("DebugSymbols.zig");
10const Dylib = @import("Dylib.zig");10const Dylib = @import("Dylib.zig");
11const MachO = @import("../MachO.zig");11const MachO = @import("../MachO.zig");
...@@ -181,22 +181,22 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {...@@ -181,22 +181,22 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {
181 return offset;181 return offset;
182}182}
183183
184pub fn writeDylinkerLC(writer: anytype) !void {184pub fn writeDylinkerLC(writer: *Writer) !void {
185 const name_len = mem.sliceTo(default_dyld_path, 0).len;185 const name_len = mem.sliceTo(default_dyld_path, 0).len;
186 const cmdsize = @as(u32, @intCast(mem.alignForward(186 const cmdsize = @as(u32, @intCast(mem.alignForward(
187 u64,187 u64,
188 @sizeOf(macho.dylinker_command) + name_len,188 @sizeOf(macho.dylinker_command) + name_len,
189 @sizeOf(u64),189 @sizeOf(u64),
190 )));190 )));
191 try writer.writeStruct(macho.dylinker_command{191 try writer.writeStruct(@as(macho.dylinker_command, .{
192 .cmd = .LOAD_DYLINKER,192 .cmd = .LOAD_DYLINKER,
193 .cmdsize = cmdsize,193 .cmdsize = cmdsize,
194 .name = @sizeOf(macho.dylinker_command),194 .name = @sizeOf(macho.dylinker_command),
195 });195 }), .little);
196 try writer.writeAll(mem.sliceTo(default_dyld_path, 0));196 try writer.writeAll(mem.sliceTo(default_dyld_path, 0));
197 const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len;197 const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len;
198 if (padding > 0) {198 if (padding > 0) {
199 try writer.writeByteNTimes(0, padding);199 try writer.splatByteAll(0, padding);
200 }200 }
201}201}
202202
...@@ -208,14 +208,14 @@ const WriteDylibLCCtx = struct {...@@ -208,14 +208,14 @@ const WriteDylibLCCtx = struct {
208 compatibility_version: u32 = 0x10000,208 compatibility_version: u32 = 0x10000,
209};209};
210210
211pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {211pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: *Writer) !void {
212 const name_len = ctx.name.len + 1;212 const name_len = ctx.name.len + 1;
213 const cmdsize = @as(u32, @intCast(mem.alignForward(213 const cmdsize = @as(u32, @intCast(mem.alignForward(
214 u64,214 u64,
215 @sizeOf(macho.dylib_command) + name_len,215 @sizeOf(macho.dylib_command) + name_len,
216 @sizeOf(u64),216 @sizeOf(u64),
217 )));217 )));
218 try writer.writeStruct(macho.dylib_command{218 try writer.writeStruct(@as(macho.dylib_command, .{
219 .cmd = ctx.cmd,219 .cmd = ctx.cmd,
220 .cmdsize = cmdsize,220 .cmdsize = cmdsize,
221 .dylib = .{221 .dylib = .{
...@@ -224,16 +224,16 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {...@@ -224,16 +224,16 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {
224 .current_version = ctx.current_version,224 .current_version = ctx.current_version,
225 .compatibility_version = ctx.compatibility_version,225 .compatibility_version = ctx.compatibility_version,
226 },226 },
227 });227 }), .little);
228 try writer.writeAll(ctx.name);228 try writer.writeAll(ctx.name);
229 try writer.writeByte(0);229 try writer.writeByte(0);
230 const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len;230 const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len;
231 if (padding > 0) {231 if (padding > 0) {
232 try writer.writeByteNTimes(0, padding);232 try writer.splatByteAll(0, padding);
233 }233 }
234}234}
235235
236pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {236pub fn writeDylibIdLC(macho_file: *MachO, writer: *Writer) !void {
237 const comp = macho_file.base.comp;237 const comp = macho_file.base.comp;
238 const gpa = comp.gpa;238 const gpa = comp.gpa;
239 assert(comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);239 assert(comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);
...@@ -259,26 +259,26 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {...@@ -259,26 +259,26 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
259 }, writer);259 }, writer);
260}260}
261261
262pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {262pub fn writeRpathLC(rpath: []const u8, writer: *Writer) !void {
263 const rpath_len = rpath.len + 1;263 const rpath_len = rpath.len + 1;
264 const cmdsize = @as(u32, @intCast(mem.alignForward(264 const cmdsize = @as(u32, @intCast(mem.alignForward(
265 u64,265 u64,
266 @sizeOf(macho.rpath_command) + rpath_len,266 @sizeOf(macho.rpath_command) + rpath_len,
267 @sizeOf(u64),267 @sizeOf(u64),
268 )));268 )));
269 try writer.writeStruct(macho.rpath_command{269 try writer.writeStruct(@as(macho.rpath_command, .{
270 .cmdsize = cmdsize,270 .cmdsize = cmdsize,
271 .path = @sizeOf(macho.rpath_command),271 .path = @sizeOf(macho.rpath_command),
272 });272 }), .little);
273 try writer.writeAll(rpath);273 try writer.writeAll(rpath);
274 try writer.writeByte(0);274 try writer.writeByte(0);
275 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;275 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
276 if (padding > 0) {276 if (padding > 0) {
277 try writer.writeByteNTimes(0, padding);277 try writer.splatByteAll(0, padding);
278 }278 }
279}279}
280280
281pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {281pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: *Writer) !void {
282 const cmd: macho.LC = switch (platform.os_tag) {282 const cmd: macho.LC = switch (platform.os_tag) {
283 .macos => .VERSION_MIN_MACOSX,283 .macos => .VERSION_MIN_MACOSX,
284 .ios => .VERSION_MIN_IPHONEOS,284 .ios => .VERSION_MIN_IPHONEOS,
...@@ -296,9 +296,9 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer...@@ -296,9 +296,9 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer
296 }));296 }));
297}297}
298298
299pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {299pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: *Writer) !void {
300 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);300 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
301 try writer.writeStruct(macho.build_version_command{301 try writer.writeStruct(@as(macho.build_version_command, .{
302 .cmdsize = cmdsize,302 .cmdsize = cmdsize,
303 .platform = platform.toApplePlatform(),303 .platform = platform.toApplePlatform(),
304 .minos = platform.toAppleVersion(),304 .minos = platform.toAppleVersion(),
...@@ -307,7 +307,7 @@ pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticV...@@ -307,7 +307,7 @@ pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticV
307 else307 else
308 platform.toAppleVersion(),308 platform.toAppleVersion(),
309 .ntools = 1,309 .ntools = 1,
310 });310 }), .little);
311 try writer.writeAll(mem.asBytes(&macho.build_tool_version{311 try writer.writeAll(mem.asBytes(&macho.build_tool_version{
312 .tool = .ZIG,312 .tool = .ZIG,
313 .version = 0x0,313 .version = 0x0,
src/link/MachO/relocatable.zig+29-33
...@@ -205,35 +205,32 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -205,35 +205,32 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
205 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});205 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
206 }206 }
207207
208 var buffer = std.array_list.Managed(u8).init(gpa);208 const buffer = try gpa.alloc(u8, total_size);
209 defer buffer.deinit();209 defer gpa.free(buffer);
210 try buffer.ensureTotalCapacityPrecise(total_size);210 var writer: Writer = .fixed(buffer);
211 const writer = buffer.writer();
212211
213 // Write magic212 // Write magic
214 try writer.writeAll(Archive.ARMAG);213 writer.writeAll(Archive.ARMAG) catch unreachable;
215214
216 // Write symtab215 // Write symtab
217 ar_symtab.write(format, macho_file, writer) catch |err| switch (err) {216 ar_symtab.write(format, macho_file, &writer) catch |err|
218 error.OutOfMemory => return error.OutOfMemory,217 return diags.fail("failed to write archive symbol table: {t}", .{err});
219 else => |e| return diags.fail("failed to write archive symbol table: {s}", .{@errorName(e)}),
220 };
221218
222 // Write object files219 // Write object files
223 for (files.items) |index| {220 for (files.items) |index| {
224 const aligned = mem.alignForward(usize, buffer.items.len, 2);221 const aligned = mem.alignForward(usize, writer.end, 2);
225 const padding = aligned - buffer.items.len;222 const padding = aligned - writer.end;
226 if (padding > 0) {223 if (padding > 0) {
227 try writer.writeByteNTimes(0, padding);224 writer.splatByteAll(0, padding) catch unreachable;
228 }225 }
229 macho_file.getFile(index).?.writeAr(format, macho_file, writer) catch |err|226 macho_file.getFile(index).?.writeAr(format, macho_file, &writer) catch |err|
230 return diags.fail("failed to write archive: {s}", .{@errorName(err)});227 return diags.fail("failed to write archive: {t}", .{err});
231 }228 }
232229
233 assert(buffer.items.len == total_size);230 assert(writer.end == total_size);
234231
235 try macho_file.setEndPos(total_size);232 try macho_file.setEndPos(total_size);
236 try macho_file.pwriteAll(buffer.items, 0);233 try macho_file.pwriteAll(writer.buffered(), 0);
237234
238 if (diags.hasErrors()) return error.LinkFailure;235 if (diags.hasErrors()) return error.LinkFailure;
239}236}
...@@ -693,8 +690,7 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc...@@ -693,8 +690,7 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
693 const buffer = try gpa.alloc(u8, needed_size);690 const buffer = try gpa.alloc(u8, needed_size);
694 defer gpa.free(buffer);691 defer gpa.free(buffer);
695692
696 var stream = std.io.fixedBufferStream(buffer);693 var writer: Writer = .fixed(buffer);
697 const writer = stream.writer();
698694
699 var ncmds: usize = 0;695 var ncmds: usize = 0;
700696
...@@ -702,43 +698,43 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc...@@ -702,43 +698,43 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
702 {698 {
703 assert(macho_file.segments.items.len == 1);699 assert(macho_file.segments.items.len == 1);
704 const seg = macho_file.segments.items[0];700 const seg = macho_file.segments.items[0];
705 writer.writeStruct(seg) catch |err| switch (err) {701 writer.writeStruct(seg, .little) catch |err| switch (err) {
706 error.NoSpaceLeft => unreachable,702 error.WriteFailed => unreachable,
707 };703 };
708 for (macho_file.sections.items(.header)) |header| {704 for (macho_file.sections.items(.header)) |header| {
709 writer.writeStruct(header) catch |err| switch (err) {705 writer.writeStruct(header, .little) catch |err| switch (err) {
710 error.NoSpaceLeft => unreachable,706 error.WriteFailed => unreachable,
711 };707 };
712 }708 }
713 ncmds += 1;709 ncmds += 1;
714 }710 }
715711
716 writer.writeStruct(macho_file.data_in_code_cmd) catch |err| switch (err) {712 writer.writeStruct(macho_file.data_in_code_cmd, .little) catch |err| switch (err) {
717 error.NoSpaceLeft => unreachable,713 error.WriteFailed => unreachable,
718 };714 };
719 ncmds += 1;715 ncmds += 1;
720 writer.writeStruct(macho_file.symtab_cmd) catch |err| switch (err) {716 writer.writeStruct(macho_file.symtab_cmd, .little) catch |err| switch (err) {
721 error.NoSpaceLeft => unreachable,717 error.WriteFailed => unreachable,
722 };718 };
723 ncmds += 1;719 ncmds += 1;
724 writer.writeStruct(macho_file.dysymtab_cmd) catch |err| switch (err) {720 writer.writeStruct(macho_file.dysymtab_cmd, .little) catch |err| switch (err) {
725 error.NoSpaceLeft => unreachable,721 error.WriteFailed => unreachable,
726 };722 };
727 ncmds += 1;723 ncmds += 1;
728724
729 if (macho_file.platform.isBuildVersionCompatible()) {725 if (macho_file.platform.isBuildVersionCompatible()) {
730 load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {726 load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, &writer) catch |err| switch (err) {
731 error.NoSpaceLeft => unreachable,727 error.WriteFailed => unreachable,
732 };728 };
733 ncmds += 1;729 ncmds += 1;
734 } else {730 } else {
735 load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {731 load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, &writer) catch |err| switch (err) {
736 error.NoSpaceLeft => unreachable,732 error.WriteFailed => unreachable,
737 };733 };
738 ncmds += 1;734 ncmds += 1;
739 }735 }
740736
741 assert(stream.pos == needed_size);737 assert(writer.end == needed_size);
742738
743 try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));739 try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
744740
src/link/MachO/synthetic.zig+12-12
...@@ -27,7 +27,7 @@ pub const GotSection = struct {...@@ -27,7 +27,7 @@ pub const GotSection = struct {
27 return got.symbols.items.len * @sizeOf(u64);27 return got.symbols.items.len * @sizeOf(u64);
28 }28 }
2929
30 pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void {30 pub fn write(got: GotSection, macho_file: *MachO, writer: *Writer) !void {
31 const tracy = trace(@src());31 const tracy = trace(@src());
32 defer tracy.end();32 defer tracy.end();
33 for (got.symbols.items) |ref| {33 for (got.symbols.items) |ref| {
...@@ -89,7 +89,7 @@ pub const StubsSection = struct {...@@ -89,7 +89,7 @@ pub const StubsSection = struct {
89 return stubs.symbols.items.len * header.reserved2;89 return stubs.symbols.items.len * header.reserved2;
90 }90 }
9191
92 pub fn write(stubs: StubsSection, macho_file: *MachO, writer: anytype) !void {92 pub fn write(stubs: StubsSection, macho_file: *MachO, writer: *Writer) !void {
93 const tracy = trace(@src());93 const tracy = trace(@src());
94 defer tracy.end();94 defer tracy.end();
95 const cpu_arch = macho_file.getTarget().cpu.arch;95 const cpu_arch = macho_file.getTarget().cpu.arch;
...@@ -174,7 +174,7 @@ pub const StubsHelperSection = struct {...@@ -174,7 +174,7 @@ pub const StubsHelperSection = struct {
174 return s;174 return s;
175 }175 }
176176
177 pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {177 pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: *Writer) !void {
178 const tracy = trace(@src());178 const tracy = trace(@src());
179 defer tracy.end();179 defer tracy.end();
180180
...@@ -217,7 +217,7 @@ pub const StubsHelperSection = struct {...@@ -217,7 +217,7 @@ pub const StubsHelperSection = struct {
217 }217 }
218 }218 }
219219
220 fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {220 fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: *Writer) !void {
221 _ = stubs_helper;221 _ = stubs_helper;
222 const obj = macho_file.getInternalObject().?;222 const obj = macho_file.getInternalObject().?;
223 const cpu_arch = macho_file.getTarget().cpu.arch;223 const cpu_arch = macho_file.getTarget().cpu.arch;
...@@ -273,7 +273,7 @@ pub const LaSymbolPtrSection = struct {...@@ -273,7 +273,7 @@ pub const LaSymbolPtrSection = struct {
273 return macho_file.stubs.symbols.items.len * @sizeOf(u64);273 return macho_file.stubs.symbols.items.len * @sizeOf(u64);
274 }274 }
275275
276 pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: anytype) !void {276 pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: *Writer) !void {
277 const tracy = trace(@src());277 const tracy = trace(@src());
278 defer tracy.end();278 defer tracy.end();
279 _ = laptr;279 _ = laptr;
...@@ -323,7 +323,7 @@ pub const TlvPtrSection = struct {...@@ -323,7 +323,7 @@ pub const TlvPtrSection = struct {
323 return tlv.symbols.items.len * @sizeOf(u64);323 return tlv.symbols.items.len * @sizeOf(u64);
324 }324 }
325325
326 pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: anytype) !void {326 pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: *Writer) !void {
327 const tracy = trace(@src());327 const tracy = trace(@src());
328 defer tracy.end();328 defer tracy.end();
329329
...@@ -394,7 +394,7 @@ pub const ObjcStubsSection = struct {...@@ -394,7 +394,7 @@ pub const ObjcStubsSection = struct {
394 return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);394 return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);
395 }395 }
396396
397 pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: anytype) !void {397 pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: *Writer) !void {
398 const tracy = trace(@src());398 const tracy = trace(@src());
399 defer tracy.end();399 defer tracy.end();
400400
...@@ -487,7 +487,7 @@ pub const Indsymtab = struct {...@@ -487,7 +487,7 @@ pub const Indsymtab = struct {
487 macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);487 macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);
488 }488 }
489489
490 pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void {490 pub fn write(ind: Indsymtab, macho_file: *MachO, writer: *Writer) !void {
491 const tracy = trace(@src());491 const tracy = trace(@src());
492 defer tracy.end();492 defer tracy.end();
493493
...@@ -564,7 +564,7 @@ pub const DataInCode = struct {...@@ -564,7 +564,7 @@ pub const DataInCode = struct {
564 macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;564 macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;
565 }565 }
566566
567 pub fn write(dice: DataInCode, macho_file: *MachO, writer: anytype) !void {567 pub fn write(dice: DataInCode, macho_file: *MachO, writer: *Writer) !void {
568 const base_address = if (!macho_file.base.isRelocatable())568 const base_address = if (!macho_file.base.isRelocatable())
569 macho_file.getTextSegment().vmaddr569 macho_file.getTextSegment().vmaddr
570 else570 else
...@@ -572,11 +572,11 @@ pub const DataInCode = struct {...@@ -572,11 +572,11 @@ pub const DataInCode = struct {
572 for (dice.entries.items) |entry| {572 for (dice.entries.items) |entry| {
573 const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);573 const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);
574 const offset = atom_address + entry.offset - base_address;574 const offset = atom_address + entry.offset - base_address;
575 try writer.writeStruct(macho.data_in_code_entry{575 try writer.writeStruct(@as(macho.data_in_code_entry, .{
576 .offset = @intCast(offset),576 .offset = @intCast(offset),
577 .length = entry.length,577 .length = entry.length,
578 .kind = entry.kind,578 .kind = entry.kind,
579 });579 }), .little);
580 }580 }
581 }581 }
582582
...@@ -594,7 +594,7 @@ const assert = std.debug.assert;...@@ -594,7 +594,7 @@ const assert = std.debug.assert;
594const macho = std.macho;594const macho = std.macho;
595const math = std.math;595const math = std.math;
596const Allocator = std.mem.Allocator;596const Allocator = std.mem.Allocator;
597const Writer = std.io.Writer;597const Writer = std.Io.Writer;
598598
599const trace = @import("../../tracy.zig").trace;599const trace = @import("../../tracy.zig").trace;
600const MachO = @import("../MachO.zig");600const MachO = @import("../MachO.zig");
src/link/Wasm/Flush.zig+176-149
...@@ -19,6 +19,7 @@ const mem = std.mem;...@@ -19,6 +19,7 @@ const mem = std.mem;
19const leb = std.leb;19const leb = std.leb;
20const log = std.log.scoped(.link);20const log = std.log.scoped(.link);
21const assert = std.debug.assert;21const assert = std.debug.assert;
22const ArrayList = std.ArrayList;
2223
23/// Ordered list of data segments that will appear in the final binary.24/// Ordered list of data segments that will appear in the final binary.
24/// When sorted, to-be-merged segments will be made adjacent.25/// When sorted, to-be-merged segments will be made adjacent.
...@@ -27,9 +28,9 @@ data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataSegmentId, u32) = .empty,...@@ -27,9 +28,9 @@ data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataSegmentId, u32) = .empty,
27/// Each time a `data_segment` offset equals zero it indicates a new group, and28/// Each time a `data_segment` offset equals zero it indicates a new group, and
28/// the next element in this array will contain the total merged segment size.29/// the next element in this array will contain the total merged segment size.
29/// Value is the virtual memory address of the end of the segment.30/// Value is the virtual memory address of the end of the segment.
30data_segment_groups: std.ArrayListUnmanaged(DataSegmentGroup) = .empty,31data_segment_groups: ArrayList(DataSegmentGroup) = .empty,
3132
32binary_bytes: std.ArrayListUnmanaged(u8) = .empty,33binary_bytes: ArrayList(u8) = .empty,
33missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty,34missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty,
34function_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.FunctionImportId) = .empty,35function_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.FunctionImportId) = .empty,
35global_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.GlobalImportId) = .empty,36global_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.GlobalImportId) = .empty,
...@@ -563,8 +564,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -563,8 +564,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
563 try binary_bytes.appendSlice(gpa, &std.wasm.magic ++ &std.wasm.version);564 try binary_bytes.appendSlice(gpa, &std.wasm.magic ++ &std.wasm.version);
564 assert(binary_bytes.items.len == 8);565 assert(binary_bytes.items.len == 8);
565566
566 const binary_writer = binary_bytes.writer(gpa);
567
568 // Type section.567 // Type section.
569 for (f.function_imports.values()) |id| {568 for (f.function_imports.values()) |id| {
570 try f.func_types.put(gpa, id.functionType(wasm), {});569 try f.func_types.put(gpa, id.functionType(wasm), {});
...@@ -576,16 +575,16 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -576,16 +575,16 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
576 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);575 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
577 for (f.func_types.keys()) |func_type_index| {576 for (f.func_types.keys()) |func_type_index| {
578 const func_type = func_type_index.ptr(wasm);577 const func_type = func_type_index.ptr(wasm);
579 try leb.writeUleb128(binary_writer, std.wasm.function_type);578 try appendLeb128(gpa, binary_bytes, std.wasm.function_type);
580 const params = func_type.params.slice(wasm);579 const params = func_type.params.slice(wasm);
581 try leb.writeUleb128(binary_writer, @as(u32, @intCast(params.len)));580 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(params.len)));
582 for (params) |param_ty| {581 for (params) |param_ty| {
583 try leb.writeUleb128(binary_writer, @intFromEnum(param_ty));582 try appendLeb128(gpa, binary_bytes, @intFromEnum(param_ty));
584 }583 }
585 const returns = func_type.returns.slice(wasm);584 const returns = func_type.returns.slice(wasm);
586 try leb.writeUleb128(binary_writer, @as(u32, @intCast(returns.len)));585 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(returns.len)));
587 for (returns) |ret_ty| {586 for (returns) |ret_ty| {
588 try leb.writeUleb128(binary_writer, @intFromEnum(ret_ty));587 try appendLeb128(gpa, binary_bytes, @intFromEnum(ret_ty));
589 }588 }
590 }589 }
591 replaceVecSectionHeader(binary_bytes, header_offset, .type, @intCast(f.func_types.entries.len));590 replaceVecSectionHeader(binary_bytes, header_offset, .type, @intCast(f.func_types.entries.len));
...@@ -605,31 +604,31 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -605,31 +604,31 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
605604
606 for (f.function_imports.values()) |id| {605 for (f.function_imports.values()) |id| {
607 const module_name = id.moduleName(wasm).slice(wasm).?;606 const module_name = id.moduleName(wasm).slice(wasm).?;
608 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));607 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
609 try binary_writer.writeAll(module_name);608 try binary_bytes.appendSlice(gpa, module_name);
610609
611 const name = id.importName(wasm).slice(wasm);610 const name = id.importName(wasm).slice(wasm);
612 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));611 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
613 try binary_writer.writeAll(name);612 try binary_bytes.appendSlice(gpa, name);
614613
615 try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.function));614 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function));
616 const type_index: FuncTypeIndex = .fromTypeIndex(id.functionType(wasm), f);615 const type_index: FuncTypeIndex = .fromTypeIndex(id.functionType(wasm), f);
617 try leb.writeUleb128(binary_writer, @intFromEnum(type_index));616 try appendLeb128(gpa, binary_bytes, @intFromEnum(type_index));
618 }617 }
619 total_imports += f.function_imports.entries.len;618 total_imports += f.function_imports.entries.len;
620619
621 for (wasm.table_imports.values()) |id| {620 for (wasm.table_imports.values()) |id| {
622 const table_import = id.value(wasm);621 const table_import = id.value(wasm);
623 const module_name = table_import.module_name.slice(wasm);622 const module_name = table_import.module_name.slice(wasm);
624 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));623 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
625 try binary_writer.writeAll(module_name);624 try binary_bytes.appendSlice(gpa, module_name);
626625
627 const name = table_import.name.slice(wasm);626 const name = table_import.name.slice(wasm);
628 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));627 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
629 try binary_writer.writeAll(name);628 try binary_bytes.appendSlice(gpa, name);
630629
631 try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.table));630 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.table));
632 try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to())));631 try appendLeb128(gpa, binary_bytes, @intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to())));
633 try emitLimits(gpa, binary_bytes, table_import.limits());632 try emitLimits(gpa, binary_bytes, table_import.limits());
634 }633 }
635 total_imports += wasm.table_imports.entries.len;634 total_imports += wasm.table_imports.entries.len;
...@@ -650,17 +649,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -650,17 +649,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
650649
651 for (f.global_imports.values()) |id| {650 for (f.global_imports.values()) |id| {
652 const module_name = id.moduleName(wasm).slice(wasm).?;651 const module_name = id.moduleName(wasm).slice(wasm).?;
653 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));652 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
654 try binary_writer.writeAll(module_name);653 try binary_bytes.appendSlice(gpa, module_name);
655654
656 const name = id.importName(wasm).slice(wasm);655 const name = id.importName(wasm).slice(wasm);
657 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));656 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
658 try binary_writer.writeAll(name);657 try binary_bytes.appendSlice(gpa, name);
659658
660 try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.global));659 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.global));
661 const global_type = id.globalType(wasm);660 const global_type = id.globalType(wasm);
662 try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.Valtype, global_type.valtype)));661 try appendLeb128(gpa, binary_bytes, @intFromEnum(@as(std.wasm.Valtype, global_type.valtype)));
663 try binary_writer.writeByte(@intFromBool(global_type.mutable));662 try binary_bytes.append(gpa, @intFromBool(global_type.mutable));
664 }663 }
665 total_imports += f.global_imports.entries.len;664 total_imports += f.global_imports.entries.len;
666665
...@@ -677,7 +676,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -677,7 +676,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
677 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);676 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
678 for (wasm.functions.keys()) |function| {677 for (wasm.functions.keys()) |function| {
679 const index: FuncTypeIndex = .fromTypeIndex(function.typeIndex(wasm), f);678 const index: FuncTypeIndex = .fromTypeIndex(function.typeIndex(wasm), f);
680 try leb.writeUleb128(binary_writer, @intFromEnum(index));679 try appendLeb128(gpa, binary_bytes, @intFromEnum(index));
681 }680 }
682681
683 replaceVecSectionHeader(binary_bytes, header_offset, .function, @intCast(wasm.functions.count()));682 replaceVecSectionHeader(binary_bytes, header_offset, .function, @intCast(wasm.functions.count()));
...@@ -689,7 +688,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -689,7 +688,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
689 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);688 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
690689
691 for (wasm.tables.keys()) |table| {690 for (wasm.tables.keys()) |table| {
692 try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table.refType(wasm))));691 try appendLeb128(gpa, binary_bytes, @intFromEnum(@as(std.wasm.RefType, table.refType(wasm))));
693 try emitLimits(gpa, binary_bytes, table.limits(wasm));692 try emitLimits(gpa, binary_bytes, table.limits(wasm));
694 }693 }
695694
...@@ -743,39 +742,39 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -743,39 +742,39 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
743742
744 for (wasm.function_exports.keys(), wasm.function_exports.values()) |exp_name, function_index| {743 for (wasm.function_exports.keys(), wasm.function_exports.values()) |exp_name, function_index| {
745 const name = exp_name.slice(wasm);744 const name = exp_name.slice(wasm);
746 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));745 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
747 try binary_bytes.appendSlice(gpa, name);746 try binary_bytes.appendSlice(gpa, name);
748 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function));747 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function));
749 const func_index = Wasm.OutputFunctionIndex.fromFunctionIndex(wasm, function_index);748 const func_index = Wasm.OutputFunctionIndex.fromFunctionIndex(wasm, function_index);
750 try leb.writeUleb128(binary_writer, @intFromEnum(func_index));749 try appendLeb128(gpa, binary_bytes, @intFromEnum(func_index));
751 }750 }
752 exports_len += wasm.function_exports.entries.len;751 exports_len += wasm.function_exports.entries.len;
753752
754 if (wasm.export_table and f.indirect_function_table.entries.len > 0) {753 if (wasm.export_table and f.indirect_function_table.entries.len > 0) {
755 const name = "__indirect_function_table";754 const name = "__indirect_function_table";
756 const index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);755 const index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);
757 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));756 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
758 try binary_bytes.appendSlice(gpa, name);757 try binary_bytes.appendSlice(gpa, name);
759 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.table));758 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.table));
760 try leb.writeUleb128(binary_writer, index);759 try appendLeb128(gpa, binary_bytes, index);
761 exports_len += 1;760 exports_len += 1;
762 }761 }
763762
764 if (export_memory) {763 if (export_memory) {
765 const name = "memory";764 const name = "memory";
766 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));765 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
767 try binary_bytes.appendSlice(gpa, name);766 try binary_bytes.appendSlice(gpa, name);
768 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));767 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));
769 try leb.writeUleb128(binary_writer, @as(u32, 0));768 try appendLeb128(gpa, binary_bytes, @as(u32, 0));
770 exports_len += 1;769 exports_len += 1;
771 }770 }
772771
773 for (wasm.global_exports.items) |exp| {772 for (wasm.global_exports.items) |exp| {
774 const name = exp.name.slice(wasm);773 const name = exp.name.slice(wasm);
775 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));774 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
776 try binary_bytes.appendSlice(gpa, name);775 try binary_bytes.appendSlice(gpa, name);
777 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.global));776 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.global));
778 try leb.writeUleb128(binary_writer, @intFromEnum(exp.global_index));777 try appendLeb128(gpa, binary_bytes, @intFromEnum(exp.global_index));
779 }778 }
780 exports_len += wasm.global_exports.items.len;779 exports_len += wasm.global_exports.items.len;
781780
...@@ -802,18 +801,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -802,18 +801,22 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
802 const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);801 const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);
803 // passive with implicit 0-index table or set table index manually802 // passive with implicit 0-index table or set table index manually
804 const flags: u32 = if (table_index == 0) 0x0 else 0x02;803 const flags: u32 = if (table_index == 0) 0x0 else 0x02;
805 try leb.writeUleb128(binary_writer, flags);804 try appendLeb128(gpa, binary_bytes, flags);
806 if (flags == 0x02) {805 if (flags == 0x02) {
807 try leb.writeUleb128(binary_writer, table_index);806 try appendLeb128(gpa, binary_bytes, table_index);
808 }807 }
809 // We start at index 1, so unresolved function pointers are invalid808 // We start at index 1, so unresolved function pointers are invalid
810 try emitInit(binary_writer, .{ .i32_const = 1 });809 {
810 var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, binary_bytes);
811 defer binary_bytes.* = aw.toArrayList();
812 try emitInit(&aw.writer, .{ .i32_const = 1 });
813 }
811 if (flags == 0x02) {814 if (flags == 0x02) {
812 try leb.writeUleb128(binary_writer, @as(u8, 0)); // represents funcref815 try appendLeb128(gpa, binary_bytes, @as(u8, 0)); // represents funcref
813 }816 }
814 try leb.writeUleb128(binary_writer, @as(u32, @intCast(f.indirect_function_table.entries.len)));817 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(f.indirect_function_table.entries.len)));
815 for (f.indirect_function_table.keys()) |func_index| {818 for (f.indirect_function_table.keys()) |func_index| {
816 try leb.writeUleb128(binary_writer, @intFromEnum(func_index));819 try appendLeb128(gpa, binary_bytes, @intFromEnum(func_index));
817 }820 }
818821
819 replaceVecSectionHeader(binary_bytes, header_offset, .element, 1);822 replaceVecSectionHeader(binary_bytes, header_offset, .element, 1);
...@@ -851,7 +854,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -851,7 +854,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
851 .object_function => |i| {854 .object_function => |i| {
852 const ptr = i.ptr(wasm);855 const ptr = i.ptr(wasm);
853 const code = ptr.code.slice(wasm);856 const code = ptr.code.slice(wasm);
854 try leb.writeUleb128(binary_writer, code.len);857 try appendLeb128(gpa, binary_bytes, code.len);
855 const code_start = binary_bytes.items.len;858 const code_start = binary_bytes.items.len;
856 try binary_bytes.appendSlice(gpa, code);859 try binary_bytes.appendSlice(gpa, code);
857 if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm);860 if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm);
...@@ -946,12 +949,14 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -946,12 +949,14 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
946 const group_size = group_end_addr - group_start_addr;949 const group_size = group_end_addr - group_start_addr;
947 log.debug("emit data section group, {d} bytes", .{group_size});950 log.debug("emit data section group, {d} bytes", .{group_size});
948 const flags: Object.DataSegmentFlags = if (segment_id.isPassive(wasm)) .passive else .active;951 const flags: Object.DataSegmentFlags = if (segment_id.isPassive(wasm)) .passive else .active;
949 try leb.writeUleb128(binary_writer, @intFromEnum(flags));952 try appendLeb128(gpa, binary_bytes, @intFromEnum(flags));
950 // Passive segments are initialized at runtime.953 // Passive segments are initialized at runtime.
951 if (flags != .passive) {954 if (flags != .passive) {
952 try emitInit(binary_writer, .{ .i32_const = @as(i32, @bitCast(group_start_addr)) });955 var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, binary_bytes);
956 defer binary_bytes.* = aw.toArrayList();
957 try emitInit(&aw.writer, .{ .i32_const = @as(i32, @bitCast(group_start_addr)) });
953 }958 }
954 try leb.writeUleb128(binary_writer, group_size);959 try appendLeb128(gpa, binary_bytes, group_size);
955 }960 }
956 if (segment_id.isEmpty(wasm)) {961 if (segment_id.isEmpty(wasm)) {
957 // It counted for virtual memory but it does not go into the binary.962 // It counted for virtual memory but it does not go into the binary.
...@@ -1077,7 +1082,7 @@ const VirtualAddrs = struct {...@@ -1077,7 +1082,7 @@ const VirtualAddrs = struct {
1077fn emitNameSection(1082fn emitNameSection(
1078 wasm: *Wasm,1083 wasm: *Wasm,
1079 data_segment_groups: []const DataSegmentGroup,1084 data_segment_groups: []const DataSegmentGroup,
1080 binary_bytes: *std.ArrayListUnmanaged(u8),1085 binary_bytes: *ArrayList(u8),
1081) !void {1086) !void {
1082 const f = &wasm.flush_buffer;1087 const f = &wasm.flush_buffer;
1083 const comp = wasm.base.comp;1088 const comp = wasm.base.comp;
...@@ -1087,7 +1092,7 @@ fn emitNameSection(...@@ -1087,7 +1092,7 @@ fn emitNameSection(
1087 defer writeCustomSectionHeader(binary_bytes, header_offset);1092 defer writeCustomSectionHeader(binary_bytes, header_offset);
10881093
1089 const name_name = "name";1094 const name_name = "name";
1090 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, name_name.len));1095 try appendLeb128(gpa, binary_bytes, @as(u32, name_name.len));
1091 try binary_bytes.appendSlice(gpa, name_name);1096 try binary_bytes.appendSlice(gpa, name_name);
10921097
1093 {1098 {
...@@ -1095,18 +1100,18 @@ fn emitNameSection(...@@ -1095,18 +1100,18 @@ fn emitNameSection(
1095 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function));1100 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function));
10961101
1097 const total_functions: u32 = @intCast(f.function_imports.entries.len + wasm.functions.entries.len);1102 const total_functions: u32 = @intCast(f.function_imports.entries.len + wasm.functions.entries.len);
1098 try leb.writeUleb128(binary_bytes.writer(gpa), total_functions);1103 try appendLeb128(gpa, binary_bytes, total_functions);
10991104
1100 for (f.function_imports.keys(), 0..) |name_index, function_index| {1105 for (f.function_imports.keys(), 0..) |name_index, function_index| {
1101 const name = name_index.slice(wasm);1106 const name = name_index.slice(wasm);
1102 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index)));1107 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1103 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1108 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1104 try binary_bytes.appendSlice(gpa, name);1109 try binary_bytes.appendSlice(gpa, name);
1105 }1110 }
1106 for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| {1111 for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| {
1107 const name = resolution.name(wasm).?;1112 const name = resolution.name(wasm).?;
1108 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index)));1113 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(function_index)));
1109 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1114 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1110 try binary_bytes.appendSlice(gpa, name);1115 try binary_bytes.appendSlice(gpa, name);
1111 }1116 }
1112 }1117 }
...@@ -1116,18 +1121,18 @@ fn emitNameSection(...@@ -1116,18 +1121,18 @@ fn emitNameSection(
1116 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global));1121 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global));
11171122
1118 const total_globals: u32 = @intCast(f.global_imports.entries.len + wasm.globals.entries.len);1123 const total_globals: u32 = @intCast(f.global_imports.entries.len + wasm.globals.entries.len);
1119 try leb.writeUleb128(binary_bytes.writer(gpa), total_globals);1124 try appendLeb128(gpa, binary_bytes, total_globals);
11201125
1121 for (f.global_imports.keys(), 0..) |name_index, global_index| {1126 for (f.global_imports.keys(), 0..) |name_index, global_index| {
1122 const name = name_index.slice(wasm);1127 const name = name_index.slice(wasm);
1123 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index)));1128 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index)));
1124 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1129 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1125 try binary_bytes.appendSlice(gpa, name);1130 try binary_bytes.appendSlice(gpa, name);
1126 }1131 }
1127 for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| {1132 for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| {
1128 const name = resolution.name(wasm).?;1133 const name = resolution.name(wasm).?;
1129 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index)));1134 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(global_index)));
1130 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1135 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1131 try binary_bytes.appendSlice(gpa, name);1136 try binary_bytes.appendSlice(gpa, name);
1132 }1137 }
1133 }1138 }
...@@ -1137,12 +1142,12 @@ fn emitNameSection(...@@ -1137,12 +1142,12 @@ fn emitNameSection(
1137 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.data_segment));1142 defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.data_segment));
11381143
1139 const total_data_segments: u32 = @intCast(data_segment_groups.len);1144 const total_data_segments: u32 = @intCast(data_segment_groups.len);
1140 try leb.writeUleb128(binary_bytes.writer(gpa), total_data_segments);1145 try appendLeb128(gpa, binary_bytes, total_data_segments);
11411146
1142 for (data_segment_groups, 0..) |group, i| {1147 for (data_segment_groups, 0..) |group, i| {
1143 const name, _ = splitSegmentName(group.first_segment.name(wasm));1148 const name, _ = splitSegmentName(group.first_segment.name(wasm));
1144 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(i)));1149 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(i)));
1145 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1150 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1146 try binary_bytes.appendSlice(gpa, name);1151 try binary_bytes.appendSlice(gpa, name);
1147 }1152 }
1148 }1153 }
...@@ -1150,7 +1155,7 @@ fn emitNameSection(...@@ -1150,7 +1155,7 @@ fn emitNameSection(
11501155
1151fn emitFeaturesSection(1156fn emitFeaturesSection(
1152 gpa: Allocator,1157 gpa: Allocator,
1153 binary_bytes: *std.ArrayListUnmanaged(u8),1158 binary_bytes: *ArrayList(u8),
1154 target: *const std.Target,1159 target: *const std.Target,
1155) Allocator.Error!void {1160) Allocator.Error!void {
1156 const feature_count = target.cpu.features.count();1161 const feature_count = target.cpu.features.count();
...@@ -1159,87 +1164,84 @@ fn emitFeaturesSection(...@@ -1159,87 +1164,84 @@ fn emitFeaturesSection(
1159 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);1164 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
1160 defer writeCustomSectionHeader(binary_bytes, header_offset);1165 defer writeCustomSectionHeader(binary_bytes, header_offset);
11611166
1162 const writer = binary_bytes.writer(gpa);
1163 const target_features = "target_features";1167 const target_features = "target_features";
1164 try leb.writeUleb128(writer, @as(u32, @intCast(target_features.len)));1168 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(target_features.len)));
1165 try writer.writeAll(target_features);1169 try binary_bytes.appendSlice(gpa, target_features);
11661170
1167 try leb.writeUleb128(writer, @as(u32, @intCast(feature_count)));1171 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(feature_count)));
11681172
1169 var safety_count = feature_count;1173 var safety_count = feature_count;
1170 for (target.cpu.arch.allFeaturesList(), 0..) |*feature, i| {1174 for (target.cpu.arch.allFeaturesList(), 0..) |*feature, i| {
1171 if (!target.cpu.has(.wasm, @as(std.Target.wasm.Feature, @enumFromInt(i)))) continue;1175 if (!target.cpu.has(.wasm, @as(std.Target.wasm.Feature, @enumFromInt(i)))) continue;
1172 safety_count -= 1;1176 safety_count -= 1;
11731177
1174 try leb.writeUleb128(writer, @as(u32, '+'));1178 try appendLeb128(gpa, binary_bytes, @as(u32, '+'));
1175 // Depends on llvm_name for the hyphenated version that matches wasm tooling conventions.1179 // Depends on llvm_name for the hyphenated version that matches wasm tooling conventions.
1176 const name = feature.llvm_name.?;1180 const name = feature.llvm_name.?;
1177 try leb.writeUleb128(writer, @as(u32, @intCast(name.len)));1181 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1178 try writer.writeAll(name);1182 try binary_bytes.appendSlice(gpa, name);
1179 }1183 }
1180 assert(safety_count == 0);1184 assert(safety_count == 0);
1181}1185}
11821186
1183fn emitBuildIdSection(gpa: Allocator, binary_bytes: *std.ArrayListUnmanaged(u8), build_id: []const u8) !void {1187fn emitBuildIdSection(gpa: Allocator, binary_bytes: *ArrayList(u8), build_id: []const u8) !void {
1184 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);1188 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
1185 defer writeCustomSectionHeader(binary_bytes, header_offset);1189 defer writeCustomSectionHeader(binary_bytes, header_offset);
11861190
1187 const writer = binary_bytes.writer(gpa);
1188 const hdr_build_id = "build_id";1191 const hdr_build_id = "build_id";
1189 try leb.writeUleb128(writer, @as(u32, @intCast(hdr_build_id.len)));1192 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(hdr_build_id.len)));
1190 try writer.writeAll(hdr_build_id);1193 try binary_bytes.appendSlice(gpa, hdr_build_id);
11911194
1192 try leb.writeUleb128(writer, @as(u32, 1));1195 try appendLeb128(gpa, binary_bytes, @as(u32, 1));
1193 try leb.writeUleb128(writer, @as(u32, @intCast(build_id.len)));1196 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(build_id.len)));
1194 try writer.writeAll(build_id);1197 try binary_bytes.appendSlice(gpa, build_id);
1195}1198}
11961199
1197fn emitProducerSection(gpa: Allocator, binary_bytes: *std.ArrayListUnmanaged(u8)) !void {1200fn emitProducerSection(gpa: Allocator, binary_bytes: *ArrayList(u8)) !void {
1198 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);1201 const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
1199 defer writeCustomSectionHeader(binary_bytes, header_offset);1202 defer writeCustomSectionHeader(binary_bytes, header_offset);
12001203
1201 const writer = binary_bytes.writer(gpa);
1202 const producers = "producers";1204 const producers = "producers";
1203 try leb.writeUleb128(writer, @as(u32, @intCast(producers.len)));1205 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(producers.len)));
1204 try writer.writeAll(producers);1206 try binary_bytes.appendSlice(gpa, producers);
12051207
1206 try leb.writeUleb128(writer, @as(u32, 2)); // 2 fields: Language + processed-by1208 try appendLeb128(gpa, binary_bytes, @as(u32, 2)); // 2 fields: Language + processed-by
12071209
1208 // language field1210 // language field
1209 {1211 {
1210 const language = "language";1212 const language = "language";
1211 try leb.writeUleb128(writer, @as(u32, @intCast(language.len)));1213 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(language.len)));
1212 try writer.writeAll(language);1214 try binary_bytes.appendSlice(gpa, language);
12131215
1214 // field_value_count (TODO: Parse object files for producer sections to detect their language)1216 // field_value_count (TODO: Parse object files for producer sections to detect their language)
1215 try leb.writeUleb128(writer, @as(u32, 1));1217 try appendLeb128(gpa, binary_bytes, @as(u32, 1));
12161218
1217 // versioned name1219 // versioned name
1218 {1220 {
1219 try leb.writeUleb128(writer, @as(u32, 3)); // len of "Zig"1221 try appendLeb128(gpa, binary_bytes, @as(u32, 3)); // len of "Zig"
1220 try writer.writeAll("Zig");1222 try binary_bytes.appendSlice(gpa, "Zig");
12211223
1222 try leb.writeUleb128(writer, @as(u32, @intCast(build_options.version.len)));1224 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(build_options.version.len)));
1223 try writer.writeAll(build_options.version);1225 try binary_bytes.appendSlice(gpa, build_options.version);
1224 }1226 }
1225 }1227 }
12261228
1227 // processed-by field1229 // processed-by field
1228 {1230 {
1229 const processed_by = "processed-by";1231 const processed_by = "processed-by";
1230 try leb.writeUleb128(writer, @as(u32, @intCast(processed_by.len)));1232 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(processed_by.len)));
1231 try writer.writeAll(processed_by);1233 try binary_bytes.appendSlice(gpa, processed_by);
12321234
1233 // field_value_count (TODO: Parse object files for producer sections to detect other used tools)1235 // field_value_count (TODO: Parse object files for producer sections to detect other used tools)
1234 try leb.writeUleb128(writer, @as(u32, 1));1236 try appendLeb128(gpa, binary_bytes, @as(u32, 1));
12351237
1236 // versioned name1238 // versioned name
1237 {1239 {
1238 try leb.writeUleb128(writer, @as(u32, 3)); // len of "Zig"1240 try appendLeb128(gpa, binary_bytes, @as(u32, 3)); // len of "Zig"
1239 try writer.writeAll("Zig");1241 try binary_bytes.appendSlice(gpa, "Zig");
12401242
1241 try leb.writeUleb128(writer, @as(u32, @intCast(build_options.version.len)));1243 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(build_options.version.len)));
1242 try writer.writeAll(build_options.version);1244 try binary_bytes.appendSlice(gpa, build_options.version);
1243 }1245 }
1244 }1246 }
1245}1247}
...@@ -1280,99 +1282,97 @@ fn wantSegmentMerge(...@@ -1280,99 +1282,97 @@ fn wantSegmentMerge(
1280const section_header_reserve_size = 1 + 5 + 5;1282const section_header_reserve_size = 1 + 5 + 5;
1281const section_header_size = 5 + 1;1283const section_header_size = 5 + 1;
12821284
1283fn reserveVecSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {1285fn reserveVecSectionHeader(gpa: Allocator, bytes: *ArrayList(u8)) Allocator.Error!u32 {
1284 try bytes.appendNTimes(gpa, 0, section_header_reserve_size);1286 try bytes.appendNTimes(gpa, 0, section_header_reserve_size);
1285 return @intCast(bytes.items.len - section_header_reserve_size);1287 return @intCast(bytes.items.len - section_header_reserve_size);
1286}1288}
12871289
1288fn replaceVecSectionHeader(1290fn replaceVecSectionHeader(
1289 bytes: *std.ArrayListUnmanaged(u8),1291 bytes: *ArrayList(u8),
1290 offset: u32,1292 offset: u32,
1291 section: std.wasm.Section,1293 section: std.wasm.Section,
1292 n_items: u32,1294 n_items: u32,
1293) void {1295) void {
1294 const size: u32 = @intCast(bytes.items.len - offset - section_header_reserve_size + uleb128size(n_items));1296 const size: u32 = @intCast(bytes.items.len - offset - section_header_reserve_size + uleb128size(n_items));
1295 var buf: [section_header_reserve_size]u8 = undefined;1297 var buf: [section_header_reserve_size]u8 = undefined;
1296 var fbw = std.io.fixedBufferStream(&buf);1298 var w: std.Io.Writer = .fixed(&buf);
1297 const w = fbw.writer();
1298 w.writeByte(@intFromEnum(section)) catch unreachable;1299 w.writeByte(@intFromEnum(section)) catch unreachable;
1299 leb.writeUleb128(w, size) catch unreachable;1300 w.writeUleb128(size) catch unreachable;
1300 leb.writeUleb128(w, n_items) catch unreachable;1301 w.writeUleb128(n_items) catch unreachable;
1301 bytes.replaceRangeAssumeCapacity(offset, section_header_reserve_size, fbw.getWritten());1302 bytes.replaceRangeAssumeCapacity(offset, section_header_reserve_size, w.buffered());
1302}1303}
13031304
1304fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {1305fn reserveCustomSectionHeader(gpa: Allocator, bytes: *ArrayList(u8)) Allocator.Error!u32 {
1305 try bytes.appendNTimes(gpa, 0, section_header_size);1306 try bytes.appendNTimes(gpa, 0, section_header_size);
1306 return @intCast(bytes.items.len - section_header_size);1307 return @intCast(bytes.items.len - section_header_size);
1307}1308}
13081309
1309fn writeCustomSectionHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void {1310fn writeCustomSectionHeader(bytes: *ArrayList(u8), offset: u32) void {
1310 return replaceHeader(bytes, offset, 0); // 0 = 'custom' section1311 return replaceHeader(bytes, offset, 0); // 0 = 'custom' section
1311}1312}
13121313
1313fn replaceHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32, tag: u8) void {1314fn replaceHeader(bytes: *ArrayList(u8), offset: u32, tag: u8) void {
1314 const size: u32 = @intCast(bytes.items.len - offset - section_header_size);1315 const size: u32 = @intCast(bytes.items.len - offset - section_header_size);
1315 var buf: [section_header_size]u8 = undefined;1316 var buf: [section_header_size]u8 = undefined;
1316 var fbw = std.io.fixedBufferStream(&buf);1317 var w: std.Io.Writer = .fixed(&buf);
1317 const w = fbw.writer();
1318 w.writeByte(tag) catch unreachable;1318 w.writeByte(tag) catch unreachable;
1319 leb.writeUleb128(w, size) catch unreachable;1319 w.writeUleb128(size) catch unreachable;
1320 bytes.replaceRangeAssumeCapacity(offset, section_header_size, fbw.getWritten());1320 bytes.replaceRangeAssumeCapacity(offset, section_header_size, w.buffered());
1321}1321}
13221322
1323const max_size_encoding = 5;1323const max_size_encoding = 5;
13241324
1325fn reserveSize(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 {1325fn reserveSize(gpa: Allocator, bytes: *ArrayList(u8)) Allocator.Error!u32 {
1326 try bytes.appendNTimes(gpa, 0, max_size_encoding);1326 try bytes.appendNTimes(gpa, 0, max_size_encoding);
1327 return @intCast(bytes.items.len - max_size_encoding);1327 return @intCast(bytes.items.len - max_size_encoding);
1328}1328}
13291329
1330fn replaceSize(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void {1330fn replaceSize(bytes: *ArrayList(u8), offset: u32) void {
1331 const size: u32 = @intCast(bytes.items.len - offset - max_size_encoding);1331 const size: u32 = @intCast(bytes.items.len - offset - max_size_encoding);
1332 var buf: [max_size_encoding]u8 = undefined;1332 var buf: [max_size_encoding]u8 = undefined;
1333 var fbw = std.io.fixedBufferStream(&buf);1333 var w: std.Io.Writer = .fixed(&buf);
1334 leb.writeUleb128(fbw.writer(), size) catch unreachable;1334 w.writeUleb128(size) catch unreachable;
1335 bytes.replaceRangeAssumeCapacity(offset, max_size_encoding, fbw.getWritten());1335 bytes.replaceRangeAssumeCapacity(offset, max_size_encoding, w.buffered());
1336}1336}
13371337
1338fn emitLimits(1338fn emitLimits(
1339 gpa: Allocator,1339 gpa: Allocator,
1340 binary_bytes: *std.ArrayListUnmanaged(u8),1340 binary_bytes: *ArrayList(u8),
1341 limits: std.wasm.Limits,1341 limits: std.wasm.Limits,
1342) Allocator.Error!void {1342) Allocator.Error!void {
1343 try binary_bytes.append(gpa, @bitCast(limits.flags));1343 try binary_bytes.append(gpa, @bitCast(limits.flags));
1344 try leb.writeUleb128(binary_bytes.writer(gpa), limits.min);1344 try appendLeb128(gpa, binary_bytes, limits.min);
1345 if (limits.flags.has_max) try leb.writeUleb128(binary_bytes.writer(gpa), limits.max);1345 if (limits.flags.has_max) try appendLeb128(gpa, binary_bytes, limits.max);
1346}1346}
13471347
1348fn emitMemoryImport(1348fn emitMemoryImport(
1349 wasm: *Wasm,1349 wasm: *Wasm,
1350 binary_bytes: *std.ArrayListUnmanaged(u8),1350 binary_bytes: *ArrayList(u8),
1351 name_index: String,1351 name_index: String,
1352 memory_import: *const Wasm.MemoryImport,1352 memory_import: *const Wasm.MemoryImport,
1353) Allocator.Error!void {1353) Allocator.Error!void {
1354 const gpa = wasm.base.comp.gpa;1354 const gpa = wasm.base.comp.gpa;
1355 const module_name = memory_import.module_name.slice(wasm);1355 const module_name = memory_import.module_name.slice(wasm);
1356 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(module_name.len)));1356 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(module_name.len)));
1357 try binary_bytes.appendSlice(gpa, module_name);1357 try binary_bytes.appendSlice(gpa, module_name);
13581358
1359 const name = name_index.slice(wasm);1359 const name = name_index.slice(wasm);
1360 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));1360 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(name.len)));
1361 try binary_bytes.appendSlice(gpa, name);1361 try binary_bytes.appendSlice(gpa, name);
13621362
1363 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));1363 try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));
1364 try emitLimits(gpa, binary_bytes, memory_import.limits());1364 try emitLimits(gpa, binary_bytes, memory_import.limits());
1365}1365}
13661366
1367pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {1367fn emitInit(writer: *std.Io.Writer, init_expr: std.wasm.InitExpression) !void {
1368 switch (init_expr) {1368 switch (init_expr) {
1369 .i32_const => |val| {1369 .i32_const => |val| {
1370 try writer.writeByte(@intFromEnum(std.wasm.Opcode.i32_const));1370 try writer.writeByte(@intFromEnum(std.wasm.Opcode.i32_const));
1371 try leb.writeIleb128(writer, val);1371 try writer.writeSleb128(val);
1372 },1372 },
1373 .i64_const => |val| {1373 .i64_const => |val| {
1374 try writer.writeByte(@intFromEnum(std.wasm.Opcode.i64_const));1374 try writer.writeByte(@intFromEnum(std.wasm.Opcode.i64_const));
1375 try leb.writeIleb128(writer, val);1375 try writer.writeSleb128(val);
1376 },1376 },
1377 .f32_const => |val| {1377 .f32_const => |val| {
1378 try writer.writeByte(@intFromEnum(std.wasm.Opcode.f32_const));1378 try writer.writeByte(@intFromEnum(std.wasm.Opcode.f32_const));
...@@ -1384,13 +1384,13 @@ pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {...@@ -1384,13 +1384,13 @@ pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
1384 },1384 },
1385 .global_get => |val| {1385 .global_get => |val| {
1386 try writer.writeByte(@intFromEnum(std.wasm.Opcode.global_get));1386 try writer.writeByte(@intFromEnum(std.wasm.Opcode.global_get));
1387 try leb.writeUleb128(writer, val);1387 try writer.writeUleb128(val);
1388 },1388 },
1389 }1389 }
1390 try writer.writeByte(@intFromEnum(std.wasm.Opcode.end));1390 try writer.writeByte(@intFromEnum(std.wasm.Opcode.end));
1391}1391}
13921392
1393pub fn emitExpr(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), expr: Wasm.Expr) Allocator.Error!void {1393pub fn emitExpr(wasm: *const Wasm, binary_bytes: *ArrayList(u8), expr: Wasm.Expr) Allocator.Error!void {
1394 const gpa = wasm.base.comp.gpa;1394 const gpa = wasm.base.comp.gpa;
1395 const slice = expr.slice(wasm);1395 const slice = expr.slice(wasm);
1396 try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode1396 try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode
...@@ -1398,21 +1398,20 @@ pub fn emitExpr(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), ex...@@ -1398,21 +1398,20 @@ pub fn emitExpr(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), ex
13981398
1399fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.array_list.Managed(u8)) !void {1399fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.array_list.Managed(u8)) !void {
1400 const gpa = wasm.base.comp.gpa;1400 const gpa = wasm.base.comp.gpa;
1401 const writer = binary_bytes.writer(gpa);1401 try appendLeb128(gpa, binary_bytes, @intFromEnum(Wasm.SubsectionType.segment_info));
1402 try leb.writeUleb128(writer, @intFromEnum(Wasm.SubsectionType.segment_info));
1403 const segment_offset = binary_bytes.items.len;1402 const segment_offset = binary_bytes.items.len;
14041403
1405 try leb.writeUleb128(writer, @as(u32, @intCast(wasm.segment_info.count())));1404 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(wasm.segment_info.count())));
1406 for (wasm.segment_info.values()) |segment_info| {1405 for (wasm.segment_info.values()) |segment_info| {
1407 log.debug("Emit segment: {s} align({d}) flags({b})", .{1406 log.debug("Emit segment: {s} align({d}) flags({b})", .{
1408 segment_info.name,1407 segment_info.name,
1409 segment_info.alignment,1408 segment_info.alignment,
1410 segment_info.flags,1409 segment_info.flags,
1411 });1410 });
1412 try leb.writeUleb128(writer, @as(u32, @intCast(segment_info.name.len)));1411 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(segment_info.name.len)));
1413 try writer.writeAll(segment_info.name);1412 try binary_bytes.appendSlice(gpa, segment_info.name);
1414 try leb.writeUleb128(writer, segment_info.alignment.toLog2Units());1413 try appendLeb128(gpa, binary_bytes, segment_info.alignment.toLog2Units());
1415 try leb.writeUleb128(writer, segment_info.flags);1414 try appendLeb128(gpa, binary_bytes, segment_info.flags);
1416 }1415 }
14171416
1418 var buf: [5]u8 = undefined;1417 var buf: [5]u8 = undefined;
...@@ -1429,7 +1428,7 @@ fn uleb128size(x: u32) u32 {...@@ -1429,7 +1428,7 @@ fn uleb128size(x: u32) u32 {
14291428
1430fn emitTagNameTable(1429fn emitTagNameTable(
1431 gpa: Allocator,1430 gpa: Allocator,
1432 code: *std.ArrayListUnmanaged(u8),1431 code: *ArrayList(u8),
1433 tag_name_offs: []const u32,1432 tag_name_offs: []const u32,
1434 tag_name_bytes: []const u8,1433 tag_name_bytes: []const u8,
1435 base: u32,1434 base: u32,
...@@ -1604,7 +1603,7 @@ fn reloc_leb_type(code: []u8, index: FuncTypeIndex) void {...@@ -1604,7 +1603,7 @@ fn reloc_leb_type(code: []u8, index: FuncTypeIndex) void {
1604 leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index));1603 leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index));
1605}1604}
16061605
1607fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!void {1606fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *ArrayList(u8)) Allocator.Error!void {
1608 const gpa = wasm.base.comp.gpa;1607 const gpa = wasm.base.comp.gpa;
16091608
1610 try binary_bytes.ensureUnusedCapacity(gpa, 5 + 1);1609 try binary_bytes.ensureUnusedCapacity(gpa, 5 + 1);
...@@ -1631,7 +1630,7 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanage...@@ -1631,7 +1630,7 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanage
16311630
1632fn emitInitMemoryFunction(1631fn emitInitMemoryFunction(
1633 wasm: *const Wasm,1632 wasm: *const Wasm,
1634 binary_bytes: *std.ArrayListUnmanaged(u8),1633 binary_bytes: *ArrayList(u8),
1635 virtual_addrs: *const VirtualAddrs,1634 virtual_addrs: *const VirtualAddrs,
1636) Allocator.Error!void {1635) Allocator.Error!void {
1637 const comp = wasm.base.comp;1636 const comp = wasm.base.comp;
...@@ -1734,7 +1733,7 @@ fn emitInitMemoryFunction(...@@ -1734,7 +1733,7 @@ fn emitInitMemoryFunction(
1734 // notify any waiters for segment initialization completion1733 // notify any waiters for segment initialization completion
1735 appendReservedI32Const(binary_bytes, flag_address);1734 appendReservedI32Const(binary_bytes, flag_address);
1736 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));1735 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));
1737 leb.writeIleb128(binary_bytes.fixedWriter(), @as(i32, -1)) catch unreachable; // number of waiters1736 appendReservedLeb128(binary_bytes, @as(i32, -1)); // number of waiters
1738 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));1737 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));
1739 appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_notify));1738 appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_notify));
1740 appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment1739 appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment
...@@ -1750,7 +1749,7 @@ fn emitInitMemoryFunction(...@@ -1750,7 +1749,7 @@ fn emitInitMemoryFunction(
1750 appendReservedI32Const(binary_bytes, flag_address);1749 appendReservedI32Const(binary_bytes, flag_address);
1751 appendReservedI32Const(binary_bytes, 1); // expected flag value1750 appendReservedI32Const(binary_bytes, 1); // expected flag value
1752 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const));1751 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const));
1753 leb.writeIleb128(binary_bytes.fixedWriter(), @as(i64, -1)) catch unreachable; // timeout1752 appendReservedLeb128(binary_bytes, @as(i64, -1)); // timeout
1754 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));1753 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix));
1755 appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_wait32));1754 appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_wait32));
1756 appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment1755 appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment
...@@ -1779,7 +1778,7 @@ fn emitInitMemoryFunction(...@@ -1779,7 +1778,7 @@ fn emitInitMemoryFunction(
1779 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));1778 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
1780}1779}
17811780
1782fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!void {1781fn emitInitTlsFunction(wasm: *const Wasm, bytes: *ArrayList(u8)) Allocator.Error!void {
1783 const comp = wasm.base.comp;1782 const comp = wasm.base.comp;
1784 const gpa = comp.gpa;1783 const gpa = comp.gpa;
17851784
...@@ -1840,14 +1839,14 @@ fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Al...@@ -1840,14 +1839,14 @@ fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Al
1840 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));1839 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
1841}1840}
18421841
1843fn emitStartSection(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), i: Wasm.OutputFunctionIndex) !void {1842fn emitStartSection(gpa: Allocator, bytes: *ArrayList(u8), i: Wasm.OutputFunctionIndex) !void {
1844 const header_offset = try reserveVecSectionHeader(gpa, bytes);1843 const header_offset = try reserveVecSectionHeader(gpa, bytes);
1845 replaceVecSectionHeader(bytes, header_offset, .start, @intFromEnum(i));1844 replaceVecSectionHeader(bytes, header_offset, .start, @intFromEnum(i));
1846}1845}
18471846
1848fn emitTagNameFunction(1847fn emitTagNameFunction(
1849 wasm: *Wasm,1848 wasm: *Wasm,
1850 code: *std.ArrayListUnmanaged(u8),1849 code: *ArrayList(u8),
1851 table_base_addr: u32,1850 table_base_addr: u32,
1852 table_index: u32,1851 table_index: u32,
1853 enum_type_ip: InternPool.Index,1852 enum_type_ip: InternPool.Index,
...@@ -1959,22 +1958,34 @@ fn emitTagNameFunction(...@@ -1959,22 +1958,34 @@ fn emitTagNameFunction(
1959}1958}
19601959
1961/// Writes an unsigned 32-bit integer as a LEB128-encoded 'i32.const' value.1960/// Writes an unsigned 32-bit integer as a LEB128-encoded 'i32.const' value.
1962fn appendReservedI32Const(bytes: *std.ArrayListUnmanaged(u8), val: u32) void {1961fn appendReservedI32Const(bytes: *ArrayList(u8), val: u32) void {
1963 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));1962 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));
1964 leb.writeIleb128(bytes.fixedWriter(), @as(i32, @bitCast(val))) catch unreachable;1963 var w: std.Io.Writer = .fromArrayList(bytes);
1964 defer bytes.* = w.toArrayList();
1965 return w.writeSleb128(val) catch |err| switch (err) {
1966 error.WriteFailed => unreachable,
1967 };
1965}1968}
19661969
1967/// Writes an unsigned 64-bit integer as a LEB128-encoded 'i64.const' value.1970/// Writes an unsigned 64-bit integer as a LEB128-encoded 'i64.const' value.
1968fn appendReservedI64Const(bytes: *std.ArrayListUnmanaged(u8), val: u64) void {1971fn appendReservedI64Const(bytes: *ArrayList(u8), val: u64) void {
1969 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const));1972 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const));
1970 leb.writeIleb128(bytes.fixedWriter(), @as(i64, @bitCast(val))) catch unreachable;1973 var w: std.Io.Writer = .fromArrayList(bytes);
1974 defer bytes.* = w.toArrayList();
1975 return w.writeSleb128(val) catch |err| switch (err) {
1976 error.WriteFailed => unreachable,
1977 };
1971}1978}
19721979
1973fn appendReservedUleb32(bytes: *std.ArrayListUnmanaged(u8), val: u32) void {1980fn appendReservedUleb32(bytes: *ArrayList(u8), val: u32) void {
1974 leb.writeUleb128(bytes.fixedWriter(), val) catch unreachable;1981 var w: std.Io.Writer = .fromArrayList(bytes);
1982 defer bytes.* = w.toArrayList();
1983 return w.writeUleb128(val) catch |err| switch (err) {
1984 error.WriteFailed => unreachable,
1985 };
1975}1986}
19761987
1977fn appendGlobal(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), mutable: u8, val: u32) Allocator.Error!void {1988fn appendGlobal(gpa: Allocator, bytes: *ArrayList(u8), mutable: u8, val: u32) Allocator.Error!void {
1978 try bytes.ensureUnusedCapacity(gpa, 9);1989 try bytes.ensureUnusedCapacity(gpa, 9);
1979 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Valtype.i32));1990 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Valtype.i32));
1980 bytes.appendAssumeCapacity(mutable);1991 bytes.appendAssumeCapacity(mutable);
...@@ -1982,3 +1993,19 @@ fn appendGlobal(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), mutable: u8,...@@ -1982,3 +1993,19 @@ fn appendGlobal(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), mutable: u8,
1982 appendReservedUleb32(bytes, val);1993 appendReservedUleb32(bytes, val);
1983 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));1994 bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
1984}1995}
1996
1997fn appendLeb128(gpa: Allocator, bytes: *ArrayList(u8), value: anytype) Allocator.Error!void {
1998 var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, bytes);
1999 defer bytes.* = aw.toArrayList();
2000 return aw.writer.writeLeb128(value) catch |err| switch (err) {
2001 error.WriteFailed => return error.OutOfMemory,
2002 };
2003}
2004
2005fn appendReservedLeb128(bytes: *ArrayList(u8), value: anytype) void {
2006 var w: std.Io.Writer = .fromArrayList(bytes);
2007 defer bytes.* = w.toArrayList();
2008 return w.writeLeb128(value) catch |err| switch (err) {
2009 error.WriteFailed => unreachable,
2010 };
2011}
src/link/riscv.zig+14-15
...@@ -9,29 +9,28 @@ pub fn writeSetSub6(comptime op: enum { set, sub }, code: *[1]u8, addend: anytyp...@@ -9,29 +9,28 @@ pub fn writeSetSub6(comptime op: enum { set, sub }, code: *[1]u8, addend: anytyp
9 mem.writeInt(u8, code, value, .little);9 mem.writeInt(u8, code, value, .little);
10}10}
1111
12pub fn writeSetSubUleb(comptime op: enum { set, sub }, stream: *std.io.FixedBufferStream([]u8), addend: i64) !void {12pub fn writeSubUleb(code: []u8, addend: i64) void {
13 switch (op) {13 var reader: std.Io.Reader = .fixed(code);
14 .set => try overwriteUleb(stream, @intCast(addend)),14 const value = reader.takeLeb128(u64) catch unreachable;
15 .sub => {15 overwriteUleb(code, value -% @as(u64, @intCast(addend)));
16 const position = try stream.getPos();16}
17 const value: u64 = try std.leb.readUleb128(u64, stream.reader());17
18 try stream.seekTo(position);18pub fn writeSetUleb(code: []u8, addend: i64) void {
19 try overwriteUleb(stream, value -% @as(u64, @intCast(addend)));19 overwriteUleb(code, @intCast(addend));
20 },
21 }
22}20}
2321
24fn overwriteUleb(stream: *std.io.FixedBufferStream([]u8), addend: u64) !void {22fn overwriteUleb(code: []u8, addend: u64) void {
25 var value: u64 = addend;23 var value: u64 = addend;
26 const writer = stream.writer();24 var i: usize = 0;
2725
28 while (true) {26 while (true) {
29 const byte = stream.buffer[stream.pos];27 const byte = code[i];
30 if (byte & 0x80 == 0) break;28 if (byte & 0x80 == 0) break;
31 try writer.writeByte(0x80 | @as(u8, @truncate(value & 0x7f)));29 code[i] = 0x80 | @as(u8, @truncate(value & 0x7f));
30 i += 1;
32 value >>= 7;31 value >>= 7;
33 }32 }
34 stream.buffer[stream.pos] = @truncate(value & 0x7f);33 code[i] = @truncate(value & 0x7f);
35}34}
3635
37pub fn writeAddend(36pub fn writeAddend(
src/main.zig+2-2
...@@ -4230,7 +4230,7 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void {...@@ -4230,7 +4230,7 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void {
4230 const decl_name = zir.nullTerminatedString(zir.getDeclaration(resolved.inst).name);4230 const decl_name = zir.nullTerminatedString(zir.getDeclaration(resolved.inst).name);
42314231
4232 const gop = try files.getOrPut(gpa, resolved.file);4232 const gop = try files.getOrPut(gpa, resolved.file);
4233 if (!gop.found_existing) try file_name_bytes.writer(gpa).print("{f}\x00", .{file.path.fmt(comp)});4233 if (!gop.found_existing) try file_name_bytes.print(gpa, "{f}\x00", .{file.path.fmt(comp)});
42344234
4235 const codegen_ns = tr.decl_codegen_ns.get(tracked_inst) orelse 0;4235 const codegen_ns = tr.decl_codegen_ns.get(tracked_inst) orelse 0;
4236 const link_ns = tr.decl_link_ns.get(tracked_inst) orelse 0;4236 const link_ns = tr.decl_link_ns.get(tracked_inst) orelse 0;
...@@ -7451,7 +7451,7 @@ const Templates = struct {...@@ -7451,7 +7451,7 @@ const Templates = struct {
7451 i += "_NAME".len;7451 i += "_NAME".len;
7452 continue;7452 continue;
7453 } else if (std.mem.startsWith(u8, contents[i + 1 ..], "FINGERPRINT")) {7453 } else if (std.mem.startsWith(u8, contents[i + 1 ..], "FINGERPRINT")) {
7454 try templates.buffer.writer().print("0x{x}", .{fingerprint.int()});7454 try templates.buffer.print("0x{x}", .{fingerprint.int()});
7455 i += "_FINGERPRINT".len;7455 i += "_FINGERPRINT".len;
7456 continue;7456 continue;
7457 } else if (std.mem.startsWith(u8, contents[i + 1 ..], "ZIGVER")) {7457 } else if (std.mem.startsWith(u8, contents[i + 1 ..], "ZIGVER")) {
test/behavior/packed-struct.zig-11
...@@ -1075,17 +1075,6 @@ test "assigning packed struct inside another packed struct" {...@@ -1075,17 +1075,6 @@ test "assigning packed struct inside another packed struct" {
1075 try expect(S.mem.padding == 0);1075 try expect(S.mem.padding == 0);
1076}1076}
10771077
1078test "packed struct used as part of anon decl name" {
1079 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1080 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1081 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1082
1083 const S = packed struct { a: u0 = 0 };
1084 var a: u8 = 0;
1085 _ = &a;
1086 try std.io.null_writer.print("\n{} {}\n", .{ a, S{} });
1087}
1088
1089test "packed struct acts as a namespace" {1078test "packed struct acts as a namespace" {
1090 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1079 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10911080
test/behavior/var_args.zig+21-14
...@@ -200,35 +200,42 @@ test "variadic functions" {...@@ -200,35 +200,42 @@ test "variadic functions" {
200 if (builtin.cpu.arch.isSPARC() and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23718200 if (builtin.cpu.arch.isSPARC() and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23718
201201
202 const S = struct {202 const S = struct {
203 fn printf(list_ptr: *std.array_list.Managed(u8), format: [*:0]const u8, ...) callconv(.c) void {203 fn printf(buffer: [*]u8, format: [*:0]const u8, ...) callconv(.c) void {
204 var ap = @cVaStart();204 var ap = @cVaStart();
205 defer @cVaEnd(&ap);205 defer @cVaEnd(&ap);
206 vprintf(list_ptr, format, &ap);206 vprintf(buffer, format, &ap);
207 }207 }
208208
209 fn vprintf(209 fn vprintf(buffer: [*]u8, format: [*:0]const u8, ap: *std.builtin.VaList) callconv(.c) void {
210 list: *std.array_list.Managed(u8),210 var i: usize = 0;
211 format: [*:0]const u8,211 for (format[0..3]) |byte| switch (byte) {
212 ap: *std.builtin.VaList,
213 ) callconv(.c) void {
214 for (std.mem.span(format)) |c| switch (c) {
215 's' => {212 's' => {
216 const arg = @cVaArg(ap, [*:0]const u8);213 const arg = @cVaArg(ap, [*:0]const u8);
217 list.writer().print("{s}", .{arg}) catch return;214 buffer[i..][0..5].* = arg[0..5].*;
215 i += 5;
218 },216 },
219 'd' => {217 'd' => {
220 const arg = @cVaArg(ap, c_int);218 const arg = @cVaArg(ap, c_int);
221 list.writer().print("{d}", .{arg}) catch return;219 switch (arg) {
220 1 => {
221 buffer[i] = '1';
222 i += 1;
223 },
224 5 => {
225 buffer[i] = '5';
226 i += 1;
227 },
228 else => unreachable,
229 }
222 },230 },
223 else => unreachable,231 else => unreachable,
224 };232 };
225 }233 }
226 };234 };
227235
228 var list = std.array_list.Managed(u8).init(std.testing.allocator);236 var buffer: [7]u8 = undefined;
229 defer list.deinit();237 S.printf(&buffer, "dsd", @as(c_int, 1), @as([*:0]const u8, "hello"), @as(c_int, 5));
230 S.printf(&list, "dsd", @as(c_int, 1), @as([*:0]const u8, "hello"), @as(c_int, 5));238 try expect(std.mem.eql(u8, &buffer, "1hello5"));
231 try std.testing.expectEqualStrings("1hello5", list.items);
232}239}
233240
234test "copy VaList" {241test "copy VaList" {
test/standalone/run_output_paths/create_file.zig+2-1
...@@ -10,7 +10,8 @@ pub fn main() !void {...@@ -10,7 +10,8 @@ pub fn main() !void {
10 dir_name, .{});10 dir_name, .{});
11 const file_name = args.next().?;11 const file_name = args.next().?;
12 const file = try dir.createFile(file_name, .{});12 const file = try dir.createFile(file_name, .{});
13 try file.deprecatedWriter().print(13 var file_writer = file.writer(&.{});
14 try file_writer.interface.print(
14 \\{s}15 \\{s}
15 \\{s}16 \\{s}
16 \\Hello, world!17 \\Hello, world!
tools/docgen.zig+21-21
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const io = std.io;
4const fs = std.fs;3const fs = std.fs;
5const process = std.process;4const process = std.process;
6const Progress = std.Progress;5const Progress = std.Progress;
...@@ -8,8 +7,10 @@ const print = std.debug.print;...@@ -8,8 +7,10 @@ const print = std.debug.print;
8const mem = std.mem;7const mem = std.mem;
9const testing = std.testing;8const testing = std.testing;
10const Allocator = std.mem.Allocator;9const Allocator = std.mem.Allocator;
10const ArrayList = std.ArrayList;
11const getExternalExecutor = std.zig.system.getExternalExecutor;11const getExternalExecutor = std.zig.system.getExternalExecutor;
12const fatal = std.process.fatal;12const fatal = std.process.fatal;
13const Writer = std.Io.Writer;
1314
14const max_doc_file_size = 10 * 1024 * 1024;15const max_doc_file_size = 10 * 1024 * 1024;
1516
...@@ -344,10 +345,10 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -344,10 +345,10 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
344 var last_action: Action = .open;345 var last_action: Action = .open;
345 var last_columns: ?u8 = null;346 var last_columns: ?u8 = null;
346347
347 var toc_buf = std.array_list.Managed(u8).init(allocator);348 var toc_buf: Writer.Allocating = .init(allocator);
348 defer toc_buf.deinit();349 defer toc_buf.deinit();
349350
350 var toc = toc_buf.writer();351 const toc = &toc_buf.writer;
351352
352 var nodes = std.array_list.Managed(Node).init(allocator);353 var nodes = std.array_list.Managed(Node).init(allocator);
353 defer nodes.deinit();354 defer nodes.deinit();
...@@ -422,7 +423,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -422,7 +423,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
422 }423 }
423 if (last_action == .open) {424 if (last_action == .open) {
424 try toc.writeByte('\n');425 try toc.writeByte('\n');
425 try toc.writeByteNTimes(' ', header_stack_size * 4);426 try toc.splatByteAll(' ', header_stack_size * 4);
426 if (last_columns) |n| {427 if (last_columns) |n| {
427 try toc.print("<ul style=\"columns: {d}\">\n", .{n});428 try toc.print("<ul style=\"columns: {d}\">\n", .{n});
428 } else {429 } else {
...@@ -432,7 +433,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -432,7 +433,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
432 last_action = .open;433 last_action = .open;
433 }434 }
434 last_columns = columns;435 last_columns = columns;
435 try toc.writeByteNTimes(' ', 4 + header_stack_size * 4);436 try toc.splatByteAll(' ', 4 + header_stack_size * 4);
436 try toc.print("<li><a id=\"toc-{s}\" href=\"#{s}\">{s}</a>", .{ urlized, urlized, content });437 try toc.print("<li><a id=\"toc-{s}\" href=\"#{s}\">{s}</a>", .{ urlized, urlized, content });
437 } else if (mem.eql(u8, tag_name, "header_close")) {438 } else if (mem.eql(u8, tag_name, "header_close")) {
438 if (header_stack_size == 0) {439 if (header_stack_size == 0) {
...@@ -442,7 +443,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -442,7 +443,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
442 _ = try eatToken(tokenizer, .bracket_close);443 _ = try eatToken(tokenizer, .bracket_close);
443444
444 if (last_action == .close) {445 if (last_action == .close) {
445 try toc.writeByteNTimes(' ', 8 + header_stack_size * 4);446 try toc.splatByteAll(' ', 8 + header_stack_size * 4);
446 try toc.writeAll("</ul></li>\n");447 try toc.writeAll("</ul></li>\n");
447 } else {448 } else {
448 try toc.writeAll("</li>\n");449 try toc.writeAll("</li>\n");
...@@ -591,30 +592,29 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -591,30 +592,29 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
591 }592 }
592 }593 }
593594
594 return Toc{595 return .{
595 .nodes = try nodes.toOwnedSlice(),596 .nodes = try nodes.toOwnedSlice(),
596 .toc = try toc_buf.toOwnedSlice(),597 .toc = try toc_buf.toOwnedSlice(),
597 .urls = urls,598 .urls = urls,
598 };599 };
599}600}
600601
601fn urlize(allocator: Allocator, input: []const u8) ![]u8 {602fn urlize(gpa: Allocator, input: []const u8) ![]u8 {
602 var buf = std.array_list.Managed(u8).init(allocator);603 var buf: ArrayList(u8) = .empty;
603 defer buf.deinit();604 defer buf.deinit(gpa);
604605
605 const out = buf.writer();
606 for (input) |c| {606 for (input) |c| {
607 switch (c) {607 switch (c) {
608 'a'...'z', 'A'...'Z', '_', '-', '0'...'9' => {608 'a'...'z', 'A'...'Z', '_', '-', '0'...'9' => {
609 try out.writeByte(c);609 try buf.append(gpa, c);
610 },610 },
611 ' ' => {611 ' ' => {
612 try out.writeByte('-');612 try buf.append(gpa, '-');
613 },613 },
614 else => {},614 else => {},
615 }615 }
616 }616 }
617 return try buf.toOwnedSlice();617 return try buf.toOwnedSlice(gpa);
618}618}
619619
620fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {620fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {
...@@ -626,7 +626,7 @@ fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {...@@ -626,7 +626,7 @@ fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {
626 return try buf.toOwnedSlice();626 return try buf.toOwnedSlice();
627}627}
628628
629fn writeEscaped(out: anytype, input: []const u8) !void {629fn writeEscaped(out: *Writer, input: []const u8) !void {
630 for (input) |c| {630 for (input) |c| {
631 try switch (c) {631 try switch (c) {
632 '&' => out.writeAll("&amp;"),632 '&' => out.writeAll("&amp;"),
...@@ -662,14 +662,14 @@ fn isType(name: []const u8) bool {...@@ -662,14 +662,14 @@ fn isType(name: []const u8) bool {
662 return false;662 return false;
663}663}
664664
665fn writeEscapedLines(out: anytype, text: []const u8) !void {665fn writeEscapedLines(out: *Writer, text: []const u8) !void {
666 return writeEscaped(out, text);666 return writeEscaped(out, text);
667}667}
668668
669fn tokenizeAndPrintRaw(669fn tokenizeAndPrintRaw(
670 allocator: Allocator,670 allocator: Allocator,
671 docgen_tokenizer: *Tokenizer,671 docgen_tokenizer: *Tokenizer,
672 out: anytype,672 out: *Writer,
673 source_token: Token,673 source_token: Token,
674 raw_src: []const u8,674 raw_src: []const u8,
675) !void {675) !void {
...@@ -907,14 +907,14 @@ fn tokenizeAndPrintRaw(...@@ -907,14 +907,14 @@ fn tokenizeAndPrintRaw(
907fn tokenizeAndPrint(907fn tokenizeAndPrint(
908 allocator: Allocator,908 allocator: Allocator,
909 docgen_tokenizer: *Tokenizer,909 docgen_tokenizer: *Tokenizer,
910 out: anytype,910 out: *Writer,
911 source_token: Token,911 source_token: Token,
912) !void {912) !void {
913 const raw_src = docgen_tokenizer.buffer[source_token.start..source_token.end];913 const raw_src = docgen_tokenizer.buffer[source_token.start..source_token.end];
914 return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src);914 return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src);
915}915}
916916
917fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: anytype, syntax_block: SyntaxBlock) !void {917fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: *Writer, syntax_block: SyntaxBlock) !void {
918 const source_type = @tagName(syntax_block.source_type);918 const source_type = @tagName(syntax_block.source_type);
919919
920 try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name });920 try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name });
...@@ -932,7 +932,7 @@ fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: any...@@ -932,7 +932,7 @@ fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: any
932 try out.writeAll("</pre></figure>");932 try out.writeAll("</pre></figure>");
933}933}
934934
935fn printShell(out: anytype, shell_content: []const u8, escape: bool) !void {935fn printShell(out: *Writer, shell_content: []const u8, escape: bool) !void {
936 const trimmed_shell_content = mem.trim(u8, shell_content, " \r\n");936 const trimmed_shell_content = mem.trim(u8, shell_content, " \r\n");
937 try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>");937 try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>");
938 var cmd_cont: bool = false;938 var cmd_cont: bool = false;
...@@ -984,7 +984,7 @@ fn genHtml(...@@ -984,7 +984,7 @@ fn genHtml(
984 tokenizer: *Tokenizer,984 tokenizer: *Tokenizer,
985 toc: *Toc,985 toc: *Toc,
986 code_dir: std.fs.Dir,986 code_dir: std.fs.Dir,
987 out: anytype,987 out: *Writer,
988) !void {988) !void {
989 for (toc.nodes) |node| {989 for (toc.nodes) |node| {
990 switch (node) {990 switch (node) {
tools/doctest.zig+60-64
...@@ -7,6 +7,7 @@ const process = std.process;...@@ -7,6 +7,7 @@ const process = std.process;
7const Allocator = std.mem.Allocator;7const Allocator = std.mem.Allocator;
8const testing = std.testing;8const testing = std.testing;
9const getExternalExecutor = std.zig.system.getExternalExecutor;9const getExternalExecutor = std.zig.system.getExternalExecutor;
10const Writer = std.Io.Writer;
1011
11const max_doc_file_size = 10 * 1024 * 1024;12const max_doc_file_size = 10 * 1024 * 1024;
1213
...@@ -108,7 +109,7 @@ pub fn main() !void {...@@ -108,7 +109,7 @@ pub fn main() !void {
108109
109fn printOutput(110fn printOutput(
110 arena: Allocator,111 arena: Allocator,
111 out: anytype,112 out: *Writer,
112 code: Code,113 code: Code,
113 /// Relative to this process' cwd.114 /// Relative to this process' cwd.
114 tmp_dir_path: []const u8,115 tmp_dir_path: []const u8,
...@@ -126,9 +127,9 @@ fn printOutput(...@@ -126,9 +127,9 @@ fn printOutput(
126 const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch);127 const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch);
127 const print = std.debug.print;128 const print = std.debug.print;
128129
129 var shell_buffer = std.array_list.Managed(u8).init(arena);130 var shell_buffer: std.Io.Writer.Allocating = .init(arena);
130 defer shell_buffer.deinit();131 defer shell_buffer.deinit();
131 var shell_out = shell_buffer.writer();132 const shell_out = &shell_buffer.writer;
132133
133 const code_name = std.fs.path.stem(input_path);134 const code_name = std.fs.path.stem(input_path);
134135
...@@ -599,7 +600,7 @@ fn printOutput(...@@ -599,7 +600,7 @@ fn printOutput(
599 }600 }
600601
601 if (!code.just_check_syntax) {602 if (!code.just_check_syntax) {
602 try printShell(out, shell_buffer.items, false);603 try printShell(out, shell_buffer.written(), false);
603 }604 }
604}605}
605606
...@@ -610,7 +611,7 @@ fn dumpArgs(args: []const []const u8) void {...@@ -610,7 +611,7 @@ fn dumpArgs(args: []const []const u8) void {
610 std.debug.print("\n", .{});611 std.debug.print("\n", .{});
611}612}
612613
613fn printSourceBlock(arena: Allocator, out: anytype, source_bytes: []const u8, name: []const u8) !void {614fn printSourceBlock(arena: Allocator, out: *Writer, source_bytes: []const u8, name: []const u8) !void {
614 try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{615 try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{
615 "zig", name,616 "zig", name,
616 });617 });
...@@ -618,7 +619,7 @@ fn printSourceBlock(arena: Allocator, out: anytype, source_bytes: []const u8, na...@@ -618,7 +619,7 @@ fn printSourceBlock(arena: Allocator, out: anytype, source_bytes: []const u8, na
618 try out.writeAll("</pre></figure>");619 try out.writeAll("</pre></figure>");
619}620}
620621
621fn tokenizeAndPrint(arena: Allocator, out: anytype, raw_src: []const u8) !void {622fn tokenizeAndPrint(arena: Allocator, out: *Writer, raw_src: []const u8) !void {
622 const src_non_terminated = mem.trim(u8, raw_src, " \r\n");623 const src_non_terminated = mem.trim(u8, raw_src, " \r\n");
623 const src = try arena.dupeZ(u8, src_non_terminated);624 const src = try arena.dupeZ(u8, src_non_terminated);
624625
...@@ -846,7 +847,7 @@ fn tokenizeAndPrint(arena: Allocator, out: anytype, raw_src: []const u8) !void {...@@ -846,7 +847,7 @@ fn tokenizeAndPrint(arena: Allocator, out: anytype, raw_src: []const u8) !void {
846 try out.writeAll("</code>");847 try out.writeAll("</code>");
847}848}
848849
849fn writeEscapedLines(out: anytype, text: []const u8) !void {850fn writeEscapedLines(out: *Writer, text: []const u8) !void {
850 return writeEscaped(out, text);851 return writeEscaped(out, text);
851}852}
852853
...@@ -974,25 +975,21 @@ fn skipPrefix(line: []const u8) []const u8 {...@@ -974,25 +975,21 @@ fn skipPrefix(line: []const u8) []const u8 {
974 return line[3..];975 return line[3..];
975}976}
976977
977fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 {978fn escapeHtml(gpa: Allocator, input: []const u8) ![]u8 {
978 var buf = std.array_list.Managed(u8).init(allocator);979 var allocating: Writer.Allocating = .init(gpa);
979 defer buf.deinit();980 defer allocating.deinit();
980981 try writeEscaped(&allocating.writer, input);
981 const out = buf.writer();982 return allocating.toOwnedSlice();
982 try writeEscaped(out, input);
983 return try buf.toOwnedSlice();
984}983}
985984
986fn writeEscaped(out: anytype, input: []const u8) !void {985fn writeEscaped(w: *Writer, input: []const u8) !void {
987 for (input) |c| {986 for (input) |c| try switch (c) {
988 try switch (c) {987 '&' => w.writeAll("&amp;"),
989 '&' => out.writeAll("&amp;"),988 '<' => w.writeAll("&lt;"),
990 '<' => out.writeAll("&lt;"),989 '>' => w.writeAll("&gt;"),
991 '>' => out.writeAll("&gt;"),990 '"' => w.writeAll("&quot;"),
992 '"' => out.writeAll("&quot;"),991 else => w.writeByte(c),
993 else => out.writeByte(c),992 };
994 };
995 }
996}993}
997994
998fn termColor(allocator: Allocator, input: []const u8) ![]u8 {995fn termColor(allocator: Allocator, input: []const u8) ![]u8 {
...@@ -1014,7 +1011,6 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 {...@@ -1014,7 +1011,6 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 {
1014 var buf = std.array_list.Managed(u8).init(allocator);1011 var buf = std.array_list.Managed(u8).init(allocator);
1015 defer buf.deinit();1012 defer buf.deinit();
10161013
1017 var out = buf.writer();
1018 var sgr_param_start_index: usize = undefined;1014 var sgr_param_start_index: usize = undefined;
1019 var sgr_num: u8 = undefined;1015 var sgr_num: u8 = undefined;
1020 var sgr_color: u8 = undefined;1016 var sgr_color: u8 = undefined;
...@@ -1037,10 +1033,10 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 {...@@ -1037,10 +1033,10 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 {
1037 .start => switch (c) {1033 .start => switch (c) {
1038 '\x1b' => state = .escape,1034 '\x1b' => state = .escape,
1039 '\n' => {1035 '\n' => {
1040 try out.writeByte(c);1036 try buf.append(c);
1041 last_new_line = buf.items.len;1037 last_new_line = buf.items.len;
1042 },1038 },
1043 else => try out.writeByte(c),1039 else => try buf.append(c),
1044 },1040 },
1045 .escape => switch (c) {1041 .escape => switch (c) {
1046 '[' => state = .lbracket,1042 '[' => state = .lbracket,
...@@ -1101,16 +1097,16 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 {...@@ -1101,16 +1097,16 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 {
1101 'm' => {1097 'm' => {
1102 state = .start;1098 state = .start;
1103 while (open_span_count != 0) : (open_span_count -= 1) {1099 while (open_span_count != 0) : (open_span_count -= 1) {
1104 try out.writeAll("</span>");1100 try buf.appendSlice("</span>");
1105 }1101 }
1106 if (sgr_num == 0) {1102 if (sgr_num == 0) {
1107 if (sgr_color != 0) return error.UnsupportedColor;1103 if (sgr_color != 0) return error.UnsupportedColor;
1108 continue;1104 continue;
1109 }1105 }
1110 if (sgr_color != 0) {1106 if (sgr_color != 0) {
1111 try out.print("<span class=\"sgr-{d}_{d}m\">", .{ sgr_color, sgr_num });1107 try buf.print("<span class=\"sgr-{d}_{d}m\">", .{ sgr_color, sgr_num });
1112 } else {1108 } else {
1113 try out.print("<span class=\"sgr-{d}m\">", .{sgr_num});1109 try buf.print("<span class=\"sgr-{d}m\">", .{sgr_num});
1114 }1110 }
1115 open_span_count += 1;1111 open_span_count += 1;
1116 },1112 },
...@@ -1156,7 +1152,7 @@ fn run(...@@ -1156,7 +1152,7 @@ fn run(
1156 return result;1152 return result;
1157}1153}
11581154
1159fn printShell(out: anytype, shell_content: []const u8, escape: bool) !void {1155fn printShell(out: *Writer, shell_content: []const u8, escape: bool) !void {
1160 const trimmed_shell_content = mem.trim(u8, shell_content, " \r\n");1156 const trimmed_shell_content = mem.trim(u8, shell_content, " \r\n");
1161 try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>");1157 try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>");
1162 var cmd_cont: bool = false;1158 var cmd_cont: bool = false;
...@@ -1401,11 +1397,11 @@ test "printShell" {...@@ -1401,11 +1397,11 @@ test "printShell" {
1401 \\</samp></pre></figure>1397 \\</samp></pre></figure>
1402 ;1398 ;
14031399
1404 var buffer = std.array_list.Managed(u8).init(test_allocator);1400 var buffer: std.Io.Writer.Allocating = .init(test_allocator);
1405 defer buffer.deinit();1401 defer buffer.deinit();
14061402
1407 try printShell(buffer.writer(), shell_out, false);1403 try printShell(&buffer.writer, shell_out, false);
1408 try testing.expectEqualSlices(u8, expected, buffer.items);1404 try testing.expectEqualSlices(u8, expected, buffer.written());
1409 }1405 }
1410 {1406 {
1411 const shell_out =1407 const shell_out =
...@@ -1418,11 +1414,11 @@ test "printShell" {...@@ -1418,11 +1414,11 @@ test "printShell" {
1418 \\</samp></pre></figure>1414 \\</samp></pre></figure>
1419 ;1415 ;
14201416
1421 var buffer = std.array_list.Managed(u8).init(test_allocator);1417 var buffer: std.Io.Writer.Allocating = .init(test_allocator);
1422 defer buffer.deinit();1418 defer buffer.deinit();
14231419
1424 try printShell(buffer.writer(), shell_out, false);1420 try printShell(&buffer.writer, shell_out, false);
1425 try testing.expectEqualSlices(u8, expected, buffer.items);1421 try testing.expectEqualSlices(u8, expected, buffer.written());
1426 }1422 }
1427 {1423 {
1428 const shell_out = "$ zig build test.zig\r\nbuild output\r\n";1424 const shell_out = "$ zig build test.zig\r\nbuild output\r\n";
...@@ -1432,11 +1428,11 @@ test "printShell" {...@@ -1432,11 +1428,11 @@ test "printShell" {
1432 \\</samp></pre></figure>1428 \\</samp></pre></figure>
1433 ;1429 ;
14341430
1435 var buffer = std.array_list.Managed(u8).init(test_allocator);1431 var buffer: std.Io.Writer.Allocating = .init(test_allocator);
1436 defer buffer.deinit();1432 defer buffer.deinit();
14371433
1438 try printShell(buffer.writer(), shell_out, false);1434 try printShell(&buffer.writer, shell_out, false);
1439 try testing.expectEqualSlices(u8, expected, buffer.items);1435 try testing.expectEqualSlices(u8, expected, buffer.written());
1440 }1436 }
1441 {1437 {
1442 const shell_out =1438 const shell_out =
...@@ -1451,11 +1447,11 @@ test "printShell" {...@@ -1451,11 +1447,11 @@ test "printShell" {
1451 \\</samp></pre></figure>1447 \\</samp></pre></figure>
1452 ;1448 ;
14531449
1454 var buffer = std.array_list.Managed(u8).init(test_allocator);1450 var buffer: std.Io.Writer.Allocating = .init(test_allocator);
1455 defer buffer.deinit();1451 defer buffer.deinit();
14561452
1457 try printShell(buffer.writer(), shell_out, false);1453 try printShell(&buffer.writer, shell_out, false);
1458 try testing.expectEqualSlices(u8, expected, buffer.items);1454 try testing.expectEqualSlices(u8, expected, buffer.written());
1459 }1455 }
1460 {1456 {
1461 const shell_out =1457 const shell_out =
...@@ -1472,11 +1468,11 @@ test "printShell" {...@@ -1472,11 +1468,11 @@ test "printShell" {
1472 \\</samp></pre></figure>1468 \\</samp></pre></figure>
1473 ;1469 ;
14741470
1475 var buffer = std.array_list.Managed(u8).init(test_allocator);1471 var buffer: std.Io.Writer.Allocating = .init(test_allocator);
1476 defer buffer.deinit();1472 defer buffer.deinit();
14771473
1478 try printShell(buffer.writer(), shell_out, false);1474 try printShell(&buffer.writer, shell_out, false);
1479 try testing.expectEqualSlices(u8, expected, buffer.items);1475 try testing.expectEqualSlices(u8, expected, buffer.written());
1480 }1476 }
1481 {1477 {
1482 const shell_out =1478 const shell_out =
...@@ -1491,11 +1487,11 @@ test "printShell" {...@@ -1491,11 +1487,11 @@ test "printShell" {
1491 \\</samp></pre></figure>1487 \\</samp></pre></figure>
1492 ;1488 ;
14931489
1494 var buffer = std.array_list.Managed(u8).init(test_allocator);1490 var buffer: std.Io.Writer.Allocating = .init(test_allocator);
1495 defer buffer.deinit();1491 defer buffer.deinit();
14961492
1497 try printShell(buffer.writer(), shell_out, false);1493 try printShell(&buffer.writer, shell_out, false);
1498 try testing.expectEqualSlices(u8, expected, buffer.items);1494 try testing.expectEqualSlices(u8, expected, buffer.written());
1499 }1495 }
1500 {1496 {
1501 const shell_out =1497 const shell_out =
...@@ -1514,11 +1510,11 @@ test "printShell" {...@@ -1514,11 +1510,11 @@ test "printShell" {
1514 \\</samp></pre></figure>1510 \\</samp></pre></figure>
1515 ;1511 ;
15161512
1517 var buffer = std.array_list.Managed(u8).init(test_allocator);1513 var buffer: std.Io.Writer.Allocating = .init(test_allocator);
1518 defer buffer.deinit();1514 defer buffer.deinit();
15191515
1520 try printShell(buffer.writer(), shell_out, false);1516 try printShell(&buffer.writer, shell_out, false);
1521 try testing.expectEqualSlices(u8, expected, buffer.items);1517 try testing.expectEqualSlices(u8, expected, buffer.written());
1522 }1518 }
1523 {1519 {
1524 // intentional space after "--build-option1 \"1520 // intentional space after "--build-option1 \"
...@@ -1536,11 +1532,11 @@ test "printShell" {...@@ -1536,11 +1532,11 @@ test "printShell" {
1536 \\</samp></pre></figure>1532 \\</samp></pre></figure>
1537 ;1533 ;
15381534
1539 var buffer = std.array_list.Managed(u8).init(test_allocator);1535 var buffer: std.Io.Writer.Allocating = .init(test_allocator);
1540 defer buffer.deinit();1536 defer buffer.deinit();
15411537
1542 try printShell(buffer.writer(), shell_out, false);1538 try printShell(&buffer.writer, shell_out, false);
1543 try testing.expectEqualSlices(u8, expected, buffer.items);1539 try testing.expectEqualSlices(u8, expected, buffer.written());
1544 }1540 }
1545 {1541 {
1546 const shell_out =1542 const shell_out =
...@@ -1553,11 +1549,11 @@ test "printShell" {...@@ -1553,11 +1549,11 @@ test "printShell" {
1553 \\</samp></pre></figure>1549 \\</samp></pre></figure>
1554 ;1550 ;
15551551
1556 var buffer = std.array_list.Managed(u8).init(test_allocator);1552 var buffer: std.Io.Writer.Allocating = .init(test_allocator);
1557 defer buffer.deinit();1553 defer buffer.deinit();
15581554
1559 try printShell(buffer.writer(), shell_out, false);1555 try printShell(&buffer.writer, shell_out, false);
1560 try testing.expectEqualSlices(u8, expected, buffer.items);1556 try testing.expectEqualSlices(u8, expected, buffer.written());
1561 }1557 }
1562 {1558 {
1563 const shell_out =1559 const shell_out =
...@@ -1572,11 +1568,11 @@ test "printShell" {...@@ -1572,11 +1568,11 @@ test "printShell" {
1572 \\</samp></pre></figure>1568 \\</samp></pre></figure>
1573 ;1569 ;
15741570
1575 var buffer = std.array_list.Managed(u8).init(test_allocator);1571 var buffer: std.Io.Writer.Allocating = .init(test_allocator);
1576 defer buffer.deinit();1572 defer buffer.deinit();
15771573
1578 try printShell(buffer.writer(), shell_out, false);1574 try printShell(&buffer.writer, shell_out, false);
1579 try testing.expectEqualSlices(u8, expected, buffer.items);1575 try testing.expectEqualSlices(u8, expected, buffer.written());
1580 }1576 }
1581 {1577 {
1582 const shell_out =1578 const shell_out =
...@@ -1587,10 +1583,10 @@ test "printShell" {...@@ -1587,10 +1583,10 @@ test "printShell" {
1587 \\</samp></pre></figure>1583 \\</samp></pre></figure>
1588 ;1584 ;
15891585
1590 var buffer = std.array_list.Managed(u8).init(test_allocator);1586 var buffer: std.Io.Writer.Allocating = .init(test_allocator);
1591 defer buffer.deinit();1587 defer buffer.deinit();
15921588
1593 try printShell(buffer.writer(), shell_out, false);1589 try printShell(&buffer.writer, shell_out, false);
1594 try testing.expectEqualSlices(u8, expected, buffer.items);1590 try testing.expectEqualSlices(u8, expected, buffer.written());
1595 }1591 }
1596}1592}
tools/gen_outline_atomics.zig+1-1
...@@ -49,7 +49,7 @@ pub fn main() !void {...@@ -49,7 +49,7 @@ pub fn main() !void {
49 @tagName(op), n.toBytes(), @tagName(order),49 @tagName(op), n.toBytes(), @tagName(order),
50 });50 });
51 try writeFunction(arena, w, name, op, n, order);51 try writeFunction(arena, w, name, op, n, order);
52 try footer.writer().print(" @export(&{s}, .{{ .name = \"{s}\", .linkage = common.linkage, .visibility = common.visibility }});\n", .{52 try footer.print(" @export(&{s}, .{{ .name = \"{s}\", .linkage = common.linkage, .visibility = common.visibility }});\n", .{
53 name, name,53 name, name,
54 });54 });
55 }55 }
tools/gen_spirv_spec.zig+8-11
...@@ -82,13 +82,11 @@ pub fn main() !void {...@@ -82,13 +82,11 @@ pub fn main() !void {
8282
83 try readExtRegistry(&exts, std.fs.cwd(), args[2]);83 try readExtRegistry(&exts, std.fs.cwd(), args[2]);
8484
85 const output_buf = try allocator.alloc(u8, 1024 * 1024);85 var allocating: std.Io.Writer.Allocating = .init(allocator);
86 var fbs = std.io.fixedBufferStream(output_buf);86 defer allocating.deinit();
87 var adapter = fbs.writer().adaptToNewApi(&.{});87 try render(&allocating.writer, core_spec, exts.items);
88 const w = &adapter.new_interface;88 try allocating.writer.writeByte(0);
89 try render(w, core_spec, exts.items);89 const output = allocating.written()[0 .. allocating.written().len - 1 :0];
90 var output: [:0]u8 = @ptrCast(fbs.getWritten());
91 output[output.len] = 0;
9290
93 var tree = try std.zig.Ast.parse(allocator, output, .zig);91 var tree = try std.zig.Ast.parse(allocator, output, .zig);
94 var color: std.zig.Color = .on;92 var color: std.zig.Color = .on;
...@@ -429,10 +427,9 @@ fn renderClass(writer: *std.io.Writer, instructions: []const Instruction) !void...@@ -429,10 +427,9 @@ fn renderClass(writer: *std.io.Writer, instructions: []const Instruction) !void
429const Formatter = struct {427const Formatter = struct {
430 data: []const u8,428 data: []const u8,
431429
432 fn format(f: Formatter, writer: *std.io.Writer) std.io.Writer.Error!void {430 fn format(f: Formatter, writer: *std.Io.Writer) std.io.Writer.Error!void {
433 var id_buf: [128]u8 = undefined;431 var id_buf: [128]u8 = undefined;
434 var fbs = std.io.fixedBufferStream(&id_buf);432 var fw: std.Io.Writer = .fixed(&id_buf);
435 const fw = fbs.writer();
436 for (f.data, 0..) |c, i| {433 for (f.data, 0..) |c, i| {
437 switch (c) {434 switch (c) {
438 '-', '_', '.', '~', ' ' => fw.writeByte('_') catch return error.WriteFailed,435 '-', '_', '.', '~', ' ' => fw.writeByte('_') catch return error.WriteFailed,
...@@ -452,7 +449,7 @@ const Formatter = struct {...@@ -452,7 +449,7 @@ const Formatter = struct {
452 }449 }
453450
454 // make sure that this won't clobber with zig keywords451 // make sure that this won't clobber with zig keywords
455 try writer.print("{f}", .{std.zig.fmtId(fbs.getWritten())});452 try writer.print("{f}", .{std.zig.fmtId(fw.buffered())});
456 }453 }
457};454};
458455
tools/migrate_langref.zig+22-18
...@@ -382,46 +382,50 @@ fn walk(arena: Allocator, tokenizer: *Tokenizer, out_dir: std.fs.Dir, w: anytype...@@ -382,46 +382,50 @@ fn walk(arena: Allocator, tokenizer: *Tokenizer, out_dir: std.fs.Dir, w: anytype
382 fatal("unable to create file '{s}': {s}", .{ name, @errorName(err) });382 fatal("unable to create file '{s}': {s}", .{ name, @errorName(err) });
383 };383 };
384 defer file.close();384 defer file.close();
385 var file_buffer: [1024]u8 = undefined;
386 var file_writer = file.writer(&file_buffer);
387 const code = &file_writer.interface;
385388
386 const source = tokenizer.buffer[source_token.start..source_token.end];389 const source = tokenizer.buffer[source_token.start..source_token.end];
387 try file.writeAll(std.mem.trim(u8, source[1..], " \t\r\n"));390 try code.writeAll(std.mem.trim(u8, source[1..], " \t\r\n"));
388 try file.writeAll("\n\n");391 try code.writeAll("\n\n");
389392
390 if (just_check_syntax) {393 if (just_check_syntax) {
391 try file.deprecatedWriter().print("// syntax\n", .{});394 try code.print("// syntax\n", .{});
392 } else switch (code_kind_id) {395 } else switch (code_kind_id) {
393 .@"test" => try file.deprecatedWriter().print("// test\n", .{}),396 .@"test" => try code.print("// test\n", .{}),
394 .lib => try file.deprecatedWriter().print("// lib\n", .{}),397 .lib => try code.print("// lib\n", .{}),
395 .test_error => |s| try file.deprecatedWriter().print("// test_error={s}\n", .{s}),398 .test_error => |s| try code.print("// test_error={s}\n", .{s}),
396 .test_safety => |s| try file.deprecatedWriter().print("// test_safety={s}\n", .{s}),399 .test_safety => |s| try code.print("// test_safety={s}\n", .{s}),
397 .exe => |s| try file.deprecatedWriter().print("// exe={s}\n", .{@tagName(s)}),400 .exe => |s| try code.print("// exe={s}\n", .{@tagName(s)}),
398 .obj => |opt| if (opt) |s| {401 .obj => |opt| if (opt) |s| {
399 try file.deprecatedWriter().print("// obj={s}\n", .{s});402 try code.print("// obj={s}\n", .{s});
400 } else {403 } else {
401 try file.deprecatedWriter().print("// obj\n", .{});404 try code.print("// obj\n", .{});
402 },405 },
403 }406 }
404407
405 if (mode != .Debug)408 if (mode != .Debug)
406 try file.deprecatedWriter().print("// optimize={s}\n", .{@tagName(mode)});409 try code.print("// optimize={s}\n", .{@tagName(mode)});
407410
408 for (link_objects.items) |link_object| {411 for (link_objects.items) |link_object| {
409 try file.deprecatedWriter().print("// link_object={s}\n", .{link_object});412 try code.print("// link_object={s}\n", .{link_object});
410 }413 }
411414
412 if (target_str) |s|415 if (target_str) |s|
413 try file.deprecatedWriter().print("// target={s}\n", .{s});416 try code.print("// target={s}\n", .{s});
414417
415 if (link_libc) try file.deprecatedWriter().print("// link_libc\n", .{});418 if (link_libc) try code.print("// link_libc\n", .{});
416 if (disable_cache) try file.deprecatedWriter().print("// disable_cache\n", .{});419 if (disable_cache) try code.print("// disable_cache\n", .{});
417 if (verbose_cimport) try file.deprecatedWriter().print("// verbose_cimport\n", .{});420 if (verbose_cimport) try code.print("// verbose_cimport\n", .{});
418421
419 if (link_mode) |m|422 if (link_mode) |m|
420 try file.deprecatedWriter().print("// link_mode={s}\n", .{@tagName(m)});423 try code.print("// link_mode={s}\n", .{@tagName(m)});
421424
422 for (additional_options.items) |o| {425 for (additional_options.items) |o| {
423 try file.deprecatedWriter().print("// additional_option={s}\n", .{o});426 try code.print("// additional_option={s}\n", .{o});
424 }427 }
428 try code.flush();
425 try w.print("{{#code|{s}#}}\n", .{basename});429 try w.print("{{#code|{s}#}}\n", .{basename});
426 } else {430 } else {
427 const close_bracket = while (true) {431 const close_bracket = while (true) {
tools/update_crc_catalog.zig+2-3
...@@ -88,10 +88,9 @@ pub fn main() anyerror!void {...@@ -88,10 +88,9 @@ pub fn main() anyerror!void {
88 \\88 \\
89 );89 );
9090
91 var stream = std.io.fixedBufferStream(catalog_txt);91 var reader: std.Io.Reader = .fixed(catalog_txt);
92 const reader = stream.reader();
9392
94 while (try reader.readUntilDelimiterOrEofAlloc(arena, '\n', std.math.maxInt(usize))) |line| {93 while (try reader.takeDelimiter('\n')) |line| {
95 if (line.len == 0 or line[0] == '#')94 if (line.len == 0 or line[0] == '#')
96 continue;95 continue;
9796