Commit 817939d20a

Jakub Konka <kubkon@jakubkonka.com>
2022-07-15 17:54:09
macho: don't store GC roots globally
Instead, if dead-strip was requested, create a temp container and pass it around.
1 parent 61b4119
Changed files (2)
src
src/link/MachO/Object.zig
@@ -360,7 +360,12 @@ fn filterDice(
 }
 
 /// Splits object into atoms assuming one-shot linking mode.
-pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) !void {
+pub fn splitIntoAtomsOneShot(
+    self: *Object,
+    macho_file: *MachO,
+    object_id: u32,
+    gc_roots: ?*std.AutoHashMap(*Atom, void),
+) !void {
     assert(macho_file.mode == .one_shot);
 
     const tracy = trace(@src());
@@ -493,6 +498,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
                     &.{},
                     match,
                     sect,
+                    gc_roots,
                 );
                 try macho_file.addAtomToSection(atom, match);
             }
@@ -538,6 +544,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
                     atom_syms[1..],
                     match,
                     sect,
+                    gc_roots,
                 );
 
                 if (arch == .x86_64 and addr == sect.addr) {
@@ -593,6 +600,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
                 filtered_syms,
                 match,
                 sect,
+                gc_roots,
             );
             try macho_file.addAtomToSection(atom, match);
         }
@@ -611,6 +619,7 @@ fn createAtomFromSubsection(
     indexes: []const SymbolAtIndex,
     match: MatchingSection,
     sect: macho.section_64,
+    gc_roots: ?*std.AutoHashMap(*Atom, void),
 ) !*Atom {
     const gpa = macho_file.base.allocator;
     const sym = self.symtab.items[sym_index];
@@ -715,23 +724,25 @@ fn createAtomFromSubsection(
         try self.atom_by_index_table.putNoClobber(gpa, inner_sym_index.index, atom);
     }
 
-    const is_gc_root = blk: {
-        if (sect.isDontDeadStrip()) break :blk true;
-        if (sect.isDontDeadStripIfReferencesLive()) {
-            // TODO if isDontDeadStripIfReferencesLive we should analyse the edges
-            // before making it a GC root
-            break :blk true;
-        }
-        if (mem.eql(u8, "__StaticInit", sect.sectName())) break :blk true;
-        switch (sect.type_()) {
-            macho.S_MOD_INIT_FUNC_POINTERS,
-            macho.S_MOD_TERM_FUNC_POINTERS,
-            => break :blk true,
-            else => break :blk false,
+    if (gc_roots) |gcr| {
+        const is_gc_root = blk: {
+            if (sect.isDontDeadStrip()) break :blk true;
+            if (sect.isDontDeadStripIfReferencesLive()) {
+                // TODO if isDontDeadStripIfReferencesLive we should analyse the edges
+                // before making it a GC root
+                break :blk true;
+            }
+            if (mem.eql(u8, "__StaticInit", sect.sectName())) break :blk true;
+            switch (sect.type_()) {
+                macho.S_MOD_INIT_FUNC_POINTERS,
+                macho.S_MOD_TERM_FUNC_POINTERS,
+                => break :blk true,
+                else => break :blk false,
+            }
+        };
+        if (is_gc_root) {
+            try gcr.putNoClobber(atom, {});
         }
-    };
-    if (is_gc_root) {
-        try macho_file.gc_roots.putNoClobber(gpa, atom, {});
     }
 
     return atom;
src/link/MachO.zig
@@ -243,8 +243,6 @@ unnamed_const_atoms: UnnamedConstTable = .{},
 /// TODO consolidate this.
 decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?MatchingSection) = .{},
 
-gc_roots: std.AutoHashMapUnmanaged(*Atom, void) = .{},
-
 const Entry = struct {
     target: SymbolWithLoc,
     atom: *Atom,
@@ -631,7 +629,8 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
     const tracy = trace(@src());
     defer tracy.end();
 
-    var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
+    const gpa = self.base.allocator;
+    var arena_allocator = std.heap.ArenaAllocator.init(gpa);
     defer arena_allocator.deinit();
     const arena = arena_allocator.allocator();
 
@@ -676,6 +675,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
     const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
     const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
     const stack_size = self.base.options.stack_size_override orelse 0;
+    const dead_strip = self.base.options.gc_sections orelse false;
 
     const id_symlink_basename = "zld.id";
 
@@ -707,7 +707,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
         man.hash.addOptional(self.base.options.search_strategy);
         man.hash.addOptional(self.base.options.headerpad_size);
         man.hash.add(self.base.options.headerpad_max_install_names);
-        man.hash.add(self.base.options.gc_sections orelse false);
+        man.hash.add(dead_strip);
         man.hash.add(self.base.options.dead_strip_dylibs);
         man.hash.addListOfBytes(self.base.options.lib_dirs);
         man.hash.addListOfBytes(self.base.options.framework_dirs);
@@ -790,14 +790,14 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
             .mode = link.determineMode(self.base.options),
         });
         // Index 0 is always a null symbol.
-        try self.locals.append(self.base.allocator, .{
+        try self.locals.append(gpa, .{
             .n_strx = 0,
             .n_type = 0,
             .n_sect = 0,
             .n_desc = 0,
             .n_value = 0,
         });
-        try self.strtab.buffer.append(self.base.allocator, 0);
+        try self.strtab.buffer.append(gpa, 0);
         try self.populateMissingMetadata();
 
         var lib_not_found = false;
@@ -964,10 +964,10 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
                 .cmdsize = cmdsize,
                 .path = @sizeOf(macho.rpath_command),
             });
-            rpath_cmd.data = try self.base.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path);
+            rpath_cmd.data = try gpa.alloc(u8, cmdsize - rpath_cmd.inner.path);
             mem.set(u8, rpath_cmd.data, 0);
             mem.copy(u8, rpath_cmd.data, rpath);
