* wiggle: Inline some trivial functions This commit marks a number of functions in wiggle as `#[inline]` as they're otherwise trivial, mostly returning constants. This comes out of some work I looked at recently with Andrew where some of these functions showed up in profiles when they shouldn't. * wiggle: Optimize the `GuestMemory` for shared memory This commit implements a minor optimization to the `GuestMemory` implementation for Wasmtime to skip most methods if a shared memory is in play. Shared memories never get borrowed and this can be used to internally skip some borrow-checker methods. * wiggle: Optimize `GuestPtr::to_vec` This commit replaces the safe implementation of `GuestPtr::to_vec` with an unsafe implementation. The purpose of this is to speed up the function when used with shared memory which otherwise performs a bunch of atomic reads for types like `u8` which does validation-per-element and isn't vectorizable. On a benchmark I was helping Andrew with this sped up the host code enough to the point that guest code dwarfed the execution time. * Fix build
102 lines
3.5 KiB
Rust
102 lines
3.5 KiB
Rust
use crate::borrow::BorrowChecker;
|
|
use crate::{BorrowHandle, GuestError, GuestMemory, Region};
|
|
use std::cell::UnsafeCell;
|
|
|
|
/// Lightweight `wasmtime::Memory` wrapper so we can implement the
|
|
/// `wiggle::GuestMemory` trait on it.
|
|
pub struct WasmtimeGuestMemory<'a> {
|
|
mem: &'a [UnsafeCell<u8>],
|
|
bc: BorrowChecker,
|
|
shared: bool,
|
|
}
|
|
|
|
// These need to be reapplied due to the usage of `UnsafeCell` internally.
|
|
unsafe impl Send for WasmtimeGuestMemory<'_> {}
|
|
unsafe impl Sync for WasmtimeGuestMemory<'_> {}
|
|
|
|
impl<'a> WasmtimeGuestMemory<'a> {
|
|
pub fn new(mem: &'a mut [u8]) -> Self {
|
|
Self {
|
|
// SAFETY: here the `&mut [u8]` is casted to `&[UnsafeCell<u8>]`
|
|
// which is losing in effect the `&mut` access but retaining the
|
|
// borrow. This is done to reflect how the memory is not safe to
|
|
// access while multiple borrows are handed out internally, checked
|
|
// with `bc` below.
|
|
//
|
|
// Additionally this allows unshared memories to have the same
|
|
// internal representation as shared memories.
|
|
mem: unsafe { std::slice::from_raw_parts(mem.as_ptr().cast(), mem.len()) },
|
|
|
|
// Wiggle does not expose any methods for functions to re-enter
|
|
// the WebAssembly instance, or expose the memory via non-wiggle
|
|
// mechanisms. However, the user-defined code may end up
|
|
// re-entering the instance, in which case this is an incorrect
|
|
// implementation - we require exactly one BorrowChecker exist per
|
|
// instance.
|
|
// This BorrowChecker construction is a holdover until it is
|
|
// integrated fully with wasmtime:
|
|
// https://github.com/bytecodealliance/wasmtime/issues/1917
|
|
bc: BorrowChecker::new(),
|
|
shared: false,
|
|
}
|
|
}
|
|
|
|
pub fn shared(mem: &'a [UnsafeCell<u8>]) -> Self {
|
|
Self {
|
|
mem,
|
|
bc: BorrowChecker::new(),
|
|
shared: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl GuestMemory for WasmtimeGuestMemory<'_> {
|
|
#[inline]
|
|
fn base(&self) -> &[UnsafeCell<u8>] {
|
|
self.mem
|
|
}
|
|
|
|
// Note that this implementation has special cases for shared memory
|
|
// specifically because no regions of a shared memory can ever be borrowed.
|
|
// In the shared memory cases `shared_borrow` and `mut_borrow` are never
|
|
// called so that can be used to optimize the other methods by quickly
|
|
// checking a flag before calling the more expensive borrow-checker methods.
|
|
|
|
#[inline]
|
|
fn has_outstanding_borrows(&self) -> bool {
|
|
!self.shared && self.bc.has_outstanding_borrows()
|
|
}
|
|
#[inline]
|
|
fn is_shared_borrowed(&self, r: Region) -> bool {
|
|
!self.shared && self.bc.is_shared_borrowed(r)
|
|
}
|
|
#[inline]
|
|
fn is_mut_borrowed(&self, r: Region) -> bool {
|
|
!self.shared && self.bc.is_mut_borrowed(r)
|
|
}
|
|
#[inline]
|
|
fn shared_borrow(&self, r: Region) -> Result<BorrowHandle, GuestError> {
|
|
debug_assert!(!self.shared);
|
|
self.bc.shared_borrow(r)
|
|
}
|
|
#[inline]
|
|
fn mut_borrow(&self, r: Region) -> Result<BorrowHandle, GuestError> {
|
|
debug_assert!(!self.shared);
|
|
self.bc.mut_borrow(r)
|
|
}
|
|
#[inline]
|
|
fn shared_unborrow(&self, h: BorrowHandle) {
|
|
debug_assert!(!self.shared);
|
|
self.bc.shared_unborrow(h)
|
|
}
|
|
#[inline]
|
|
fn mut_unborrow(&self, h: BorrowHandle) {
|
|
debug_assert!(!self.shared);
|
|
self.bc.mut_unborrow(h)
|
|
}
|
|
#[inline]
|
|
fn is_shared_memory(&self) -> bool {
|
|
self.shared
|
|
}
|
|
}
|