来自 Rust 的 WASM 没有返回预期的类型
WASM from Rust not returning the expected types
嘿@all 我正在玩 WebAssembly Studio 并创建了一个空的 Rust 项目。
在我的 Rust 代码中,我返回指针和“Hello World”字符串的长度。
编译工作正常,但我期望生成的 WASM 有一个返回两个 i32 的函数。但是我发现一个函数接受一个 i32 并且什么都不返回。
为什么函数没有签名 fn () -> (i32,i32) ?
我应该如何从 WASM 模块中提取这两个值?
(使用 Rust-wasmtime)
您可以在下面找到我正在谈论的代码片段。
提前致谢!
#[no_mangle]
pub extern "C" fn say() -> (*const u8,i32) {
let pointcut = "Hello World";
(pointcut.as_ptr(),11)
}
(module
(type $t0 (func (param i32)))
(func $say (export "say") (type $t0) (param $p0 i32)
get_local $p0
i32.const 11
i32.store offset=4
get_local $p0
i32.const 1024
i32.store)
(table $T0 1 1 anyfunc)
(memory $memory (export "memory") 17)
(data (i32.const 1024) "Hello World"))
WebAssembly 最近才具备 return multiple values 的能力。使用的编译器似乎还不支持这个或者出于兼容性原因不使用它,即对于还不知道这个特性的运行时。
因此,编译器重写代码如下:
#[no_mangle]
pub extern "C" fn say(output: &mut (*const u8, i32)) {
let pointcut = "Hello World";
output.1 = 11;
output.0 = pointcut.as_ptr();
}
至少这会导致与您的代码相同的 WebAssembly 代码。参数output
对应WebAssembly代码中的$p0
WebAssembly 代码现在执行以下操作:
首先,数字 11 被写入元组中的第二项,因此在 output + 4
的内存地址处。偏移量是 4 个字节,因为元组的第一个 i32
有 4 个字节。
其次,将字符串pointcut
的内存地址写入元组的第一个值。正如您在生成的 WebAssembly 代码的数据部分中看到的那样,该字符串被放入内存地址 1024 的线性内存中。注意:pointcut
是一个字符串文字,因此是静态的,因此它不存在于堆栈中,这将是非法的(正如 Coder-256 已经评论过的)并且会导致编译器错误。编辑:由于原始指针没有编译错误。仅对引用执行寿命检查。
所以要得到这两个值,你必须在线性内存中分配8个字节的内存(给两个i32
),用指向这个内存区的指针调用函数,然后读取这两个值.将函数拆分为两个单独的函数可能更方便,其中一个 return 是指针,另一个是长度。至少,这将使提取值更容易,因为两个函数都会 return 一个 i32
.
编辑:我找到了一个article from Mozilla,它也解释了我在“wasm-bindgen”部分的想法。
嘿@all 我正在玩 WebAssembly Studio 并创建了一个空的 Rust 项目。
在我的 Rust 代码中,我返回指针和“Hello World”字符串的长度。 编译工作正常,但我期望生成的 WASM 有一个返回两个 i32 的函数。但是我发现一个函数接受一个 i32 并且什么都不返回。
为什么函数没有签名 fn () -> (i32,i32) ?
我应该如何从 WASM 模块中提取这两个值? (使用 Rust-wasmtime)
您可以在下面找到我正在谈论的代码片段。 提前致谢!
#[no_mangle]
pub extern "C" fn say() -> (*const u8,i32) {
let pointcut = "Hello World";
(pointcut.as_ptr(),11)
}
(module
(type $t0 (func (param i32)))
(func $say (export "say") (type $t0) (param $p0 i32)
get_local $p0
i32.const 11
i32.store offset=4
get_local $p0
i32.const 1024
i32.store)
(table $T0 1 1 anyfunc)
(memory $memory (export "memory") 17)
(data (i32.const 1024) "Hello World"))
WebAssembly 最近才具备 return multiple values 的能力。使用的编译器似乎还不支持这个或者出于兼容性原因不使用它,即对于还不知道这个特性的运行时。
因此,编译器重写代码如下:
#[no_mangle]
pub extern "C" fn say(output: &mut (*const u8, i32)) {
let pointcut = "Hello World";
output.1 = 11;
output.0 = pointcut.as_ptr();
}
至少这会导致与您的代码相同的 WebAssembly 代码。参数output
对应WebAssembly代码中的$p0
WebAssembly 代码现在执行以下操作:
首先,数字 11 被写入元组中的第二项,因此在 output + 4
的内存地址处。偏移量是 4 个字节,因为元组的第一个 i32
有 4 个字节。
其次,将字符串pointcut
的内存地址写入元组的第一个值。正如您在生成的 WebAssembly 代码的数据部分中看到的那样,该字符串被放入内存地址 1024 的线性内存中。注意:pointcut
是一个字符串文字,因此是静态的,因此它不存在于堆栈中,这将是非法的(正如 Coder-256 已经评论过的)并且会导致编译器错误。编辑:由于原始指针没有编译错误。仅对引用执行寿命检查。
所以要得到这两个值,你必须在线性内存中分配8个字节的内存(给两个i32
),用指向这个内存区的指针调用函数,然后读取这两个值.将函数拆分为两个单独的函数可能更方便,其中一个 return 是指针,另一个是长度。至少,这将使提取值更容易,因为两个函数都会 return 一个 i32
.
编辑:我找到了一个article from Mozilla,它也解释了我在“wasm-bindgen”部分的想法。