-            try self.load_commands.append(self.base.allocator, .{ .rpath = rpath_cmd });
+            try self.load_commands.append(gpa, .{ .rpath = rpath_cmd });
             try rpath_table.putNoClobber(rpath, {});
             self.load_commands_dirty = true;
         }
@@ -975,11 +975,11 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
         // code signature and entitlements
         if (self.base.options.entitlements) |path| {
             if (self.code_signature) |*csig| {
-                try csig.addEntitlements(self.base.allocator, path);
+                try csig.addEntitlements(gpa, path);
                 csig.code_directory.ident = self.base.options.emit.?.sub_path;
             } else {
                 var csig = CodeSignature.init(self.page_size);
-                try csig.addEntitlements(self.base.allocator, path);
+                try csig.addEntitlements(gpa, path);
                 csig.code_directory.ident = self.base.options.emit.?.sub_path;
                 self.code_signature = csig;
             }
@@ -1033,10 +1033,8 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
                 try argv.append("-headerpad_max_install_names");
             }
 
-            if (self.base.options.gc_sections) |is_set| {
-                if (is_set) {
-                    try argv.append("-dead_strip");
-                }
+            if (dead_strip) {
+                try argv.append("-dead_strip");
             }
 
             if (self.base.options.dead_strip_dylibs) {
@@ -1120,7 +1118,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
         var dependent_libs = std.fifo.LinearFifo(struct {
             id: Dylib.Id,
             parent: u16,
-        }, .Dynamic).init(self.base.allocator);
+        }, .Dynamic).init(gpa);
         defer dependent_libs.deinit();
         try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs);
         try self.parseAndForceLoadStaticArchives(must_link_archives.keys());
@@ -1153,11 +1151,21 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
 
         try self.createTentativeDefAtoms();
 
-        for (self.objects.items) |*object, object_id| {
-            try object.splitIntoAtomsOneShot(self, @intCast(u32, object_id));
+        if (dead_strip) {
+            var gc_roots = std.AutoHashMap(*Atom, void).init(gpa);
+            defer gc_roots.deinit();
+
+            for (self.objects.items) |*object, object_id| {
+                try object.splitIntoAtomsOneShot(self, @intCast(u32, object_id), &gc_roots);
+            }
+
+            try self.gcAtoms(&gc_roots);
+        } else {
+            for (self.objects.items) |*object, object_id| {
+                try object.splitIntoAtomsOneShot(self, @intCast(u32, object_id), null);
+            }
         }
 
-        try self.gcAtoms();
         try self.pruneAndSortSections();
         try self.allocateSegments();
         try self.allocateSymbols();
@@ -1184,7 +1192,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
         try self.writeLinkeditSegment();
 
         if (self.code_signature) |*csig| {
-            csig.clear(self.base.allocator);
+            csig.clear(gpa);
             csig.code_directory.ident = self.base.options.emit.?.sub_path;
             // Preallocate space for the code signature.
             // 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 {
     self.locals.deinit(self.base.allocator);
     self.locals_free_list.deinit(self.base.allocator);
     self.unresolved.deinit(self.base.allocator);
-    self.gc_roots.deinit(self.base.allocator);
 
     for (self.objects.items) |*object| {
         object.deinit(self.base.allocator);
@@ -5447,9 +5454,8 @@ fn pruneAndSortSections(self: *MachO) !void {
     self.sections_order_dirty = false;
 }
 
-fn gcAtoms(self: *MachO) !void {
-    const dead_strip = self.base.options.gc_sections orelse return;
-    if (!dead_strip) return;
+fn gcAtoms(self: *MachO, gc_roots: *std.AutoHashMap(*Atom, void)) !void {
+    assert(self.base.options.gc_sections.?);
 
     const gpa = self.base.allocator;
 
@@ -5461,7 +5467,7 @@ fn gcAtoms(self: *MachO) !void {
             log.debug("skipping {s}", .{self.getSymbolName(global)});
             continue;
         };
-        _ = try self.gc_roots.getOrPut(gpa, gc_root);
+        _ = try gc_roots.getOrPut(gc_root);
     }
 
     // Add any atom targeting an import as GC root
@@ -5474,7 +5480,7 @@ fn gcAtoms(self: *MachO) !void {
                 if ((try rel.getTargetAtom(self)) == null) {
                     const target_sym = self.getSymbol(rel.target);
                     if (target_sym.undf()) {
-                        _ = try self.gc_roots.getOrPut(gpa, atom);
+                        _ = try gc_roots.getOrPut(atom);
                         break;
                     }
                 }
@@ -5488,14 +5494,14 @@ fn gcAtoms(self: *MachO) !void {
 
     var stack = std.ArrayList(*Atom).init(gpa);
     defer stack.deinit();
-    try stack.ensureUnusedCapacity(self.gc_roots.count());
+    try stack.ensureUnusedCapacity(gc_roots.count());
 
     var retained = std.AutoHashMap(*Atom, void).init(gpa);
     defer retained.deinit();
-    try retained.ensureUnusedCapacity(self.gc_roots.count());
+    try retained.ensureUnusedCapacity(gc_roots.count());
 
     log.debug("GC roots:", .{});
-    var gc_roots_it = self.gc_roots.keyIterator();
+    var gc_roots_it = gc_roots.keyIterator();
     while (gc_roots_it.next()) |gc_root| {
         self.logAtom(gc_root.*);