How should "env::memory" be provided to WASM programs?

Program Versions

$ rustc --version --verbose
rustc 1.65.0-nightly (0b79f758c 2022-08-18)
binary: rustc
commit-hash: 0b79f758c9aa6646606662a6d623a0752286cd17
commit-date: 2022-08-18
host: x86_64-unknown-linux-gnu
release: 1.65.0-nightly
LLVM version: 15.0.0
$ cargo --version
cargo 1.65.0-nightly (9809f8ff3 2022-08-16)
$ wasmtime --version
wasmtime-cli 0.39.1
$ nodejs --version
v12.22.9

Steps to Reproduce

I created a new Rust crate containing this source code:

use std::sync::atomic::{AtomicI32, Ordering};

static VALUE: AtomicI32 = AtomicI32::new(5);

fn basic_op() -> i32 {
    VALUE.fetch_add(1, Ordering::SeqCst)
}

fn main() {
    let v = basic_op() + basic_op() + basic_op();
}

Then, I compiled it to the target wasm32-unknown-unknown, with the appropriate features enabled for atomics and global memory.

$ RUSTFLAGS='-C target-feature=+atomics,+bulk-memory,+mutable-globals' cargo build --target wasm32-unknown-unknown -Z build-std=panic_abort,std

Then, I attempted to run the resulting .wasm file in the wasmtime runtime:

$ wasmtime run --wasm-features all target/wasm32-unknown-unknown/debug/simple-atomic.wasm                 
Error: failed to run main module `target/wasm32-unknown-unknown/debug/simple-atomic.wasm`

Caused by:
    0: failed to instantiate "target/wasm32-unknown-unknown/debug/simple-atomic.wasm"
    1: unknown import: `env::memory` has not been defined

Believing this to be a bug in wasmtime, I then tried compiling the file in nodejs.

$ nodejs --experimental-repl-await --experimental-wasm-anyref --experimental-wasm-bulk-memory --experimental-wasm-bigint --experimental-wasm-eh --experimental-wasm-mv --experimental-wasm-return-call --experimental-wasm-sat-f2i-conversions --experimental-wasm-se --experimental-wasm-simd --experimental-wasm-threads --experimental-wasm-type-reflection --experimental-wasm-anyref
Welcome to Node.js v12.22.9.
Type ".help" for more information.
> const fs = require("fs");
undefined
> let source = fs.readFileSync("target/wasm32-unknown-unknown/debug/simple-atomic.wasm")
undefined
> let instance = await WebAssembly.instantiate(source, {});
Uncaught:
TypeError: WebAssembly.instantiate(): Import #0 module="env" error: module is not an object or function
> let instance = await WebAssembly.instantiate(source, { env: { memory: [] } });
Uncaught:
LinkError: WebAssembly.instantiate(): Import #0 module="env" function="memory" error: memory import must be a WebAssembly.Memory object

It looks like the WASM file expects a "memory" object in its environment. I cannot find any documentation on this "memory" object. I assume it's supposed to be an object where global memory is stored. How should this be set from the JS end? Is there a way, within wasmtime, to successfully invoke this code?

The wasmtime cli assumes wasi programs. Wasi doesn't yet support multithreading. I believe it is waiting on the wasm threads proposal (which add native threads in a single wasm instance rather than having multiple wasm instances share memory.) You will have to manually handle the wasm multithreading. That is you need an instance of a SharedMemory and then provide it as memory entry in the env import. This is done for each thread. In addition for a single thread you need to invoke the method to initialize the memory.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.