Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cmd/gravity/src/codegen/exports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ mod tests {
assert!(generated.contains("if err1 != nil {"));
assert!(generated.contains("panic(err1)"));
assert!(generated.contains("results1 := raw1[0]"));
assert!(generated.contains("result2 := api.DecodeU32(results1)"));
assert!(generated.contains("result2 := api.DecodeU32(uint64(results1))"));
assert!(generated.contains("return result2"));
}
}
179 changes: 170 additions & 9 deletions cmd/gravity/src/codegen/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ impl Bindgen for Func<'_> {
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$result := $WAZERO_API_DECODE_U32($operand)
$result := $WAZERO_API_DECODE_U32(uint64($operand))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may look weird but operand can sometimes be a uint32 now, if this U32FromI32 instruction is called after a PointerLoad, as happens in records, which calls ReadUint32Le. Since DecodeU32 requires the arg to be a uint64, we have to explicitly cast, which should be a no-op since the u32 always fits in the u64.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've actually encountered this today and it is a bigger problem than just this fix. I think all of the read/writes need to be converted to the uint64 variant but that large of a change is going to need validation.

};
results.push(Operand::SingleValue(result.into()));
}
Expand Down Expand Up @@ -1087,16 +1087,168 @@ impl Bindgen for Func<'_> {
Instruction::I32Load8S { .. } => todo!("implement instruction: {inst:?}"),
Instruction::I32Load16U { .. } => todo!("implement instruction: {inst:?}"),
Instruction::I32Load16S { .. } => todo!("implement instruction: {inst:?}"),
Instruction::I64Load { .. } => todo!("implement instruction: {inst:?}"),
Instruction::F32Load { .. } => todo!("implement instruction: {inst:?}"),
Instruction::F64Load { .. } => todo!("implement instruction: {inst:?}"),
Instruction::I64Load { offset } => {
// TODO(#58): Support additional ArchitectureSize
let offset = offset.size_wasm32();
let tmp = self.tmp();
let value = &format!("value{tmp}");
let ok = &format!("ok{tmp}");
let default = &format!("default{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$value, $ok := i.module.Memory().ReadUint64Le(uint32($operand + $offset))
$(match &self.result {
GoResult::Anon(GoType::ValueOrError(typ)) => {
if !$ok {
var $default $(typ.as_ref())
return $default, $ERRORS_NEW("failed to read i64 from memory")
}
}
GoResult::Anon(GoType::Error) => {
if !$ok {
return $ERRORS_NEW("failed to read i64 from memory")
}
}
GoResult::Anon(_) | GoResult::Empty => {
$(comment(&["The return type doesn't contain an error so we panic if one is encountered"]))
if !$ok {
panic($ERRORS_NEW("failed to read i64 from memory"))
}
}
})
};
results.push(Operand::SingleValue(value.into()));
}
Instruction::F32Load { offset } => {
// TODO(#58): Support additional ArchitectureSize
let offset = offset.size_wasm32();
let tmp = self.tmp();
let value = &format!("value{tmp}");
let ok = &format!("ok{tmp}");
let default = &format!("default{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$value, $ok := i.module.Memory().ReadUint64Le(uint32($operand + $offset))
$(match &self.result {
GoResult::Anon(GoType::ValueOrError(typ)) => {
if !$ok {
var $default $(typ.as_ref())
return $default, $ERRORS_NEW("failed to read f32 from memory")
}
}
GoResult::Anon(GoType::Error) => {
if !$ok {
return $ERRORS_NEW("failed to read f32 from memory")
}
}
GoResult::Anon(_) | GoResult::Empty => {
$(comment(&["The return type doesn't contain an error so we panic if one is encountered"]))
if !$ok {
panic($ERRORS_NEW("failed to read f32 from memory"))
}
}
})
};
results.push(Operand::SingleValue(value.into()));
}
Instruction::F64Load { offset } => {
// TODO(#58): Support additional ArchitectureSize
let offset = offset.size_wasm32();
let tmp = self.tmp();
let value = &format!("value{tmp}");
let ok = &format!("ok{tmp}");
let default = &format!("default{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$value, $ok := i.module.Memory().ReadUint64Le(uint32($operand + $offset))
$(match &self.result {
GoResult::Anon(GoType::ValueOrError(typ)) => {
if !$ok {
var $default $(typ.as_ref())
return $default, $ERRORS_NEW("failed to read f64 from memory")
}
}
GoResult::Anon(GoType::Error) => {
if !$ok {
return $ERRORS_NEW("failed to read f64 from memory")
}
}
GoResult::Anon(_) | GoResult::Empty => {
$(comment(&["The return type doesn't contain an error so we panic if one is encountered"]))
if !$ok {
panic($ERRORS_NEW("failed to read f64 from memory"))
}
}
})
};
results.push(Operand::SingleValue(value.into()));
}
Instruction::I32Store16 { .. } => todo!("implement instruction: {inst:?}"),
Instruction::I64Store { .. } => todo!("implement instruction: {inst:?}"),
Instruction::F32Store { .. } => todo!("implement instruction: {inst:?}"),
Instruction::F64Store { .. } => todo!("implement instruction: {inst:?}"),
Instruction::F32Store { offset } => {
// TODO(#58): Support additional ArchitectureSize
let offset = offset.size_wasm32();
let tag = &operands[0];
let ptr = &operands[1];
match &self.direction {
Direction::Export => {
quote_in! { self.body =>
$['\r']
i.module.Memory().WriteUint64Le($ptr+$offset, $tag)
}
}
Direction::Import { .. } => {
quote_in! { self.body =>
$['\r']
mod.Memory().WriteUint64Le($ptr+$offset, $tag)
}
}
}
}
Instruction::F64Store { offset } => {
// TODO(#58): Support additional ArchitectureSize
let offset = offset.size_wasm32();
let tag = &operands[0];
let ptr = &operands[1];
match &self.direction {
Direction::Export => {
quote_in! { self.body =>
$['\r']
i.module.Memory().WriteUint64Le($ptr+$offset, $tag)
}
}
Direction::Import { .. } => {
quote_in! { self.body =>
$['\r']
mod.Memory().WriteUint64Le($ptr+$offset, $tag)
}
}
}
}
Instruction::I32FromChar => todo!("implement instruction: {inst:?}"),
Instruction::I64FromU64 => todo!("implement instruction: {inst:?}"),
Instruction::I64FromS64 => todo!("implement instruction: {inst:?}"),
Instruction::I64FromU64 => {
let tmp = self.tmp();
let value = format!("value{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$(&value) := int64($operand)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a Wazero utility for this since a U64 could wrap in an I64?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I can see 😕 from what I can tell the behaviour is correct though and follows two's complement behaviour that both Go and Wasm expect.

}
results.push(Operand::SingleValue(value.into()));
}
Instruction::I64FromS64 => {
let tmp = self.tmp();
let value = format!("value{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$(&value) := $operand
}
results.push(Operand::SingleValue(value.into()));
}
Instruction::I32FromS32 => {
let tmp = self.tmp();
let value = format!("value{tmp}");
Expand Down Expand Up @@ -1196,7 +1348,16 @@ impl Bindgen for Func<'_> {
results.push(Operand::SingleValue(result.into()));
}
Instruction::S64FromI64 => todo!("implement instruction: {inst:?}"),
Instruction::U64FromI64 => todo!("implement instruction: {inst:?}"),
Instruction::U64FromI64 => {
let tmp = self.tmp();
let value = format!("value{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$(&value) := uint64($operand)
}
results.push(Operand::SingleValue(value.into()));
}
Instruction::CharFromI32 => todo!("implement instruction: {inst:?}"),
Instruction::F32FromCoreF32 => {
let tmp = self.tmp();
Expand Down
2 changes: 1 addition & 1 deletion cmd/gravity/tests/cmd/instructions.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func (i *InstructionsInstance) U32Roundtrip(
}

results1 := raw1[0]
result2 := api.DecodeU32(results1)
result2 := api.DecodeU32(uint64(results1))
return result2
}

Expand Down
Empty file.
Loading