Skip to content

Commit 255547d

Browse files
authored
Merge pull request #20731 from ziglang/parallel-macho-2
The tale of parallel MachO: part 2
2 parents ac24593 + f1af53f commit 255547d

35 files changed

+1325
-1189
lines changed

build.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ fn addCompilerStep(b: *std.Build, options: AddCompilerStepOptions) *std.Build.St
618618
.root_source_file = b.path("src/main.zig"),
619619
.target = options.target,
620620
.optimize = options.optimize,
621-
.max_rss = 7_100_000_000,
621+
.max_rss = 7_500_000_000,
622622
.strip = options.strip,
623623
.sanitize_thread = options.sanitize_thread,
624624
.single_threaded = options.single_threaded,

src/Compilation.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ win32_resource_table: if (dev.env.supports(.win32_resource)) std.AutoArrayHashMa
105105
pub fn deinit(_: @This(), _: Allocator) void {}
106106
} = .{},
107107

108-
link_error_flags: link.File.ErrorFlags = .{},
109108
link_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
109+
link_errors_mutex: std.Thread.Mutex = .{},
110+
link_error_flags: link.File.ErrorFlags = .{},
110111
lld_errors: std.ArrayListUnmanaged(LldError) = .{},
111112

112113
work_queues: [
@@ -3067,7 +3068,6 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
30673068
total += @intFromBool(comp.link_error_flags.no_entry_point_found);
30683069
}
30693070
total += @intFromBool(comp.link_error_flags.missing_libc);
3070-
30713071
total += comp.link_errors.items.len;
30723072

30733073
// Compile log errors only count if there are no other errors.

src/arch/x86_64/Emit.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,12 @@ pub fn emitMir(emit: *Emit) Error!void {
163163
const zo = macho_file.getZigObject().?;
164164
const atom = zo.symbols.items[data.atom_index].getAtom(macho_file).?;
165165
const sym = &zo.symbols.items[data.sym_index];
166-
if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
166+
if (sym.getSectionFlags().needs_zig_got and !is_obj_or_static_lib) {
167167
_ = try sym.getOrCreateZigGotEntry(data.sym_index, macho_file);
168168
}
169-
const @"type": link.File.MachO.Relocation.Type = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
169+
const @"type": link.File.MachO.Relocation.Type = if (sym.getSectionFlags().needs_zig_got and !is_obj_or_static_lib)
170170
.zig_got_load
171-
else if (sym.flags.needs_got)
171+
else if (sym.getSectionFlags().needs_got)
172172
// TODO: it is possible to emit .got_load here that can potentially be relaxed
173173
// however this requires always to use a MOVQ mnemonic
174174
.got

src/arch/x86_64/Lower.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
451451
break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
452452
},
453453
.mov => {
454-
if (is_obj_or_static_lib and macho_sym.flags.needs_zig_got) emit_mnemonic = .lea;
454+
if (is_obj_or_static_lib and macho_sym.getSectionFlags().needs_zig_got) emit_mnemonic = .lea;
455455
break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
456456
},
457457
else => unreachable,

src/codegen.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ fn genDeclRef(
924924
const name = decl.name.toSlice(ip);
925925
const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
926926
const sym_index = try macho_file.getGlobalSymbol(name, lib_name);
927-
zo.symbols.items[sym_index].flags.needs_got = true;
927+
zo.symbols.items[sym_index].setSectionFlags(.{ .needs_got = true });
928928
return GenResult.mcv(.{ .load_symbol = sym_index });
929929
}
930930
const sym_index = try zo.getOrCreateMetadataForDecl(macho_file, decl_index);

src/link.zig

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,58 @@ pub const File = struct {
439439
}
440440
}
441441

