Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust wasm32-unknown-unknown Math functions not linking

I'm trying the new wasm32-unknown-unknown target for Rust, and I'm experiencing issues invoking math functions (e.g. sin, cos, exp, atan2).

Cargo.toml:

[package]
name = "wasm_math"
version = "0.1.0"
authors = ["..."]

[lib]
path = "src/lib.rs"
crate-type = ["cdylib"]

[dependencies]

src/lib.rs:

#[no_mangle]
pub extern "C" fn invoke_sin(x: f64) -> f64 {
    x.sin()
}

index.html:

<!doctype html>
<html lang="en">
  <head><meta charset="utf-8"><title>Wasm Math</title></head>
  <body></body>
  <script>
    const imports = { env: { } };
    fetch("target/wasm32-unknown-unknown/release/wasm_math.wasm").then(response =>
      response.arrayBuffer()
    ).then(bytes =>
      WebAssembly.instantiate(bytes, imports)
    ).then(results => {
      alert(results.instance.exports.invoke_sin(1.0));
    });
  </script>
</html>

I build the project with the command

cargo build --release --target wasm32-unknown-unknown

When I open the html file in firefox, I get the following error:

LinkError: import object field 'sin' is not a Function

Is there something wrong with my setup? Or is this a shortcoming in Rust/WebAssembly/Firefox? I could manually add the sin function to the imports.env object in the javascript, but that seems very hacky and I would have to do that for every math function that I use. Is there a better way?

I'm using the nightly Rust toolchain (nightly-x86_64-unknown-linux-gnu rustc 1.24.0-nightly (cddc4a62d 2017-12-26)) and Firefox 57.0.1 (64-bit).

like image 297
Iceberg Avatar asked Dec 13 '22 19:12

Iceberg


2 Answers

According to the WASM FAQ sin isn't included.

•WebAssembly doesn’t include its own math functions like sin , cos , exp , pow , and so on. WebAssembly’s strategy for such functions is to allow them to be implemented as library routines in WebAssembly itself (note that x86’s sin and cos instructions are slow and imprecise and are generally avoided these days anyway). Users wishing to use faster and less precise math functions on WebAssembly can simply select a math library implementation which does so.

Rust appears to rely on LLVM to provide sin (f64 impl here) which it does not do for WASM. I would think LLVM should provide it as part of their llvm.sin.f64 intrinsic, but it appears that they don't guarantee implementation for every target per https://llvm.org/docs/LangRef.html#llvm-sin-intrinsic (emphasis mine):

This is an overloaded intrinsic. You can use llvm.sin on any floating-point or vector of floating-point type. Not all targets support all types however.

Maybe, given this, Rust should consider implementing sin itself.

like image 189
Kyle Avatar answered Dec 19 '22 11:12

Kyle


Kyle is spot-on on the diagnosis. I'll add two suggestions.


I know you said you didn't want to manually add the Math functions to your import object, but doing so isn't too bad:

let mathImports = {};
for (let name of Object.getOwnPropertyNames(Math))
  if (typeof Math[name] === "function")
    mathImports[name] = Math[name];

The tricky thing is figuring out how to do so before regular imports (so they don't overwrite anything you've already got), and figuring out which module to put imports in (because WebAssembly imports have a namespace the spec calls module and then a field which you're seeing in the error message, FWIW the error message in Safari will contain both module and field).


You could build a subset of a C library into WebAssembly, and use that as part of your import object. I have a port of musl libc available. The WebAssembly waterfall builds and uses it, instructions for building are in the waterfall's source.

Again, putting its values into the import object is tricky to do right. I'd iterate over the exports of the module with WebAssembly.Module.exports and make sure the name mangling is right (looks like your code expects sin directly, and often C names are mangled with an extra underscore at the start). Then same as above, add them to an import object and get module / field right.

like image 20
JF Bastien Avatar answered Dec 19 '22 12:12

JF Bastien