Impossible? wasm32: efficiently calling into Rust code from dynamically generated wasm32 code

Suppose our Rust crate has a function foo(i32) -> i32.

On x86_64, we can easily write wasm32 code that calls foo (using it as an 'import'). After the wasm32 is JIT-ted, I believe the 'overhead' of this "dynamically generated wasm32 calling base Rust function" is just the overhead of a function call.

On Rust/wasm32, we can generate wasm32 code on the fly. We can then load this wasm32 in browser/Chrome. However, I believe we can only provide only JS functions as 'imports' ? As a result, is the 'overhead' of calling a base Rust function something like:

  1. newly generated wasm32 tries to call foo
  2. packages arguments into a JSValue
  3. stops wasm32 runtime, runs JS code on JS interpreter
  4. JS interpreter sees call to Rust/wasm32/foo, sends data over
  5. (precompiled) Rust/wasm32 is invoked
  6. Rust/wasm32/foo runs
  7. reverse above steps to send data back to the dynamically generated wasm32

Basically, instead of "just a function call (as on x86_64)" is the overhead something now like: serialize to JS, swap wasm32 runtime for JS runtime, invoke JS function, swap JS runtime for other wasm32 runtime, ... ? [This seems significantly heavier weight.]

============================================

Practically, why does this matter? Rust, among other things, has a great HashMap. Something that is not trivial to re-implement in wasm32. On wasm32/x86_64, where the overhead is just a function call, I don't mind just 'stealing' Rust's HashMap. However, on wasm32/Browser, if function calls has such high overhead, invoking Rust's HashMap may not make sense.

I'm no wasm expert, but I think you're basically asking for inter-module calls like this question:
https://stackoverflow.com/questions/59727133/can-multiple-wasm-modules-interact-with-each-other-and-share-memory-directly-via

1 Like

Thanks, the SO link was really helpful. It sounds like the person is asking 2 questions (sharing function, sharing memory), and the response of

Yes, you can instantiate module b exporting one of its functions, then instantiate a importing that same function so that the two can interact. However, this is not going to be as fast as one WebAssembly functions calling another as the call is going via the host environment.

seems to suggest that unfortunately there is no direct wasm32 calling, and there is this "JS translation overhead" , or atleast taht is how I am interpreting

However, this is not going to be as fast as one WebAssembly functions calling another as the call is going via the host environment.

I believe in at least Firefox wasm and js use the exact same call frame layout and thus have pretty cheap calls between them. Calls between two wasm modules could be even cheaper I think as there shouldn't be a need to check the argument types. In the past calls between wasm and js went through a trampoline implemented in C++, which is slow, but this is no longer the case: Calls between JavaScript and WebAssembly are finally fast 🎉 - Mozilla Hacks - the Web developer blog

4 Likes

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.