From f9963909a1cf73eaee47102f4e4dcafe5afa3898 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 17 Aug 2020 23:49:06 +0200 Subject: stage2/wasm: only free types after func overwrite Functions which are free'd are not immediately removed from the binary as this would cause a shifting of function indexes. Instead, they hang around until they can be overwritten by a new function. This means that the types associated with these dead functions must also remain until the function is overwritten to avoid a type mismatch. --- src-self-hosted/link/Wasm.zig | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'src-self-hosted/link') diff --git a/src-self-hosted/link/Wasm.zig b/src-self-hosted/link/Wasm.zig index cf1a8c21c2..a381cfad57 100644 --- a/src-self-hosted/link/Wasm.zig +++ b/src-self-hosted/link/Wasm.zig @@ -33,7 +33,6 @@ pub const base_tag = link.File.Tag.wasm; pub const FnData = struct { funcidx: u32, - typeidx: u32, }; base: link.File, @@ -99,7 +98,6 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { return error.TODOImplementNonFnDeclsForWasm; if (decl.fn_link.wasm) |fn_data| { - self.types.free(fn_data.typeidx); self.funcs.free(fn_data.funcidx); } @@ -113,7 +111,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { try codegen.genCode(&buf, decl); const funcidx = try self.funcs.new(typeidx, buf.items); - decl.fn_link.wasm = .{ .typeidx = typeidx, .funcidx = funcidx }; + decl.fn_link.wasm = .{ .funcidx = funcidx }; // TODO: we should be more smart and set this only when needed self.exports.dirty = true; @@ -132,7 +130,6 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { // TODO: remove this assert when non-function Decls are implemented assert(decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn); if (decl.fn_link.wasm) |fn_data| { - self.types.free(fn_data.typeidx); self.funcs.free(fn_data.funcidx); decl.fn_link.wasm = null; } @@ -307,21 +304,20 @@ const Funcs = struct { /// This section needs special handling to keep the indexes matching with /// the codesec, so we cant just use a VecSection. funcsec: Section, - /// Number of functions listed in the funcsec. Must be kept in sync with - /// codesec.entries.items.len. - funcs_count: u32, + /// The typeidx stored for each function, indexed by funcidx. + func_types: std.ArrayListUnmanaged(u32) = std.ArrayListUnmanaged(u32){}, codesec: VecSection, fn init(file: fs.File, funcs_offset: u64, funcs_size: u64, code_offset: u64, code_size: u64) !Funcs { return Funcs{ .funcsec = (try VecSection.init(spec.funcs_id, file, funcs_offset, funcs_size)).section, - .funcs_count = 0, .codesec = try VecSection.init(spec.code_id, file, code_offset, code_size), }; } fn deinit(self: *Funcs) void { const wasm = @fieldParentPtr(Wasm, "funcs", self); + self.func_types.deinit(wasm.base.allocator); self.codesec.deinit(wasm.base.allocator); } @@ -333,25 +329,30 @@ const Funcs = struct { const file = wasm.base.file.?; const allocator = wasm.base.allocator; - assert(self.funcs_count == self.codesec.entries.items.len); + assert(self.func_types.items.len == self.codesec.entries.items.len); // TODO: consider nop-padding the code if there is a close but not perfect fit const funcidx = try self.codesec.addEntry(file, allocator, code); - if (self.funcs_count < self.codesec.entries.items.len) { + if (self.func_types.items.len < self.codesec.entries.items.len) { // u32 vector length + funcs_count u32s in the vector - const current = 5 + self.funcs_count * 5; + const current = 5 + @intCast(u32, self.func_types.items.len) * 5; try self.funcsec.resize(file, current, current + 5); - self.funcs_count += 1; + try self.func_types.append(allocator, typeidx); // Update the size in the section header and the item count of // the contents vector. + const count = @intCast(u32, self.func_types.items.len); var size_and_count: [10]u8 = undefined; - leb.writeUnsignedFixed(5, size_and_count[0..5], 5 + self.funcs_count * 5); - leb.writeUnsignedFixed(5, size_and_count[5..], self.funcs_count); + leb.writeUnsignedFixed(5, size_and_count[0..5], 5 + count * 5); + leb.writeUnsignedFixed(5, size_and_count[5..], count); try file.pwriteAll(&size_and_count, self.funcsec.offset + 1); + } else { + // We are overwriting a dead function and may now free the type + wasm.types.free(self.func_types.items[funcidx]); } - assert(self.funcs_count == self.codesec.entries.items.len); + + assert(self.func_types.items.len == self.codesec.entries.items.len); var typeidx_leb: [5]u8 = undefined; leb.writeUnsignedFixed(5, &typeidx_leb, typeidx); -- cgit v1.2.3