authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-07-15 17:54:09+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-07-22 16:58:20+02:00
log817939d20a097c195fc924398081e64556cc0aea
treef7fbb5817dd72f0196b9e541dcb84eab2c0186b6
parent61b4119a7d5862f58fc4a34024456e3feca292a5

macho: don't store GC roots globally

Instead, if dead-strip was requested, create a temp container and pass it around.

2 files changed, 62 insertions(+), 45 deletions(-)

src/link/MachO.zig+34-28
...@@ -243,8 +243,6 @@ unnamed_const_atoms: UnnamedConstTable = .{},...@@ -243,8 +243,6 @@ unnamed_const_atoms: UnnamedConstTable = .{},
243/// TODO consolidate this.243/// TODO consolidate this.
244decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?MatchingSection) = .{},244decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?MatchingSection) = .{},
245245
246gc_roots: std.AutoHashMapUnmanaged(*Atom, void) = .{},
247
248const Entry = struct {246const Entry = struct {
249 target: SymbolWithLoc,247 target: SymbolWithLoc,
250 atom: *Atom,248 atom: *Atom,
...@@ -631,7 +629,8 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -631,7 +629,8 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
631 const tracy = trace(@src());629 const tracy = trace(@src());
632 defer tracy.end();630 defer tracy.end();
633631
634 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);632 const gpa = self.base.allocator;
633 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
635 defer arena_allocator.deinit();634 defer arena_allocator.deinit();
636 const arena = arena_allocator.allocator();635 const arena = arena_allocator.allocator();
637636
...@@ -676,6 +675,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -676,6 +675,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
676 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;675 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
677 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;676 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
678 const stack_size = self.base.options.stack_size_override orelse 0;677 const stack_size = self.base.options.stack_size_override orelse 0;
678 const dead_strip = self.base.options.gc_sections orelse false;
679679
680 const id_symlink_basename = "zld.id";680 const id_symlink_basename = "zld.id";
681681
...@@ -707,7 +707,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -707,7 +707,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
707 man.hash.addOptional(self.base.options.search_strategy);707 man.hash.addOptional(self.base.options.search_strategy);
708 man.hash.addOptional(self.base.options.headerpad_size);708 man.hash.addOptional(self.base.options.headerpad_size);
709 man.hash.add(self.base.options.headerpad_max_install_names);709 man.hash.add(self.base.options.headerpad_max_install_names);
710 man.hash.add(self.base.options.gc_sections orelse false);710 man.hash.add(dead_strip);
711 man.hash.add(self.base.options.dead_strip_dylibs);711 man.hash.add(self.base.options.dead_strip_dylibs);
712 man.hash.addListOfBytes(self.base.options.lib_dirs);712 man.hash.addListOfBytes(self.base.options.lib_dirs);
713 man.hash.addListOfBytes(self.base.options.framework_dirs);713 man.hash.addListOfBytes(self.base.options.framework_dirs);
...@@ -790,14 +790,14 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -790,14 +790,14 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
790 .mode = link.determineMode(self.base.options),790 .mode = link.determineMode(self.base.options),
791 });791 });
792 // Index 0 is always a null symbol.792 // Index 0 is always a null symbol.
793 try self.locals.append(self.base.allocator, .{793 try self.locals.append(gpa, .{
794 .n_strx = 0,794 .n_strx = 0,
795 .n_type = 0,795 .n_type = 0,
796 .n_sect = 0,796 .n_sect = 0,
797 .n_desc = 0,797 .n_desc = 0,
798 .n_value = 0,798 .n_value = 0,
799 });799 });
800 try self.strtab.buffer.append(self.base.allocator, 0);800 try self.strtab.buffer.append(gpa, 0);
801 try self.populateMissingMetadata();801 try self.populateMissingMetadata();
802802
803 var lib_not_found = false;803 var lib_not_found = false;
...@@ -964,10 +964,10 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -964,10 +964,10 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
964 .cmdsize = cmdsize,964 .cmdsize = cmdsize,
965 .path = @sizeOf(macho.rpath_command),965 .path = @sizeOf(macho.rpath_command),
966 });966 });
967 rpath_cmd.data = try self.base.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path);967 rpath_cmd.data = try gpa.alloc(u8, cmdsize - rpath_cmd.inner.path);
968 mem.set(u8, rpath_cmd.data, 0);968 mem.set(u8, rpath_cmd.data, 0);
969 mem.copy(u8, rpath_cmd.data, rpath);969 mem.copy(u8, rpath_cmd.data, rpath);
970 try self.load_commands.append(self.base.allocator, .{ .rpath = rpath_cmd });970 try self.load_commands.append(gpa, .{ .rpath = rpath_cmd });
971 try rpath_table.putNoClobber(rpath, {});971 try rpath_table.putNoClobber(rpath, {});
972 self.load_commands_dirty = true;972 self.load_commands_dirty = true;
973 }973 }
...@@ -975,11 +975,11 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -975,11 +975,11 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
975 // code signature and entitlements975 // code signature and entitlements
976 if (self.base.options.entitlements) |path| {976 if (self.base.options.entitlements) |path| {
977 if (self.code_signature) |*csig| {977 if (self.code_signature) |*csig| {
978 try csig.addEntitlements(self.base.allocator, path);978 try csig.addEntitlements(gpa, path);
979 csig.code_directory.ident = self.base.options.emit.?.sub_path;979 csig.code_directory.ident = self.base.options.emit.?.sub_path;
980 } else {980 } else {
981 var csig = CodeSignature.init(self.page_size);981 var csig = CodeSignature.init(self.page_size);
982 try csig.addEntitlements(self.base.allocator, path);982 try csig.addEntitlements(gpa, path);
983 csig.code_directory.ident = self.base.options.emit.?.sub_path;983 csig.code_directory.ident = self.base.options.emit.?.sub_path;
984 self.code_signature = csig;984 self.code_signature = csig;
985 }985 }
...@@ -1033,10 +1033,8 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -1033,10 +1033,8 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
1033 try argv.append("-headerpad_max_install_names");1033 try argv.append("-headerpad_max_install_names");
1034 }1034 }
10351035
1036 if (self.base.options.gc_sections) |is_set| {1036 if (dead_strip) {
1037 if (is_set) {1037 try argv.append("-dead_strip");
1038 try argv.append("-dead_strip");
1039 }
1040 }1038 }
10411039
1042 if (self.base.options.dead_strip_dylibs) {1040 if (self.base.options.dead_strip_dylibs) {
...@@ -1120,7 +1118,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -1120,7 +1118,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
1120 var dependent_libs = std.fifo.LinearFifo(struct {1118 var dependent_libs = std.fifo.LinearFifo(struct {
1121 id: Dylib.Id,1119 id: Dylib.Id,
1122 parent: u16,1120 parent: u16,
1123 }, .Dynamic).init(self.base.allocator);1121 }, .Dynamic).init(gpa);
1124 defer dependent_libs.deinit();1122 defer dependent_libs.deinit();
1125 try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs);1123 try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs);
1126 try self.parseAndForceLoadStaticArchives(must_link_archives.keys());1124 try self.parseAndForceLoadStaticArchives(must_link_archives.keys());
...@@ -1153,11 +1151,21 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -1153,11 +1151,21 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
11531151
1154 try self.createTentativeDefAtoms();1152 try self.createTentativeDefAtoms();
11551153
1156 for (self.objects.items) |*object, object_id| {1154 if (dead_strip) {
1157 try object.splitIntoAtomsOneShot(self, @intCast(u32, object_id));1155 var gc_roots = std.AutoHashMap(*Atom, void).init(gpa);
1156 defer gc_roots.deinit();
1157
1158 for (self.objects.items) |*object, object_id| {
1159 try object.splitIntoAtomsOneShot(self, @intCast(u32, object_id), &gc_roots);
1160 }
1161
1162 try self.gcAtoms(&gc_roots);
1163 } else {
1164 for (self.objects.items) |*object, object_id| {
1165 try object.splitIntoAtomsOneShot(self, @intCast(u32, object_id), null);
1166 }
1158 }1167 }
11591168
1160 try self.gcAtoms();
1161 try self.pruneAndSortSections();1169 try self.pruneAndSortSections();
1162 try self.allocateSegments();1170 try self.allocateSegments();
1163 try self.allocateSymbols();1171 try self.allocateSymbols();
...@@ -1184,7 +1192,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -1184,7 +1192,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
1184 try self.writeLinkeditSegment();1192 try self.writeLinkeditSegment();
11851193
1186 if (self.code_signature) |*csig| {1194 if (self.code_signature) |*csig| {
1187 csig.clear(self.base.allocator);1195 csig.clear(gpa);
1188 csig.code_directory.ident = self.base.options.emit.?.sub_path;1196 csig.code_directory.ident = self.base.options.emit.?.sub_path;
1189 // Preallocate space for the code signature.1197 // Preallocate space for the code signature.
1190 // We need to do this at this stage so that we have the load commands with proper values1198 // We need to do this at this stage so that we have the load commands with proper values
...@@ -3294,7 +3302,6 @@ pub fn deinit(self: *MachO) void {...@@ -3294,7 +3302,6 @@ pub fn deinit(self: *MachO) void {
3294 self.locals.deinit(self.base.allocator);3302 self.locals.deinit(self.base.allocator);
3295 self.locals_free_list.deinit(self.base.allocator);3303 self.locals_free_list.deinit(self.base.allocator);
3296 self.unresolved.deinit(self.base.allocator);3304 self.unresolved.deinit(self.base.allocator);
3297 self.gc_roots.deinit(self.base.allocator);
32983305
3299 for (self.objects.items) |*object| {3306 for (self.objects.items) |*object| {
3300 object.deinit(self.base.allocator);3307 object.deinit(self.base.allocator);
...@@ -5447,9 +5454,8 @@ fn pruneAndSortSections(self: *MachO) !void {...@@ -5447,9 +5454,8 @@ fn pruneAndSortSections(self: *MachO) !void {
5447 self.sections_order_dirty = false;5454 self.sections_order_dirty = false;
5448}5455}
54495456
5450fn gcAtoms(self: *MachO) !void {5457fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void {
5451 const dead_strip = self.base.options.gc_sections orelse return;5458 assert(self.base.options.gc_sections.?);
5452 if (!dead_strip) return;
54535459
5454 const gpa = self.base.allocator;5460 const gpa = self.base.allocator;
54555461
...@@ -5461,7 +5467,7 @@ fn gcAtoms(self: *MachO) !void {...@@ -5461,7 +5467,7 @@ fn gcAtoms(self: *MachO) !void {
5461 log.debug("skipping {s}", .{self.getSymbolName(global)});5467 log.debug("skipping {s}", .{self.getSymbolName(global)});
5462 continue;5468 continue;
5463 };5469 };
5464 _ = try self.gc_roots.getOrPut(gpa, gc_root);5470 _ = try gc_roots.getOrPut(gc_root);
5465 }5471 }
54665472
5467 // Add any atom targeting an import as GC root5473 // Add any atom targeting an import as GC root
...@@ -5474,7 +5480,7 @@ fn gcAtoms(self: *MachO) !void {...@@ -5474,7 +5480,7 @@ fn gcAtoms(self: *MachO) !void {
5474 if ((try rel.getTargetAtom(self)) == null) {5480 if ((try rel.getTargetAtom(self)) == null) {
5475 const target_sym = self.getSymbol(rel.target);5481 const target_sym = self.getSymbol(rel.target);
5476 if (target_sym.undf()) {5482 if (target_sym.undf()) {
5477 _ = try self.gc_roots.getOrPut(gpa, atom);5483 _ = try gc_roots.getOrPut(atom);
5478 break;5484 break;
5479 }5485 }
5480 }5486 }
...@@ -5488,14 +5494,14 @@ fn gcAtoms(self: *MachO) !void {...@@ -5488,14 +5494,14 @@ fn gcAtoms(self: *MachO) !void {
54885494
5489 var stack = std.ArrayList(*Atom).init(gpa);5495 var stack = std.ArrayList(*Atom).init(gpa);
5490 defer stack.deinit();5496 defer stack.deinit();
5491 try stack.ensureUnusedCapacity(self.gc_roots.count());5497 try stack.ensureUnusedCapacity(gc_roots.count());
54925498
5493 var retained = std.AutoHashMap(*Atom, void).init(gpa);5499 var retained = std.AutoHashMap(*Atom, void).init(gpa);
5494 defer retained.deinit();5500 defer retained.deinit();
5495 try retained.ensureUnusedCapacity(self.gc_roots.count());5501 try retained.ensureUnusedCapacity(gc_roots.count());
54965502
5497 log.debug("GC roots:", .{});5503 log.debug("GC roots:", .{});
5498 var gc_roots_it = self.gc_roots.keyIterator();5504 var gc_roots_it = gc_roots.keyIterator();
5499 while (gc_roots_it.next()) |gc_root| {5505 while (gc_roots_it.next()) |gc_root| {
5500 self.logAtom(gc_root.*);5506 self.logAtom(gc_root.*);
55015507
src/link/MachO/Object.zig+28-17
...@@ -360,7 +360,12 @@ fn filterDice(...@@ -360,7 +360,12 @@ fn filterDice(
360}360}
361361
362/// Splits object into atoms assuming one-shot linking mode.362/// Splits object into atoms assuming one-shot linking mode.
363pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) !void {363pub fn splitIntoAtomsOneShot(
364 self: *Object,
365 macho_file: *MachO,
366 object_id: u32,
367 gc_roots: ?*std.AutoHashMap(*Atom, void),
368) !void {
364 assert(macho_file.mode == .one_shot);369 assert(macho_file.mode == .one_shot);
365370
366 const tracy = trace(@src());371 const tracy = trace(@src());
...@@ -493,6 +498,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -493,6 +498,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
493 &.{},498 &.{},
494 match,499 match,
495 sect,500 sect,
501 gc_roots,
496 );502 );
497 try macho_file.addAtomToSection(atom, match);503 try macho_file.addAtomToSection(atom, match);
498 }504 }
...@@ -538,6 +544,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -538,6 +544,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
538 atom_syms[1..],544 atom_syms[1..],
539 match,545 match,
540 sect,546 sect,
547 gc_roots,
541 );548 );
542549
543 if (arch == .x86_64 and addr == sect.addr) {550 if (arch == .x86_64 and addr == sect.addr) {
...@@ -593,6 +600,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -593,6 +600,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
593 filtered_syms,600 filtered_syms,
594 match,601 match,
595 sect,602 sect,
603 gc_roots,
596 );604 );
597 try macho_file.addAtomToSection(atom, match);605 try macho_file.addAtomToSection(atom, match);
598 }606 }
...@@ -611,6 +619,7 @@ fn createAtomFromSubsection(...@@ -611,6 +619,7 @@ fn createAtomFromSubsection(
611 indexes: []const SymbolAtIndex,619 indexes: []const SymbolAtIndex,
612 match: MatchingSection,620 match: MatchingSection,
613 sect: macho.section_64,621 sect: macho.section_64,
622 gc_roots: ?*std.AutoHashMap(*Atom, void),
614) !*Atom {623) !*Atom {
615 const gpa = macho_file.base.allocator;624 const gpa = macho_file.base.allocator;
616 const sym = self.symtab.items[sym_index];625 const sym = self.symtab.items[sym_index];
...@@ -715,23 +724,25 @@ fn createAtomFromSubsection(...@@ -715,23 +724,25 @@ fn createAtomFromSubsection(
715 try self.atom_by_index_table.putNoClobber(gpa, inner_sym_index.index, atom);724 try self.atom_by_index_table.putNoClobber(gpa, inner_sym_index.index, atom);
716 }725 }
717726
718 const is_gc_root = blk: {727 if (gc_roots) |gcr| {
719 if (sect.isDontDeadStrip()) break :blk true;728 const is_gc_root = blk: {
720 if (sect.isDontDeadStripIfReferencesLive()) {729 if (sect.isDontDeadStrip()) break :blk true;
721 // TODO if isDontDeadStripIfReferencesLive we should analyse the edges730 if (sect.isDontDeadStripIfReferencesLive()) {
722 // before making it a GC root731 // TODO if isDontDeadStripIfReferencesLive we should analyse the edges
723 break :blk true;732 // before making it a GC root
724 }733 break :blk true;
725 if (mem.eql(u8, "__StaticInit", sect.sectName())) break :blk true;734 }
726 switch (sect.type_()) {735 if (mem.eql(u8, "__StaticInit", sect.sectName())) break :blk true;
727 macho.S_MOD_INIT_FUNC_POINTERS,736 switch (sect.type_()) {
728 macho.S_MOD_TERM_FUNC_POINTERS,737 macho.S_MOD_INIT_FUNC_POINTERS,
729 => break :blk true,738 macho.S_MOD_TERM_FUNC_POINTERS,
730 else => break :blk false,739 => break :blk true,
740 else => break :blk false,
741 }
742 };
743 if (is_gc_root) {
744 try gcr.putNoClobber(atom, {});
731 }745 }
732 };
733 if (is_gc_root) {
734 try macho_file.gc_roots.putNoClobber(gpa, atom, {});
735 }746 }
736747
737 return atom;748 return atom;