-
Notifications
You must be signed in to change notification settings - Fork 2.7k
executor: Migrate wasmtime backend to a high-level API #4686
Conversation
This may solve a problem with segfaults.
tomusdrw
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My WASM / wasmtime / low level knowledge is pretty limited, but it looks reasonable. I like the unsafe abstractions introduced and the docs are very convincing that everything is correct :)
| // available in substrate. | ||
| // | ||
| // This, however, cannot happen since the signature of this function is created from | ||
| // a `dyn Function` signature of which cannot have a non substrate value by definition. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the values that we support change over time? Would the documentation above still be valid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess no. But I am not sure what would be a better way?
| pub fn extract_heap_base(&self) -> Result<u32> { | ||
| let heap_base_export = self | ||
| .instance | ||
| .get_export("__heap_base") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should stuff like __heap_base rather be declared as some constants? Usually I prefer that over random strings sprinkled all over, at least you can maintain some convention, even if the constant is only used in one place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would also give a place to leave some docs!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be a good idea to address this in a follow-up PR!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine with me!
Co-Authored-By: Tomasz Drwięga <[email protected]>
Demi-Marie
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are still many places where code could be made safer. I don’t see any explicit unsoundness, but I also am not convinced that the code is safe either.
| /// # Safety | ||
| /// | ||
| /// This wrapper requires exclusive ownership over the given instance and all its components. | ||
| /// Since `Instance` is a `Clone` we cannot use typesystem to prevent this, hence unsafe. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can (and should) use RefCell or Mutex for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if I agree: how would they help from violating the invariant? It would still be possible to clone the memory instance from within this module and create aliases, right?
| /// | ||
| /// Wasmtime doesn't provide comprehensive documentation about the exact behavior of the data | ||
| /// pointer. If a dynamic style heap is used the base pointer of the heap can change. Since | ||
| /// growing, we cannot guarantee the lifetime of the returned slice reference. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A better approach would be for this to be a function taking a callback, such that the reference cannot escape the callback.
| /// See `[memory_as_slice]`. In addition to those requirements, since a mutable reference is | ||
| /// returned it must be ensured that only one mutable and no shared references to memory exists | ||
| /// at the same time. | ||
| unsafe fn memory_as_slice_mut(&self) -> &mut [u8] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
# Conflicts: # Cargo.lock # client/executor/common/src/sandbox.rs # client/executor/wasmi/src/lib.rs # client/executor/wasmtime/src/function_executor.rs # client/executor/wasmtime/src/runtime.rs # client/executor/wasmtime/src/util.rs
bkchr
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
|
||
| let resolved = match import_ty.name() { | ||
| "memory" => { | ||
| memory_import_index = Some(externs.len()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we error when a second memory instance is requested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure!
First, it won't be possible atm, since if the module has 2 memory imports then it is a not valid module. Second, as soon as multiple memories are supported then it is OK (although useless) to import the same memory twice.
Co-Authored-By: Bastian Köcher <[email protected]>
* Migrate wasmtime backend to wasmtime-api * Port to a newer version of wasmtime * Update to the latest changes. * Rejig the sandbox module a bit * Materialze * Fixes. * executor wasm_runtime fix * Refactor everything * More refactoring * Even more refactorings * More cleaning. * Update to the latest wasmtime * Reformat * Renames * Refactoring and comments. * Docs * Rename FunctionExecutor to host. * Imrpove docs. * fmt * Remove panic * Assert the number of arguments are equal between wasmtime and hostfunc. * Comment a possible panic if there is no corresponding value variant. * Check signature of the entrypoint. * Use git version of wasmtime * Refine and doc the sandbox code. * Comment RefCells. * Update wasmtime to the latest-ish master. This may solve a problem with segfaults. * Apply suggestions from code review Co-Authored-By: Tomasz Drwięga <[email protected]> * Use full SHA1 hash of wasmtime commit. * Add a panic message. * Add some documentation * Update wasmtime version to include SIGSEGV fix * Update to crates.io version of wasmtime * Make it work. * Move the creation of memory into `InstanceWrapper::new` * Make `InstanceWrapper` !Send & !Sync * Avoid using `take_mut` * Update client/executor/wasmtime/Cargo.toml Co-Authored-By: Bastian Köcher <[email protected]> * Limit maximum size of memory. * Rename `init_state` to `with_initialized_state` Co-authored-by: Tomasz Drwięga <[email protected]> Co-authored-by: Bastian Köcher <[email protected]>
Fixes #4599
This PR is basically a refactoring that migrates the code from wasmtime-runtime, wasmtime-jit et al to the now stable
wasmtimecrate. The crate is now sprinkled with comments. Hopefully, one now doesn't have to have a black belt in unsafejitsu to deal with this crate.Note that this PR relies on some fixes on the wasmtime side, hence the git reference.
This PR should not introduce any significant functional changes and should have the same behavior.
TODO: