Description
I'm working on a WASM library using wasm_bindgen
which wraps ndarray
. I have the following basic structure:
pub enum DynArray {
Float32(ArrayD<f32>),
Float64(ArrayD<f64>),
...
}
impl DynArray {
pub fn sin(&self) -> DynArray {
match self {
DynArray::Float32(arr) => arr.map(|e| e.sin()).into(),
DynArray::Float64(arr) => arr.map(|e| e.sin()).into(),
...
}
}
}
i.e. sin() is implemented by first dispatching on type and then mapping.
However, calling sin
on a Float64
array results in the following runtime error:
RuntimeError: unreachable
at wasm_array_bug.wasm.signature_mismatch:sin (5e6ff9aa49a8693eccd3.module.wasm:0x59426)
at wasm_array_bug.wasm.std::f64::<impl f64>::sin::hb3cd0e4a298bd1b1 (5e6ff9aa49a8693eccd3.module.wasm:0x55d96)
at wasm_array_bug.wasm.wasm_array_bug::DynArray::sin::{{closure}}::hc86147a10cddb9c5 (5e6ff9aa49a8693eccd3.module.wasm:0x560a6)
at wasm_array_bug.wasm.ndarray::iterators::to_vec_mapped::{{closure}}::h0f8b6901051cb335 (5e6ff9aa49a8693eccd3.module.wasm:0x414f7)
at wasm_array_bug.wasm.<core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::fold::h83c1cb924c78a7c1 (5e6ff9aa49a8693eccd3.module.wasm:0x31beb)
at wasm_array_bug.wasm.ndarray::iterators::to_vec_mapped::h2d7cca19531985df (5e6ff9aa49a8693eccd3.module.wasm:0x2c54f)
at wasm_array_bug.wasm.ndarray::impl_constructors::<impl ndarray::ArrayBase<S,D>>::from_shape_trusted_iter_unchecked::hd85ecc6b56c06e67 (5e6ff9aa49a8693eccd3.module.wasm:0x2b1db)
at wasm_array_bug.wasm.ndarray::impl_methods::<impl ndarray::ArrayBase<S,D>>::map::h753b54be2654f42f (5e6ff9aa49a8693eccd3.module.wasm:0x35707)
at wasm_array_bug.wasm.wasm_array_bug::DynArray::sin::h634584090a112859 (5e6ff9aa49a8693eccd3.module.wasm:0x3a986)
at wasm_array_bug.wasm.wasm_array_bug::sin::h90417ccd7ffb0d96 (5e6ff9aa49a8693eccd3.module.wasm:0x5208f)
This error originates in the implementation of f64::sin()
.
Interestingly, I don't get the same error for f32. I also don't get the same error if I remove the enum & match:
#[wasm_bindgen]
pub struct Float64Array {
inner: ArrayD<f64>
}
#[wasm_bindgen]
pub fn sin_float64(arr: &Float64Array) -> Float64Array {
arr.inner.map(|e| e.sin()).into()
}
This makes me think there's likely some strange miscompilation. For reference, here's the f64::sin()
function compiled in the broken case (with enum/match):
(func $std::f64::<impl f64>::sin::hb3cd0e4a298bd1b1 (;960;) (param $var0 f64) (result f64)
(local $var1 i32)
(local $var2 i32)
(local $var3 i32)
(local $var4 i32)
(local $var5 i32)
(local $var6 f64)
(local $var7 f64)
global.get $global0
local.set $var1
i32.const 16
local.set $var2
local.get $var1
local.get $var2
i32.sub
local.set $var3
local.get $var3
global.set $global0
local.get $var3
local.get $var0
f64.store
local.get $var0
call $signature_mismatch:sin
local.set $var6
local.get $var3
local.get $var6
f64.store offset=8
local.get $var3
f64.load offset=8
local.set $var7
i32.const 16
local.set $var4
local.get $var3
local.get $var4
i32.add
local.set $var5
local.get $var5
global.set $global0
local.get $var7
return
)
This appears to push $var0
to the stack and then immediately calls $signature_mismatch:sin
, which halts.
The working case (without enum/match) compiles to the following:
(func $std::f64::<impl f64>::sin::hb3cd0e4a298bd1b1 (;743;) (param $var0 f64) (result f64)
(local $var1 i32)
(local $var2 i32)
(local $var3 i32)
(local $var4 i32)
(local $var5 i32)
(local $var6 f64)
(local $var7 f64)
global.get $global0
local.set $var1
i32.const 16
local.set $var2
local.get $var1
local.get $var2
i32.sub
local.set $var3
local.get $var3
global.set $global0
local.get $var3
local.get $var0
f64.store
local.get $var0
call $sin
local.set $var6
local.get $var3
local.get $var6
f64.store offset=8
local.get $var3
f64.load offset=8
local.set $var7
i32.const 16
local.set $var4
local.get $var3
local.get $var4
i32.add
local.set $var5
local.get $var5
global.set $global0
local.get $var7
return
)
I've uploaded the complete code to reproduce the issue here: https://github.com/hexane360/wasm-array-bug
I'm filing this issue here because it appears to be a miscompilation. It's possible this is actually a problem in wasm-bindgen
or wasm-pack
. Please let me know and I'll open an issue there instead.
Meta
rustc --version --verbose
:
rustc 1.79.0 (129f3b996 2024-06-10)
binary: rustc
commit-hash: 129f3b9964af4d4a709d1383930ade12dfe7c081
commit-date: 2024-06-10
host: aarch64-apple-darwin
release: 1.79.0
LLVM version: 18.1.7
wasm-pack
version0.12.1
wasm-bindgen
version0.2.92