Commit 2169a5559d

Jakub Konka <kubkon@jakubkonka.com>
2024-01-18 14:59:15
macho: implement more self-hosted primitives
1 parent 55c8b82
Changed files (3)
src/link/MachO/Atom.zig
@@ -324,6 +324,70 @@ pub fn grow(self: *Atom, macho_file: *MachO) !void {
         try self.allocate(macho_file);
 }
 
+pub fn free(self: *Atom, macho_file: *MachO) void {
+    log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.getName(macho_file) });
+
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
+    const free_list = &macho_file.sections.items(.free_list)[self.out_n_sect];
+    const last_atom_index = &macho_file.sections.items(.last_atom_index)[self.out_n_sect];
+    var already_have_free_list_node = false;
+    {
+        var i: usize = 0;
+        // TODO turn free_list into a hash map
+        while (i < free_list.items.len) {
+            if (free_list.items[i] == self.atom_index) {
+                _ = free_list.swapRemove(i);
+                continue;
+            }
+            if (free_list.items[i] == self.prev_index) {
+                already_have_free_list_node = true;
+            }
+            i += 1;
+        }
+    }
+
+    if (macho_file.getAtom(last_atom_index.*)) |last_atom| {
+        if (last_atom.atom_index == self.atom_index) {
+            if (macho_file.getAtom(self.prev_index)) |_| {
+                // TODO shrink the section size here
+                last_atom_index.* = self.prev_index;
+            } else {
+                last_atom_index.* = 0;
+            }
+        }
+    }
+
+    if (macho_file.getAtom(self.prev_index)) |prev| {
+        prev.next_index = self.next_index;
+        if (!already_have_free_list_node and prev.*.freeListEligible(macho_file)) {
+            // The free list is heuristics, it doesn't have to be perfect, so we can
+            // ignore the OOM here.
+            free_list.append(gpa, prev.atom_index) catch {};
+        }
+    } else {
+        self.prev_index = 0;
+    }
+
+    if (macho_file.getAtom(self.next_index)) |next| {
+        next.prev_index = self.prev_index;
+    } else {
+        self.next_index = 0;
+    }
+
+    // TODO create relocs free list
+    self.freeRelocs(macho_file);
+    // TODO figure out how to free input section mappind in ZigModule
+    // const zig_object = macho_file.zigObjectPtr().?
+    // assert(zig_object.atoms.swapRemove(self.atom_index));
+    self.* = .{};
+}
+
+pub fn freeRelocs(self: *Atom, macho_file: *MachO) void {
+    self.getFile(macho_file).zig_object.freeAtomRelocs(self.*);
+    self.relocs.len = 0;
+}
+
 pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
     const tracy = trace(@src());
     defer tracy.end();
src/link/MachO/ZigObject.zig
@@ -129,6 +129,10 @@ pub fn getAtomRelocs(self: *ZigObject, atom: Atom) []const Relocation {
     return relocs.items[0..atom.relocs.len];
 }
 
