| ... | @@ -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 local | 624 | // 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); |
| 643 | | 644 | |
| 644 | // we emit the payload value as the first local, and the error as the second | 645 | // 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 i32 | 650 | 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; |
| 651 | | 653 | |
| 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' const | 1047 | // 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' const | 1055 | // 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(); |
| 1280 | | 1282 | |
| 1281 | // load the error value which is the payload's multi_value index + 1 | 1283 | // 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 { |
| 1293 | | 1295 | |
| 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 | } |
| 1299 | | 1304 | |
| 1300 | fn genWrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue { | 1305 | fn genWrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue { |