authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2020-08-17 23:49:06+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2020-08-18 01:01:13+02:00
logf9963909a1cf73eaee47102f4e4dcafe5afa3898
treecdeae4330ae7e20f9f286f1a16f344a45e6eacb8
parent60fb50ee5a4a06687bf2f7b8774cc46f73a5b07e
signaturelock-open Commit is signed but in an unrecognized format.

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.

1 files changed, 16 insertions(+), 15 deletions(-)

src-self-hosted/link/Wasm.zig+16-15
......@@ -33,7 +33,6 @@ pub const base_tag = link.File.Tag.wasm;
3333
3434pub const FnData = struct {
3535 funcidx: u32,
36 typeidx: u32,
3736};
3837
3938base: link.File,
......@@ -99,7 +98,6 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
9998 return error.TODOImplementNonFnDeclsForWasm;
10099
101100 if (decl.fn_link.wasm) |fn_data| {
102 self.types.free(fn_data.typeidx);
103101 self.funcs.free(fn_data.funcidx);
104102 }
105103
......@@ -113,7 +111,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
113111 try codegen.genCode(&buf, decl);
114112 const funcidx = try self.funcs.new(typeidx, buf.items);
115113
116 decl.fn_link.wasm = .{ .typeidx = typeidx, .funcidx = funcidx };
114 decl.fn_link.wasm = .{ .funcidx = funcidx };
117115
118116 // TODO: we should be more smart and set this only when needed
119117 self.exports.dirty = true;
......@@ -132,7 +130,6 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
132130 // TODO: remove this assert when non-function Decls are implemented
133131 assert(decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn);
134132 if (decl.fn_link.wasm) |fn_data| {
135 self.types.free(fn_data.typeidx);
136133 self.funcs.free(fn_data.funcidx);
137134 decl.fn_link.wasm = null;
138135 }
......@@ -307,21 +304,20 @@ const Funcs = struct {
307304 /// This section needs special handling to keep the indexes matching with
308305 /// the codesec, so we cant just use a VecSection.
309306 funcsec: Section,
310 /// Number of functions listed in the funcsec. Must be kept in sync with
311 /// codesec.entries.items.len.
312 funcs_count: u32,
307 /// The typeidx stored for each function, indexed by funcidx.
308 func_types: std.ArrayListUnmanaged(u32) = std.ArrayListUnmanaged(u32){},
313309 codesec: VecSection,
314310
315311 fn init(file: fs.File, funcs_offset: u64, funcs_size: u64, code_offset: u64, code_size: u64) !Funcs {
316312 return Funcs{
317313 .funcsec = (try VecSection.init(spec.funcs_id, file, funcs_offset, funcs_size)).section,
318 .funcs_count = 0,
319314 .codesec = try VecSection.init(spec.code_id, file, code_offset, code_size),
320315 };
321316 }
322317
323318 fn deinit(self: *Funcs) void {
324319 const wasm = @fieldParentPtr(Wasm, "funcs", self);
320 self.func_types.deinit(wasm.base.allocator);
325321 self.codesec.deinit(wasm.base.allocator);
326322 }
327323
......@@ -333,25 +329,30 @@ const Funcs = struct {
333329 const file = wasm.base.file.?;
334330 const allocator = wasm.base.allocator;
335331
336 assert(self.funcs_count == self.codesec.entries.items.len);
332 assert(self.func_types.items.len == self.codesec.entries.items.len);
337333
338334 // TODO: consider nop-padding the code if there is a close but not perfect fit
339335 const funcidx = try self.codesec.addEntry(file, allocator, code);
340336
341 if (self.funcs_count < self.codesec.entries.items.len) {
337 if (self.func_types.items.len < self.codesec.entries.items.len) {
342338 // u32 vector length + funcs_count u32s in the vector
343 const current = 5 + self.funcs_count * 5;
339 const current = 5 + @intCast(u32, self.func_types.items.len) * 5;
344340 try self.funcsec.resize(file, current, current + 5);
345 self.funcs_count += 1;
341 try self.func_types.append(allocator, typeidx);
346342
347343 // Update the size in the section header and the item count of
348344 // the contents vector.
345 const count = @intCast(u32, self.func_types.items.len);
349346 var size_and_count: [10]u8 = undefined;
350 leb.writeUnsignedFixed(5, size_and_count[0..5], 5 + self.funcs_count * 5);
351 leb.writeUnsignedFixed(5, size_and_count[5..], self.funcs_count);
347 leb.writeUnsignedFixed(5, size_and_count[0..5], 5 + count * 5);
348 leb.writeUnsignedFixed(5, size_and_count[5..], count);
352349 try file.pwriteAll(&size_and_count, self.funcsec.offset + 1);
350 } else {
351 // We are overwriting a dead function and may now free the type
352 wasm.types.free(self.func_types.items[funcidx]);
353353 }
354 assert(self.funcs_count == self.codesec.entries.items.len);
354
355 assert(self.func_types.items.len == self.codesec.entries.items.len);
355356
356357 var typeidx_leb: [5]u8 = undefined;
357358 leb.writeUnsignedFixed(5, &typeidx_leb, typeidx);