| ... | ... | @@ -1019,7 +1019,18 @@ pub fn deleteExport(self: *MachO, exp: Export) void { |
| 1019 | 1019 | self.global_symbols.items[sym_index].n_type = 0; |
| 1020 | 1020 | } |
| 1021 | 1021 | |
| 1022 | | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {} |
| 1022 | pub 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 | } |
| 1023 | 1034 | |
| 1024 | 1035 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { |
| 1025 | 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 | 1352 | const text_section = &self.sections.items[self.text_section_index.?]; |
| 1342 | 1353 | const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den; |
| 1343 | 1354 | |
| 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 | 1360 | var block_placement: ?*TextBlock = null; |
| 1345 | | const addr = blk: { |
| 1346 | | if (self.last_text_block) |last| { |
| 1361 | var free_list_removal: ?usize = null; |
| 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 | 1403 | const last_symbol = self.local_symbols.items[last.local_sym_index]; |
| 1348 | 1404 | // TODO pad out with NOPs and reenable |
| 1349 | 1405 | // const ideal_capacity = last.size * alloc_num / alloc_den; |
| 1350 | 1406 | // const ideal_capacity_end_addr = last_symbol.n_value + ideal_capacity; |
| 1351 | 1407 | // const new_start_addr = mem.alignForwardGeneric(u64, ideal_capacity_end_addr, alignment); |
| 1352 | | const end_addr = last_symbol.n_value + last.size; |
| 1353 | | const new_start_addr = mem.alignForwardGeneric(u64, end_addr, alignment); |
| 1408 | const end_vaddr = last_symbol.n_value + last.size; |
| 1409 | const new_start_vaddr = mem.alignForwardGeneric(u64, end_vaddr, alignment); |
| 1354 | 1410 | block_placement = last; |
| 1355 | | break :blk new_start_addr; |
| 1411 | break :blk new_start_vaddr; |
| 1356 | 1412 | } else { |
| 1357 | 1413 | break :blk text_section.addr; |
| 1358 | 1414 | } |
| ... | ... | @@ -1361,11 +1417,13 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 1361 | 1417 | const expand_text_section = block_placement == null or block_placement.?.next == null; |
| 1362 | 1418 | if (expand_text_section) { |
| 1363 | 1419 | const text_capacity = self.allocatedSize(text_section.offset); |
| 1364 | | const needed_size = (addr + new_block_size) - text_section.addr; |
| 1365 | | assert(needed_size <= text_capacity); // TODO handle growth |
| 1420 | const needed_size = (vaddr + new_block_size) - text_section.addr; |
| 1421 | assert(needed_size <= text_capacity); // TODO must move the entire text section. |
| 1366 | 1422 | |
| 1367 | 1423 | self.last_text_block = text_block; |
| 1368 | 1424 | text_section.size = needed_size; // TODO temp until we pad out with NOPs |
| 1425 | |
| 1426 | self.cmd_table_dirty = true; |
| 1369 | 1427 | } |
| 1370 | 1428 | text_block.size = new_block_size; |
| 1371 | 1429 | |
| ... | ... | @@ -1384,8 +1442,11 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 1384 | 1442 | text_block.prev = null; |
| 1385 | 1443 | text_block.next = null; |
| 1386 | 1444 | } |
| 1445 | if (free_list_removal) |i| { |
| 1446 | _ = self.text_block_free_list.swapRemove(i); |
| 1447 | } |
| 1387 | 1448 | |
| 1388 | | return addr; |
| 1449 | return vaddr; |
| 1389 | 1450 | } |
| 1390 | 1451 | |
| 1391 | 1452 | fn makeStaticString(comptime bytes: []const u8) [16]u8 { |