aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2023-05-01 19:18:49 -0400
committerJacob Young <jacobly0@users.noreply.github.com>2023-05-01 19:22:53 -0400
commit3b1ea390a301dbdc992043d97cf618a94e8801de (patch)
tree7a3889971c17987ed1644945f1399e3c4309ed92 /src/link
parentdb88b414722e698a392ec65a3ef46730341aea25 (diff)
downloadzig-3b1ea390a301dbdc992043d97cf618a94e8801de.tar.gz
zig-3b1ea390a301dbdc992043d97cf618a94e8801de.zip
x86_64: cleanup lazy symbols
In theory fixes updating lazy symbols during incremental compilation.
Diffstat (limited to 'src/link')
-rw-r--r--src/link/Coff.zig77
-rw-r--r--src/link/Elf.zig75
-rw-r--r--src/link/MachO.zig78
3 files changed, 131 insertions, 99 deletions
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.?,
});