+pub fn freeAtomRelocs(self: *ZigObject, atom: Atom) void {
+    self.relocs.items[atom.relocs.pos].clearRetainingCapacity();
+}
+
 pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) void {
     _ = self;
     _ = macho_file;
@@ -263,11 +267,42 @@ pub fn lowerAnonDecl(
     @panic("TODO lowerAnonDecl");
 }
 
-pub fn freeDecl(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void {
+fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void {
+    const gpa = macho_file.base.comp.gpa;
+    const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;
+    for (unnamed_consts.items) |sym_index| {
+        self.freeDeclMetadata(macho_file, sym_index);
+    }
+    unnamed_consts.clearAndFree(gpa);
+}
+
+fn freeDeclMetadata(self: *ZigObject, macho_file: *MachO, sym_index: Symbol.Index) void {
     _ = self;
-    _ = macho_file;
-    _ = decl_index;
-    @panic("TODO freeDecl");
+    const gpa = macho_file.base.comp.gpa;
+    const sym = macho_file.getSymbol(sym_index);
+    sym.getAtom(macho_file).?.free(macho_file);
+    log.debug("adding %{d} to local symbols free list", .{sym_index});
+    macho_file.symbols_free_list.append(gpa, sym_index) catch {};
+    macho_file.symbols.items[sym_index] = .{};
+    // TODO free GOT entry here
+}
+
+pub fn freeDecl(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void {
+    const gpa = macho_file.base.comp.gpa;
+    const mod = macho_file.base.comp.module.?;
+    const decl = mod.declPtr(decl_index);
+
+    log.debug("freeDecl {*}", .{decl});
+
+    if (self.decls.fetchRemove(decl_index)) |const_kv| {
+        var kv = const_kv;
+        const sym_index = kv.value.symbol_index;
+        self.freeDeclMetadata(macho_file, sym_index);
+        self.freeUnnamedConsts(macho_file, decl_index);
+        kv.value.exports.deinit(gpa);
+    }
+
+    // TODO free decl in dSYM
 }
 
 pub fn updateFunc(
@@ -278,13 +313,61 @@ pub fn updateFunc(
     air: Air,
     liveness: Liveness,
 ) !void {
-    _ = self;
-    _ = macho_file;
-    _ = mod;
-    _ = func_index;
-    _ = air;
-    _ = liveness;
-    @panic("TODO updateFunc");
+    const tracy = trace(@src());
+    defer tracy.end();
+
+    const gpa = macho_file.base.comp.gpa;
+    const func = mod.funcInfo(func_index);
+    const decl_index = func.owner_decl;
+    const decl = mod.declPtr(decl_index);
+
+    const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
+    self.freeUnnamedConsts(macho_file, decl_index);
+    macho_file.getSymbol(sym_index).getAtom(macho_file).?.freeRelocs(macho_file);
+
+    var code_buffer = std.ArrayList(u8).init(gpa);
+    defer code_buffer.deinit();
+
+    var decl_state: ?Dwarf.DeclState = null; // TODO: Dwarf
+    defer if (decl_state) |*ds| ds.deinit();
+
+    const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;
+    const res = try codegen.generateFunction(
+        &macho_file.base,
+        decl.srcLoc(mod),
+        func_index,
+        air,
+        liveness,
+        &code_buffer,
+        dio,
+    );
+
+    const code = switch (res) {
+        .ok => code_buffer.items,
+        .fail => |em| {
+            decl.analysis = .codegen_failure;
+            try mod.failed_decls.put(mod.gpa, decl_index, em);
+            return;
+        },
+    };
+
+    const sect_index = try self.getDeclOutputSection(macho_file, decl, code);
+    try self.updateDeclCode(macho_file, decl_index, sym_index, sect_index, code);
+
+    // if (decl_state) |*ds| {
+    //     const sym = elf_file.symbol(sym_index);
+    //     try self.dwarf.?.commitDeclState(
+    //         mod,
+    //         decl_index,
+    //         sym.value,
+    //         sym.atom(elf_file).?.size,
+    //         ds,
+    //     );
+    // }
+
+    // Since we updated the vaddr and the size, each corresponding export
+    // symbol also needs to be updated.
+    return self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
 }
 
 pub fn updateDecl(
@@ -313,7 +396,7 @@ pub fn updateDecl(
     }
 
     const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
-    // TODO: free relocs if any
+    macho_file.getSymbol(sym_index).getAtom(macho_file).?.freeRelocs(macho_file);
 
     const gpa = macho_file.base.comp.gpa;
     var code_buffer = std.ArrayList(u8).init(gpa);
@@ -431,7 +514,7 @@ fn updateDeclCode(
         }
     } else {
         try atom.allocate(macho_file);
-        // TODO: freeDeclMetadata in case of error
+        errdefer self.freeDeclMetadata(macho_file, sym_index);
 
         sym.value = 0;
         sym.flags.needs_zig_got = true;
src/link/MachO.zig
@@ -20,6 +20,7 @@ sections: std.MultiArrayList(Section) = .{},
 
 symbols: std.ArrayListUnmanaged(Symbol) = .{},
 symbols_extra: std.ArrayListUnmanaged(u32) = .{},
+symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
 globals: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
 /// This table will be populated after `scanRelocs` has run.
 /// Key is symbol index.
@@ -327,6 +328,7 @@ pub fn deinit(self: *MachO) void {
 
     self.symbols.deinit(gpa);
     self.symbols_extra.deinit(gpa);
+    self.symbols_free_list.deinit(gpa);
     self.globals.deinit(gpa);
     {
         var it = self.undefs.iterator();
@@ -3260,9 +3262,8 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
 }
 
 pub fn growSection(self: *MachO, sect_index: u8, size: u64) !void {
-    _ = self;
-    _ = sect_index;
-    _ = size;
+    const sect = &self.sections.items(.header)[sect_index];
+    std.debug.print("curr={x}, needed={x}\n", .{ sect.size, size });
     @panic("TODO growSection");
 }