diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 8e61af1c9f..a658103c1a 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -112,7 +112,7 @@ const Owner = union(enum) { mod_fn: *const Module.Fn, lazy_sym: link.File.LazySymbol, - fn getOwnerDecl(owner: Owner) Module.Decl.Index { + fn getDecl(owner: Owner) Module.Decl.Index { return switch (owner) { .mod_fn => |mod_fn| mod_fn.owner_decl, .lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(), @@ -1688,35 +1688,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { const data_reg = try self.register_manager.allocReg(null, gp); const data_lock = self.register_manager.lockRegAssumeUnused(data_reg); defer self.register_manager.unlockReg(data_lock); - - const data_lazy_sym = link.File.LazySymbol{ .kind = .const_data, .ty = enum_ty }; - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const atom = elf_file.getAtom(atom_index); - _ = try atom.getOrCreateOffsetTableEntry(elf_file); - const got_addr = atom.getOffsetTableAddress(elf_file); - try self.asmRegisterMemory( - .mov, - data_reg.to64(), - Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), - ); - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index }); - } else { - return self.fail("TODO implement {s} for {}", .{ - @tagName(lazy_sym.kind), - lazy_sym.ty.fmt(self.bin_file.options.module.?), - }); - } + try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty }); var data_off: i32 = 0; for ( @@ -6262,7 +6234,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { // TODO: this might need adjusting like the linkers do. // Instead of flattening the owner and passing Decl.Index here we may // want to special case LazySymbol in DWARF linker too. - try dw.genArgDbgInfo(name, ty, self.owner.getOwnerDecl(), loc); + try dw.genArgDbgInfo(name, ty, self.owner.getDecl(), loc); }, .plan9 => {}, .none => {}, @@ -6306,7 +6278,7 @@ fn genVarDbgInfo( // TODO: this might need adjusting like the linkers do. // Instead of flattening the owner and passing Decl.Index here we may // want to special case LazySymbol in DWARF linker too. - try dw.genVarDbgInfo(name, ty, self.owner.getOwnerDecl(), is_ptr, loc); + try dw.genVarDbgInfo(name, ty, self.owner.getDecl(), is_ptr, loc); }, .plan9 => {}, .none => {}, @@ -6630,38 +6602,13 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { } fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { + const mod = self.bin_file.options.module.?; const un_op = self.air.instructions.items(.data)[inst].un_op; const addr_reg = try self.register_manager.allocReg(null, gp); const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); defer self.register_manager.unlockReg(addr_lock); - - const mod = self.bin_file.options.module.?; - const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod); - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const atom = elf_file.getAtom(atom_index); - _ = try atom.getOrCreateOffsetTableEntry(elf_file); - const got_addr = atom.getOffsetTableAddress(elf_file); - try self.asmRegisterMemory( - .mov, - addr_reg.to64(), - Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), - ); - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); - } else { - return self.fail("TODO implement airCmpLtErrorsLen for x86_64 {s}", .{@tagName(self.bin_file.tag)}); - } + try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod)); try self.spillEflagsIfOccupied(); self.eflags_inst = inst; @@ -7999,6 +7946,67 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue) }); } +fn genLazySymbolRef( + self: *Self, + comptime tag: Mir.Inst.Tag, + reg: Register, + lazy_sym: link.File.LazySymbol, +) InnerError!void { + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const atom = elf_file.getAtom(atom_index); + _ = try atom.getOrCreateOffsetTableEntry(elf_file); + const got_addr = atom.getOffsetTableAddress(elf_file); + const got_mem = + Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }); + switch (tag) { + .lea, .mov => try self.asmRegisterMemory(.mov, reg.to64(), got_mem), + .call => try self.asmMemory(.call, got_mem), + else => unreachable, + } + switch (tag) { + .lea, .call => {}, + .mov => try self.asmRegisterMemory( + tag, + reg.to64(), + Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }), + ), + else => unreachable, + } + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; + switch (tag) { + .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }), + .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }), + else => unreachable, + } + switch (tag) { + .lea, .mov => {}, + .call => try self.asmRegister(.call, reg), + else => unreachable, + } + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| + return self.fail("{s} creating lazy symbol", .{@errorName(err)}); + const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; + switch (tag) { + .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }), + .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }), + else => unreachable, + } + switch (tag) { + .lea, .mov => {}, + .call => try self.asmRegister(.call, reg), + else => unreachable, + } + } else { + return self.fail("TODO implement genLazySymbol for x86_64 {s}", .{@tagName(self.bin_file.tag)}); + } +} + fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[inst].un_op; const result = result: { @@ -8701,6 +8709,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { } fn airTagName(self: *Self, inst: Air.Inst.Index) !void { + const mod = self.bin_file.options.module.?; const un_op = self.air.instructions.items(.data)[inst].un_op; const inst_ty = self.air.typeOfIndex(inst); const enum_ty = self.air.typeOf(un_op); @@ -8731,38 +8740,17 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { const operand = try self.resolveInst(un_op); try self.genSetReg(param_regs[1], enum_ty, operand); - const mod = self.bin_file.options.module.?; - const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod); - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const atom = elf_file.getAtom(atom_index); - _ = try atom.getOrCreateOffsetTableEntry(elf_file); - const got_addr = atom.getOffsetTableAddress(elf_file); - try self.asmMemory( - .call, - Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), - ); - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); - try self.asmRegister(.call, .rax); - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); - try self.asmRegister(.call, .rax); - } else { - return self.fail("TODO implement airTagName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); - } + try self.genLazySymbolRef( + .call, + .rax, + link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod), + ); return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); } fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { + const mod = self.bin_file.options.module.?; const un_op = self.air.instructions.items(.data)[inst].un_op; const err_ty = self.air.typeOf(un_op); @@ -8774,33 +8762,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { const addr_reg = try self.register_manager.allocReg(null, gp); const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); defer self.register_manager.unlockReg(addr_lock); - - const mod = self.bin_file.options.module.?; - const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod); - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const atom = elf_file.getAtom(atom_index); - _ = try atom.getOrCreateOffsetTableEntry(elf_file); - const got_addr = atom.getOffsetTableAddress(elf_file); - try self.asmRegisterMemory( - .mov, - addr_reg.to64(), - Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), - ); - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); - } else { - return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); - } + try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod)); const start_reg = try self.register_manager.allocReg(null, gp); const start_lock = self.register_manager.lockRegAssumeUnused(start_reg); @@ -9117,7 +9079,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV } fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { - return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getOwnerDecl())) { + return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl())) { .mcv => |mcv| switch (mcv) { .none => .none, .undef => .undef, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 41d4617e53..81e8c57bdd 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -143,8 +143,11 @@ const Section = struct { const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); const LazySymbolMetadata = struct { - text_atom: ?Atom.Index = null, - rdata_atom: ?Atom.Index = null, + const State = enum { unused, pending_flush, flushed }; + text_atom: Atom.Index = undefined, + rdata_atom: Atom.Index = undefined, + text_state: State = .unused, + rdata_state: State = .unused, }; const DeclMetadata = struct { @@ -1150,8 +1153,6 @@ pub fn updateDecl( const tracy = trace(@src()); defer tracy.end(); - try self.updateLazySymbol(decl_index); - const decl = module.declPtr(decl_index); if (decl.val.tag() == .extern_fn) { @@ -1194,21 +1195,6 @@ pub fn updateDecl( return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn updateLazySymbol(self: *Coff, decl: ?Module.Decl.Index) !void { - const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return; - const mod = self.base.options.module.?; - if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( - link.File.LazySymbol.initDecl(.code, decl, mod), - atom, - self.text_section_index.?, - ); - if (metadata.rdata_atom) |atom| try self.updateLazySymbolAtom( - link.File.LazySymbol.initDecl(.const_data, decl, mod), - atom, - self.rdata_section_index.?, - ); -} - fn updateLazySymbolAtom( self: *Coff, sym: link.File.LazySymbol, @@ -1279,14 +1265,19 @@ pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Ato const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom_ptr = switch (sym.kind) { - .code => &gop.value_ptr.text_atom, - .const_data => &gop.value_ptr.rdata_atom, + const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { + .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state }, + .const_data => .{ .atom = &gop.value_ptr.rdata_atom, .state = &gop.value_ptr.rdata_state }, }; - if (atom_ptr.*) |atom| return atom; - const atom = try self.createAtom(); - atom_ptr.* = atom; - try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + switch (metadata.state.*) { + .unused => metadata.atom.* = try self.createAtom(), + .pending_flush => return metadata.atom.*, + .flushed => {}, + } + metadata.state.* = .pending_flush; + const atom = metadata.atom.*; + // anyerror needs to be deferred until flushModule + if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { .code => self.text_section_index.?, .const_data => self.rdata_section_index.?, }); @@ -1617,15 +1608,35 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod sub_prog_node.activate(); defer sub_prog_node.end(); - // Most lazy symbols can be updated when the corresponding decl is, - // so we only have to worry about the one without an associated decl. - self.updateLazySymbol(null) catch |err| switch (err) { - error.CodegenFail => return error.FlushFailure, - else => |e| return e, - }; - const gpa = self.base.allocator; + const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; + + if (self.lazy_syms.getPtr(.none)) |metadata| { + // Most lazy symbols can be updated on first use, but + // anyerror needs to wait for everything to be flushed. + if (metadata.text_state != .unused) self.updateLazySymbolAtom( + link.File.LazySymbol.initDecl(.code, null, module), + metadata.text_atom, + self.text_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + if (metadata.rdata_state != .unused) self.updateLazySymbolAtom( + link.File.LazySymbol.initDecl(.const_data, null, module), + metadata.rdata_atom, + self.rdata_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + } + for (self.lazy_syms.values()) |*metadata| { + if (metadata.text_state != .unused) metadata.text_state = .flushed; + if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed; + } + while (self.unresolved.popOrNull()) |entry| { assert(entry.value); // We only expect imports generated by the incremental linker for now. const global = self.globals.items[entry.key]; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ec113e5c8a..724ec76500 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -65,8 +65,11 @@ const Section = struct { }; const LazySymbolMetadata = struct { - text_atom: ?Atom.Index = null, - rodata_atom: ?Atom.Index = null, + const State = enum { unused, pending_flush, flushed }; + text_atom: Atom.Index = undefined, + rodata_atom: Atom.Index = undefined, + text_state: State = .unused, + rodata_state: State = .unused, }; const DeclMetadata = struct { @@ -1032,17 +1035,35 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node sub_prog_node.activate(); defer sub_prog_node.end(); - // Most lazy symbols can be updated when the corresponding decl is, - // so we only have to worry about the one without an associated decl. - self.updateLazySymbol(null) catch |err| switch (err) { - error.CodegenFail => return error.FlushFailure, - else => |e| return e, - }; - // TODO This linker code currently assumes there is only 1 compilation unit and it // corresponds to the Zig source code. const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; + if (self.lazy_syms.getPtr(.none)) |metadata| { + // Most lazy symbols can be updated on first use, but + // anyerror needs to wait for everything to be flushed. + if (metadata.text_state != .unused) self.updateLazySymbolAtom( + File.LazySymbol.initDecl(.code, null, module), + metadata.text_atom, + self.text_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + if (metadata.rodata_state != .unused) self.updateLazySymbolAtom( + File.LazySymbol.initDecl(.const_data, null, module), + metadata.rodata_atom, + self.rodata_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + } + for (self.lazy_syms.values()) |*metadata| { + if (metadata.text_state != .unused) metadata.text_state = .flushed; + if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed; + } + const target_endian = self.base.options.target.cpu.arch.endian(); const foreign_endian = target_endian != builtin.cpu.arch.endian(); @@ -2378,14 +2399,19 @@ pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Inde const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom_ptr = switch (sym.kind) { - .code => &gop.value_ptr.text_atom, - .const_data => &gop.value_ptr.rodata_atom, + const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { + .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state }, + .const_data => .{ .atom = &gop.value_ptr.rodata_atom, .state = &gop.value_ptr.rodata_state }, }; - if (atom_ptr.*) |atom| return atom; - const atom = try self.createAtom(); - atom_ptr.* = atom; - try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + switch (metadata.state.*) { + .unused => metadata.atom.* = try self.createAtom(), + .pending_flush => return metadata.atom.*, + .flushed => {}, + } + metadata.state.* = .pending_flush; + const atom = metadata.atom.*; + // anyerror needs to be deferred until flushModule + if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { .code => self.text_section_index.?, .const_data => self.rodata_section_index.?, }); @@ -2598,8 +2624,6 @@ pub fn updateDecl( const tracy = trace(@src()); defer tracy.end(); - try self.updateLazySymbol(decl_index); - const decl = module.declPtr(decl_index); if (decl.val.tag() == .extern_fn) { @@ -2666,21 +2690,6 @@ pub fn updateDecl( return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn updateLazySymbol(self: *Elf, decl: ?Module.Decl.Index) !void { - const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return; - const mod = self.base.options.module.?; - if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( - File.LazySymbol.initDecl(.code, decl, mod), - atom, - self.text_section_index.?, - ); - if (metadata.rodata_atom) |atom| try self.updateLazySymbolAtom( - File.LazySymbol.initDecl(.const_data, decl, mod), - atom, - self.rodata_section_index.?, - ); -} - fn updateLazySymbolAtom( self: *Elf, sym: File.LazySymbol, diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 458b283d4f..a346ec756f 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -236,8 +236,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) { const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); const LazySymbolMetadata = struct { - text_atom: ?Atom.Index = null, - data_const_atom: ?Atom.Index = null, + const State = enum { unused, pending_flush, flushed }; + text_atom: Atom.Index = undefined, + data_const_atom: Atom.Index = undefined, + text_state: State = .unused, + data_const_state: State = .unused, }; const TlvSymbolTable = std.AutoArrayHashMapUnmanaged(SymbolWithLoc, Atom.Index); @@ -493,15 +496,33 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No sub_prog_node.activate(); defer sub_prog_node.end(); - // Most lazy symbols can be updated when the corresponding decl is, - // so we only have to worry about the one without an associated decl. - self.updateLazySymbol(null) catch |err| switch (err) { - error.CodegenFail => return error.FlushFailure, - else => |e| return e, - }; - const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; + if (self.lazy_syms.getPtr(.none)) |metadata| { + // Most lazy symbols can be updated on first use, but + // anyerror needs to wait for everything to be flushed. + if (metadata.text_state != .unused) self.updateLazySymbolAtom( + File.LazySymbol.initDecl(.code, null, module), + metadata.text_atom, + self.text_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + if (metadata.data_const_state != .unused) self.updateLazySymbolAtom( + File.LazySymbol.initDecl(.const_data, null, module), + metadata.data_const_atom, + self.data_const_section_index.?, + ) catch |err| return switch (err) { + error.CodegenFail => error.FlushFailure, + else => |e| e, + }; + } + for (self.lazy_syms.values()) |*metadata| { + if (metadata.text_state != .unused) metadata.text_state = .flushed; + if (metadata.data_const_state != .unused) metadata.data_const_state = .flushed; + } + if (self.d_sym) |*d_sym| { try d_sym.dwarf.flushModule(module); } @@ -1960,8 +1981,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) const tracy = trace(@src()); defer tracy.end(); - try self.updateLazySymbol(decl_index); - const decl = module.declPtr(decl_index); if (decl.val.tag() == .extern_fn) { @@ -2036,21 +2055,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn updateLazySymbol(self: *MachO, decl: ?Module.Decl.Index) !void { - const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return; - const mod = self.base.options.module.?; - if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( - File.LazySymbol.initDecl(.code, decl, mod), - atom, - self.text_section_index.?, - ); - if (metadata.data_const_atom) |atom| try self.updateLazySymbolAtom( - File.LazySymbol.initDecl(.const_data, decl, mod), - atom, - self.data_const_section_index.?, - ); -} - fn updateLazySymbolAtom( self: *MachO, sym: File.LazySymbol, @@ -2125,14 +2129,22 @@ pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.In const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; - const atom_ptr = switch (sym.kind) { - .code => &gop.value_ptr.text_atom, - .const_data => &gop.value_ptr.data_const_atom, + const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { + .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state }, + .const_data => .{ + .atom = &gop.value_ptr.data_const_atom, + .state = &gop.value_ptr.data_const_state, + }, }; - if (atom_ptr.*) |atom| return atom; - const atom = try self.createAtom(); - atom_ptr.* = atom; - try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { + switch (metadata.state.*) { + .unused => metadata.atom.* = try self.createAtom(), + .pending_flush => return metadata.atom.*, + .flushed => {}, + } + metadata.state.* = .pending_flush; + const atom = metadata.atom.*; + // anyerror needs to be deferred until flushModule + if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { .code => self.text_section_index.?, .const_data => self.data_const_section_index.?, });