-
Notifications
You must be signed in to change notification settings - Fork 2.7k
wasmtime: kill the stubs #8959
Description
Currently, we use runtime_interface machinery to declare the functions available to be called by the wasm substrate runtimes. Specifically from a declaration like the following a set of sp_wasm_interface::Function will be generated.
#[runtime_interface]
pub trait Foo {
fn bar(&self, baz: &[u8]) -> Option<Vec<u8>> {
// implementation is omitted
}
}When we create a wasm runtime instance those will be passed to the instantiated module as imports.
Looking at the Function closely it has two parts:
- functions to query
nameandsignature execute. This function must be invoked when the wasm instance calls the corresponding host function.
Note that execute takes a vector of wasm values. These parameters have the type sp_wasm_interface::Value. That is, a Substrate representation of wasm values. The concrete implementation must adapt these values from the engine specific to the Substrate ones.
Most importantly though, wasmtime jitted machine code doesn't operate on vectors of such Values. Instead, the machine code generated by wasmtime passes values as a normal machine code generated by a normal native compiler would. That means, wasmtime internally has to generate a thunk that adapts values passed via the ABI to the vector of [Val].
To give an idea how severe is the overhead, I ran a quick benchmark that would import 15k kusama blocks. Out of 47 seconds of runtime, at least 4s are spent within machinery related to conversions.
There is a way shave some of that time. wasmtime provides a Func::wrap. In nutshell, It takes a closure with reified types and under the hood generates an extern "C" function shim. That shim upon call will call the closure. The rustc/LLVM optimizer should be able to slim this down to be almost like a hand-rolled one. All without losing safety guarantees.
However, the problem is, at the place where we generate Funcs for the wasmtime (source) we only have Function and it's execute. It seems to me the part of the solution would involve changing runtime_interface so that it somehow knows how to generate the implementations for wasmtime.