authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-10-10 23:52:24+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-10-13 08:38:17+02:00
logfc660af07774887df8a5ed479cb7c2c662b173ce
tree7291621d8092f6753004b64edbeaa1b545cf2542
parent78ec7b671de6ca8d1466bf408e906c8799dcd19c

Update allocateTextBlock to use node free list


1 files changed, 70 insertions(+), 9 deletions(-)

src/link/MachO.zig+70-9
...@@ -1019,7 +1019,18 @@ pub fn deleteExport(self: *MachO, exp: Export) void {...@@ -1019,7 +1019,18 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
1019 self.global_symbols.items[sym_index].n_type = 0;1019 self.global_symbols.items[sym_index].n_type = 0;
1020}1020}
10211021
1022pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {}1022pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
1023 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
1024 self.freeTextBlock(&decl.link.macho);
1025 if (decl.link.macho.local_sym_index != 0) {
1026 self.local_symbol_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {};
1027 self.offset_table_free_list.append(self.base.allocator, decl.link.macho.offset_table_index) catch {};
1028
1029 self.local_symbols.items[decl.link.macho.local_sym_index].n_type = 0;
1030
1031 decl.link.macho.local_sym_index = 0;
1032 }
1033}
10231034
1024pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {1035pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {
1025 assert(decl.link.macho.local_sym_index != 0);1036 assert(decl.link.macho.local_sym_index != 0);
...@@ -1341,18 +1352,63 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,...@@ -1341,18 +1352,63 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
1341 const text_section = &self.sections.items[self.text_section_index.?];1352 const text_section = &self.sections.items[self.text_section_index.?];
1342 const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den;1353 const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den;
13431354
1355 // We use these to indicate our intention to update metadata, placing the new block,
1356 // and possibly removing a free list node.
1357 // It would be simpler to do it inside the for loop below, but that would cause a
1358 // problem if an error was returned later in the function. So this action
1359 // is actually carried out at the end of the function, when errors are no longer possible.
1344 var block_placement: ?*TextBlock = null;1360 var block_placement: ?*TextBlock = null;
1345 const addr = blk: {1361 var free_list_removal: ?usize = null;
1346 if (self.last_text_block) |last| {1362
1363 // First we look for an appropriately sized free list node.
1364 // The list is unordered. We'll just take the first thing that works.
1365 const vaddr = blk: {
1366 var i: usize = 0;
1367 while (i < self.text_block_free_list.items.len) {
1368 const big_block = self.text_block_free_list.items[i];
1369 // We now have a pointer to a live text block that has too much capacity.
1370 // Is it enough that we could fit this new text block?
1371 const sym = self.local_symbols.items[big_block.local_sym_index];
1372 const capacity = big_block.capacity(self.*);
1373 const ideal_capacity = capacity * alloc_num / alloc_den;
1374 const ideal_capacity_end_vaddr = sym.n_value + ideal_capacity;
1375 const capacity_end_vaddr = sym.n_value + capacity;
1376 const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity;
1377 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
1378 if (new_start_vaddr < ideal_capacity_end_vaddr) {
1379 // Additional bookkeeping here to notice if this free list node
1380 // should be deleted because the block that it points to has grown to take up
1381 // more of the extra capacity.
1382 if (!big_block.freeListEligible(self.*)) {
1383 _ = self.text_block_free_list.swapRemove(i);
1384 } else {
1385 i += 1;
1386 }
1387 continue;
1388 }
1389 // At this point we know that we will place the new block here. But the
1390 // remaining question is whether there is still yet enough capacity left
1391 // over for there to still be a free list node.
1392 const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr;
1393 const keep_free_list_node = remaining_capacity >= min_text_capacity;
1394
1395 // Set up the metadata to be updated, after errors are no longer possible.
1396 block_placement = big_block;
1397 if (!keep_free_list_node) {
1398 free_list_removal = i;
1399 }
1400 break :blk new_start_vaddr;
1401 }
1402 else if (self.last_text_block) |last| {
1347 const last_symbol = self.local_symbols.items[last.local_sym_index];1403 const last_symbol = self.local_symbols.items[last.local_sym_index];
1348 // TODO pad out with NOPs and reenable1404 // TODO pad out with NOPs and reenable
1349 // const ideal_capacity = last.size * alloc_num / alloc_den;1405 // const ideal_capacity = last.size * alloc_num / alloc_den;
1350 // const ideal_capacity_end_addr = last_symbol.n_value + ideal_capacity;1406 // const ideal_capacity_end_addr = last_symbol.n_value + ideal_capacity;
1351 // const new_start_addr = mem.alignForwardGeneric(u64, ideal_capacity_end_addr, alignment);1407 // const new_start_addr = mem.alignForwardGeneric(u64, ideal_capacity_end_addr, alignment);
1352 const end_addr = last_symbol.n_value + last.size;1408 const end_vaddr = last_symbol.n_value + last.size;
1353 const new_start_addr = mem.alignForwardGeneric(u64, end_addr, alignment);1409 const new_start_vaddr = mem.alignForwardGeneric(u64, end_vaddr, alignment);
1354 block_placement = last;1410 block_placement = last;
1355 break :blk new_start_addr;1411 break :blk new_start_vaddr;
1356 } else {1412 } else {
1357 break :blk text_section.addr;1413 break :blk text_section.addr;
1358 }1414 }
...@@ -1361,11 +1417,13 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,...@@ -1361,11 +1417,13 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
1361 const expand_text_section = block_placement == null or block_placement.?.next == null;1417 const expand_text_section = block_placement == null or block_placement.?.next == null;
1362 if (expand_text_section) {1418 if (expand_text_section) {
1363 const text_capacity = self.allocatedSize(text_section.offset);1419 const text_capacity = self.allocatedSize(text_section.offset);
1364 const needed_size = (addr + new_block_size) - text_section.addr;1420 const needed_size = (vaddr + new_block_size) - text_section.addr;
1365 assert(needed_size <= text_capacity); // TODO handle growth1421 assert(needed_size <= text_capacity); // TODO must move the entire text section.
13661422
1367 self.last_text_block = text_block;1423 self.last_text_block = text_block;
1368 text_section.size = needed_size; // TODO temp until we pad out with NOPs1424 text_section.size = needed_size; // TODO temp until we pad out with NOPs
1425
1426 self.cmd_table_dirty = true;
1369 }1427 }
1370 text_block.size = new_block_size;1428 text_block.size = new_block_size;
13711429
...@@ -1384,8 +1442,11 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,...@@ -1384,8 +1442,11 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
1384 text_block.prev = null;1442 text_block.prev = null;
1385 text_block.next = null;1443 text_block.next = null;
1386 }1444 }
1445 if (free_list_removal) |i| {
1446 _ = self.text_block_free_list.swapRemove(i);
1447 }
13871448
1388 return addr;1449 return vaddr;
1389}1450}
13901451
1391fn makeStaticString(comptime bytes: []const u8) [16]u8 {1452fn makeStaticString(comptime bytes: []const u8) [16]u8 {