authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-25 15:11:21+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-25 15:11:21+02:00
logaf57ccbe279d73f91358ec28fb4afd54868650e8
treea23a15e7337b088c8757e1a8968add84b05ee123
parentea4bd2b87962794233df1693cdea3da266e27b86

macho: generalise free list usage to all sections


1 files changed, 63 insertions(+), 32 deletions(-)

src/link/MachO.zig+63-32
......@@ -194,10 +194,10 @@ section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},
194194/// overcapacity can be negative. A simple way to have negative overcapacity is to
195195/// allocate a fresh text block, which will have ideal capacity, and then grow it
196196/// by 1 byte. It will then have -1 overcapacity.
197text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{},
197block_free_lists: std.AutoHashMapUnmanaged(MatchingSection, std.ArrayListUnmanaged(*TextBlock)) = .{},
198198
199199/// Pointer to the last allocated text block
200last_text_block: ?*TextBlock = null,
200blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
201201
202202/// List of TextBlocks that are owned directly by the linker.
203203/// Currently these are only TextBlocks that are the result of linking
......@@ -206,8 +206,6 @@ last_text_block: ?*TextBlock = null,
206206/// TODO consolidate this.
207207managed_blocks: std.ArrayListUnmanaged(*TextBlock) = .{},
208208
209blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
210
211209/// Table of Decls that are currently alive.
212210/// We store them here so that we can properly dispose of any allocated
213211/// memory within the TextBlock in the incremental linker.
......@@ -1535,6 +1533,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15351533
15361534 if (res) |match| {
15371535 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
1536 _ = try self.block_free_lists.getOrPutValue(self.base.allocator, match, .{});
15381537 }
15391538
15401539 return res;
......@@ -3417,8 +3416,13 @@ pub fn deinit(self: *MachO) void {
34173416 }
34183417 self.managed_blocks.deinit(self.base.allocator);
34193418 self.blocks.deinit(self.base.allocator);
3420 self.text_block_free_list.deinit(self.base.allocator);
3421
3419 {
3420 var it = self.block_free_lists.valueIterator();
3421 while (it.next()) |free_list| {
3422 free_list.deinit(self.base.allocator);
3423 }
3424 self.block_free_lists.deinit(self.base.allocator);
3425 }
34223426 for (self.decls.keys()) |decl| {
34233427 decl.link.macho.deinit(self.base.allocator);
34243428 }
......@@ -3441,16 +3445,21 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void {
34413445 log.debug("freeTextBlock {*}", .{text_block});
34423446 text_block.deinit(self.base.allocator);
34433447
3448 const match = MatchingSection{
3449 .seg = self.text_segment_cmd_index.?,
3450 .sect = self.text_section_index.?,
3451 };
3452 const text_block_free_list = self.block_free_lists.getPtr(match).?;
34443453 var already_have_free_list_node = false;
34453454 {
34463455 var i: usize = 0;
34473456 // TODO turn text_block_free_list into a hash map
3448 while (i < self.text_block_free_list.items.len) {
3449 if (self.text_block_free_list.items[i] == text_block) {
3450 _ = self.text_block_free_list.swapRemove(i);
3457 while (i < text_block_free_list.items.len) {
3458 if (text_block_free_list.items[i] == text_block) {
3459 _ = text_block_free_list.swapRemove(i);
34513460 continue;
34523461 }
3453 if (self.text_block_free_list.items[i] == text_block.prev) {
3462 if (text_block_free_list.items[i] == text_block.prev) {
34543463 already_have_free_list_node = true;
34553464 }
34563465 i += 1;
......@@ -3458,10 +3467,15 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void {
34583467 }
34593468 // TODO process free list for dbg info just like we do above for vaddrs
34603469
3461 if (self.last_text_block == text_block) {
3462 // TODO shrink the __text section size here
3463 self.last_text_block = text_block.prev;
3470 if (self.blocks.getPtr(match)) |last_text_block| {
3471 if (last_text_block.* == text_block) {
3472 if (text_block.prev) |prev| {
3473 // TODO shrink the __text section size here
3474 last_text_block.* = prev;
3475 }
3476 }
34643477 }
3478
34653479 if (self.d_sym) |*ds| {
34663480 if (ds.dbg_info_decl_first == text_block) {
34673481 ds.dbg_info_decl_first = text_block.dbg_info_next;
......@@ -3478,7 +3492,7 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void {
34783492 if (!already_have_free_list_node and prev.freeListEligible(self.*)) {
34793493 // The free list is heuristics, it doesn't have to be perfect, so we can ignore
34803494 // the OOM here.
3481 self.text_block_free_list.append(self.base.allocator, prev) catch {};
3495 text_block_free_list.append(self.base.allocator, prev) catch {};
34823496 }
34833497 } else {
34843498 text_block.prev = null;
......@@ -4035,10 +4049,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
40354049 .@"align" = alignment,
40364050 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
40374051 });
4038 _ = try self.section_ordinals.getOrPut(self.base.allocator, .{
4052 const match = MatchingSection{
40394053 .seg = self.text_segment_cmd_index.?,
40404054 .sect = self.text_section_index.?,
4041 });
4055 };
4056 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4057 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
40424058 self.load_commands_dirty = true;
40434059 }
40444060
......@@ -4070,10 +4086,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
40704086 .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
40714087 .reserved2 = stub_size,
40724088 });
4073 _ = try self.section_ordinals.getOrPut(self.base.allocator, .{
4089 const match = MatchingSection{
40744090 .seg = self.text_segment_cmd_index.?,
40754091 .sect = self.stubs_section_index.?,
4076 });
4092 };
4093 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4094 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
40774095 self.load_commands_dirty = true;
40784096 }
40794097
......@@ -4103,10 +4121,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
41034121 .@"align" = alignment,
41044122 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
41054123 });
4106 _ = try self.section_ordinals.getOrPut(self.base.allocator, .{
4124 const match = MatchingSection{
41074125 .seg = self.text_segment_cmd_index.?,
41084126 .sect = self.stub_helper_section_index.?,
4109 });
4127 };
4128 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4129 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
41104130 self.load_commands_dirty = true;
41114131 }
41124132
......@@ -4148,10 +4168,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
41484168 .@"align" = 3, // 2^3 = @sizeOf(u64)
41494169 .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
41504170 });
4151 _ = try self.section_ordinals.getOrPut(self.base.allocator, .{
4171 const match = MatchingSection{
41524172 .seg = self.data_const_segment_cmd_index.?,
41534173 .sect = self.got_section_index.?,
4154 });
4174 };
4175 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4176 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
41554177 self.load_commands_dirty = true;
41564178 }
41574179
......@@ -4193,10 +4215,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
41934215 .@"align" = 3, // 2^3 = @sizeOf(u64)
41944216 .flags = macho.S_LAZY_SYMBOL_POINTERS,
41954217 });
4196 _ = try self.section_ordinals.getOrPut(self.base.allocator, .{
4218 const match = MatchingSection{
41974219 .seg = self.data_segment_cmd_index.?,
41984220 .sect = self.la_symbol_ptr_section_index.?,
4199 });
4221 };
4222 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4223 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
42004224 self.load_commands_dirty = true;
42014225 }
42024226
......@@ -4216,10 +4240,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
42164240 .offset = @intCast(u32, off),
42174241 .@"align" = 3, // 2^3 = @sizeOf(u64)
42184242 });
4219 _ = try self.section_ordinals.getOrPut(self.base.allocator, .{
4243 const match = MatchingSection{
42204244 .seg = self.data_segment_cmd_index.?,
42214245 .sect = self.data_section_index.?,
4222 });
4246 };
4247 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
4248 try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
42234249 self.load_commands_dirty = true;
42244250 }
42254251
......@@ -4470,6 +4496,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {
44704496fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {
44714497 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
44724498 const text_section = &text_segment.sections.items[self.text_section_index.?];
4499 const match = MatchingSection{
4500 .seg = self.text_segment_cmd_index.?,
4501 .sect = self.text_section_index.?,
4502 };
4503 const text_block_free_list = self.block_free_lists.getPtr(match).?;
44734504 const new_block_ideal_capacity = padToIdeal(new_block_size);
44744505
44754506 // We use these to indicate our intention to update metadata, placing the new block,
......@@ -4484,8 +4515,8 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
44844515 // The list is unordered. We'll just take the first thing that works.
44854516 const vaddr = blk: {
44864517 var i: usize = 0;
4487 while (i < self.text_block_free_list.items.len) {
4488 const big_block = self.text_block_free_list.items[i];
4518 while (i < text_block_free_list.items.len) {
4519 const big_block = text_block_free_list.items[i];
44894520 // We now have a pointer to a live text block that has too much capacity.
44904521 // Is it enough that we could fit this new text block?
44914522 const sym = self.locals.items[big_block.local_sym_index];
......@@ -4500,7 +4531,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
45004531 // should be deleted because the block that it points to has grown to take up
45014532 // more of the extra capacity.
45024533 if (!big_block.freeListEligible(self.*)) {
4503 const bl = self.text_block_free_list.swapRemove(i);
4534 const bl = text_block_free_list.swapRemove(i);
45044535 bl.deinit(self.base.allocator);
45054536 } else {
45064537 i += 1;
......@@ -4519,7 +4550,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
45194550 free_list_removal = i;
45204551 }
45214552 break :blk new_start_vaddr;
4522 } else if (self.last_text_block) |last| {
4553 } else if (self.blocks.get(match)) |last| {
45234554 const last_symbol = self.locals.items[last.local_sym_index];
45244555 // TODO We should pad out the excess capacity with NOPs. For executables,
45254556 // no padding seems to be OK, but it will probably not be for objects.
......@@ -4538,7 +4569,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
45384569 const needed_size = (vaddr + new_block_size) - text_section.addr;
45394570 assert(needed_size <= text_segment.inner.filesize); // TODO must move the entire text section.
45404571
4541 self.last_text_block = text_block;
4572 _ = try self.blocks.getOrPutValue(self.base.allocator, match, text_block);
45424573 text_section.size = needed_size;
45434574 self.load_commands_dirty = true; // TODO Make more granular.
45444575
......@@ -4567,7 +4598,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
45674598 text_block.next = null;
45684599 }
45694600 if (free_list_removal) |i| {
4570 _ = self.text_block_free_list.swapRemove(i);
4601 _ = text_block_free_list.swapRemove(i);
45714602 }
45724603
45734604 return vaddr;