authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-01 19:18:49-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-01 19:22:53-04:00
log3b1ea390a301dbdc992043d97cf618a94e8801de
tree7a3889971c17987ed1644945f1399e3c4309ed92
parentdb88b414722e698a392ec65a3ef46730341aea25

x86_64: cleanup lazy symbols

In theory fixes updating lazy symbols during incremental compilation.

4 files changed, 207 insertions(+), 213 deletions(-)

src/arch/x86_64/CodeGen.zig+76-114
......@@ -112,7 +112,7 @@ const Owner = union(enum) {
112112 mod_fn: *const Module.Fn,
113113 lazy_sym: link.File.LazySymbol,
114114
115 fn getOwnerDecl(owner: Owner) Module.Decl.Index {
115 fn getDecl(owner: Owner) Module.Decl.Index {
116116 return switch (owner) {
117117 .mod_fn => |mod_fn| mod_fn.owner_decl,
118118 .lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(),
......@@ -1688,35 +1688,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
16881688 const data_reg = try self.register_manager.allocReg(null, gp);
16891689 const data_lock = self.register_manager.lockRegAssumeUnused(data_reg);
16901690 defer self.register_manager.unlockReg(data_lock);
1691
1692 const data_lazy_sym = link.File.LazySymbol{ .kind = .const_data, .ty = enum_ty };
1693 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
1694 const atom_index = elf_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err|
1695 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
1696 const atom = elf_file.getAtom(atom_index);
1697 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
1698 const got_addr = atom.getOffsetTableAddress(elf_file);
1699 try self.asmRegisterMemory(
1700 .mov,
1701 data_reg.to64(),
1702 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }),
1703 );
1704 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
1705 const atom_index = coff_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err|
1706 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
1707 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
1708 try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index });
1709 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
1710 const atom_index = macho_file.getOrCreateAtomForLazySymbol(data_lazy_sym) catch |err|
1711 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
1712 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
1713 try self.genSetReg(data_reg, Type.usize, .{ .lea_got = sym_index });
1714 } else {
1715 return self.fail("TODO implement {s} for {}", .{
1716 @tagName(lazy_sym.kind),
1717 lazy_sym.ty.fmt(self.bin_file.options.module.?),
1718 });
1719 }
1691 try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty });
17201692
17211693 var data_off: i32 = 0;
17221694 for (
......@@ -6262,7 +6234,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
62626234 // TODO: this might need adjusting like the linkers do.
62636235 // Instead of flattening the owner and passing Decl.Index here we may
62646236 // want to special case LazySymbol in DWARF linker too.
6265 try dw.genArgDbgInfo(name, ty, self.owner.getOwnerDecl(), loc);
6237 try dw.genArgDbgInfo(name, ty, self.owner.getDecl(), loc);
62666238 },
62676239 .plan9 => {},
62686240 .none => {},
......@@ -6306,7 +6278,7 @@ fn genVarDbgInfo(
63066278 // TODO: this might need adjusting like the linkers do.
63076279 // Instead of flattening the owner and passing Decl.Index here we may
63086280 // want to special case LazySymbol in DWARF linker too.
6309 try dw.genVarDbgInfo(name, ty, self.owner.getOwnerDecl(), is_ptr, loc);
6281 try dw.genVarDbgInfo(name, ty, self.owner.getDecl(), is_ptr, loc);
63106282 },
63116283 .plan9 => {},
63126284 .none => {},
......@@ -6630,38 +6602,13 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
66306602}
66316603
66326604fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
6605 const mod = self.bin_file.options.module.?;
66336606 const un_op = self.air.instructions.items(.data)[inst].un_op;
66346607
66356608 const addr_reg = try self.register_manager.allocReg(null, gp);
66366609 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
66376610 defer self.register_manager.unlockReg(addr_lock);
6638
6639 const mod = self.bin_file.options.module.?;
6640 const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod);
6641 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6642 const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
6643 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
6644 const atom = elf_file.getAtom(atom_index);
6645 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
6646 const got_addr = atom.getOffsetTableAddress(elf_file);
6647 try self.asmRegisterMemory(
6648 .mov,
6649 addr_reg.to64(),
6650 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }),
6651 );
6652 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
6653 const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
6654 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
6655 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
6656 try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index });
6657 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6658 const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
6659 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
6660 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
6661 try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index });
6662 } else {
6663 return self.fail("TODO implement airCmpLtErrorsLen for x86_64 {s}", .{@tagName(self.bin_file.tag)});
6664 }
6611 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
66656612
66666613 try self.spillEflagsIfOccupied();
66676614 self.eflags_inst = inst;
......@@ -7999,6 +7946,67 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue)
79997946 });
80007947}
80017948
7949fn genLazySymbolRef(
7950 self: *Self,
7951 comptime tag: Mir.Inst.Tag,
7952 reg: Register,
7953 lazy_sym: link.File.LazySymbol,
7954) InnerError!void {
7955 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
7956 const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
7957 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
7958 const atom = elf_file.getAtom(atom_index);
7959 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
7960 const got_addr = atom.getOffsetTableAddress(elf_file);
7961 const got_mem =
7962 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) });
7963 switch (tag) {
7964 .lea, .mov => try self.asmRegisterMemory(.mov, reg.to64(), got_mem),
7965 .call => try self.asmMemory(.call, got_mem),
7966 else => unreachable,
7967 }
7968 switch (tag) {
7969 .lea, .call => {},
7970 .mov => try self.asmRegisterMemory(
7971 tag,
7972 reg.to64(),
7973 Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }),
7974 ),
7975 else => unreachable,
7976 }
7977 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
7978 const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
7979 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
7980 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
7981 switch (tag) {
7982 .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }),
7983 .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }),
7984 else => unreachable,
7985 }
7986 switch (tag) {
7987 .lea, .mov => {},
7988 .call => try self.asmRegister(.call, reg),
7989 else => unreachable,
7990 }
7991 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
7992 const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
7993 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
7994 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
7995 switch (tag) {
7996 .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }),
7997 .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }),
7998 else => unreachable,
7999 }
8000 switch (tag) {
8001 .lea, .mov => {},
8002 .call => try self.asmRegister(.call, reg),
8003 else => unreachable,
8004 }
8005 } else {
8006 return self.fail("TODO implement genLazySymbol for x86_64 {s}", .{@tagName(self.bin_file.tag)});
8007 }
8008}
8009
80028010fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
80038011 const un_op = self.air.instructions.items(.data)[inst].un_op;
80048012 const result = result: {
......@@ -8701,6 +8709,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
87018709}
87028710
87038711fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
8712 const mod = self.bin_file.options.module.?;
87048713 const un_op = self.air.instructions.items(.data)[inst].un_op;
87058714 const inst_ty = self.air.typeOfIndex(inst);
87068715 const enum_ty = self.air.typeOf(un_op);
......@@ -8731,38 +8740,17 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
87318740 const operand = try self.resolveInst(un_op);
87328741 try self.genSetReg(param_regs[1], enum_ty, operand);
87338742
8734 const mod = self.bin_file.options.module.?;
8735 const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod);
8736 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
8737 const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
8738 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
8739 const atom = elf_file.getAtom(atom_index);
8740 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
8741 const got_addr = atom.getOffsetTableAddress(elf_file);
8742 try self.asmMemory(
8743 .call,
8744 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }),
8745 );
8746 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
8747 const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
8748 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
8749 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
8750 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
8751 try self.asmRegister(.call, .rax);
8752 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
8753 const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
8754 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
8755 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
8756 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index });
8757 try self.asmRegister(.call, .rax);
8758 } else {
8759 return self.fail("TODO implement airTagName for x86_64 {s}", .{@tagName(self.bin_file.tag)});
8760 }
8743 try self.genLazySymbolRef(
8744 .call,
8745 .rax,
8746 link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod),
8747 );
87618748
87628749 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
87638750}
87648751
87658752fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8753 const mod = self.bin_file.options.module.?;
87668754 const un_op = self.air.instructions.items(.data)[inst].un_op;
87678755
87688756 const err_ty = self.air.typeOf(un_op);
......@@ -8774,33 +8762,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
87748762 const addr_reg = try self.register_manager.allocReg(null, gp);
87758763 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
87768764 defer self.register_manager.unlockReg(addr_lock);
8777
8778 const mod = self.bin_file.options.module.?;
8779 const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, mod);
8780 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
8781 const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
8782 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
8783 const atom = elf_file.getAtom(atom_index);
8784 _ = try atom.getOrCreateOffsetTableEntry(elf_file);
8785 const got_addr = atom.getOffsetTableAddress(elf_file);
8786 try self.asmRegisterMemory(
8787 .mov,
8788 addr_reg.to64(),
8789 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }),
8790 );
8791 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
8792 const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
8793 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
8794 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
8795 try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index });
8796 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
8797 const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
8798 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
8799 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
8800 try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index });
8801 } else {
8802 return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)});
8803 }
8765 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
88048766
88058767 const start_reg = try self.register_manager.allocReg(null, gp);
88068768 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
91179079}
91189080
91199081fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
9120 return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getOwnerDecl())) {
9082 return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl())) {
91219083 .mcv => |mcv| switch (mcv) {
91229084 .none => .none,
91239085 .undef => .undef,
src/link/Coff.zig+44-33
......@@ -143,8 +143,11 @@ const Section = struct {
143143const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
144144
145145const LazySymbolMetadata = struct {
146 text_atom: ?Atom.Index = null,
147 rdata_atom: ?Atom.Index = null,
146 const State = enum { unused, pending_flush, flushed };
147 text_atom: Atom.Index = undefined,
148 rdata_atom: Atom.Index = undefined,
149 text_state: State = .unused,
150 rdata_state: State = .unused,
148151};
149152
150153const DeclMetadata = struct {
......@@ -1150,8 +1153,6 @@ pub fn updateDecl(
11501153 const tracy = trace(@src());
11511154 defer tracy.end();
11521155
1153 try self.updateLazySymbol(decl_index);
1154
11551156 const decl = module.declPtr(decl_index);
11561157
11571158 if (decl.val.tag() == .extern_fn) {
......@@ -1194,21 +1195,6 @@ pub fn updateDecl(
11941195 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
11951196}
11961197
1197fn updateLazySymbol(self: *Coff, decl: ?Module.Decl.Index) !void {
1198 const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return;
1199 const mod = self.base.options.module.?;
1200 if (metadata.text_atom) |atom| try self.updateLazySymbolAtom(
1201 link.File.LazySymbol.initDecl(.code, decl, mod),
1202 atom,
1203 self.text_section_index.?,
1204 );
1205 if (metadata.rdata_atom) |atom| try self.updateLazySymbolAtom(
1206 link.File.LazySymbol.initDecl(.const_data, decl, mod),
1207 atom,
1208 self.rdata_section_index.?,
1209 );
1210}
1211
12121198fn updateLazySymbolAtom(
12131199 self: *Coff,
12141200 sym: link.File.LazySymbol,
......@@ -1279,14 +1265,19 @@ pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Ato
12791265 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
12801266 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
12811267 if (!gop.found_existing) gop.value_ptr.* = .{};
1282 const atom_ptr = switch (sym.kind) {
1283 .code => &gop.value_ptr.text_atom,
1284 .const_data => &gop.value_ptr.rdata_atom,
1268 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
1269 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
1270 .const_data => .{ .atom = &gop.value_ptr.rdata_atom, .state = &gop.value_ptr.rdata_state },
12851271 };
1286 if (atom_ptr.*) |atom| return atom;
1287 const atom = try self.createAtom();
1288 atom_ptr.* = atom;
1289 try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {
1272 switch (metadata.state.*) {
1273 .unused => metadata.atom.* = try self.createAtom(),
1274 .pending_flush => return metadata.atom.*,
1275 .flushed => {},
1276 }
1277 metadata.state.* = .pending_flush;
1278 const atom = metadata.atom.*;
1279 // anyerror needs to be deferred until flushModule
1280 if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {
12901281 .code => self.text_section_index.?,
12911282 .const_data => self.rdata_section_index.?,
12921283 });
......@@ -1617,15 +1608,35 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
16171608 sub_prog_node.activate();
16181609 defer sub_prog_node.end();
16191610
1620 // Most lazy symbols can be updated when the corresponding decl is,
1621 // so we only have to worry about the one without an associated decl.
1622 self.updateLazySymbol(null) catch |err| switch (err) {
1623 error.CodegenFail => return error.FlushFailure,
1624 else => |e| return e,
1625 };
1626
16271611 const gpa = self.base.allocator;
16281612
1613 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
1614
1615 if (self.lazy_syms.getPtr(.none)) |metadata| {
1616 // Most lazy symbols can be updated on first use, but
1617 // anyerror needs to wait for everything to be flushed.
1618 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
1619 link.File.LazySymbol.initDecl(.code, null, module),
1620 metadata.text_atom,
1621 self.text_section_index.?,
1622 ) catch |err| return switch (err) {
1623 error.CodegenFail => error.FlushFailure,
1624 else => |e| e,
1625 };
1626 if (metadata.rdata_state != .unused) self.updateLazySymbolAtom(
1627 link.File.LazySymbol.initDecl(.const_data, null, module),
1628 metadata.rdata_atom,
1629 self.rdata_section_index.?,
1630 ) catch |err| return switch (err) {
1631 error.CodegenFail => error.FlushFailure,
1632 else => |e| e,
1633 };
1634 }
1635 for (self.lazy_syms.values()) |*metadata| {
1636 if (metadata.text_state != .unused) metadata.text_state = .flushed;
1637 if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed;
1638 }
1639
16291640 while (self.unresolved.popOrNull()) |entry| {
16301641 assert(entry.value); // We only expect imports generated by the incremental linker for now.
16311642 const global = self.globals.items[entry.key];
src/link/Elf.zig+42-33
......@@ -65,8 +65,11 @@ const Section = struct {
6565};
6666
6767const LazySymbolMetadata = struct {
68 text_atom: ?Atom.Index = null,
69 rodata_atom: ?Atom.Index = null,
68 const State = enum { unused, pending_flush, flushed };
69 text_atom: Atom.Index = undefined,
70 rodata_atom: Atom.Index = undefined,
71 text_state: State = .unused,
72 rodata_state: State = .unused,
7073};
7174
7275const DeclMetadata = struct {
......@@ -1032,17 +1035,35 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10321035 sub_prog_node.activate();
10331036 defer sub_prog_node.end();
10341037
1035 // Most lazy symbols can be updated when the corresponding decl is,
1036 // so we only have to worry about the one without an associated decl.
1037 self.updateLazySymbol(null) catch |err| switch (err) {
1038 error.CodegenFail => return error.FlushFailure,
1039 else => |e| return e,
1040 };
1041
10421038 // TODO This linker code currently assumes there is only 1 compilation unit and it
10431039 // corresponds to the Zig source code.
10441040 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
10451041
1042 if (self.lazy_syms.getPtr(.none)) |metadata| {
1043 // Most lazy symbols can be updated on first use, but
1044 // anyerror needs to wait for everything to be flushed.
1045 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
1046 File.LazySymbol.initDecl(.code, null, module),
1047 metadata.text_atom,
1048 self.text_section_index.?,
1049 ) catch |err| return switch (err) {
1050 error.CodegenFail => error.FlushFailure,
1051 else => |e| e,
1052 };
1053 if (metadata.rodata_state != .unused) self.updateLazySymbolAtom(
1054 File.LazySymbol.initDecl(.const_data, null, module),
1055 metadata.rodata_atom,
1056 self.rodata_section_index.?,
1057 ) catch |err| return switch (err) {
1058 error.CodegenFail => error.FlushFailure,
1059 else => |e| e,
1060 };
1061 }
1062 for (self.lazy_syms.values()) |*metadata| {
1063 if (metadata.text_state != .unused) metadata.text_state = .flushed;
1064 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
1065 }
1066
10461067 const target_endian = self.base.options.target.cpu.arch.endian();
10471068 const foreign_endian = target_endian != builtin.cpu.arch.endian();
10481069
......@@ -2378,14 +2399,19 @@ pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Inde
23782399 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
23792400 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
23802401 if (!gop.found_existing) gop.value_ptr.* = .{};
2381 const atom_ptr = switch (sym.kind) {
2382 .code => &gop.value_ptr.text_atom,
2383 .const_data => &gop.value_ptr.rodata_atom,
2402 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
2403 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
2404 .const_data => .{ .atom = &gop.value_ptr.rodata_atom, .state = &gop.value_ptr.rodata_state },
23842405 };
2385 if (atom_ptr.*) |atom| return atom;
2386 const atom = try self.createAtom();
2387 atom_ptr.* = atom;
2388 try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {
2406 switch (metadata.state.*) {
2407 .unused => metadata.atom.* = try self.createAtom(),
2408 .pending_flush => return metadata.atom.*,
2409 .flushed => {},
2410 }
2411 metadata.state.* = .pending_flush;
2412 const atom = metadata.atom.*;
2413 // anyerror needs to be deferred until flushModule
2414 if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {
23892415 .code => self.text_section_index.?,
23902416 .const_data => self.rodata_section_index.?,
23912417 });
......@@ -2598,8 +2624,6 @@ pub fn updateDecl(
25982624 const tracy = trace(@src());
25992625 defer tracy.end();
26002626
2601 try self.updateLazySymbol(decl_index);
2602
26032627 const decl = module.declPtr(decl_index);
26042628
26052629 if (decl.val.tag() == .extern_fn) {
......@@ -2666,21 +2690,6 @@ pub fn updateDecl(
26662690 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
26672691}
26682692
2669fn updateLazySymbol(self: *Elf, decl: ?Module.Decl.Index) !void {
2670 const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return;
2671 const mod = self.base.options.module.?;
2672 if (metadata.text_atom) |atom| try self.updateLazySymbolAtom(
2673 File.LazySymbol.initDecl(.code, decl, mod),
2674 atom,
2675 self.text_section_index.?,
2676 );
2677 if (metadata.rodata_atom) |atom| try self.updateLazySymbolAtom(
2678 File.LazySymbol.initDecl(.const_data, decl, mod),
2679 atom,
2680 self.rodata_section_index.?,
2681 );
2682}
2683
26842693fn updateLazySymbolAtom(
26852694 self: *Elf,
26862695 sym: File.LazySymbol,
src/link/MachO.zig+45-33
......@@ -236,8 +236,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
236236const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
237237
238238const LazySymbolMetadata = struct {
239 text_atom: ?Atom.Index = null,
240 data_const_atom: ?Atom.Index = null,
239 const State = enum { unused, pending_flush, flushed };
240 text_atom: Atom.Index = undefined,
241 data_const_atom: Atom.Index = undefined,
242 text_state: State = .unused,
243 data_const_state: State = .unused,
241244};
242245
243246const TlvSymbolTable = std.AutoArrayHashMapUnmanaged(SymbolWithLoc, Atom.Index);
......@@ -493,15 +496,33 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
493496 sub_prog_node.activate();
494497 defer sub_prog_node.end();
495498
496 // Most lazy symbols can be updated when the corresponding decl is,
497 // so we only have to worry about the one without an associated decl.
498 self.updateLazySymbol(null) catch |err| switch (err) {
499 error.CodegenFail => return error.FlushFailure,
500 else => |e| return e,
501 };
502
503499 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
504500
501 if (self.lazy_syms.getPtr(.none)) |metadata| {
502 // Most lazy symbols can be updated on first use, but
503 // anyerror needs to wait for everything to be flushed.
504 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
505 File.LazySymbol.initDecl(.code, null, module),
506 metadata.text_atom,
507 self.text_section_index.?,
508 ) catch |err| return switch (err) {
509 error.CodegenFail => error.FlushFailure,
510 else => |e| e,
511 };
512 if (metadata.data_const_state != .unused) self.updateLazySymbolAtom(
513 File.LazySymbol.initDecl(.const_data, null, module),
514 metadata.data_const_atom,
515 self.data_const_section_index.?,
516 ) catch |err| return switch (err) {
517 error.CodegenFail => error.FlushFailure,
518 else => |e| e,
519 };
520 }
521 for (self.lazy_syms.values()) |*metadata| {
522 if (metadata.text_state != .unused) metadata.text_state = .flushed;
523 if (metadata.data_const_state != .unused) metadata.data_const_state = .flushed;
524 }
525
505526 if (self.d_sym) |*d_sym| {
506527 try d_sym.dwarf.flushModule(module);
507528 }
......@@ -1960,8 +1981,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
19601981 const tracy = trace(@src());
19611982 defer tracy.end();
19621983
1963 try self.updateLazySymbol(decl_index);
1964
19651984 const decl = module.declPtr(decl_index);
19661985
19671986 if (decl.val.tag() == .extern_fn) {
......@@ -2036,21 +2055,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
20362055 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
20372056}
20382057
2039fn updateLazySymbol(self: *MachO, decl: ?Module.Decl.Index) !void {
2040 const metadata = self.lazy_syms.get(Module.Decl.OptionalIndex.init(decl)) orelse return;
2041 const mod = self.base.options.module.?;
2042 if (metadata.text_atom) |atom| try self.updateLazySymbolAtom(
2043 File.LazySymbol.initDecl(.code, decl, mod),
2044 atom,
2045 self.text_section_index.?,
2046 );
2047 if (metadata.data_const_atom) |atom| try self.updateLazySymbolAtom(
2048 File.LazySymbol.initDecl(.const_data, decl, mod),
2049 atom,
2050 self.data_const_section_index.?,
2051 );
2052}
2053
20542058fn updateLazySymbolAtom(
20552059 self: *MachO,
20562060 sym: File.LazySymbol,
......@@ -2125,14 +2129,22 @@ pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.In
21252129 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
21262130 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
21272131 if (!gop.found_existing) gop.value_ptr.* = .{};
2128 const atom_ptr = switch (sym.kind) {
2129 .code => &gop.value_ptr.text_atom,
2130 .const_data => &gop.value_ptr.data_const_atom,
2132 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
2133 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
2134 .const_data => .{
2135 .atom = &gop.value_ptr.data_const_atom,
2136 .state = &gop.value_ptr.data_const_state,
2137 },
21312138 };
2132 if (atom_ptr.*) |atom| return atom;
2133 const atom = try self.createAtom();
2134 atom_ptr.* = atom;
2135 try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {
2139 switch (metadata.state.*) {
2140 .unused => metadata.atom.* = try self.createAtom(),
2141 .pending_flush => return metadata.atom.*,
2142 .flushed => {},
2143 }
2144 metadata.state.* = .pending_flush;
2145 const atom = metadata.atom.*;
2146 // anyerror needs to be deferred until flushModule
2147 if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {
21362148 .code => self.text_section_index.?,
21372149 .const_data => self.data_const_section_index.?,
21382150 });