From cb25d8e4bc78d6fe21e0cb0b979aa8250a086c2e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Aug 2020 23:13:54 -0700 Subject: [PATCH] stage2 .debug_line: handle Decl deletes and updates --- src-self-hosted/link.zig | 66 ++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 012a44d757..0746a3f6fb 100644 --- a/src-self-hosted/link.zig +++ b/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; + }; };