442+
pub const ErrorWithNotes = struct {
443+
base: *const File,
444+
445+
/// Allocated index in base.errors array.
446+
index: usize,
447+
448+
/// Next available note slot.
449+
note_slot: usize = 0,
450+
451+
pub fn addMsg(
452+
err: ErrorWithNotes,
453+
comptime format: []const u8,
454+
args: anytype,
455+
) error{OutOfMemory}!void {
456+
const gpa = err.base.comp.gpa;
457+
const err_msg = &err.base.comp.link_errors.items[err.index];
458+
err_msg.msg = try std.fmt.allocPrint(gpa, format, args);
459+
}
460+
461+
pub fn addNote(
462+
err: *ErrorWithNotes,
463+
comptime format: []const u8,
464+
args: anytype,
465+
) error{OutOfMemory}!void {
466+
const gpa = err.base.comp.gpa;
467+
const err_msg = &err.base.comp.link_errors.items[err.index];
468+
assert(err.note_slot < err_msg.notes.len);
469+
err_msg.notes[err.note_slot] = .{ .msg = try std.fmt.allocPrint(gpa, format, args) };
470+
err.note_slot += 1;
471+
}
472+
};
473+
474+
pub fn addErrorWithNotes(base: *const File, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
475+
base.comp.link_errors_mutex.lock();
476+
defer base.comp.link_errors_mutex.unlock();
477+
const gpa = base.comp.gpa;
478+
try base.comp.link_errors.ensureUnusedCapacity(gpa, 1);
479+
return base.addErrorWithNotesAssumeCapacity(note_count);
480+
}
481+
482+
pub fn addErrorWithNotesAssumeCapacity(base: *const File, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
483+
const gpa = base.comp.gpa;
484+
const index = base.comp.link_errors.items.len;
485+
const err = base.comp.link_errors.addOneAssumeCapacity();
486+
err.* = .{ .msg = undefined, .notes = try gpa.alloc(ErrorMsg, note_count) };
487+
return .{ .base = base, .index = index };
488+
}
489+
490+
pub fn hasErrors(base: *const File) bool {
491+
return base.comp.link_errors.items.len > 0 or base.comp.link_error_flags.isSet();
492+
}
493+
442494
pub fn releaseLock(self: *File) void {
443495
if (self.lock) |*lock| {
444496
lock.release();
@@ -874,9 +926,23 @@ pub const File = struct {
874926
}
875927
};
876928

877-
pub const ErrorFlags = struct {
929+
pub const ErrorFlags = packed struct {
878930
no_entry_point_found: bool = false,
879931
missing_libc: bool = false,
932+
933+
const Int = blk: {
934+
const bits = @typeInfo(@This()).Struct.fields.len;
935+
break :blk @Type(.{
936+
.Int = .{
937+
.signedness = .unsigned,
938+
.bits = bits,
939+
},
940+
});
941+
};
942+
943+
fn isSet(ef: ErrorFlags) bool {
944+
return @as(Int, @bitCast(ef)) > 0;
945+
}
880946
};
881947

882948
pub const ErrorMsg = struct {

src/link/Elf.zig

Lines changed: 33 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -995,12 +995,12 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
995995
if (maybe_phdr) |phdr| {
996996
const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr);
997997
if (needed_size > mem_capacity) {
998-
var err = try self.addErrorWithNotes(2);
999-
try err.addMsg(self, "fatal linker error: cannot expand load segment phdr({d}) in virtual memory", .{
998+
var err = try self.base.addErrorWithNotes(2);
999+
try err.addMsg("fatal linker error: cannot expand load segment phdr({d}) in virtual memory", .{
10001000
self.phdr_to_shdr_table.get(shdr_index).?,
10011001
});
1002-
try err.addNote(self, "TODO: emit relocations to memory locations in self-hosted backends", .{});
1003-
try err.addNote(self, "as a workaround, try increasing pre-allocated virtual memory of each segment", .{});
1002+
try err.addNote("TODO: emit relocations to memory locations in self-hosted backends", .{});
1003+
try err.addNote("as a workaround, try increasing pre-allocated virtual memory of each segment", .{});
10041004
}
10051005

10061006
phdr.p_memsz = needed_size;
@@ -1276,7 +1276,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
12761276
};
12771277
}
12781278

1279-
if (comp.link_errors.items.len > 0) return error.FlushFailure;
1279+
if (self.base.hasErrors()) return error.FlushFailure;
12801280

12811281
// Dedup shared objects
12821282
{
@@ -1423,7 +1423,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
14231423
try self.writeElfHeader();
14241424
}
14251425

1426-
if (comp.link_errors.items.len > 0) return error.FlushFailure;
1426+
if (self.base.hasErrors()) return error.FlushFailure;
14271427
}
14281428

14291429
/// --verbose-link output
@@ -2852,9 +2852,9 @@ fn writePhdrTable(self: *Elf) !void {
28522852
}
28532853

28542854
pub fn writeElfHeader(self: *Elf) !void {
2855-
const comp = self.base.comp;
2856-
if (comp.link_errors.items.len > 0) return; // We had errors, so skip flushing to render the output unusable
2855+
if (self.base.hasErrors()) return; // We had errors, so skip flushing to render the output unusable
28572856

2857+
const comp = self.base.comp;
28582858
var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
28592859

28602860
var index: usize = 0;
@@ -4298,9 +4298,9 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {
42984298
// (revisit getMaxNumberOfPhdrs())
42994299
// 2. shift everything in file to free more space for EHDR + PHDR table
43004300
// TODO verify `getMaxNumberOfPhdrs()` is accurate and convert this into no-op
4301-
var err = try self.addErrorWithNotes(1);
4302-
try err.addMsg(self, "fatal linker error: not enough space reserved for EHDR and PHDR table", .{});
4303-
try err.addNote(self, "required 0x{x}, available 0x{x}", .{ needed_size, available_space });
4301+
var err = try self.base.addErrorWithNotes(1);
4302+
try err.addMsg("fatal linker error: not enough space reserved for EHDR and PHDR table", .{});
4303+
try err.addNote("required 0x{x}, available 0x{x}", .{ needed_size, available_space });
43044304
}
43054305

43064306
phdr_table_load.p_filesz = needed_size + ehsize;
@@ -5863,56 +5863,6 @@ pub fn tlsAddress(self: *Elf) i64 {
58635863
return @intCast(phdr.p_vaddr);
58645864
}
58655865

5866-
const ErrorWithNotes = struct {
5867-
/// Allocated index in comp.link_errors array.
5868-
index: usize,
5869-
5870-
/// Next available note slot.
5871-
note_slot: usize = 0,
5872-
5873-
pub fn addMsg(
5874-
err: ErrorWithNotes,
5875-
elf_file: *Elf,
5876-
comptime format: []const u8,
5877-
args: anytype,
5878-
) error{OutOfMemory}!void {
5879-
const comp = elf_file.base.comp;
5880-
const gpa = comp.gpa;
5881-
const err_msg = &comp.link_errors.items[err.index];
5882-
err_msg.msg = try std.fmt.allocPrint(gpa, format, args);
5883-
}
5884-
5885-
pub fn addNote(
5886-
err: *ErrorWithNotes,
5887-
elf_file: *Elf,
5888-
comptime format: []const u8,
5889-
args: anytype,
5890-
) error{OutOfMemory}!void {
5891-
const comp = elf_file.base.comp;
5892-
const gpa = comp.gpa;
5893-
const err_msg = &comp.link_errors.items[err.index];
5894-
assert(err.note_slot < err_msg.notes.len);
5895-
err_msg.notes[err.note_slot] = .{ .msg = try std.fmt.allocPrint(gpa, format, args) };
5896-
err.note_slot += 1;
5897-
}
5898-
};
5899-
5900-
pub fn addErrorWithNotes(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
5901-
const comp = self.base.comp;
5902-
const gpa = comp.gpa;
5903-
try comp.link_errors.ensureUnusedCapacity(gpa, 1);
5904-
return self.addErrorWithNotesAssumeCapacity(note_count);
5905-
}
5906-
5907-
fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
5908-
const comp = self.base.comp;
5909-
const gpa = comp.gpa;
5910-
const index = comp.link_errors.items.len;
5911-
const err = comp.link_errors.addOneAssumeCapacity();
5912-
err.* = .{ .msg = undefined, .notes = try gpa.alloc(link.File.ErrorMsg, note_count) };
5913-
return .{ .index = index };
5914-
}
5915-
59165866
pub fn getShString(self: Elf, off: u32) [:0]const u8 {
59175867
assert(off < self.shstrtab.items.len);
59185868
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.shstrtab.items.ptr + off)), 0);
@@ -5940,11 +5890,10 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
59405890
}
59415891

