authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-05-28 10:50:16+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-05-28 12:58:17+02:00
log8a81dfc9997c4ae8a109071be9754d3bb52a78f0
tree2c6b34496644cd2f61ad3553f46c8a561f282b0b
parent967a299c346937316158f58f3d3ae1be7ee0f551
signaturelock-open Commit is signed but in an unrecognized format.

wasm: Reverse the order of error and payload

This will set us up to correctly retrieve the error local index and payload index depending on that of the multi_value's index. As from now, the error will always use the multi_value's index, and the payload will use the following locals.

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

src/codegen/wasm.zig+21-16
......@@ -623,7 +623,8 @@ pub const Context = struct {
623623 .Struct => {
624624 // for each struct field, generate a local
625625 const struct_data: *Module.Struct = ty.castTag(.@"struct").?.data;
626 try self.locals.ensureCapacity(self.gpa, self.locals.items.len + struct_data.fields.count());
626 const fields_len = @intCast(u32, struct_data.fields.count());
627 try self.locals.ensureCapacity(self.gpa, self.locals.items.len + fields_len);
627628 for (struct_data.fields.items()) |entry| {
628629 const val_type = try self.genValtype(
629630 .{ .node_offset = struct_data.node_offset },
......@@ -634,19 +635,20 @@ pub const Context = struct {
634635 }
635636 return WValue{ .multi_value = .{
636637 .index = initial_index,
637 .count = @intCast(u32, struct_data.fields.count()),
638 .count = fields_len,
638639 } };
639640 },
640641 .ErrorUnion => {
641 // generate a local for both the error and the payload.
642642 const payload_type = ty.errorUnionChild();
643 const val_type = try self.genValtype(.{ .node_offset = 0 }, payload_type);
643644
644 // we emit the payload value as the first local, and the error as the second
645 // The first local is also used to find the index of the error.
645 // we emit the error value as the first local, and the payload as the following.
646 // The first local is also used to find the index of the error and payload.
647 //
648 // TODO: Add support where the payload is a type that contains multiple locals such as a struct.
646649 try self.locals.ensureCapacity(self.gpa, self.locals.items.len + 2);
647 const val_type = try self.genValtype(.{ .node_offset = 0 }, payload_type);
648 self.locals.appendAssumeCapacity(val_type);
649650 self.locals.appendAssumeCapacity(wasm.valtype(.i32)); // error values are always i32
651 self.locals.appendAssumeCapacity(val_type);
650652 self.local_index += 2;
651653
652654 return WValue{ .multi_value = .{
......@@ -1039,6 +1041,9 @@ pub const Context = struct {
10391041 const error_type = ty.errorUnionSet();
10401042 const payload_type = ty.errorUnionChild();
10411043 if (value.getError()) |_| {
1044 // write the error value
1045 try self.emitConstant(src, data, error_type);
1046
10421047 // no payload, so write a '0' const
10431048 const opcode: wasm.Opcode = buildOpcode(.{
10441049 .op = .@"const",
......@@ -1046,15 +1051,12 @@ pub const Context = struct {
10461051 });
10471052 try writer.writeByte(wasm.opcode(opcode));
10481053 try leb.writeULEB128(writer, @as(u32, 0));
1049
1050 // write the error value
1051 try self.emitConstant(src, data, error_type);
10521054 } else {
1053 // payload first
1054 try self.emitConstant(src, data, payload_type);
10551055 // no error, so write a '0' const
10561056 try writer.writeByte(wasm.opcode(.i32_const));
10571057 try leb.writeULEB128(writer, @as(u32, 0));
1058 // after the error code, we emit the payload
1059 try self.emitConstant(src, data, payload_type);
10581060 }
10591061 },
10601062 else => |zig_type| return self.fail(src, "Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),
......@@ -1278,8 +1280,8 @@ pub const Context = struct {
12781280 const offset = self.code.items.len;
12791281 const writer = self.code.writer();
12801282
1281 // load the error value which is the payload's multi_value index + 1
1282 try self.emitWValue(.{ .local = operand.multi_value.index + 1 });
1283 // load the error value which is positioned at multi_value's index
1284 try self.emitWValue(.{ .local = operand.multi_value.index });
12831285 // Compare the error value with '0'
12841286 try writer.writeByte(wasm.opcode(.i32_const));
12851287 try leb.writeILEB128(writer, @as(i32, 0));
......@@ -1293,8 +1295,11 @@ pub const Context = struct {
12931295
12941296 fn genUnwrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
12951297 const operand = self.resolveInst(inst.operand);
1296 // payload's local index is that of its multi_value index, so convert it to a `WValue.local`
1297 return WValue{ .local = operand.multi_value.index };
1298 // The index of multi_value contains the error code. To get the initial index of the payload we get
1299 // the following index. Next, convert it to a `WValue.local`
1300 //
1301 // TODO: Check if payload is a type that requires a multi_value as well and emit that instead. i.e. a struct.
1302 return WValue{ .local = operand.multi_value.index + 1 };
12981303 }
12991304
13001305 fn genWrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {