Commit cb25d8e4bc
Changed files (1)
src-self-hosted
src-self-hosted/link.zig
@@ -1731,11 +1731,8 @@ pub const File = struct {
pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
if (decl.link.local_sym_index != 0) return;
- // Here we also ensure capacity for the free lists so that they can be appended to without fail.
try self.local_symbols.ensureCapacity(self.allocator, self.local_symbols.items.len + 1);
- try self.local_symbol_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len);
try self.offset_table.ensureCapacity(self.allocator, self.offset_table.items.len + 1);
- try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len);
if (self.local_symbol_free_list.popOrNull()) |i| {
log.debug(.link, "reusing symbol index {} for {}\n", .{ i, decl.name });
@@ -1768,15 +1765,37 @@ pub const File = struct {
}
pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
+ // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
self.freeTextBlock(&decl.link);
if (decl.link.local_sym_index != 0) {
- self.local_symbol_free_list.appendAssumeCapacity(decl.link.local_sym_index);
- self.offset_table_free_list.appendAssumeCapacity(decl.link.offset_table_index);
+ self.local_symbol_free_list.append(self.allocator, decl.link.local_sym_index) catch {};
+ self.offset_table_free_list.append(self.allocator, decl.link.offset_table_index) catch {};
self.local_symbols.items[decl.link.local_sym_index].st_info = 0;
decl.link.local_sym_index = 0;
}
+ // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing
+ // is desired for both.
+ _ = self.dbg_line_fn_free_list.remove(&decl.fn_link);
+ if (decl.fn_link.prev) |prev| {
+ _ = self.dbg_line_fn_free_list.put(self.allocator, prev, {}) catch {};
+ prev.next = decl.fn_link.next;
+ if (decl.fn_link.next) |next| {
+ next.prev = prev;
+ } else {
+ self.dbg_line_fn_last = prev;
+ }
+ } else if (decl.fn_link.next) |next| {
+ self.dbg_line_fn_first = next;
+ next.prev = null;
+ }
+ if (self.dbg_line_fn_first == &decl.fn_link) {
+ self.dbg_line_fn_first = null;
+ }
+ if (self.dbg_line_fn_last == &decl.fn_link) {
+ self.dbg_line_fn_last = null;
+ }
}
pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
@@ -1923,18 +1942,35 @@ pub const File = struct {
const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
const src_fn = &decl.fn_link;
+ src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
if (self.dbg_line_fn_last) |last| {
- if (src_fn.prev == null and src_fn.next == null) {
+ if (src_fn.next) |next| {
+ // Update existing function - non-last item.
+ if (src_fn.off + src_fn.len + min_nop_size > next.off) {
+ // It grew too big, so we move it to a new location.
+ if (src_fn.prev) |prev| {
+ _ = self.dbg_line_fn_free_list.put(self.allocator, prev, {}) catch {};
+ prev.next = src_fn.next;
+ }
+ next.prev = src_fn.prev;
+ // Populate where it used to be with NOPs.
+ const file_pos = debug_line_sect.sh_offset + src_fn.off;
+ try self.pwriteWithNops(0, &[0]u8{}, src_fn.len, file_pos);
+ // TODO Look at the free list before appending at the end.
+ src_fn.prev = last;
+ last.next = src_fn;
+ self.dbg_line_fn_last = src_fn;
+
+ src_fn.off = last.off + (last.len * alloc_num / alloc_den);
+ }
+ } else if (src_fn.prev == null) {
// Append new function.
+ // TODO Look at the free list before appending at the end.
src_fn.prev = last;
last.next = src_fn;
self.dbg_line_fn_last = src_fn;
src_fn.off = last.off + (last.len * alloc_num / alloc_den);
- src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
- } else {
- // Update existing function.
- @panic("TODO updateDecl for .debug_line: add new SrcFn: update");
}
} else {
// This is the first function of the Line Number Program.
@@ -1942,7 +1978,6 @@ pub const File = struct {
self.dbg_line_fn_last = src_fn;
src_fn.off = self.dbgLineNeededHeaderBytes() * alloc_num / alloc_den;
- src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
}
const needed_size = src_fn.off + src_fn.len;
@@ -1982,10 +2017,7 @@ pub const File = struct {
const tracy = trace(@src());
defer tracy.end();
- // In addition to ensuring capacity for global_symbols, we also ensure capacity for freeing all of
- // them, so that deleting exports is guaranteed to succeed.
try self.global_symbols.ensureCapacity(self.allocator, self.global_symbols.items.len + exports.len);
- try self.global_symbol_free_list.ensureCapacity(self.allocator, self.global_symbols.items.len);
const typed_value = decl.typed_value.most_recent.typed_value;
if (decl.link.local_sym_index == 0) return;
const decl_sym = self.local_symbols.items[decl.link.local_sym_index];
@@ -2052,7 +2084,7 @@ pub const File = struct {
pub fn deleteExport(self: *Elf, exp: Export) void {
const sym_index = exp.sym_index orelse return;
- self.global_symbol_free_list.appendAssumeCapacity(sym_index);
+ self.global_symbol_free_list.append(self.allocator, sym_index) catch {};
self.global_symbols.items[sym_index].st_info = 0;
}
@@ -2284,7 +2316,7 @@ pub const File = struct {
}
/// Writes to the file a buffer, prefixed and suffixed by the specified number of
- /// bytes of NOPs. Asserts each padding size is at least two bytes and total padding bytes
+ /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes
/// are less than 126,976 bytes (if this limit is ever reached, this function can be
/// improved to make more than one pwritev call, or the limit can be raised by a fixed
/// amount by increasing the length of `vecs`).
@@ -2361,6 +2393,8 @@ pub const File = struct {
try self.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
}
+ const min_nop_size = 2;
+
};
};