| ... | @@ -102,11 +102,11 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, | ... | @@ -102,11 +102,11 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 102 | /// or removed from the freelist. | 102 | /// or removed from the freelist. |
| 103 | /// | 103 | /// |
| 104 | /// A text block has surplus capacity when its overcapacity value is greater than | 104 | /// A text block has surplus capacity when its overcapacity value is greater than |
| 105 | /// minimum_text_block_size * alloc_num / alloc_den. That is, when it has so | 105 | /// padToIdeal(minimum_text_block_size). That is, when it has so |
| 106 | /// much extra capacity, that we could fit a small new symbol in it, itself with | 106 | /// much extra capacity, that we could fit a small new symbol in it, itself with |
| 107 | /// ideal_capacity or more. | 107 | /// ideal_capacity or more. |
| 108 | /// | 108 | /// |
| 109 | /// Ideal capacity is defined by size * alloc_num / alloc_den. | 109 | /// Ideal capacity is defined by size + (size / ideal_factor) |
| 110 | /// | 110 | /// |
| 111 | /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that | 111 | /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that |
| 112 | /// overcapacity can be negative. A simple way to have negative overcapacity is to | 112 | /// overcapacity can be negative. A simple way to have negative overcapacity is to |
| ... | @@ -127,15 +127,15 @@ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, | ... | @@ -127,15 +127,15 @@ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, |
| 127 | dbg_info_decl_first: ?*TextBlock = null, | 127 | dbg_info_decl_first: ?*TextBlock = null, |
| 128 | dbg_info_decl_last: ?*TextBlock = null, | 128 | dbg_info_decl_last: ?*TextBlock = null, |
| 129 | | 129 | |
| 130 | /// `alloc_num / alloc_den` is the factor of padding when allocating. | 130 | /// When allocating, the ideal_capacity is calculated by |
| 131 | const alloc_num = 4; | 131 | /// actual_capacity + (actual_capacity / ideal_factor) |
| 132 | const alloc_den = 3; | 132 | const ideal_factor = 3; |
| 133 | | 133 | |
| 134 | /// In order for a slice of bytes to be considered eligible to keep metadata pointing at | 134 | /// In order for a slice of bytes to be considered eligible to keep metadata pointing at |
| 135 | /// it as a possible place to put new symbols, it must have enough room for this many bytes | 135 | /// it as a possible place to put new symbols, it must have enough room for this many bytes |
| 136 | /// (plus extra for reserved capacity). | 136 | /// (plus extra for reserved capacity). |
| 137 | const minimum_text_block_size = 64; | 137 | const minimum_text_block_size = 64; |
| 138 | const min_text_capacity = minimum_text_block_size * alloc_num / alloc_den; | 138 | const min_text_capacity = padToIdeal(minimum_text_block_size); |
| 139 | | 139 | |
| 140 | pub const PtrWidth = enum { p32, p64 }; | 140 | pub const PtrWidth = enum { p32, p64 }; |
| 141 | | 141 | |
| ... | @@ -154,7 +154,7 @@ pub const TextBlock = struct { | ... | @@ -154,7 +154,7 @@ pub const TextBlock = struct { |
| 154 | prev: ?*TextBlock, | 154 | prev: ?*TextBlock, |
| 155 | next: ?*TextBlock, | 155 | next: ?*TextBlock, |
| 156 | | 156 | |
| 157 | /// Previous/next linked list pointers. This value is `next ^ prev`. | 157 | /// Previous/next linked list pointers. |
| 158 | /// This is the linked list node for this Decl's corresponding .debug_info tag. | 158 | /// This is the linked list node for this Decl's corresponding .debug_info tag. |
| 159 | dbg_info_prev: ?*TextBlock, | 159 | dbg_info_prev: ?*TextBlock, |
| 160 | dbg_info_next: ?*TextBlock, | 160 | dbg_info_next: ?*TextBlock, |
| ... | @@ -194,7 +194,7 @@ pub const TextBlock = struct { | ... | @@ -194,7 +194,7 @@ pub const TextBlock = struct { |
| 194 | const self_sym = elf_file.local_symbols.items[self.local_sym_index]; | 194 | const self_sym = elf_file.local_symbols.items[self.local_sym_index]; |
| 195 | const next_sym = elf_file.local_symbols.items[next.local_sym_index]; | 195 | const next_sym = elf_file.local_symbols.items[next.local_sym_index]; |
| 196 | const cap = next_sym.st_value - self_sym.st_value; | 196 | const cap = next_sym.st_value - self_sym.st_value; |
| 197 | const ideal_cap = self_sym.st_size * alloc_num / alloc_den; | 197 | const ideal_cap = padToIdeal(self_sym.st_size); |
| 198 | if (cap <= ideal_cap) return false; | 198 | if (cap <= ideal_cap) return false; |
| 199 | const surplus = cap - ideal_cap; | 199 | const surplus = cap - ideal_cap; |
| 200 | return surplus >= min_text_capacity; | 200 | return surplus >= min_text_capacity; |
| ... | @@ -338,12 +338,12 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { | ... | @@ -338,12 +338,12 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { |
| 338 | if (start < ehdr_size) | 338 | if (start < ehdr_size) |
| 339 | return ehdr_size; | 339 | return ehdr_size; |
| 340 | | 340 | |
| 341 | const end = start + satMul(size, alloc_num) / alloc_den; | 341 | const end = start + padToIdeal(size); |
| 342 | | 342 | |
| 343 | if (self.shdr_table_offset) |off| { | 343 | if (self.shdr_table_offset) |off| { |
| 344 | const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr); | 344 | const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr); |
| 345 | const tight_size = self.sections.items.len * shdr_size; | 345 | const tight_size = self.sections.items.len * shdr_size; |
| 346 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; | 346 | const increased_size = padToIdeal(tight_size); |
| 347 | const test_end = off + increased_size; | 347 | const test_end = off + increased_size; |
| 348 | if (end > off and start < test_end) { | 348 | if (end > off and start < test_end) { |
| 349 | return test_end; | 349 | return test_end; |
| ... | @@ -353,7 +353,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { | ... | @@ -353,7 +353,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { |
| 353 | if (self.phdr_table_offset) |off| { | 353 | if (self.phdr_table_offset) |off| { |
| 354 | const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr); | 354 | const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr); |
| 355 | const tight_size = self.sections.items.len * phdr_size; | 355 | const tight_size = self.sections.items.len * phdr_size; |
| 356 | const increased_size = satMul(tight_size, alloc_num) / alloc_den; | 356 | const increased_size = padToIdeal(tight_size); |
| 357 | const test_end = off + increased_size; | 357 | const test_end = off + increased_size; |
| 358 | if (end > off and start < test_end) { | 358 | if (end > off and start < test_end) { |
| 359 | return test_end; | 359 | return test_end; |
| ... | @@ -361,14 +361,14 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { | ... | @@ -361,14 +361,14 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { |
| 361 | } | 361 | } |
| 362 | | 362 | |
| 363 | for (self.sections.items) |section| { | 363 | for (self.sections.items) |section| { |
| 364 | const increased_size = satMul(section.sh_size, alloc_num) / alloc_den; | 364 | const increased_size = padToIdeal(section.sh_size); |
| 365 | const test_end = section.sh_offset + increased_size; | 365 | const test_end = section.sh_offset + increased_size; |
| 366 | if (end > section.sh_offset and start < test_end) { | 366 | if (end > section.sh_offset and start < test_end) { |
| 367 | return test_end; | 367 | return test_end; |
| 368 | } | 368 | } |
| 369 | } | 369 | } |
| 370 | for (self.program_headers.items) |program_header| { | 370 | for (self.program_headers.items) |program_header| { |
| 371 | const increased_size = satMul(program_header.p_filesz, alloc_num) / alloc_den; | 371 | const increased_size = padToIdeal(program_header.p_filesz); |
| 372 | const test_end = program_header.p_offset + increased_size; | 372 | const test_end = program_header.p_offset + increased_size; |
| 373 | if (end > program_header.p_offset and start < test_end) { | 373 | if (end > program_header.p_offset and start < test_end) { |
| 374 | return test_end; | 374 | return test_end; |
| ... | @@ -1956,7 +1956,7 @@ fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignm | ... | @@ -1956,7 +1956,7 @@ fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignm |
| 1956 | fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | 1956 | fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 1957 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | 1957 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| 1958 | const shdr = &self.sections.items[self.text_section_index.?]; | 1958 | const shdr = &self.sections.items[self.text_section_index.?]; |
| 1959 | const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; | 1959 | const new_block_ideal_capacity = padToIdeal(new_block_size); |
| 1960 | | 1960 | |
| 1961 | // We use these to indicate our intention to update metadata, placing the new block, | 1961 | // We use these to indicate our intention to update metadata, placing the new block, |
| 1962 | // and possibly removing a free list node. | 1962 | // and possibly removing a free list node. |
| ... | @@ -1976,7 +1976,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al | ... | @@ -1976,7 +1976,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 1976 | // Is it enough that we could fit this new text block? | 1976 | // Is it enough that we could fit this new text block? |
| 1977 | const sym = self.local_symbols.items[big_block.local_sym_index]; | 1977 | const sym = self.local_symbols.items[big_block.local_sym_index]; |
| 1978 | const capacity = big_block.capacity(self.*); | 1978 | const capacity = big_block.capacity(self.*); |
| 1979 | const ideal_capacity = capacity * alloc_num / alloc_den; | 1979 | const ideal_capacity = padToIdeal(capacity); |
| 1980 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; | 1980 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; |
| 1981 | const capacity_end_vaddr = sym.st_value + capacity; | 1981 | const capacity_end_vaddr = sym.st_value + capacity; |
| 1982 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity; | 1982 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity; |
| ... | @@ -2006,7 +2006,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al | ... | @@ -2006,7 +2006,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 2006 | break :blk new_start_vaddr; | 2006 | break :blk new_start_vaddr; |
| 2007 | } else if (self.last_text_block) |last| { | 2007 | } else if (self.last_text_block) |last| { |
| 2008 | const sym = self.local_symbols.items[last.local_sym_index]; | 2008 | const sym = self.local_symbols.items[last.local_sym_index]; |
| 2009 | const ideal_capacity = sym.st_size * alloc_num / alloc_den; | 2009 | const ideal_capacity = padToIdeal(sym.st_size); |
| 2010 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; | 2010 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; |
| 2011 | const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment); | 2011 | const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment); |
| 2012 | // Set up the metadata to be updated, after errors are no longer possible. | 2012 | // Set up the metadata to be updated, after errors are no longer possible. |
| ... | @@ -2370,7 +2370,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2370,7 +2370,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2370 | | 2370 | |
| 2371 | // Now we have the full contents and may allocate a region to store it. | 2371 | // Now we have the full contents and may allocate a region to store it. |
| 2372 | | 2372 | |
| 2373 | // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for | 2373 | // This logic is nearly identical to the logic below in `updateDeclDebugInfoAllocation` for |
| 2374 | // `TextBlock` and the .debug_info. If you are editing this logic, you | 2374 | // `TextBlock` and the .debug_info. If you are editing this logic, you |
| 2375 | // probably need to edit that logic too. | 2375 | // probably need to edit that logic too. |
| 2376 | | 2376 | |
| ... | @@ -2386,6 +2386,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2386,6 +2386,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2386 | _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | 2386 | _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; |
| 2387 | prev.next = src_fn.next; | 2387 | prev.next = src_fn.next; |
| 2388 | } | 2388 | } |
| | 2389 | assert(src_fn.prev != next); |
| 2389 | next.prev = src_fn.prev; | 2390 | next.prev = src_fn.prev; |
| 2390 | src_fn.next = null; | 2391 | src_fn.next = null; |
| 2391 | // Populate where it used to be with NOPs. | 2392 | // Populate where it used to be with NOPs. |
| ... | @@ -2396,23 +2397,24 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2396,23 +2397,24 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2396 | last.next = src_fn; | 2397 | last.next = src_fn; |
| 2397 | self.dbg_line_fn_last = src_fn; | 2398 | self.dbg_line_fn_last = src_fn; |
| 2398 | | 2399 | |
| 2399 | src_fn.off = last.off + (last.len * alloc_num / alloc_den); | 2400 | src_fn.off = last.off + padToIdeal(last.len); |
| 2400 | } | 2401 | } |
| 2401 | } else if (src_fn.prev == null) { | 2402 | } else if (src_fn.prev == null) { |
| 2402 | // Append new function. | 2403 | // Append new function. |
| 2403 | // TODO Look at the free list before appending at the end. | 2404 | // TODO Look at the free list before appending at the end. |
| | 2405 | assert(src_fn != last); |
| 2404 | src_fn.prev = last; | 2406 | src_fn.prev = last; |
| 2405 | last.next = src_fn; | 2407 | last.next = src_fn; |
| 2406 | self.dbg_line_fn_last = src_fn; | 2408 | self.dbg_line_fn_last = src_fn; |
| 2407 | | 2409 | |
| 2408 | src_fn.off = last.off + (last.len * alloc_num / alloc_den); | 2410 | src_fn.off = last.off + padToIdeal(last.len); |
| 2409 | } | 2411 | } |
| 2410 | } else { | 2412 | } else { |
| 2411 | // This is the first function of the Line Number Program. | 2413 | // This is the first function of the Line Number Program. |
| 2412 | self.dbg_line_fn_first = src_fn; | 2414 | self.dbg_line_fn_first = src_fn; |
| 2413 | self.dbg_line_fn_last = src_fn; | 2415 | self.dbg_line_fn_last = src_fn; |
| 2414 | | 2416 | |
| 2415 | src_fn.off = self.dbgLineNeededHeaderBytes() * alloc_num / alloc_den; | 2417 | src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes()); |
| 2416 | } | 2418 | } |
| 2417 | | 2419 | |
| 2418 | const last_src_fn = self.dbg_line_fn_last.?; | 2420 | const last_src_fn = self.dbg_line_fn_last.?; |
| ... | @@ -2544,7 +2546,7 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) ! | ... | @@ -2544,7 +2546,7 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) ! |
| 2544 | last.dbg_info_next = text_block; | 2546 | last.dbg_info_next = text_block; |
| 2545 | self.dbg_info_decl_last = text_block; | 2547 | self.dbg_info_decl_last = text_block; |
| 2546 | | 2548 | |
| 2547 | text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den); | 2549 | text_block.dbg_info_off = last.dbg_info_off + padToIdeal(last.dbg_info_len); |
| 2548 | } | 2550 | } |
| 2549 | } else if (text_block.dbg_info_prev == null) { | 2551 | } else if (text_block.dbg_info_prev == null) { |
| 2550 | // Append new Decl. | 2552 | // Append new Decl. |
| ... | @@ -2553,14 +2555,14 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) ! | ... | @@ -2553,14 +2555,14 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) ! |
| 2553 | last.dbg_info_next = text_block; | 2555 | last.dbg_info_next = text_block; |
| 2554 | self.dbg_info_decl_last = text_block; | 2556 | self.dbg_info_decl_last = text_block; |
| 2555 | | 2557 | |
| 2556 | text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den); | 2558 | text_block.dbg_info_off = last.dbg_info_off + padToIdeal(last.dbg_info_len); |
| 2557 | } | 2559 | } |
| 2558 | } else { | 2560 | } else { |
| 2559 | // This is the first Decl of the .debug_info | 2561 | // This is the first Decl of the .debug_info |
| 2560 | self.dbg_info_decl_first = text_block; | 2562 | self.dbg_info_decl_first = text_block; |
| 2561 | self.dbg_info_decl_last = text_block; | 2563 | self.dbg_info_decl_last = text_block; |
| 2562 | | 2564 | |
| 2563 | text_block.dbg_info_off = self.dbgInfoNeededHeaderBytes() * alloc_num / alloc_den; | 2565 | text_block.dbg_info_off = padToIdeal(self.dbgInfoNeededHeaderBytes()); |
| 2564 | } | 2566 | } |
| 2565 | } | 2567 | } |
| 2566 | | 2568 | |
| ... | @@ -3127,12 +3129,6 @@ fn pwriteDbgInfoNops( | ... | @@ -3127,12 +3129,6 @@ fn pwriteDbgInfoNops( |
| 3127 | try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); | 3129 | try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); |
| 3128 | } | 3130 | } |
| 3129 | | 3131 | |
| 3130 | /// Saturating multiplication | | |
| 3131 | fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { | | |
| 3132 | const T = @TypeOf(a, b); | | |
| 3133 | return std.math.mul(T, a, b) catch std.math.maxInt(T); | | |
| 3134 | } | | |
| 3135 | | | |
| 3136 | fn bswapAllFields(comptime S: type, ptr: *S) void { | 3132 | fn bswapAllFields(comptime S: type, ptr: *S) void { |
| 3137 | @panic("TODO implement bswapAllFields"); | 3133 | @panic("TODO implement bswapAllFields"); |
| 3138 | } | 3134 | } |
| ... | @@ -3194,3 +3190,9 @@ fn getLDMOption(target: std.Target) ?[]const u8 { | ... | @@ -3194,3 +3190,9 @@ fn getLDMOption(target: std.Target) ?[]const u8 { |
| 3194 | else => return null, | 3190 | else => return null, |
| 3195 | } | 3191 | } |
| 3196 | } | 3192 | } |
| | 3193 | |
| | 3194 | fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| | 3195 | // TODO https://github.com/ziglang/zig/issues/1284 |
| | 3196 | return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch |
| | 3197 | std.math.maxInt(@TypeOf(actual_size)); |
| | 3198 | } |