59425892
fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
5943-
const comp = self.base.comp;
5944-
const gpa = comp.gpa;
5893+
const gpa = self.base.comp.gpa;
59455894
const max_notes = 4;
59465895

5947-
try comp.link_errors.ensureUnusedCapacity(gpa, undefs.count());
5896+
try self.base.comp.link_errors.ensureUnusedCapacity(gpa, undefs.count());
59485897

59495898
var it = undefs.iterator();
59505899
while (it.next()) |entry| {
@@ -5953,18 +5902,18 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
59535902
const natoms = @min(atoms.len, max_notes);
59545903
const nnotes = natoms + @intFromBool(atoms.len > max_notes);
59555904

5956-
var err = try self.addErrorWithNotesAssumeCapacity(nnotes);
5957-
try err.addMsg(self, "undefined symbol: {s}", .{self.symbol(undef_index).name(self)});
5905+
var err = try self.base.addErrorWithNotesAssumeCapacity(nnotes);
5906+
try err.addMsg("undefined symbol: {s}", .{self.symbol(undef_index).name(self)});
59585907

59595908
for (atoms[0..natoms]) |atom_index| {
59605909
const atom_ptr = self.atom(atom_index).?;
59615910
const file_ptr = self.file(atom_ptr.file_index).?;
5962-
try err.addNote(self, "referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
5911+
try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
59635912
}
59645913

59655914
if (atoms.len > max_notes) {
59665915
const remaining = atoms.len - max_notes;
5967-
try err.addNote(self, "referenced {d} more times", .{remaining});
5916+
try err.addNote("referenced {d} more times", .{remaining});
59685917
}
59695918
}
59705919
}
@@ -5978,19 +5927,19 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor
59785927
const notes = entry.value_ptr.*;
59795928
const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
59805929

