diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 3fc22255ce..d0d60a5587 100644 --- a/src/link/MachO.zig +++ b/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"); } diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 374a98021f..5da72886be 100644 --- a/src/link/MachO/Atom.zig +++ b/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(); diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index c574900bce..ceb9c7fe61 100644 --- a/src/link/MachO/ZigObject.zig +++ b/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;