authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-08-16 23:23:57+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-08-16 23:23:57+02:00
log46af37a1ad8bcff989ae18624b02760ab7a5bfa5
treed3cf92e07a8595883e86f00c9de099127338e775
parent23541774d6b01b1b614cc5aa3514295ce88917a5

wasm: fix and test when dead function emitted after incremental update


2 files changed, 59 insertions(+), 0 deletions(-)

src/link/Wasm/Flush.zig+9
......@@ -249,6 +249,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
249249 };
250250 const is_obj = comp.config.output_mode == .Obj;
251251 const allow_undefined = is_obj or wasm.import_symbols;
252 const zcu_references = if (comp.zcu) |zcu| try zcu.resolveReferences() else null;
252253
253254 const entry_name = if (wasm.entry_resolution.isNavOrUnresolved(wasm)) wasm.entry_name else .none;
254255
......@@ -1223,6 +1224,14 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
12231224 try emitTagIndexFunction(wasm, binary_bytes, ip_index);
12241225 },
12251226 else => {
1227 if (!zcu_references.?.contains(.wrap(.{ .func = ip_index }))) {
1228 try binary_bytes.appendSlice(gpa, &.{
1229 0, // no locals
1230 @backingInt(std.wasm.Opcode.@"unreachable"),
1231 @backingInt(std.wasm.Opcode.end),
1232 });
1233 continue;
1234 }
12261235 const func = i.value(wasm).function;
12271236 const mir: Mir = .{
12281237 .instructions = wasm.mir_instructions.slice().subslice(func.instructions_off, func.instructions_len),
test/incremental/remove_function_with_changed_callee created+50
......@@ -0,0 +1,50 @@
1#update=initial version
2#file=main.zig
3const std = @import("std");
4const io = std.Io.Threaded.global_single_threaded.io();
5
6const A = enum(u32) {
7 zero,
8 one,
9};
10
11fn foo() !void {
12 try bar(.zero);
13}
14
15fn bar(a: A) !void {
16 const msg = switch (a) {
17 .zero => "0",
18 .one => "1",
19 };
20 try std.Io.File.stdout().writeStreamingAll(io, msg);
21}
22
23pub fn main() !void {
24 try foo();
25}
26#expect_stdout="0"
27#update=remove foo and change bar wasm function type
28#file=main.zig
29//! This update must preserve `bar` `InternPool.Index` value, while changing its wasm function type.
30//! If `foo` code is preserved in the binary without any changes, wasm type checking will fail.
31const std = @import("std");
32const io = std.Io.Threaded.global_single_threaded.io();
33
34const A = enum(u64) {
35 zero,
36 one,
37};
38
39fn bar(a: A) !void {
40 const msg = switch (a) {
41 .zero => "0",
42 .one => "1",
43 };
44 try std.Io.File.stdout().writeStreamingAll(io, msg);
45}
46
47pub fn main() !void {
48 try bar(.one);
49}
50#expect_stdout="1"