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) {...@@ -112,7 +112,7 @@ const Owner = union(enum) {
112 mod_fn: *const Module.Fn,112 mod_fn: *const Module.Fn,
113 lazy_sym: link.File.LazySymbol,113 lazy_sym: link.File.LazySymbol,
114114
115 fn getOwnerDecl(owner: Owner) Module.Decl.Index {115 fn getDecl(owner: Owner) Module.Decl.Index {
116 return switch (owner) {116 return switch (owner) {
117 .mod_fn => |mod_fn| mod_fn.owner_decl,117 .mod_fn => |mod_fn| mod_fn.owner_decl,
118 .lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(),118 .lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(),
...@@ -1688,35 +1688,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -1688,35 +1688,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
1688 const data_reg = try self.register_manager.allocReg(null, gp);1688 const data_reg = try self.register_manager.allocReg(null, gp);
1689 const data_lock = self.register_manager.lockRegAssumeUnused(data_reg);1689 const data_lock = self.register_manager.lockRegAssumeUnused(data_reg);
1690 defer self.register_manager.unlockReg(data_lock);1690 defer self.register_manager.unlockReg(data_lock);
16911691 try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty });
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 }
17201692
1721 var data_off: i32 = 0;1693 var data_off: i32 = 0;
1722 for (1694 for (
...@@ -6262,7 +6234,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {...@@ -6262,7 +6234,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
6262 // TODO: this might need adjusting like the linkers do.6234 // TODO: this might need adjusting like the linkers do.
6263 // Instead of flattening the owner and passing Decl.Index here we may6235 // Instead of flattening the owner and passing Decl.Index here we may
6264 // want to special case LazySymbol in DWARF linker too.6236 // 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);
6266 },6238 },
6267 .plan9 => {},6239 .plan9 => {},
6268 .none => {},6240 .none => {},
...@@ -6306,7 +6278,7 @@ fn genVarDbgInfo(...@@ -6306,7 +6278,7 @@ fn genVarDbgInfo(
6306 // TODO: this might need adjusting like the linkers do.6278 // TODO: this might need adjusting like the linkers do.
6307 // Instead of flattening the owner and passing Decl.Index here we may6279 // Instead of flattening the owner and passing Decl.Index here we may
6308 // want to special case LazySymbol in DWARF linker too.6280 // 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);
6310 },6282 },
6311 .plan9 => {},6283 .plan9 => {},
6312 .none => {},6284 .none => {},
...@@ -6630,38 +6602,13 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {...@@ -6630,38 +6602,13 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
6630}6602}
66316603
6632fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {6604fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
6605 const mod = self.bin_file.options.module.?;
6633 const un_op = self.air.instructions.items(.data)[inst].un_op;6606 const un_op = self.air.instructions.items(.data)[inst].un_op;
66346607
6635 const addr_reg = try self.register_manager.allocReg(null, gp);6608 const addr_reg = try self.register_manager.allocReg(null, gp);
6636 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);6609 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
6637 defer self.register_manager.unlockReg(addr_lock);6610 defer self.register_manager.unlockReg(addr_lock);
66386611 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
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 }
66656612
6666 try self.spillEflagsIfOccupied();6613 try self.spillEflagsIfOccupied();
6667 self.eflags_inst = inst;6614 self.eflags_inst = inst;
...@@ -7999,6 +7946,67 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue)...@@ -7999,6 +7946,67 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue)
7999 });7946 });
8000}7947}
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
8002fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {8010fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
8003 const un_op = self.air.instructions.items(.data)[inst].un_op;8011 const un_op = self.air.instructions.items(.data)[inst].un_op;
8004 const result = result: {8012 const result = result: {
...@@ -8701,6 +8709,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -8701,6 +8709,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
8701}8709}
87028710
8703fn airTagName(self: *Self, inst: Air.Inst.Index) !void {8711fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
8712 const mod = self.bin_file.options.module.?;
8704 const un_op = self.air.instructions.items(.data)[inst].un_op;8713 const un_op = self.air.instructions.items(.data)[inst].un_op;
8705 const inst_ty = self.air.typeOfIndex(inst);8714 const inst_ty = self.air.typeOfIndex(inst);
8706 const enum_ty = self.air.typeOf(un_op);8715 const enum_ty = self.air.typeOf(un_op);
...@@ -8731,38 +8740,17 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8731,38 +8740,17 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
8731 const operand = try self.resolveInst(un_op);8740 const operand = try self.resolveInst(un_op);
8732 try self.genSetReg(param_regs[1], enum_ty, operand);8741 try self.genSetReg(param_regs[1], enum_ty, operand);
87338742
8734 const mod = self.bin_file.options.module.?;8743 try self.genLazySymbolRef(
8735 const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod);8744 .call,
8736 if (self.bin_file.cast(link.File.Elf)) |elf_file| {8745 .rax,
8737 const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|8746 link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod),
8738 return self.fail("{s} creating lazy symbol", .{@errorName(err)});8747 );
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 }
87618748
8762 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });8749 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
8763}8750}
87648751
8765fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {8752fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8753 const mod = self.bin_file.options.module.?;
8766 const un_op = self.air.instructions.items(.data)[inst].un_op;8754 const un_op = self.air.instructions.items(.data)[inst].un_op;
87678755
8768 const err_ty = self.air.typeOf(un_op);8756 const err_ty = self.air.typeOf(un_op);
...@@ -8774,33 +8762,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8774,33 +8762,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8774 const addr_reg = try self.register_manager.allocReg(null, gp);8762 const addr_reg = try self.register_manager.allocReg(null, gp);
8775 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);8763 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
8776 defer self.register_manager.unlockReg(addr_lock);8764 defer self.register_manager.unlockReg(addr_lock);
87778765 try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod));
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 }
88048766
8805 const start_reg = try self.register_manager.allocReg(null, gp);8767 const start_reg = try self.register_manager.allocReg(null, gp);
8806 const start_lock = self.register_manager.lockRegAssumeUnused(start_reg);8768 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...@@ -9117,7 +9079,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
9117}9079}
91189080
9119fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {9081fn 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())) {
9121 .mcv => |mcv| switch (mcv) {9083 .mcv => |mcv| switch (mcv) {
9122 .none => .none,9084 .none => .none,
9123 .undef => .undef,9085 .undef => .undef,
src/link/Coff.zig+44-33
...@@ -143,8 +143,11 @@ const Section = struct {...@@ -143,8 +143,11 @@ const Section = struct {
143const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);143const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
144144
145const LazySymbolMetadata = struct {145const LazySymbolMetadata = struct {
146 text_atom: ?Atom.Index = null,146 const State = enum { unused, pending_flush, flushed };
147 rdata_atom: ?Atom.Index = null,147 text_atom: Atom.Index = undefined,
148 rdata_atom: Atom.Index = undefined,
149 text_state: State = .unused,
150 rdata_state: State = .unused,
148};151};
149152
150const DeclMetadata = struct {153const DeclMetadata = struct {
...@@ -1150,8 +1153,6 @@ pub fn updateDecl(...@@ -1150,8 +1153,6 @@ pub fn updateDecl(
1150 const tracy = trace(@src());1153 const tracy = trace(@src());
1151 defer tracy.end();1154 defer tracy.end();
11521155
1153 try self.updateLazySymbol(decl_index);
1154
1155 const decl = module.declPtr(decl_index);1156 const decl = module.declPtr(decl_index);
11561157
1157 if (decl.val.tag() == .extern_fn) {1158 if (decl.val.tag() == .extern_fn) {
...@@ -1194,21 +1195,6 @@ pub fn updateDecl(...@@ -1194,21 +1195,6 @@ pub fn updateDecl(
1194 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));1195 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
1195}1196}
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
1212fn updateLazySymbolAtom(1198fn updateLazySymbolAtom(
1213 self: *Coff,1199 self: *Coff,
1214 sym: link.File.LazySymbol,1200 sym: link.File.LazySymbol,
...@@ -1279,14 +1265,19 @@ pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Ato...@@ -1279,14 +1265,19 @@ pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Ato
1279 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());1265 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
1280 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();1266 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
1281 if (!gop.found_existing) gop.value_ptr.* = .{};1267 if (!gop.found_existing) gop.value_ptr.* = .{};
1282 const atom_ptr = switch (sym.kind) {1268 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
1283 .code => &gop.value_ptr.text_atom,1269 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
1284 .const_data => &gop.value_ptr.rdata_atom,1270 .const_data => .{ .atom = &gop.value_ptr.rdata_atom, .state = &gop.value_ptr.rdata_state },
1285 };1271 };
1286 if (atom_ptr.*) |atom| return atom;1272 switch (metadata.state.*) {
1287 const atom = try self.createAtom();1273 .unused => metadata.atom.* = try self.createAtom(),
1288 atom_ptr.* = atom;1274 .pending_flush => return metadata.atom.*,
1289 try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {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) {
1290 .code => self.text_section_index.?,1281 .code => self.text_section_index.?,
1291 .const_data => self.rdata_section_index.?,1282 .const_data => self.rdata_section_index.?,
1292 });1283 });
...@@ -1617,15 +1608,35 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1617,15 +1608,35 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1617 sub_prog_node.activate();1608 sub_prog_node.activate();
1618 defer sub_prog_node.end();1609 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
1627 const gpa = self.base.allocator;1611 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
1629 while (self.unresolved.popOrNull()) |entry| {1640 while (self.unresolved.popOrNull()) |entry| {
1630 assert(entry.value); // We only expect imports generated by the incremental linker for now.1641 assert(entry.value); // We only expect imports generated by the incremental linker for now.
1631 const global = self.globals.items[entry.key];1642 const global = self.globals.items[entry.key];
src/link/Elf.zig+42-33
...@@ -65,8 +65,11 @@ const Section = struct {...@@ -65,8 +65,11 @@ const Section = struct {
65};65};
6666
67const LazySymbolMetadata = struct {67const LazySymbolMetadata = struct {
68 text_atom: ?Atom.Index = null,68 const State = enum { unused, pending_flush, flushed };
69 rodata_atom: ?Atom.Index = null,69 text_atom: Atom.Index = undefined,
70 rodata_atom: Atom.Index = undefined,
71 text_state: State = .unused,
72 rodata_state: State = .unused,
70};73};
7174
72const DeclMetadata = struct {75const DeclMetadata = struct {
...@@ -1032,17 +1035,35 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1032,17 +1035,35 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1032 sub_prog_node.activate();1035 sub_prog_node.activate();
1033 defer sub_prog_node.end();1036 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
1042 // TODO This linker code currently assumes there is only 1 compilation unit and it1038 // TODO This linker code currently assumes there is only 1 compilation unit and it
1043 // corresponds to the Zig source code.1039 // corresponds to the Zig source code.
1044 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;1040 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
1046 const target_endian = self.base.options.target.cpu.arch.endian();1067 const target_endian = self.base.options.target.cpu.arch.endian();
1047 const foreign_endian = target_endian != builtin.cpu.arch.endian();1068 const foreign_endian = target_endian != builtin.cpu.arch.endian();
10481069
...@@ -2378,14 +2399,19 @@ pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Inde...@@ -2378,14 +2399,19 @@ pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Inde
2378 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());2399 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
2379 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();2400 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
2380 if (!gop.found_existing) gop.value_ptr.* = .{};2401 if (!gop.found_existing) gop.value_ptr.* = .{};
2381 const atom_ptr = switch (sym.kind) {2402 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
2382 .code => &gop.value_ptr.text_atom,2403 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
2383 .const_data => &gop.value_ptr.rodata_atom,2404 .const_data => .{ .atom = &gop.value_ptr.rodata_atom, .state = &gop.value_ptr.rodata_state },
2384 };2405 };
2385 if (atom_ptr.*) |atom| return atom;2406 switch (metadata.state.*) {
2386 const atom = try self.createAtom();2407 .unused => metadata.atom.* = try self.createAtom(),
2387 atom_ptr.* = atom;2408 .pending_flush => return metadata.atom.*,
2388 try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {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) {
2389 .code => self.text_section_index.?,2415 .code => self.text_section_index.?,
2390 .const_data => self.rodata_section_index.?,2416 .const_data => self.rodata_section_index.?,
2391 });2417 });
...@@ -2598,8 +2624,6 @@ pub fn updateDecl(...@@ -2598,8 +2624,6 @@ pub fn updateDecl(
2598 const tracy = trace(@src());2624 const tracy = trace(@src());
2599 defer tracy.end();2625 defer tracy.end();
26002626
2601 try self.updateLazySymbol(decl_index);
2602
2603 const decl = module.declPtr(decl_index);2627 const decl = module.declPtr(decl_index);
26042628
2605 if (decl.val.tag() == .extern_fn) {2629 if (decl.val.tag() == .extern_fn) {
...@@ -2666,21 +2690,6 @@ pub fn updateDecl(...@@ -2666,21 +2690,6 @@ pub fn updateDecl(
2666 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));2690 return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
2667}2691}
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
2684fn updateLazySymbolAtom(2693fn updateLazySymbolAtom(
2685 self: *Elf,2694 self: *Elf,
2686 sym: File.LazySymbol,2695 sym: File.LazySymbol,
src/link/MachO.zig+45-33
...@@ -236,8 +236,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {...@@ -236,8 +236,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
236const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);236const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
237237
238const LazySymbolMetadata = struct {238const LazySymbolMetadata = struct {
239 text_atom: ?Atom.Index = null,239 const State = enum { unused, pending_flush, flushed };
240 data_const_atom: ?Atom.Index = null,240 text_atom: Atom.Index = undefined,
241 data_const_atom: Atom.Index = undefined,
242 text_state: State = .unused,
243 data_const_state: State = .unused,
241};244};
242245
243const TlvSymbolTable = std.AutoArrayHashMapUnmanaged(SymbolWithLoc, Atom.Index);246const TlvSymbolTable = std.AutoArrayHashMapUnmanaged(SymbolWithLoc, Atom.Index);
...@@ -493,15 +496,33 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -493,15 +496,33 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
493 sub_prog_node.activate();496 sub_prog_node.activate();
494 defer sub_prog_node.end();497 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
503 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;499 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
505 if (self.d_sym) |*d_sym| {526 if (self.d_sym) |*d_sym| {
506 try d_sym.dwarf.flushModule(module);527 try d_sym.dwarf.flushModule(module);
507 }528 }
...@@ -1960,8 +1981,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -1960,8 +1981,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
1960 const tracy = trace(@src());1981 const tracy = trace(@src());
1961 defer tracy.end();1982 defer tracy.end();
19621983
1963 try self.updateLazySymbol(decl_index);
1964
1965 const decl = module.declPtr(decl_index);1984 const decl = module.declPtr(decl_index);
19661985
1967 if (decl.val.tag() == .extern_fn) {1986 if (decl.val.tag() == .extern_fn) {
...@@ -2036,21 +2055,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -2036,21 +2055,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
2036 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));2055 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
2037}2056}
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
2054fn updateLazySymbolAtom(2058fn updateLazySymbolAtom(
2055 self: *MachO,2059 self: *MachO,
2056 sym: File.LazySymbol,2060 sym: File.LazySymbol,
...@@ -2125,14 +2129,22 @@ pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.In...@@ -2125,14 +2129,22 @@ pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.In
2125 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());2129 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl());
2126 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();2130 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
2127 if (!gop.found_existing) gop.value_ptr.* = .{};2131 if (!gop.found_existing) gop.value_ptr.* = .{};
2128 const atom_ptr = switch (sym.kind) {2132 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
2129 .code => &gop.value_ptr.text_atom,2133 .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state },
2130 .const_data => &gop.value_ptr.data_const_atom,2134 .const_data => .{
2135 .atom = &gop.value_ptr.data_const_atom,
2136 .state = &gop.value_ptr.data_const_state,
2137 },
2131 };2138 };
2132 if (atom_ptr.*) |atom| return atom;2139 switch (metadata.state.*) {
2133 const atom = try self.createAtom();2140 .unused => metadata.atom.* = try self.createAtom(),
2134 atom_ptr.* = atom;2141 .pending_flush => return metadata.atom.*,
2135 try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) {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) {
2136 .code => self.text_section_index.?,2148 .code => self.text_section_index.?,
2137 .const_data => self.data_const_section_index.?,2149 .const_data => self.data_const_section_index.?,
2138 });2150 });