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 {...@@ -623,7 +623,8 @@ pub const Context = struct {
623 .Struct => {623 .Struct => {
624 // for each struct field, generate a local624 // for each struct field, generate a local
625 const struct_data: *Module.Struct = ty.castTag(.@"struct").?.data;625 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);
627 for (struct_data.fields.items()) |entry| {628 for (struct_data.fields.items()) |entry| {
628 const val_type = try self.genValtype(629 const val_type = try self.genValtype(
629 .{ .node_offset = struct_data.node_offset },630 .{ .node_offset = struct_data.node_offset },
...@@ -634,19 +635,20 @@ pub const Context = struct {...@@ -634,19 +635,20 @@ pub const Context = struct {
634 }635 }
635 return WValue{ .multi_value = .{636 return WValue{ .multi_value = .{
636 .index = initial_index,637 .index = initial_index,
637 .count = @intCast(u32, struct_data.fields.count()),638 .count = fields_len,
638 } };639 } };
639 },640 },
640 .ErrorUnion => {641 .ErrorUnion => {
641 // generate a local for both the error and the payload.
642 const payload_type = ty.errorUnionChild();642 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 second645 // we emit the error value as the first local, and the payload as the following.
645 // The first local is also used to find the index of the error.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.
646 try self.locals.ensureCapacity(self.gpa, self.locals.items.len + 2);649 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);
649 self.locals.appendAssumeCapacity(wasm.valtype(.i32)); // error values are always i32650 self.locals.appendAssumeCapacity(wasm.valtype(.i32)); // error values are always i32
651 self.locals.appendAssumeCapacity(val_type);
650 self.local_index += 2;652 self.local_index += 2;
651653
652 return WValue{ .multi_value = .{654 return WValue{ .multi_value = .{
...@@ -1039,6 +1041,9 @@ pub const Context = struct {...@@ -1039,6 +1041,9 @@ pub const Context = struct {
1039 const error_type = ty.errorUnionSet();1041 const error_type = ty.errorUnionSet();
1040 const payload_type = ty.errorUnionChild();1042 const payload_type = ty.errorUnionChild();
1041 if (value.getError()) |_| {1043 if (value.getError()) |_| {
1044 // write the error value
1045 try self.emitConstant(src, data, error_type);
1046
1042 // no payload, so write a '0' const1047 // no payload, so write a '0' const
1043 const opcode: wasm.Opcode = buildOpcode(.{1048 const opcode: wasm.Opcode = buildOpcode(.{
1044 .op = .@"const",1049 .op = .@"const",
...@@ -1046,15 +1051,12 @@ pub const Context = struct {...@@ -1046,15 +1051,12 @@ pub const Context = struct {
1046 });1051 });
1047 try writer.writeByte(wasm.opcode(opcode));1052 try writer.writeByte(wasm.opcode(opcode));
1048 try leb.writeULEB128(writer, @as(u32, 0));1053 try leb.writeULEB128(writer, @as(u32, 0));
1049
1050 // write the error value
1051 try self.emitConstant(src, data, error_type);
1052 } else {1054 } else {
1053 // payload first
1054 try self.emitConstant(src, data, payload_type);
1055 // no error, so write a '0' const1055 // no error, so write a '0' const
1056 try writer.writeByte(wasm.opcode(.i32_const));1056 try writer.writeByte(wasm.opcode(.i32_const));
1057 try leb.writeULEB128(writer, @as(u32, 0));1057 try leb.writeULEB128(writer, @as(u32, 0));
1058 // after the error code, we emit the payload
1059 try self.emitConstant(src, data, payload_type);
1058 }1060 }
1059 },1061 },
1060 else => |zig_type| return self.fail(src, "Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),1062 else => |zig_type| return self.fail(src, "Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),
...@@ -1278,8 +1280,8 @@ pub const Context = struct {...@@ -1278,8 +1280,8 @@ pub const Context = struct {
1278 const offset = self.code.items.len;1280 const offset = self.code.items.len;
1279 const writer = self.code.writer();1281 const writer = self.code.writer();
12801282
1281 // load the error value which is the payload's multi_value index + 11283 // load the error value which is positioned at multi_value's index
1282 try self.emitWValue(.{ .local = operand.multi_value.index + 1 });1284 try self.emitWValue(.{ .local = operand.multi_value.index });
1283 // Compare the error value with '0'1285 // Compare the error value with '0'
1284 try writer.writeByte(wasm.opcode(.i32_const));1286 try writer.writeByte(wasm.opcode(.i32_const));
1285 try leb.writeILEB128(writer, @as(i32, 0));1287 try leb.writeILEB128(writer, @as(i32, 0));
...@@ -1293,8 +1295,11 @@ pub const Context = struct {...@@ -1293,8 +1295,11 @@ pub const Context = struct {
12931295
1294 fn genUnwrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {1296 fn genUnwrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
1295 const operand = self.resolveInst(inst.operand);1297 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`1298 // The index of multi_value contains the error code. To get the initial index of the payload we get
1297 return WValue{ .local = operand.multi_value.index };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 };
1298 }1303 }
12991304
1300 fn genWrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {1305 fn genWrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {