authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-08-29 16:35:52-04:00
committergravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-09-18 19:44:40-04:00
log4cb2d6bc3e3ab7c27cabdc7318abaea1afc34654
treeb2ea6cb79fa7dd76089160079a4e41b45585f2d2
parentf388b575533b8e36999bc5ee406421feb7e80baa

plan9 linker: add free lists for got_index and sym_index

This allows the same global offset and symbol table index to be re-used if a decl is freed.

1 files changed, 30 insertions(+), 11 deletions(-)

src/link/Plan9.zig+30-11
......@@ -39,6 +39,11 @@ magic: u32,
3939entry_val: ?u64 = null,
4040
4141got_len: usize = 0,
42// A list of all the free got indexes, so when making a new decl
43// don't make a new one, just use one from here.
44got_index_free_list: std.ArrayListUnmanaged(u64) = .{},
45
46syms_index_free_list: std.ArrayListUnmanaged(u64) = .{},
4247
4348const Bases = struct {
4449 text: u64,
......@@ -212,8 +217,12 @@ fn updateFinish(self: *Plan9, decl: *Module.Decl) !void {
212217 if (decl.link.plan9.sym_index) |s| {
213218 self.syms.items[s] = sym;
214219 } else {
215 try self.syms.append(self.base.allocator, sym);
216 decl.link.plan9.sym_index = self.syms.items.len - 1;
220 if (self.syms_index_free_list.popOrNull()) |i| {
221 decl.link.plan9.sym_index = i;
222 } else {
223 try self.syms.append(self.base.allocator, sym);
224 decl.link.plan9.sym_index = self.syms.items.len - 1;
225 }
217226 }
218227}
219228
......@@ -244,14 +253,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
244253
245254 const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
246255
247 // TODO I changed this assert from == to >= but this code all needs to be audited; see
248 // the comment in `freeDecl`.
249 assert(self.got_len >= self.fn_decl_table.count() + self.data_decl_table.count());
256 assert(self.got_len == self.fn_decl_table.count() + self.data_decl_table.count() + self.got_index_free_list.items.len);
250257 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;
251258 var got_table = try self.base.allocator.alloc(u8, got_size);
252259 defer self.base.allocator.free(got_table);
253260
254 // + 2 for header, got, symbols
261 // + 3 for header, got, symbols
255262 var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.fn_decl_table.count() + self.data_decl_table.count() + 3);
256263 defer self.base.allocator.free(iovecs);
257264
......@@ -380,18 +387,24 @@ fn addDeclExports(
380387}
381388
382389pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void {
383 // TODO this is not the correct check for being function body,
384 // it could just be a function pointer.
385390 // TODO audit the lifetimes of decls table entries. It's possible to get
386391 // allocateDeclIndexes and then freeDecl without any updateDecl in between.
387392 // However that is planned to change, see the TODO comment in Module.zig
388393 // in the deleteUnusedDecl function.
389 const is_fn = (decl.ty.zigTypeTag() == .Fn);
394 const is_fn = (decl.val.tag() == .function);
390395 if (is_fn) {
391396 _ = self.fn_decl_table.swapRemove(decl);
392397 } else {
393398 _ = self.data_decl_table.swapRemove(decl);
394399 }
400 if (decl.link.plan9.got_index) |i| {
401 // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length
402 self.got_index_free_list.append(self.base.allocator, i) catch {};
403 }
404 if (decl.link.plan9.sym_index) |i| {
405 self.syms_index_free_list.append(self.base.allocator, i) catch {};
406 self.syms.items[i] = undefined;
407 }
395408}
396409
397410pub fn updateDeclExports(
......@@ -418,6 +431,8 @@ pub fn deinit(self: *Plan9) void {
418431 }
419432 self.data_decl_table.deinit(self.base.allocator);
420433 self.syms.deinit(self.base.allocator);
434 self.got_index_free_list.deinit(self.base.allocator);
435 self.syms_index_free_list.deinit(self.base.allocator);
421436}
422437
423438pub const Export = ?usize;
......@@ -481,7 +496,11 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
481496
482497pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void {
483498 if (decl.link.plan9.got_index == null) {
484 self.got_len += 1;
485 decl.link.plan9.got_index = self.got_len - 1;
499 if (self.got_index_free_list.popOrNull()) |i| {
500 decl.link.plan9.got_index = i;
501 } else {
502 self.got_len += 1;
503 decl.link.plan9.got_index = self.got_len - 1;
504 }
486505 }
487506}