5981-
var err = try self.addErrorWithNotes(nnotes + 1);
5982-
try err.addMsg(self, "duplicate symbol definition: {s}", .{sym.name(self)});
5983-
try err.addNote(self, "defined by {}", .{sym.file(self).?.fmtPath()});
5930+
var err = try self.base.addErrorWithNotes(nnotes + 1);
5931+
try err.addMsg("duplicate symbol definition: {s}", .{sym.name(self)});
5932+
try err.addNote("defined by {}", .{sym.file(self).?.fmtPath()});
59845933

59855934
var inote: usize = 0;
59865935
while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
59875936
const file_ptr = self.file(notes.items[inote]).?;
5988-
try err.addNote(self, "defined by {}", .{file_ptr.fmtPath()});
5937+
try err.addNote("defined by {}", .{file_ptr.fmtPath()});
59895938
}
59905939

59915940
if (notes.items.len > max_notes) {
59925941
const remaining = notes.items.len - max_notes;
5993-
try err.addNote(self, "defined {d} more times", .{remaining});
5942+
try err.addNote("defined {d} more times", .{remaining});
59945943
}
59955944

59965945
has_dupes = true;
@@ -6005,16 +5954,16 @@ fn reportMissingLibraryError(
60055954
comptime format: []const u8,
60065955
args: anytype,
60075956
) error{OutOfMemory}!void {
6008-
var err = try self.addErrorWithNotes(checked_paths.len);
6009-
try err.addMsg(self, format, args);
5957+
var err = try self.base.addErrorWithNotes(checked_paths.len);
5958+
try err.addMsg(format, args);
60105959
for (checked_paths) |path| {
6011-
try err.addNote(self, "tried {s}", .{path});
5960+
try err.addNote("tried {s}", .{path});
60125961
}
60135962
}
60145963

60155964
pub fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
6016-
var err = try self.addErrorWithNotes(0);
6017-
try err.addMsg(self, "fatal linker error: unsupported CPU architecture {s}", .{
5965+
var err = try self.base.addErrorWithNotes(0);
5966+
try err.addMsg("fatal linker error: unsupported CPU architecture {s}", .{
60185967
@tagName(self.getTarget().cpu.arch),
60195968
});
60205969
}
@@ -6025,9 +5974,9 @@ pub fn reportParseError(
60255974
comptime format: []const u8,
60265975
args: anytype,
60275976
) error{OutOfMemory}!void {
6028-
var err = try self.addErrorWithNotes(1);
6029-
try err.addMsg(self, format, args);
6030-
try err.addNote(self, "while parsing {s}", .{path});
5977+
var err = try self.base.addErrorWithNotes(1);
5978+
try err.addMsg(format, args);
5979+
try err.addNote("while parsing {s}", .{path});
60315980
}
60325981

60335982
pub fn reportParseError2(
@@ -6036,9 +5985,9 @@ pub fn reportParseError2(
60365985
comptime format: []const u8,
60375986
args: anytype,
60385987
) error{OutOfMemory}!void {
6039-
var err = try self.addErrorWithNotes(1);
6040-
try err.addMsg(self, format, args);
6041-
try err.addNote(self, "while parsing {}", .{self.file(file_index).?.fmtPath()});
5988+
var err = try self.base.addErrorWithNotes(1);
5989+
try err.addMsg(format, args);
5990+
try err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});
60425991
}
60435992

60445993
const FormatShdrCtx = struct {

0 commit comments

Comments
 (0)