authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-05-08 20:22:55+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-05-19 20:19:00+02:00
log99422cb5284f3e15c1b5a8598a6b1622c0e7b6ca
treecf712b929c5f3fd1128cd83a97863203c762d8f4
parentf2860bb4f40565e43f51757e6cb604bb2df16ae0
signature Commit is signed but in an unrecognized format.

wasm: add `dead` tag to `WValue`

This new tag is used for freed locals that are not allowed to have any remaining references pointing to it. This new tag allows us to easily identify liveness bugs. Previously we would set the entire region to `undefined` which would incorrectly set the tag to `function_index`, making codegen think it was a valid `WValue` while it wasn't.

1 files changed, 9 insertions(+), 2 deletions(-)

src/arch/wasm/CodeGen.zig+9-2
......@@ -29,6 +29,9 @@ const errUnionErrorOffset = codegen.errUnionErrorOffset;
2929
3030/// Wasm Value, created when generating an instruction
3131const WValue = union(enum) {
32 /// `WValue` which has been freed and may no longer hold
33 /// any references.
34 dead: void,
3235 /// May be referenced but is unused
3336 none: void,
3437 /// The value lives on top of the stack
......@@ -86,6 +89,7 @@ const WValue = union(enum) {
8689 fn offset(value: WValue) u32 {
8790 switch (value) {
8891 .stack_offset => |stack_offset| return stack_offset.value,
92 .dead => unreachable,
8993 else => return 0,
9094 }
9195 }
......@@ -123,7 +127,7 @@ const WValue = union(enum) {
123127 .f64 => gen.free_locals_f64.append(gen.gpa, local_value) catch return,
124128 .v128 => gen.free_locals_v128.append(gen.gpa, local_value) catch return,
125129 }
126 value.* = undefined;
130 value.* = .dead;
127131 }
128132};
129133
......@@ -832,6 +836,7 @@ const Branch = struct {
832836
833837 fn deinit(branch: *Branch, gpa: Allocator) void {
834838 branch.values.deinit(gpa);
839 branch.* = undefined;
835840 }
836841};
837842
......@@ -884,7 +889,7 @@ fn processDeath(func: *CodeGen, ref: Air.Inst.Ref) void {
884889 if (value.local.value < reserved_indexes) {
885890 return; // function arguments can never be re-used
886891 }
887 log.debug("Decreasing reference for ref: %{?d}, using local '{d}'\n", .{ Air.refToIndex(ref), value.local.value });
892 log.debug("Decreasing reference for ref: %{?d}, using local '{d}'", .{ Air.refToIndex(ref), value.local.value });
888893 value.local.references -= 1; // if this panics, a call to `reuseOperand` was forgotten by the developer
889894 if (value.local.references == 0) {
890895 value.free(func);
......@@ -1030,6 +1035,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 {
10301035/// Writes the bytecode depending on the given `WValue` in `val`
10311036fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {
10321037 switch (value) {
1038 .dead => unreachable, // reference to free'd `WValue` (missing reuseOperand?)
10331039 .none, .stack => {}, // no-op
10341040 .local => |idx| try func.addLabel(.local_get, idx.value),
10351041 .imm32 => |val| try func.addImm32(@bitCast(i32, val)),
......@@ -1226,6 +1232,7 @@ fn genFunc(func: *CodeGen) InnerError!void {
12261232 defer {
12271233 var outer_branch = func.branches.pop();
12281234 outer_branch.deinit(func.gpa);
1235 assert(func.branches.items.len == 0); // missing branch merge
12291236 }
12301237 // Generate MIR for function body
12311238 try func.genBody(func.air.getMainBody());