From 81a89169f556d2ba8c6ddc75ae0ac471f213f1c3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 4 May 2024 15:02:26 -0700 Subject: [PATCH] Add support for `#![no_std]` to the `wasmtime` crate (#8533) * Always fall back to custom platform for Wasmtime This commit updates Wasmtime's platform support to no longer require an opt-in `RUSTFLAGS` `--cfg` flag to be specified. With `no_std` becoming officially supported this should provide a better onboarding experience where the fallback custom platform is used. This will cause linker errors if the symbols aren't implemented and searching/googling should lead back to our docs/repo (eventually, hopefully). * Change Wasmtime's TLS state to a single pointer This commit updates the management of TLS to rely on just a single pointer rather than a pair of a pointer and a `bool`. Additionally management of the TLS state is pushed into platform-specific modules to enable different means of managing it, namely the "custom" platform now has a C function required to implement TLS state for Wasmtime. * Delay conversion to `Instant` in atomic intrinsics The `Duration` type is available in `no_std` but the `Instant` type is not. The intention is to only support the `threads` proposal if `std` is active but to assist with this split push the `Duration` further into Wasmtime to avoid using a type that can't be mentioned in `no_std`. * Gate more parts of Wasmtime on the `profiling` feature Move `serde_json` to an optional dependency and gate the guest profiler entirely on the `profiling` feature. * Refactor conversion to `anyhow::Error` in `wasmtime-environ` Have a dedicated trait for consuming `self` in addition to a `Result`-friendly trait. * Gate `gimli` in Wasmtime on `addr2line` Cut down the dependency list if `addr2line` isn't enabled since then the dependency is not used. While here additionally lift the version requirement for `addr2line` up to the workspace level. * Update `bindgen!` to have `no_std`-compatible output Pull most types from Wasmtime's `__internal` module as the source of truth. * Use an `Option` for `gc_store` instead of `OnceCell` No need for synchronization here when mutability is already available in the necessary contexts. * Enable embedder-defined host feature detection * Add `#![no_std]` support to the `wasmtime` crate This commit enables compiling the `runtime`, `gc`, and `component-model` features of the `wasmtime` crate on targets that do not have `std`. This tags the crate as `#![no_std]` and then updates everything internally to import from `core` or `alloc` and adapt for the various idioms. This ended up requiring some relatively extensive changes, but nothing too too bad in the grand scheme of things. * Require `std` for the perfmap profiling agent prtest:full * Fix build on wasm * Fix windows build * Remove unused import * Fix Windows/Unix build without `std` feature * Fix some doc links * Remove unused import * Fix build of wasi-common in isolation * Fix no_std build on macos * Re-fix build * Fix standalone build of wasmtime-cli-flags * Resolve a merge conflict * Review comments * Remove unused import --- .github/workflows/main.yml | 12 +- Cargo.lock | 2 + Cargo.toml | 5 +- crates/c-api/Cargo.toml | 2 +- crates/cli-flags/Cargo.toml | 2 +- crates/component-macro/Cargo.toml | 1 + crates/component-macro/src/component.rs | 32 +-- .../component-macro/tests/codegen_no_std.rs | 16 ++ crates/environ/src/lib.rs | 38 ++- crates/wasi-common/Cargo.toml | 2 +- crates/wasi/Cargo.toml | 2 +- crates/wasmtime/Cargo.toml | 61 +++-- crates/wasmtime/src/compile.rs | 1 + crates/wasmtime/src/compile/code_builder.rs | 1 + crates/wasmtime/src/config.rs | 143 +++++++++- crates/wasmtime/src/engine.rs | 204 +++++++------- crates/wasmtime/src/engine/serialization.rs | 32 ++- crates/wasmtime/src/lib.rs | 18 ++ crates/wasmtime/src/profiling_agent.rs | 3 +- .../wasmtime/src/profiling_agent/jitdump.rs | 1 + .../wasmtime/src/profiling_agent/perfmap.rs | 1 + crates/wasmtime/src/profiling_agent/vtune.rs | 1 + crates/wasmtime/src/runtime.rs | 13 +- crates/wasmtime/src/runtime/code.rs | 2 +- crates/wasmtime/src/runtime/code_memory.rs | 12 +- .../src/runtime/component/component.rs | 20 +- crates/wasmtime/src/runtime/component/func.rs | 19 +- .../src/runtime/component/func/host.rs | 21 +- .../src/runtime/component/func/options.rs | 17 +- .../src/runtime/component/func/typed.rs | 70 +++-- .../src/runtime/component/instance.rs | 10 +- .../wasmtime/src/runtime/component/linker.rs | 13 +- .../src/runtime/component/matching.rs | 5 +- crates/wasmtime/src/runtime/component/mod.rs | 3 + .../src/runtime/component/resource_table.rs | 19 +- .../src/runtime/component/resources.rs | 13 +- .../wasmtime/src/runtime/component/storage.rs | 4 +- .../wasmtime/src/runtime/component/store.rs | 1 + .../wasmtime/src/runtime/component/types.rs | 6 +- .../wasmtime/src/runtime/component/values.rs | 26 +- crates/wasmtime/src/runtime/coredump.rs | 4 +- crates/wasmtime/src/runtime/debug.rs | 5 +- .../wasmtime/src/runtime/externals/global.rs | 6 +- .../wasmtime/src/runtime/externals/table.rs | 32 ++- crates/wasmtime/src/runtime/func.rs | 23 +- crates/wasmtime/src/runtime/func/typed.rs | 10 +- crates/wasmtime/src/runtime/gc.rs | 14 +- .../src/runtime/gc/disabled/externref.rs | 2 +- .../src/runtime/gc/disabled/rooting.rs | 24 +- .../wasmtime/src/runtime/gc/enabled/anyref.rs | 5 +- .../src/runtime/gc/enabled/externref.rs | 12 +- crates/wasmtime/src/runtime/gc/enabled/i31.rs | 5 +- .../src/runtime/gc/enabled/rooting.rs | 56 ++-- crates/wasmtime/src/runtime/instance.rs | 11 +- crates/wasmtime/src/runtime/instantiate.rs | 5 +- crates/wasmtime/src/runtime/limits.rs | 1 + crates/wasmtime/src/runtime/linker.rs | 22 +- crates/wasmtime/src/runtime/memory.rs | 30 ++- crates/wasmtime/src/runtime/module.rs | 50 ++-- .../wasmtime/src/runtime/module/registry.rs | 26 +- crates/wasmtime/src/runtime/profiling.rs | 5 +- crates/wasmtime/src/runtime/resources.rs | 4 +- crates/wasmtime/src/runtime/stack.rs | 4 +- crates/wasmtime/src/runtime/store.rs | 114 ++++---- crates/wasmtime/src/runtime/store/data.rs | 11 +- .../wasmtime/src/runtime/store/func_refs.rs | 4 +- crates/wasmtime/src/runtime/trampoline.rs | 5 +- .../wasmtime/src/runtime/trampoline/func.rs | 5 +- .../wasmtime/src/runtime/trampoline/global.rs | 4 +- .../wasmtime/src/runtime/trampoline/memory.rs | 7 +- .../wasmtime/src/runtime/trampoline/table.rs | 1 + crates/wasmtime/src/runtime/trap.rs | 7 +- crates/wasmtime/src/runtime/type_registry.rs | 43 ++- crates/wasmtime/src/runtime/types.rs | 3 +- crates/wasmtime/src/runtime/types/matching.rs | 1 + crates/wasmtime/src/runtime/unix.rs | 1 + crates/wasmtime/src/runtime/v128.rs | 4 +- crates/wasmtime/src/runtime/values.rs | 2 +- crates/wasmtime/src/runtime/vm.rs | 10 +- .../wasmtime/src/runtime/vm/arch/aarch64.rs | 6 +- crates/wasmtime/src/runtime/vm/arch/x86_64.rs | 4 +- crates/wasmtime/src/runtime/vm/async_yield.rs | 2 +- crates/wasmtime/src/runtime/vm/component.rs | 24 +- .../src/runtime/vm/component/libcalls.rs | 16 +- .../src/runtime/vm/component/resources.rs | 3 +- crates/wasmtime/src/runtime/vm/cow.rs | 43 +-- crates/wasmtime/src/runtime/vm/export.rs | 2 +- crates/wasmtime/src/runtime/vm/gc.rs | 9 +- crates/wasmtime/src/runtime/vm/gc/disabled.rs | 1 + .../wasmtime/src/runtime/vm/gc/enabled/drc.rs | 22 +- .../src/runtime/vm/gc/enabled/externref.rs | 7 +- .../src/runtime/vm/gc/enabled/free_list.rs | 8 +- crates/wasmtime/src/runtime/vm/gc/gc_ref.rs | 33 ++- .../wasmtime/src/runtime/vm/gc/gc_runtime.rs | 17 +- .../wasmtime/src/runtime/vm/gc/host_data.rs | 3 +- crates/wasmtime/src/runtime/vm/gc/i31.rs | 5 +- crates/wasmtime/src/runtime/vm/instance.rs | 34 +-- .../src/runtime/vm/instance/allocator.rs | 32 ++- .../vm/instance/allocator/on_demand.rs | 3 +- .../runtime/vm/instance/allocator/pooling.rs | 5 +- .../allocator/pooling/gc_heap_pool.rs | 1 + .../allocator/pooling/index_allocator.rs | 1 + .../instance/allocator/pooling/memory_pool.rs | 1 + .../allocator/pooling/unix_stack_pool.rs | 1 + crates/wasmtime/src/runtime/vm/libcalls.rs | 99 +++++-- crates/wasmtime/src/runtime/vm/memory.rs | 25 +- crates/wasmtime/src/runtime/vm/mmap.rs | 18 +- crates/wasmtime/src/runtime/vm/mmap_vec.rs | 17 +- crates/wasmtime/src/runtime/vm/module_id.rs | 2 +- crates/wasmtime/src/runtime/vm/mpk/enabled.rs | 1 + crates/wasmtime/src/runtime/vm/mpk/mod.rs | 2 +- crates/wasmtime/src/runtime/vm/mpk/pkru.rs | 4 +- crates/wasmtime/src/runtime/vm/mpk/sys.rs | 1 + .../wasmtime/src/runtime/vm/send_sync_ptr.rs | 10 +- crates/wasmtime/src/runtime/vm/store_box.rs | 2 + .../src/runtime/vm/sys/custom/capi.rs | 11 + .../src/runtime/vm/sys/custom/mmap.rs | 17 +- .../wasmtime/src/runtime/vm/sys/custom/mod.rs | 16 +- .../src/runtime/vm/sys/custom/traphandlers.rs | 2 +- .../wasmtime/src/runtime/vm/sys/custom/vm.rs | 27 +- .../wasmtime/src/runtime/vm/sys/miri/mod.rs | 14 + crates/wasmtime/src/runtime/vm/sys/mod.rs | 10 +- .../wasmtime/src/runtime/vm/sys/unix/mmap.rs | 31 ++- .../wasmtime/src/runtime/vm/sys/unix/mod.rs | 14 + .../src/runtime/vm/sys/unix/signals.rs | 2 +- .../src/runtime/vm/sys/unix/unwind.rs | 5 +- crates/wasmtime/src/runtime/vm/sys/unix/vm.rs | 29 +- .../src/runtime/vm/sys/windows/mmap.rs | 11 +- .../src/runtime/vm/sys/windows/mod.rs | 14 + crates/wasmtime/src/runtime/vm/table.rs | 22 +- .../src/runtime/vm/threads/parking_spot.rs | 2 + .../src/runtime/vm/threads/shared_memory.rs | 13 +- .../vm/threads/shared_memory_disabled.rs | 11 +- .../wasmtime/src/runtime/vm/traphandlers.rs | 112 ++++---- .../src/runtime/vm/traphandlers/backtrace.rs | 9 +- .../vm/traphandlers/coredump_enabled.rs | 7 +- crates/wasmtime/src/runtime/vm/vmcontext.rs | 30 +-- .../vm/vmcontext/vm_host_func_context.rs | 3 +- crates/wasmtime/src/runtime/windows.rs | 1 + crates/wasmtime/src/sync_nostd.rs | 255 ++++++++++++++++++ crates/wasmtime/src/sync_std.rs | 52 ++++ crates/wit-bindgen/Cargo.toml | 3 + crates/wit-bindgen/src/lib.rs | 34 ++- crates/wit-bindgen/src/rust.rs | 4 +- .../embedding/wasmtime-platform.c | 8 + .../embedding/wasmtime-platform.h | 15 ++ tests/all/memory.rs | 4 +- 147 files changed, 1765 insertions(+), 919 deletions(-) create mode 100644 crates/component-macro/tests/codegen_no_std.rs create mode 100644 crates/wasmtime/src/sync_nostd.rs create mode 100644 crates/wasmtime/src/sync_std.rs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 98cd8b8bced4..360a7b295471 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -323,6 +323,7 @@ jobs: - run: cargo check -p wasmtime --no-default-features --features pooling-allocator - run: cargo check -p wasmtime --no-default-features --features cranelift - run: cargo check -p wasmtime --no-default-features --features component-model + - run: cargo check -p wasmtime --no-default-features --features runtime,component-model - run: cargo check -p wasmtime --no-default-features --features cranelift,wat,async,cache - run: cargo check -p wasmtime --no-default-features --features winch - run: cargo check -p wasmtime --no-default-features --features wmemcheck @@ -363,16 +364,7 @@ jobs: # Checks for no_std support, ensure that crates can build on a no_std # target - run: rustup target add x86_64-unknown-none - - run: cargo check -p wasmtime-jit-icache-coherence - env: - CARGO_BUILD_TARGET: x86_64-unknown-none - - run: cargo check -p wasmtime-asm-macros - env: - CARGO_BUILD_TARGET: x86_64-unknown-none - - run: cargo check -p wasmtime-slab - env: - CARGO_BUILD_TARGET: x86_64-unknown-none - - run: cargo check -p wasmtime-environ --features gc,component-model + - run: cargo check -p wasmtime --no-default-features --features gc,component-model env: CARGO_BUILD_TARGET: x86_64-unknown-none diff --git a/Cargo.lock b/Cargo.lock index 4cd3570af4c3..ad402dbf2046 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3402,9 +3402,11 @@ dependencies = [ "encoding_rs", "fxprof-processed-profile", "gimli", + "hashbrown 0.14.3", "indexmap 2.0.0", "ittapi", "libc", + "libm", "log", "mach2", "memfd", diff --git a/Cargo.toml b/Cargo.toml index bed1553dd623..df798c828535 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ path = "src/bin/wasmtime.rs" doc = false [dependencies] -wasmtime = { workspace = true } +wasmtime = { workspace = true, features = ['std'] } wasmtime-cache = { workspace = true, optional = true } wasmtime-cli-flags = { workspace = true } wasmtime-cranelift = { workspace = true, optional = true } @@ -246,6 +246,7 @@ wit-component = "0.206.0" cc = "1.0" object = { version = "0.33", default-features = false, features = ['read_core', 'elf'] } gimli = { version = "0.28.0", default-features = false, features = ['read'] } +addr2line = { version = "0.21.0", default-features = false } anyhow = { version = "1.0.22", default-features = false } windows-sys = "0.52.0" env_logger = "0.10" @@ -253,7 +254,7 @@ log = { version = "0.4.8", default-features = false } clap = { version = "4.3.12", default-features = false, features = ["std", "derive"] } hashbrown = { version = "0.14", default-features = false } capstone = "0.12.0" -once_cell = "1.12.0" +once_cell = { version = "1.12.0", default-features = false } smallvec = { version = "1.6.1", features = ["union"] } tracing = "0.1.26" bitflags = "2.0" diff --git a/crates/c-api/Cargo.toml b/crates/c-api/Cargo.toml index d5f6aab28e74..1bbf9a82aad0 100644 --- a/crates/c-api/Cargo.toml +++ b/crates/c-api/Cargo.toml @@ -22,7 +22,7 @@ doctest = false env_logger = { workspace = true, optional = true } anyhow = { workspace = true } once_cell = { workspace = true } -wasmtime = { workspace = true, features = ['cranelift', 'runtime', 'gc'] } +wasmtime = { workspace = true, features = ['cranelift', 'runtime', 'gc', 'std'] } wasmtime-c-api-macros = { workspace = true } log = { workspace = true } tracing = { workspace = true } diff --git a/crates/cli-flags/Cargo.toml b/crates/cli-flags/Cargo.toml index a77d405088f2..4ed645c7c2f2 100644 --- a/crates/cli-flags/Cargo.toml +++ b/crates/cli-flags/Cargo.toml @@ -12,7 +12,7 @@ edition.workspace = true workspace = true [dependencies] -anyhow = { workspace = true } +anyhow = { workspace = true, features = ['std'] } clap = { workspace = true } file-per-thread-logger = { workspace = true, optional = true } tracing-subscriber = { workspace = true, optional = true } diff --git a/crates/component-macro/Cargo.toml b/crates/component-macro/Cargo.toml index 03077ec147b1..98f27cae6f56 100644 --- a/crates/component-macro/Cargo.toml +++ b/crates/component-macro/Cargo.toml @@ -37,3 +37,4 @@ serde_json = { workspace = true } [features] async = [] +std = ['wasmtime-wit-bindgen/std'] diff --git a/crates/component-macro/src/component.rs b/crates/component-macro/src/component.rs index 00d5ba83e217..9f7ef47bdf3b 100644 --- a/crates/component-macro/src/component.rs +++ b/crates/component-macro/src/component.rs @@ -569,7 +569,7 @@ impl Expander for LowerExpander { &self, cx: &mut #internal::LowerContext<'_, T>, ty: #internal::InterfaceType, - dst: &mut std::mem::MaybeUninit, + dst: &mut core::mem::MaybeUninit, ) -> #internal::anyhow::Result<()> { #extract_ty #lowers @@ -677,7 +677,7 @@ impl Expander for LowerExpander { &self, cx: &mut #internal::LowerContext<'_, T>, ty: #internal::InterfaceType, - dst: &mut std::mem::MaybeUninit, + dst: &mut core::mem::MaybeUninit, ) -> #internal::anyhow::Result<()> { #extract_ty match self { @@ -1136,7 +1136,7 @@ pub fn expand_flags(flags: &Flags) -> Result { } pub fn all() -> Self { - use std::ops::Not; + use core::ops::Not; Self::default().not() } @@ -1149,21 +1149,21 @@ pub fn expand_flags(flags: &Flags) -> Result { } } - impl std::cmp::PartialEq for #name { + impl core::cmp::PartialEq for #name { fn eq(&self, rhs: &#name) -> bool { #eq } } - impl std::cmp::Eq for #name { } + impl core::cmp::Eq for #name { } - impl std::fmt::Debug for #name { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + impl core::fmt::Debug for #name { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { #internal::format_flags(&self.as_array(), &[#rust_names], f) } } - impl std::ops::BitOr for #name { + impl core::ops::BitOr for #name { type Output = #name; fn bitor(self, rhs: #name) -> #name { @@ -1171,13 +1171,13 @@ pub fn expand_flags(flags: &Flags) -> Result { } } - impl std::ops::BitOrAssign for #name { + impl core::ops::BitOrAssign for #name { fn bitor_assign(&mut self, rhs: #name) { #bitor_assign } } - impl std::ops::BitAnd for #name { + impl core::ops::BitAnd for #name { type Output = #name; fn bitand(self, rhs: #name) -> #name { @@ -1185,13 +1185,13 @@ pub fn expand_flags(flags: &Flags) -> Result { } } - impl std::ops::BitAndAssign for #name { + impl core::ops::BitAndAssign for #name { fn bitand_assign(&mut self, rhs: #name) { #bitand_assign } } - impl std::ops::BitXor for #name { + impl core::ops::BitXor for #name { type Output = #name; fn bitxor(self, rhs: #name) -> #name { @@ -1199,13 +1199,13 @@ pub fn expand_flags(flags: &Flags) -> Result { } } - impl std::ops::BitXorAssign for #name { + impl core::ops::BitXorAssign for #name { fn bitxor_assign(&mut self, rhs: #name) { #bitxor_assign } } - impl std::ops::Not for #name { + impl core::ops::Not for #name { type Output = #name; fn not(self) -> #name { @@ -1220,7 +1220,7 @@ pub fn expand_flags(flags: &Flags) -> Result { &self, cx: &mut #internal::LowerContext<'_, T>, _ty: #internal::InterfaceType, - dst: &mut std::mem::MaybeUninit, + dst: &mut core::mem::MaybeUninit, ) -> #internal::anyhow::Result<()> { #( self.#field_names.lower( @@ -1245,7 +1245,7 @@ pub fn expand_flags(flags: &Flags) -> Result { #field_interface_type, offset, )?; - offset += std::mem::size_of_val(&self.#field_names); + offset += core::mem::size_of_val(&self.#field_names); )* Ok(()) } diff --git a/crates/component-macro/tests/codegen_no_std.rs b/crates/component-macro/tests/codegen_no_std.rs new file mode 100644 index 000000000000..ecd8b82814f8 --- /dev/null +++ b/crates/component-macro/tests/codegen_no_std.rs @@ -0,0 +1,16 @@ +// The output of `bindgen!` should be compatible with `no_std` by default, so +// test that here with a no_std crate. + +#![no_std] + +extern crate std; + +macro_rules! gentest { + ($id:ident $name:tt $path:tt) => { + mod $id { + wasmtime::component::bindgen!(in $path); + } + }; +} + +component_macro_test_helpers::foreach!(gentest); diff --git a/crates/environ/src/lib.rs b/crates/environ/src/lib.rs index 70bf77b7b3df..6a7a36f93f67 100644 --- a/crates/environ/src/lib.rs +++ b/crates/environ/src/lib.rs @@ -33,7 +33,7 @@ extern crate alloc; /// /// and then `use crate::*` works as usual. pub mod prelude { - pub use crate::Err2Anyhow; + pub use crate::{Err2Anyhow, IntoAnyhow}; pub use alloc::borrow::ToOwned; pub use alloc::boxed::Box; pub use alloc::format; @@ -62,20 +62,42 @@ pub trait Err2Anyhow { fn err2anyhow(self) -> anyhow::Result; } -#[cfg(feature = "std")] -impl> Err2Anyhow for Result { +impl Err2Anyhow for Result { fn err2anyhow(self) -> anyhow::Result { - self.map_err(|e| e.into()) + match self { + Ok(e) => Ok(e), + Err(e) => Err(e.into_anyhow()), + } + } +} + +/// Convenience trait to convert a value into `anyhow::Error` +/// +/// This trait is not a suitable public interface of Wasmtime so it's just an +/// internal implementation detail for now. This trait is conditionally +/// implemented on the `std` feature with different bounds. +pub trait IntoAnyhow { + /// Converts `self` into an `anyhow::Error`. + fn into_anyhow(self) -> anyhow::Error; +} + +#[cfg(feature = "std")] +impl IntoAnyhow for T +where + T: Into, +{ + fn into_anyhow(self) -> anyhow::Error { + self.into() } } #[cfg(not(feature = "std"))] -impl Err2Anyhow for Result +impl IntoAnyhow for T where - E: core::fmt::Display + core::fmt::Debug + Send + Sync + 'static, + T: core::fmt::Display + core::fmt::Debug + Send + Sync + 'static, { - fn err2anyhow(self) -> anyhow::Result { - self.map_err(anyhow::Error::msg) + fn into_anyhow(self) -> anyhow::Error { + anyhow::Error::msg(self) } } diff --git a/crates/wasi-common/Cargo.toml b/crates/wasi-common/Cargo.toml index fbe8f2e27cdd..d15c0299488c 100644 --- a/crates/wasi-common/Cargo.toml +++ b/crates/wasi-common/Cargo.toml @@ -15,7 +15,7 @@ include = ["src/**/*", "tests/**/*", "witx", "README.md", "LICENSE", "build.rs"] workspace = true [dependencies] -anyhow = { workspace = true } +anyhow = { workspace = true, features = ['std'] } thiserror = { workspace = true } wiggle = { workspace = true } tracing = { workspace = true } diff --git a/crates/wasi/Cargo.toml b/crates/wasi/Cargo.toml index 75622a96ea2c..2816f16c9d29 100644 --- a/crates/wasi/Cargo.toml +++ b/crates/wasi/Cargo.toml @@ -15,7 +15,7 @@ include = ["src/**/*", "README.md", "LICENSE", "witx/*", "wit/**/*", "tests/*"] workspace = true [dependencies] -wasmtime = { workspace = true, features = ["component-model", "async", "runtime"] } +wasmtime = { workspace = true, features = ["component-model", "async", "runtime", "std"] } anyhow = { workspace = true } wiggle = { workspace = true, optional = true, features = ["wasmtime"] } tokio = { workspace = true, features = ["time", "sync", "io-std", "io-util", "rt", "rt-multi-thread", "net"] } diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 7f14f346e8e9..8aad132e5073 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -21,7 +21,7 @@ features = ["component-model"] [dependencies] wasmtime-asm-macros = { workspace = true, optional = true } -wasmtime-environ = { workspace = true, features = ['std'] } +wasmtime-environ = { workspace = true } wasmtime-jit-debug = { workspace = true, features = ["gdb_jit_int", "perf_jitdump"], optional = true } wasmtime-jit-icache-coherence = { workspace = true, optional = true } wasmtime-cache = { workspace = true, optional = true } @@ -43,25 +43,25 @@ log = { workspace = true } wat = { workspace = true, optional = true } serde = { workspace = true } serde_derive = { workspace = true } -serde_json = { workspace = true } +serde_json = { workspace = true, optional = true } sptr = { workspace = true } postcard = { workspace = true } indexmap = { workspace = true } paste = "1.0.3" once_cell = { workspace = true } rayon = { version = "1.0", optional = true } -object = { workspace = true, features = ['std'] } +object = { workspace = true } async-trait = { workspace = true, optional = true } encoding_rs = { version = "0.8.31", optional = true } bumpalo = "3.11.0" fxprof-processed-profile = { version = "0.6.0", optional = true } -gimli = { workspace = true, features = ['std'] } -# Support address-to-file/line information in traps when wasm files have DWARF -# debugging information. -addr2line = { version = "0.21.0", default-features = false, optional = true } -semver = { version = "1.0.17", optional = true } +gimli = { workspace = true, optional = true } +addr2line = { workspace = true, optional = true } +semver = { version = "1.0.17", optional = true, default-features = false } smallvec = { workspace = true, optional = true } memoffset = { workspace = true, optional = true } +hashbrown = { workspace = true } +libm = "0.2.7" [target.'cfg(target_os = "windows")'.dependencies.windows-sys] workspace = true @@ -127,21 +127,22 @@ default = [ 'runtime', 'component-model', 'threads', + 'std', ] # An on-by-default feature enabling runtime compilation of WebAssembly modules # with the Cranelift compiler. Cranelift is the default compilation backend of # Wasmtime. If disabled then WebAssembly modules can only be created from # precompiled WebAssembly modules. -cranelift = ["dep:wasmtime-cranelift"] +cranelift = ["dep:wasmtime-cranelift", "std"] # Enables support for winch, the WebAssembly baseline compiler. The Winch compiler # strategy in `Config` will be available. It is currently in active development # and shouldn't be used in production applications. -winch = ["dep:wasmtime-winch"] +winch = ["dep:wasmtime-winch", "std"] # Enables support for incremental compilation cache to be enabled in `Config`. -incremental-cache = ["wasmtime-cranelift?/incremental-cache"] +incremental-cache = ["wasmtime-cranelift?/incremental-cache", "std"] # Enables support for profiling guest modules. profiling = [ @@ -149,14 +150,16 @@ profiling = [ "dep:wasmtime-jit-debug", "dep:ittapi", "dep:rustix", - "rustix/thread" + "rustix/thread", + "dep:serde_json", + "std", ] # Enables parallel compilation of WebAssembly code. -parallel-compilation = ["dep:rayon"] +parallel-compilation = ["dep:rayon", "std"] # Enables support for automatic cache configuration to be enabled in `Config`. -cache = ["dep:wasmtime-cache"] +cache = ["dep:wasmtime-cache", "std"] # Enables support for "async stores" as well as defining host functions as # `async fn` and calling functions asynchronously. @@ -165,10 +168,11 @@ async = [ "dep:async-trait", "wasmtime-component-macro?/async", "runtime", + "std", ] # Enables support for the pooling instance allocation strategy -pooling-allocator = ["runtime"] +pooling-allocator = ["runtime", "std"] # Enables support for all architectures in Cranelift, allowing # cross-compilation using the `wasmtime` crate's API, notably the @@ -192,18 +196,19 @@ wmemcheck = [ "dep:wasmtime-wmemcheck", "wasmtime-cranelift?/wmemcheck", "wasmtime-environ/wmemcheck", + "std", ] # Enables support for demangling WebAssembly function names at runtime in # errors such as backtraces. -demangle = ["wasmtime-environ/demangle"] +demangle = ["wasmtime-environ/demangle", "std"] # Enable support for generating core dumps on traps. -coredump = ["dep:wasm-encoder", "runtime"] +coredump = ["dep:wasm-encoder", "runtime", "std"] # Export some symbols from the final binary to assist in debugging # Cranelift-generated code with native debuggers like GDB and LLDB. -debug-builtins = ["dep:wasmtime-jit-debug"] +debug-builtins = ["dep:wasmtime-jit-debug", "std"] # Enable support for executing compiled Wasm modules. runtime = [ @@ -239,4 +244,22 @@ runtime = [ gc = ["wasmtime-environ/gc", "wasmtime-cranelift?/gc"] # Enable runtime support for the WebAssembly threads proposal. -threads = ["wasmtime-cranelift?/threads"] +threads = ["wasmtime-cranelift?/threads", "std"] + +# Controls whether backtraces will attempt to parse DWARF information in +# WebAssembly modules and components to provide filenames and line numbers in +# stack traces. +addr2line = ["dep:addr2line", "dep:gimli", "std"] + +# Enables support for the Rust standard library, enabling APIs that require +# types and traits from Rust's `std` such as `Path` and `Error`. +# +# Many features of the Wasmtime crate implicitly require this `std` feature. +# This will be automatically enabled if necessary. +std = [ + 'postcard/use-std', + 'wasmtime-component-macro?/std', + 'wasmtime-environ/std', + 'object/std', + 'once_cell/std', +] diff --git a/crates/wasmtime/src/compile.rs b/crates/wasmtime/src/compile.rs index acb889355c1c..4078b7fe4f77 100644 --- a/crates/wasmtime/src/compile.rs +++ b/crates/wasmtime/src/compile.rs @@ -22,6 +22,7 @@ //! functions. It is up to the caller to serialize the relevant parts of the //! `Artifacts` into the ELF file. +use crate::prelude::*; use crate::Engine; use anyhow::{Context, Result}; use std::{ diff --git a/crates/wasmtime/src/compile/code_builder.rs b/crates/wasmtime/src/compile/code_builder.rs index 6d4d421b3d0a..c3a11e63db7c 100644 --- a/crates/wasmtime/src/compile/code_builder.rs +++ b/crates/wasmtime/src/compile/code_builder.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use crate::Engine; use anyhow::{anyhow, bail, Context, Result}; use std::borrow::Cow; diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index c7cf119581c3..f3796c79c389 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -1,11 +1,12 @@ +use crate::prelude::*; +use alloc::sync::Arc; use anyhow::{bail, ensure, Result}; +use core::fmt; +use core::str::FromStr; +use hashbrown::{HashMap, HashSet}; use serde_derive::{Deserialize, Serialize}; -use std::collections::{HashMap, HashSet}; -use std::fmt; #[cfg(any(feature = "cache", feature = "cranelift", feature = "winch"))] use std::path::Path; -use std::str::FromStr; -use std::sync::Arc; use target_lexicon::Architecture; use wasmparser::WasmFeatures; #[cfg(feature = "cache")] @@ -85,8 +86,8 @@ impl Default for ModuleVersionStrategy { } } -impl std::hash::Hash for ModuleVersionStrategy { - fn hash(&self, hasher: &mut H) { +impl core::hash::Hash for ModuleVersionStrategy { + fn hash(&self, hasher: &mut H) { match self { Self::WasmtimeVersion => env!("CARGO_PKG_VERSION").hash(hasher), Self::Custom(s) => s.hash(hasher), @@ -133,6 +134,7 @@ pub struct Config { pub(crate) wmemcheck: bool, pub(crate) coredump_on_trap: bool, pub(crate) macos_use_mach_ports: bool, + pub(crate) detect_host_feature: Option Option>, } #[derive(Default, Clone)] @@ -251,6 +253,10 @@ impl Config { wmemcheck: false, coredump_on_trap: false, macos_use_mach_ports: !cfg!(miri), + #[cfg(feature = "std")] + detect_host_feature: Some(detect_host_feature), + #[cfg(not(feature = "std"))] + detect_host_feature: None, }; #[cfg(any(feature = "cranelift", feature = "winch"))] { @@ -469,8 +475,10 @@ impl Config { /// filename/line number for each wasm frame in the stack trace. /// /// By default this option is `WasmBacktraceDetails::Environment`, meaning - /// that wasm will read `WASMTIME_BACKTRACE_DETAILS` to indicate whether details - /// should be parsed. + /// that wasm will read `WASMTIME_BACKTRACE_DETAILS` to indicate whether + /// details should be parsed. Note that the `std` feature of this crate must + /// be active to read environment variables, otherwise this is disabled by + /// default. pub fn wasm_backtrace_details(&mut self, enable: WasmBacktraceDetails) -> &mut Self { self.wasm_backtrace_details_env_used = false; self.tunables.parse_wasm_debuginfo = match enable { @@ -478,9 +486,16 @@ impl Config { WasmBacktraceDetails::Disable => Some(false), WasmBacktraceDetails::Environment => { self.wasm_backtrace_details_env_used = true; - std::env::var("WASMTIME_BACKTRACE_DETAILS") - .map(|s| Some(s == "1")) - .unwrap_or(Some(false)) + #[cfg(feature = "std")] + { + std::env::var("WASMTIME_BACKTRACE_DETAILS") + .map(|s| Some(s == "1")) + .unwrap_or(Some(false)) + } + #[cfg(not(feature = "std"))] + { + Some(false) + } } }; self @@ -2040,6 +2055,43 @@ impl Config { self.macos_use_mach_ports = mach_ports; self } + + /// Configures an embedder-provided function, `detect`, which is used to + /// determine if an ISA-specific feature is available on the current host. + /// + /// This function is used to verify that any features enabled for a compiler + /// backend, such as AVX support on x86\_64, are also available on the host. + /// It is undefined behavior to execute an AVX instruction on a host that + /// doesn't support AVX instructions, for example. + /// + /// When the `std` feature is active on this crate then this function is + /// configured to a default implementation that uses the standard library's + /// feature detection. When the `std` feature is disabled then there is no + /// default available and this method must be called to configure a feature + /// probing function. + /// + /// The `detect` function provided is given a string name of an ISA feature. + /// The function should then return: + /// + /// * `Some(true)` - indicates that the feature was found on the host and it + /// is supported. + /// * `Some(false)` - the feature name was recognized but it was not + /// detected on the host, for example the CPU is too old. + /// * `None` - the feature name was not recognized and it's not known + /// whether it's on the host or not. + /// + /// Feature names passed to `detect` match the same feature name used in the + /// Rust standard library. For example `"sse4.2"` is used on x86\_64. + /// + /// # Unsafety + /// + /// This function is `unsafe` because it is undefined behavior to execute + /// instructions that a host does not support. This means that the result of + /// `detect` must be correct for memory safe execution at runtime. + pub unsafe fn detect_host_feature(&mut self, detect: fn(&str) -> Option) -> &mut Self { + self.detect_host_feature = Some(detect); + self + } } /// If building without the runtime feature we can't determine the page size of @@ -2778,3 +2830,72 @@ pub(crate) fn probestack_supported(arch: Architecture) -> bool { Architecture::X86_64 | Architecture::Aarch64(_) | Architecture::Riscv64(_) ) } + +#[cfg(feature = "std")] +fn detect_host_feature(feature: &str) -> Option { + #[cfg(target_arch = "aarch64")] + { + return match feature { + "lse" => Some(std::arch::is_aarch64_feature_detected!("lse")), + "paca" => Some(std::arch::is_aarch64_feature_detected!("paca")), + + _ => None, + }; + } + + // There is no is_s390x_feature_detected macro yet, so for now + // we use getauxval from the libc crate directly. + #[cfg(all(target_arch = "s390x", target_os = "linux"))] + { + let v = unsafe { libc::getauxval(libc::AT_HWCAP) }; + const HWCAP_S390X_VXRS_EXT2: libc::c_ulong = 32768; + + return match feature { + // There is no separate HWCAP bit for mie2, so assume + // that any machine with vxrs_ext2 also has mie2. + "vxrs_ext2" | "mie2" => Some((v & HWCAP_S390X_VXRS_EXT2) != 0), + + _ => None, + }; + } + + #[cfg(target_arch = "riscv64")] + { + return match feature { + // due to `is_riscv64_feature_detected` is not stable. + // we cannot use it. For now lie and say all features are always + // found to keep tests working. + _ => Some(true), + }; + } + + #[cfg(target_arch = "x86_64")] + { + return match feature { + "sse3" => Some(std::is_x86_feature_detected!("sse3")), + "ssse3" => Some(std::is_x86_feature_detected!("ssse3")), + "sse4.1" => Some(std::is_x86_feature_detected!("sse4.1")), + "sse4.2" => Some(std::is_x86_feature_detected!("sse4.2")), + "popcnt" => Some(std::is_x86_feature_detected!("popcnt")), + "avx" => Some(std::is_x86_feature_detected!("avx")), + "avx2" => Some(std::is_x86_feature_detected!("avx2")), + "fma" => Some(std::is_x86_feature_detected!("fma")), + "bmi1" => Some(std::is_x86_feature_detected!("bmi1")), + "bmi2" => Some(std::is_x86_feature_detected!("bmi2")), + "avx512bitalg" => Some(std::is_x86_feature_detected!("avx512bitalg")), + "avx512dq" => Some(std::is_x86_feature_detected!("avx512dq")), + "avx512f" => Some(std::is_x86_feature_detected!("avx512f")), + "avx512vl" => Some(std::is_x86_feature_detected!("avx512vl")), + "avx512vbmi" => Some(std::is_x86_feature_detected!("avx512vbmi")), + "lzcnt" => Some(std::is_x86_feature_detected!("lzcnt")), + + _ => None, + }; + } + + #[allow(unreachable_code)] + { + let _ = feature; + return None; + } +} diff --git a/crates/wasmtime/src/engine.rs b/crates/wasmtime/src/engine.rs index 9b0453cf9769..3bf8bcb1df3f 100644 --- a/crates/wasmtime/src/engine.rs +++ b/crates/wasmtime/src/engine.rs @@ -1,16 +1,18 @@ +use crate::prelude::*; #[cfg(feature = "runtime")] use crate::runtime::type_registry::TypeRegistry; #[cfg(feature = "runtime")] use crate::runtime::vm::GcRuntime; +use crate::sync::OnceLock; use crate::Config; +use alloc::sync::Arc; use anyhow::{Context, Result}; +use core::sync::atomic::{AtomicU64, Ordering}; #[cfg(any(feature = "cranelift", feature = "winch"))] use object::write::{Object, StandardSegment}; use object::SectionKind; -use once_cell::sync::OnceCell; +#[cfg(feature = "std")] use std::path::Path; -use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::Arc; use wasmparser::WasmFeatures; use wasmtime_environ::obj; use wasmtime_environ::{FlagValue, ObjectKind, Tunables}; @@ -64,7 +66,8 @@ struct EngineInner { /// One-time check of whether the compiler's settings, if present, are /// compatible with the native host. - compatible_with_native_host: OnceCell>, + #[cfg(any(feature = "cranelift", feature = "winch"))] + compatible_with_native_host: OnceLock>, } impl Default for Engine { @@ -128,7 +131,8 @@ impl Engine { epoch: AtomicU64::new(0), #[cfg(feature = "runtime")] unique_id_allocator: crate::runtime::vm::CompiledModuleIdAllocator::new(), - compatible_with_native_host: OnceCell::new(), + #[cfg(any(feature = "cranelift", feature = "winch"))] + compatible_with_native_host: OnceLock::new(), config, tunables, }), @@ -208,6 +212,7 @@ impl Engine { } /// Like [`Engine::detect_precompiled`], but performs the detection on a file. + #[cfg(feature = "std")] pub fn detect_precompiled_file(&self, path: impl AsRef) -> Result> { serialization::detect_precompiled_file(path) } @@ -232,11 +237,18 @@ impl Engine { /// Note that if cranelift is disabled this trivially returns `Ok` because /// loaded serialized modules are checked separately. pub(crate) fn check_compatible_with_native_host(&self) -> Result<()> { - self.inner - .compatible_with_native_host - .get_or_init(|| self._check_compatible_with_native_host()) - .clone() - .map_err(anyhow::Error::msg) + #[cfg(any(feature = "cranelift", feature = "winch"))] + { + self.inner + .compatible_with_native_host + .get_or_init(|| self._check_compatible_with_native_host()) + .clone() + .map_err(anyhow::Error::msg) + } + #[cfg(not(any(feature = "cranelift", feature = "winch")))] + { + Ok(()) + } } fn _check_compatible_with_native_host(&self) -> Result<(), String> { @@ -391,112 +403,80 @@ impl Engine { } } - #[allow(unused_assignments)] - let mut enabled = None; + let host_feature = match flag { + // aarch64 features to detect + "has_lse" => "lse", + "has_pauth" => "paca", + + // aarch64 features which don't need detection + // No effect on its own. + "sign_return_address_all" => return Ok(()), + // The pointer authentication instructions act as a `NOP` when + // unsupported, so it is safe to enable them. + "sign_return_address" => return Ok(()), + // No effect on its own. + "sign_return_address_with_bkey" => return Ok(()), + // The `BTI` instruction acts as a `NOP` when unsupported, so it + // is safe to enable it regardless of whether the host supports it + // or not. + "use_bti" => return Ok(()), + + // s390x features to detect + "has_vxrs_ext2" => "vxrs_ext2", + "has_mie2" => "mie2", + + // x64 features to detect + "has_sse3" => "sse3", + "has_ssse3" => "ssse3", + "has_sse41" => "sse4.1", + "has_sse42" => "sse4.2", + "has_popcnt" => "popcnt", + "has_avx" => "avx", + "has_avx2" => "avx2", + "has_fma" => "fma", + "has_bmi1" => "bmi1", + "has_bmi2" => "bmi2", + "has_avx512bitalg" => "avx512bitalg", + "has_avx512dq" => "avx512dq", + "has_avx512f" => "avx512f", + "has_avx512vl" => "avx512vl", + "has_avx512vbmi" => "avx512vbmi", + "has_lzcnt" => "lzcnt", - #[cfg(target_arch = "aarch64")] - { - enabled = match flag { - "has_lse" => Some(std::arch::is_aarch64_feature_detected!("lse")), - // No effect on its own, but in order to simplify the code on a - // platform without pointer authentication support we fail if - // "has_pauth" is enabled, but "sign_return_address" is not. - "has_pauth" => Some(std::arch::is_aarch64_feature_detected!("paca")), - // No effect on its own. - "sign_return_address_all" => Some(true), - // The pointer authentication instructions act as a `NOP` when - // unsupported (but keep in mind "has_pauth" as well), so it is - // safe to enable them. - "sign_return_address" => Some(true), - // No effect on its own. - "sign_return_address_with_bkey" => Some(true), - // The `BTI` instruction acts as a `NOP` when unsupported, so it - // is safe to enable it. - "use_bti" => Some(true), - // fall through to the very bottom to indicate that support is - // not enabled to test whether this feature is enabled on the - // host. - _ => None, - }; - } - - // There is no is_s390x_feature_detected macro yet, so for now - // we use getauxval from the libc crate directly. - #[cfg(all(target_arch = "s390x", target_os = "linux"))] - { - let v = unsafe { libc::getauxval(libc::AT_HWCAP) }; - const HWCAP_S390X_VXRS_EXT2: libc::c_ulong = 32768; - - enabled = match flag { - // There is no separate HWCAP bit for mie2, so assume - // that any machine with vxrs_ext2 also has mie2. - "has_vxrs_ext2" | "has_mie2" => Some((v & HWCAP_S390X_VXRS_EXT2) != 0), - // fall through to the very bottom to indicate that support is - // not enabled to test whether this feature is enabled on the - // host. - _ => None, - } - } - - #[cfg(target_arch = "riscv64")] - { - enabled = match flag { - // make sure `test_isa_flags_mismatch` test pass. - "not_a_flag" => None, - // due to `is_riscv64_feature_detected` is not stable. - // we cannot use it. - _ => Some(true), + _ => { + // FIXME: should enumerate risc-v features and plumb them + // through to the `detect_host_feature` function. + if cfg!(target_arch = "riscv64") && flag != "not_a_flag" { + return Ok(()); + } + return Err(format!( + "don't know how to test for target-specific flag {flag:?} at runtime" + )); } - } - - #[cfg(target_arch = "x86_64")] - { - enabled = match flag { - "has_sse3" => Some(std::is_x86_feature_detected!("sse3")), - "has_ssse3" => Some(std::is_x86_feature_detected!("ssse3")), - "has_sse41" => Some(std::is_x86_feature_detected!("sse4.1")), - "has_sse42" => Some(std::is_x86_feature_detected!("sse4.2")), - "has_popcnt" => Some(std::is_x86_feature_detected!("popcnt")), - "has_avx" => Some(std::is_x86_feature_detected!("avx")), - "has_avx2" => Some(std::is_x86_feature_detected!("avx2")), - "has_fma" => Some(std::is_x86_feature_detected!("fma")), - "has_bmi1" => Some(std::is_x86_feature_detected!("bmi1")), - "has_bmi2" => Some(std::is_x86_feature_detected!("bmi2")), - "has_avx512bitalg" => Some(std::is_x86_feature_detected!("avx512bitalg")), - "has_avx512dq" => Some(std::is_x86_feature_detected!("avx512dq")), - "has_avx512f" => Some(std::is_x86_feature_detected!("avx512f")), - "has_avx512vl" => Some(std::is_x86_feature_detected!("avx512vl")), - "has_avx512vbmi" => Some(std::is_x86_feature_detected!("avx512vbmi")), - "has_lzcnt" => Some(std::is_x86_feature_detected!("lzcnt")), - - // fall through to the very bottom to indicate that support is - // not enabled to test whether this feature is enabled on the - // host. - _ => None, - }; - } - - #[cfg(target_family = "wasm")] - { - let _ = &mut enabled; - } + }; - match enabled { - Some(true) => return Ok(()), - Some(false) => { + let detect = match self.config().detect_host_feature { + Some(detect) => detect, + None => { return Err(format!( - "compilation setting {:?} is enabled, but not available on the host", - flag + "cannot determine if host feature {host_feature:?} is \ + available at runtime, configure a probing function with \ + `Config::detect_host_feature`" )) } - // fall through - None => {} - } + }; - Err(format!( - "cannot test if target-specific flag {:?} is available at runtime", - flag - )) + match detect(host_feature) { + Some(true) => Ok(()), + Some(false) => Err(format!( + "compilation setting {flag:?} is enabled, but not \ + available on the host", + )), + None => Err(format!( + "failed to detect if target-specific flag {flag:?} is \ + available at runtime" + )), + } } } @@ -553,6 +533,7 @@ impl Engine { serialization::append_compiler_info(self, obj, &serialization::Metadata::new(&self)) } + #[cfg(any(feature = "cranelift", feature = "winch"))] pub(crate) fn append_bti(&self, obj: &mut Object<'_>) { let section = obj.add_section( obj.segment_name(StandardSegment::Data).to_vec(), @@ -706,6 +687,7 @@ impl Engine { } /// Like `load_code_bytes`, but creates a mmap from a file on disk. + #[cfg(feature = "std")] pub(crate) fn load_code_file( &self, path: &Path, @@ -734,13 +716,13 @@ impl Engine { /// A weak reference to an [`Engine`]. #[derive(Clone)] pub struct EngineWeak { - inner: std::sync::Weak, + inner: alloc::sync::Weak, } impl EngineWeak { /// Upgrade this weak reference into an [`Engine`]. Returns `None` if /// strong references (the [`Engine`] type itself) no longer exist. pub fn upgrade(&self) -> Option { - std::sync::Weak::upgrade(&self.inner).map(|inner| Engine { inner }) + alloc::sync::Weak::upgrade(&self.inner).map(|inner| Engine { inner }) } } diff --git a/crates/wasmtime/src/engine/serialization.rs b/crates/wasmtime/src/engine/serialization.rs index 78f02229da95..1415aa19ae84 100644 --- a/crates/wasmtime/src/engine/serialization.rs +++ b/crates/wasmtime/src/engine/serialization.rs @@ -21,13 +21,14 @@ //! other random ELF files, as well as provide better error messages for //! using wasmtime artifacts across versions. +use crate::prelude::*; use crate::{Engine, ModuleVersionStrategy, Precompiled}; use anyhow::{anyhow, bail, ensure, Context, Result}; +use core::str::FromStr; #[cfg(any(feature = "cranelift", feature = "winch"))] use object::write::{Object, StandardSegment}; use object::{File, FileFlags, Object as _, ObjectSection, SectionKind}; use serde_derive::{Deserialize, Serialize}; -use std::str::FromStr; use wasmtime_environ::obj; use wasmtime_environ::{FlagValue, ObjectKind, Tunables}; @@ -55,7 +56,9 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R // structured well enough to make this easy and additionally it's not really // a perf issue right now so doing that is left for another day's // refactoring. - let obj = File::parse(mmap).context("failed to parse precompiled artifact as an ELF")?; + let obj = File::parse(mmap) + .err2anyhow() + .context("failed to parse precompiled artifact as an ELF")?; let expected_e_flags = match expected { ObjectKind::Module => obj::EF_WASMTIME_MODULE, ObjectKind::Component => obj::EF_WASMTIME_COMPONENT, @@ -72,7 +75,8 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R let data = obj .section_by_name(obj::ELF_WASM_ENGINE) .ok_or_else(|| anyhow!("failed to find section `{}`", obj::ELF_WASM_ENGINE))? - .data()?; + .data() + .err2anyhow()?; let (first, data) = data .split_first() .ok_or_else(|| anyhow!("invalid engine section"))?; @@ -91,7 +95,7 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R match &engine.config().module_version { ModuleVersionStrategy::WasmtimeVersion => { - let version = std::str::from_utf8(version)?; + let version = core::str::from_utf8(version).err2anyhow()?; if version != env!("CARGO_PKG_VERSION") { bail!( "Module was compiled with incompatible Wasmtime version '{}'", @@ -100,7 +104,7 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R } } ModuleVersionStrategy::Custom(v) => { - let version = std::str::from_utf8(&version)?; + let version = core::str::from_utf8(&version).err2anyhow()?; if version != v { bail!( "Module was compiled with incompatible version '{}'", @@ -110,7 +114,9 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R } ModuleVersionStrategy::None => { /* ignore the version info, accept all */ } } - postcard::from_bytes::>(data)?.check_compatible(engine) + postcard::from_bytes::>(data) + .err2anyhow()? + .check_compatible(engine) } #[cfg(any(feature = "cranelift", feature = "winch"))] @@ -160,6 +166,7 @@ pub fn detect_precompiled_bytes(bytes: &[u8]) -> Option { detect_precompiled(File::parse(bytes).ok()?) } +#[cfg(feature = "std")] pub fn detect_precompiled_file(path: impl AsRef) -> Result> { let read_cache = object::ReadCache::new(std::fs::File::open(path)?); let obj = File::parse(&read_cache)?; @@ -311,7 +318,7 @@ impl Metadata<'_> { Ok(()) } - fn check_int(found: T, expected: T, feature: &str) -> Result<()> { + fn check_int(found: T, expected: T, feature: &str) -> Result<()> { if found == expected { return Ok(()); } @@ -633,13 +640,16 @@ Caused by: match metadata.check_compatible(&engine) { Ok(_) => unreachable!(), - Err(e) => assert!(format!("{:?}", e).starts_with( - "\ + Err(e) => assert!( + format!("{e:?}").starts_with( + "\ compilation settings of module incompatible with native host Caused by: - cannot test if target-specific flag \"not_a_flag\" is available at runtime", - )), + don't know how to test for target-specific flag \"not_a_flag\" at runtime", + ), + "bad error {e:?}", + ), } Ok(()) diff --git a/crates/wasmtime/src/lib.rs b/crates/wasmtime/src/lib.rs index 8b9c1288b812..34d77986fae7 100644 --- a/crates/wasmtime/src/lib.rs +++ b/crates/wasmtime/src/lib.rs @@ -269,6 +269,14 @@ // most features enabled. This will present warnings in stripped-down doc builds // and will prevent the doc build from failing. #![cfg_attr(feature = "default", deny(rustdoc::broken_intra_doc_links))] +#![no_std] + +#[cfg(any(feature = "std", unix, windows))] +#[macro_use] +extern crate std; +extern crate alloc; + +use wasmtime_environ::prelude; #[cfg(feature = "runtime")] mod runtime; @@ -287,6 +295,16 @@ mod profiling_agent; pub use crate::config::*; pub use crate::engine::*; +#[cfg(feature = "std")] +mod sync_std; +#[cfg(feature = "std")] +use sync_std as sync; + +#[cfg_attr(feature = "std", allow(dead_code))] +mod sync_nostd; +#[cfg(not(feature = "std"))] +use sync_nostd as sync; + /// A convenience wrapper for `Result`. /// /// This type can be used to interact with `wasmtimes`'s extensive use diff --git a/crates/wasmtime/src/profiling_agent.rs b/crates/wasmtime/src/profiling_agent.rs index dece223d3e1a..d431e25b87a5 100644 --- a/crates/wasmtime/src/profiling_agent.rs +++ b/crates/wasmtime/src/profiling_agent.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; #[allow(unused)] use anyhow::{bail, Result}; @@ -17,7 +18,7 @@ cfg_if::cfg_if! { } cfg_if::cfg_if! { - if #[cfg(unix)] { + if #[cfg(all(unix, feature = "std"))] { mod perfmap; pub use perfmap::new as new_perfmap; } else { diff --git a/crates/wasmtime/src/profiling_agent/jitdump.rs b/crates/wasmtime/src/profiling_agent/jitdump.rs index ee886066821c..25344bbd159f 100644 --- a/crates/wasmtime/src/profiling_agent/jitdump.rs +++ b/crates/wasmtime/src/profiling_agent/jitdump.rs @@ -11,6 +11,7 @@ //! sudo perf report -i perf.jit.data -F+period,srcline //! Note: For descriptive results, the WASM file being executed should contain dwarf debug data +use crate::prelude::*; use crate::profiling_agent::ProfilingAgent; use anyhow::Result; use std::process; diff --git a/crates/wasmtime/src/profiling_agent/perfmap.rs b/crates/wasmtime/src/profiling_agent/perfmap.rs index 25e1c6d2359f..423eed30412a 100644 --- a/crates/wasmtime/src/profiling_agent/perfmap.rs +++ b/crates/wasmtime/src/profiling_agent/perfmap.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use crate::profiling_agent::ProfilingAgent; use anyhow::Result; use std::io::{self, BufWriter, Write}; diff --git a/crates/wasmtime/src/profiling_agent/vtune.rs b/crates/wasmtime/src/profiling_agent/vtune.rs index 4c7fd3fbb68d..a2f8b6609cb8 100644 --- a/crates/wasmtime/src/profiling_agent/vtune.rs +++ b/crates/wasmtime/src/profiling_agent/vtune.rs @@ -12,6 +12,7 @@ //! installed](https://www.intel.com/content/www/us/en/developer/tools/oneapi/vtune-profiler.html#standalone) //! for this to work. +use crate::prelude::*; use crate::profiling_agent::ProfilingAgent; use anyhow::Result; use ittapi::jit::MethodLoadBuilder; diff --git a/crates/wasmtime/src/runtime.rs b/crates/wasmtime/src/runtime.rs index 487fcb0733a6..b3a5ecd527ea 100644 --- a/crates/wasmtime/src/runtime.rs +++ b/crates/wasmtime/src/runtime.rs @@ -12,7 +12,6 @@ pub(crate) mod limits; pub(crate) mod linker; pub(crate) mod memory; pub(crate) mod module; -pub(crate) mod profiling; pub(crate) mod resources; pub(crate) mod store; pub(crate) mod trampoline; @@ -27,12 +26,6 @@ pub(crate) mod vm; #[cfg(feature = "component-model")] pub mod component; -#[cfg(feature = "async")] -pub(crate) mod stack; - -#[cfg(feature = "coredump")] -mod coredump; - cfg_if::cfg_if! { if #[cfg(miri)] { // no extensions on miri @@ -68,12 +61,18 @@ pub use values::*; pub(crate) use uninhabited::*; +#[cfg(feature = "profiling")] +mod profiling; #[cfg(feature = "profiling")] pub use profiling::GuestProfiler; +#[cfg(feature = "async")] +pub(crate) mod stack; #[cfg(feature = "async")] pub use stack::*; +#[cfg(feature = "coredump")] +mod coredump; #[cfg(feature = "coredump")] pub use coredump::*; diff --git a/crates/wasmtime/src/runtime/code.rs b/crates/wasmtime/src/runtime/code.rs index 3aefe725e05a..b8c96fa81df4 100644 --- a/crates/wasmtime/src/runtime/code.rs +++ b/crates/wasmtime/src/runtime/code.rs @@ -1,5 +1,5 @@ use crate::{code_memory::CodeMemory, type_registry::TypeCollection}; -use std::sync::Arc; +use alloc::sync::Arc; #[cfg(feature = "component-model")] use wasmtime_environ::component::ComponentTypes; use wasmtime_environ::ModuleTypes; diff --git a/crates/wasmtime/src/runtime/code_memory.rs b/crates/wasmtime/src/runtime/code_memory.rs index 4b5a1b2d6edb..f106b1877f69 100644 --- a/crates/wasmtime/src/runtime/code_memory.rs +++ b/crates/wasmtime/src/runtime/code_memory.rs @@ -1,11 +1,12 @@ //! Memory management for executable code. +use crate::prelude::*; use crate::runtime::vm::{libcalls, MmapVec, UnwindRegistration}; use anyhow::{anyhow, bail, Context, Result}; +use core::mem::ManuallyDrop; +use core::ops::Range; use object::read::{File, Object, ObjectSection}; use object::ObjectSymbol; -use std::mem::ManuallyDrop; -use std::ops::Range; use wasmtime_environ::obj; use wasmtime_jit_icache_coherence as icache_coherence; @@ -57,6 +58,7 @@ impl CodeMemory { /// `publish` method is used to actually make the memory executable. pub fn new(mmap: MmapVec) -> Result { let obj = File::parse(&mmap[..]) + .err2anyhow() .with_context(|| "failed to parse internal compilation artifact")?; let mut relocations = Vec::new(); @@ -70,8 +72,8 @@ impl CodeMemory { let mut info_data = 0..0; let mut dwarf = 0..0; for section in obj.sections() { - let data = section.data()?; - let name = section.name()?; + let data = section.data().err2anyhow()?; + let name = section.name().err2anyhow()?; let range = subslice_range(data, &mmap); // Double-check that sections are all aligned properly. @@ -102,7 +104,7 @@ impl CodeMemory { for (offset, reloc) in section.relocations() { assert_eq!(reloc.kind(), object::RelocationKind::Absolute); assert_eq!(reloc.encoding(), object::RelocationEncoding::Generic); - assert_eq!(usize::from(reloc.size()), std::mem::size_of::() * 8); + assert_eq!(usize::from(reloc.size()), core::mem::size_of::() * 8); assert_eq!(reloc.addend(), 0); let sym = match reloc.target() { object::RelocationTarget::Symbol(id) => id, diff --git a/crates/wasmtime/src/runtime/component/component.rs b/crates/wasmtime/src/runtime/component/component.rs index 0235a66ea801..e2a3b768a4b3 100644 --- a/crates/wasmtime/src/runtime/component/component.rs +++ b/crates/wasmtime/src/runtime/component/component.rs @@ -1,5 +1,6 @@ use crate::component::matching::InstanceType; use crate::component::types; +use crate::prelude::*; use crate::runtime::vm::component::ComponentRuntimeInfo; use crate::runtime::vm::{ VMArrayCallFunction, VMFuncRef, VMFunctionBody, VMNativeCallFunction, VMWasmCallFunction, @@ -9,12 +10,14 @@ use crate::{ ResourcesRequired, }; use crate::{FuncType, ValType}; +use alloc::sync::Arc; use anyhow::Result; -use std::mem; -use std::ops::Range; +use core::any::Any; +use core::mem; +use core::ops::Range; +use core::ptr::NonNull; +#[cfg(feature = "std")] use std::path::Path; -use std::ptr::NonNull; -use std::sync::Arc; use wasmtime_environ::component::{ AllCallFunc, CompiledComponentInfo, ComponentArtifacts, ComponentTypes, GlobalInitializer, InstantiateModule, StaticModuleIndex, TrampolineIndex, TypeComponentIndex, VMComponentOffsets, @@ -78,7 +81,7 @@ struct ComponentInner { /// A cached handle to the `wasmtime::FuncType` for the canonical ABI's /// `realloc`, to avoid the need to look up types in the registry and take /// locks when calling `realloc` via `TypedFunc::call_raw`. - realloc_func_type: Arc, + realloc_func_type: Arc, } pub(crate) struct AllCallFuncPointers { @@ -158,7 +161,7 @@ impl Component { /// /// This is a convenience function for reading the contents of `file` on /// disk and then calling [`Component::new`]. - #[cfg(any(feature = "cranelift", feature = "winch"))] + #[cfg(all(feature = "std", any(feature = "cranelift", feature = "winch")))] pub fn from_file(engine: &Engine, file: impl AsRef) -> Result { crate::CodeBuilder::new(engine) .wasm_file(file.as_ref())? @@ -215,6 +218,7 @@ impl Component { /// [`Module::deserialize_file`] method. /// /// [`Module::deserialize_file`]: crate::Module::deserialize_file + #[cfg(feature = "std")] pub unsafe fn deserialize_file(engine: &Engine, path: impl AsRef) -> Result { let code = engine.load_code_file(path.as_ref(), ObjectKind::Component)?; Component::from_parts(engine, code, None) @@ -371,7 +375,7 @@ impl Component { static_modules, } = match artifacts { Some(artifacts) => artifacts, - None => postcard::from_bytes(code_memory.wasmtime_info())?, + None => postcard::from_bytes(code_memory.wasmtime_info()).err2anyhow()?, }; // Validate that the component can be used with the current instance @@ -620,7 +624,7 @@ impl ComponentRuntimeInfo for ComponentInner { } } - fn realloc_func_type(&self) -> &Arc { + fn realloc_func_type(&self) -> &Arc { &self.realloc_func_type } } diff --git a/crates/wasmtime/src/runtime/component/func.rs b/crates/wasmtime/src/runtime/component/func.rs index 444925575d1d..2822e9ad1aa5 100644 --- a/crates/wasmtime/src/runtime/component/func.rs +++ b/crates/wasmtime/src/runtime/component/func.rs @@ -2,14 +2,15 @@ use crate::component::instance::{Instance, InstanceData}; use crate::component::storage::storage_as_slice; use crate::component::types::Type; use crate::component::values::Val; +use crate::prelude::*; use crate::runtime::vm::component::ResourceTables; use crate::runtime::vm::{Export, ExportFunction}; use crate::store::{StoreOpaque, Stored}; use crate::{AsContext, AsContextMut, StoreContextMut, ValRaw}; +use alloc::sync::Arc; use anyhow::{bail, Context, Result}; -use std::mem::{self, MaybeUninit}; -use std::ptr::NonNull; -use std::sync::Arc; +use core::mem::{self, MaybeUninit}; +use core::ptr::NonNull; use wasmtime_environ::component::{ CanonicalOptions, ComponentTypes, CoreDef, InterfaceType, RuntimeComponentInstanceIndex, TypeFuncIndex, TypeTuple, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, @@ -45,12 +46,12 @@ macro_rules! map_maybe_uninit { unsafe { use $crate::component::__internal::MaybeUninitExt; - let m: &mut std::mem::MaybeUninit<_> = $maybe_uninit; + let m: &mut core::mem::MaybeUninit<_> = $maybe_uninit; // Note the usage of `addr_of_mut!` here which is an attempt to "stay // safe" here where we never accidentally create `&mut T` where `T` is // actually uninitialized, hopefully appeasing the Rust unsafe // guidelines gods. - m.map(|p| std::ptr::addr_of_mut!((*p)$($field)*)) + m.map(|p| core::ptr::addr_of_mut!((*p)$($field)*)) } } }) @@ -68,7 +69,7 @@ pub trait MaybeUninitExt { impl MaybeUninitExt for MaybeUninit { unsafe fn map(&mut self, f: impl FnOnce(*mut T) -> *mut U) -> &mut MaybeUninit { let new_ptr = f(self.as_mut_ptr()); - std::mem::transmute::<*mut U, &mut MaybeUninit>(new_ptr) + core::mem::transmute::<*mut U, &mut MaybeUninit>(new_ptr) } } @@ -720,11 +721,11 @@ impl Func { cx: &mut LiftContext<'_>, results_ty: &TypeTuple, results: &mut [Val], - src: &mut std::slice::Iter<'_, ValRaw>, + src: &mut core::slice::Iter<'_, ValRaw>, ) -> Result<()> { // FIXME: needs to read an i64 for memory64 - let ptr = usize::try_from(src.next().unwrap().get_u32())?; - if ptr % usize::try_from(results_ty.abi.align32)? != 0 { + let ptr = usize::try_from(src.next().unwrap().get_u32()).err2anyhow()?; + if ptr % usize::try_from(results_ty.abi.align32).err2anyhow()? != 0 { bail!("return pointer not aligned"); } diff --git a/crates/wasmtime/src/runtime/component/func/host.rs b/crates/wasmtime/src/runtime/component/func/host.rs index 81e4d2fd5a40..2a700046c192 100644 --- a/crates/wasmtime/src/runtime/component/func/host.rs +++ b/crates/wasmtime/src/runtime/component/func/host.rs @@ -2,16 +2,17 @@ use crate::component::func::{LiftContext, LowerContext, Options}; use crate::component::matching::InstanceType; use crate::component::storage::slice_to_storage_mut; use crate::component::{ComponentNamedList, ComponentType, Lift, Lower, Val}; +use crate::prelude::*; use crate::runtime::vm::component::{ InstanceFlags, VMComponentContext, VMLowering, VMLoweringCallee, }; use crate::runtime::vm::{VMFuncRef, VMMemoryDefinition, VMOpaqueContext}; use crate::{AsContextMut, StoreContextMut, ValRaw}; +use alloc::sync::Arc; use anyhow::{bail, Context, Result}; -use std::any::Any; -use std::mem::{self, MaybeUninit}; -use std::ptr::NonNull; -use std::sync::Arc; +use core::any::Any; +use core::mem::{self, MaybeUninit}; +use core::ptr::NonNull; use wasmtime_environ::component::{ CanonicalAbiInfo, InterfaceType, StringEncoding, TypeFuncIndex, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, @@ -63,7 +64,7 @@ impl HostFunc { memory, realloc, string_encoding, - std::slice::from_raw_parts_mut(storage, storage_len), + core::slice::from_raw_parts_mut(storage, storage_len), |store, args| (*data)(store, args), ) }) @@ -275,8 +276,8 @@ where fn validate_inbounds(memory: &[u8], ptr: &ValRaw) -> Result { // FIXME: needs memory64 support - let ptr = usize::try_from(ptr.get_u32())?; - if ptr % usize::try_from(T::ALIGN32)? != 0 { + let ptr = usize::try_from(ptr.get_u32()).err2anyhow()?; + if ptr % usize::try_from(T::ALIGN32).err2anyhow()? != 0 { bail!("pointer not aligned"); } let end = match ptr.checked_add(T::SIZE32) { @@ -394,8 +395,8 @@ where fn validate_inbounds_dynamic(abi: &CanonicalAbiInfo, memory: &[u8], ptr: &ValRaw) -> Result { // FIXME: needs memory64 support - let ptr = usize::try_from(ptr.get_u32())?; - if ptr % usize::try_from(abi.align32)? != 0 { + let ptr = usize::try_from(ptr.get_u32()).err2anyhow()?; + if ptr % usize::try_from(abi.align32).err2anyhow()? != 0 { bail!("pointer not aligned"); } let end = match ptr.checked_add(usize::try_from(abi.size32).unwrap()) { @@ -431,7 +432,7 @@ extern "C" fn dynamic_entrypoint( memory, realloc, string_encoding, - std::slice::from_raw_parts_mut(storage, storage_len), + core::slice::from_raw_parts_mut(storage, storage_len), |store, params, results| (*data)(store, params, results), ) }) diff --git a/crates/wasmtime/src/runtime/component/func/options.rs b/crates/wasmtime/src/runtime/component/func/options.rs index 20bc865f1ed1..8d7f3ca51522 100644 --- a/crates/wasmtime/src/runtime/component/func/options.rs +++ b/crates/wasmtime/src/runtime/component/func/options.rs @@ -1,15 +1,16 @@ use crate::component::matching::InstanceType; use crate::component::resources::{HostResourceData, HostResourceIndex, HostResourceTables}; use crate::component::ResourceType; +use crate::prelude::*; use crate::runtime::vm::component::{ CallContexts, ComponentInstance, InstanceFlags, ResourceTable, ResourceTables, }; use crate::runtime::vm::{VMFuncRef, VMMemoryDefinition}; use crate::store::{StoreId, StoreOpaque}; use crate::{FuncType, StoreContextMut}; +use alloc::sync::Arc; use anyhow::{bail, Result}; -use std::ptr::NonNull; -use std::sync::Arc; +use core::ptr::NonNull; use wasmtime_environ::component::{ComponentTypes, StringEncoding, TypeResourceTableIndex}; /// Runtime representation of canonical ABI options in the component model. @@ -89,10 +90,10 @@ impl Options { let realloc = self.realloc.unwrap(); let params = ( - u32::try_from(old)?, - u32::try_from(old_size)?, + u32::try_from(old).err2anyhow()?, + u32::try_from(old_size).err2anyhow()?, old_align, - u32::try_from(new_size)?, + u32::try_from(new_size).err2anyhow()?, ); type ReallocFunc = crate::TypedFunc<(u32, u32, u32, u32), u32>; @@ -108,7 +109,7 @@ impl Options { if result % old_align != 0 { bail!("realloc return: result not aligned"); } - let result = usize::try_from(result)?; + let result = usize::try_from(result).err2anyhow()?; let memory = self.memory_mut(store.0); @@ -138,7 +139,7 @@ impl Options { // is an optional configuration in canonical ABI options. unsafe { let memory = self.memory.unwrap().as_ref(); - std::slice::from_raw_parts(memory.base, memory.current_length()) + core::slice::from_raw_parts(memory.base, memory.current_length()) } } @@ -149,7 +150,7 @@ impl Options { // See comments in `memory` about the unsafety unsafe { let memory = self.memory.unwrap().as_ref(); - std::slice::from_raw_parts_mut(memory.base, memory.current_length()) + core::slice::from_raw_parts_mut(memory.base, memory.current_length()) } } diff --git a/crates/wasmtime/src/runtime/component/func/typed.rs b/crates/wasmtime/src/runtime/component/func/typed.rs index 9994b44577f4..81a8d70f9d5e 100644 --- a/crates/wasmtime/src/runtime/component/func/typed.rs +++ b/crates/wasmtime/src/runtime/component/func/typed.rs @@ -1,17 +1,18 @@ use crate::component::func::{Func, LiftContext, LowerContext, Options}; use crate::component::matching::InstanceType; use crate::component::storage::{storage_as_slice, storage_as_slice_mut}; +use crate::prelude::*; use crate::runtime::vm::component::ComponentInstance; use crate::runtime::vm::SendSyncPtr; use crate::{AsContextMut, StoreContext, StoreContextMut, ValRaw}; +use alloc::borrow::Cow; +use alloc::sync::Arc; use anyhow::{anyhow, bail, Context, Result}; -use std::borrow::Cow; -use std::fmt; -use std::marker; -use std::mem::{self, MaybeUninit}; -use std::ptr::NonNull; -use std::str; -use std::sync::Arc; +use core::fmt; +use core::marker; +use core::mem::{self, MaybeUninit}; +use core::ptr::NonNull; +use core::str; use wasmtime_environ::component::{ CanonicalAbiInfo, ComponentTypes, InterfaceType, StringEncoding, VariantInfo, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, @@ -315,8 +316,8 @@ where ) -> Result { assert!(Return::flatten_count() > MAX_FLAT_RESULTS); // FIXME: needs to read an i64 for memory64 - let ptr = usize::try_from(dst.get_u32())?; - if ptr % usize::try_from(Return::ALIGN32)? != 0 { + let ptr = usize::try_from(dst.get_u32()).err2anyhow()?; + if ptr % usize::try_from(Return::ALIGN32).err2anyhow()? != 0 { bail!("return pointer not aligned"); } @@ -668,8 +669,8 @@ macro_rules! forward_type_impls { forward_type_impls! { (T: ComponentType + ?Sized) &'_ T => T, (T: ComponentType + ?Sized) Box => T, - (T: ComponentType + ?Sized) std::rc::Rc => T, - (T: ComponentType + ?Sized) std::sync::Arc => T, + (T: ComponentType + ?Sized) alloc::rc::Rc => T, + (T: ComponentType + ?Sized) alloc::sync::Arc => T, () String => str, (T: ComponentType) Vec => [T], } @@ -701,8 +702,8 @@ macro_rules! forward_lowers { forward_lowers! { (T: Lower + ?Sized) &'_ T => T, (T: Lower + ?Sized) Box => T, - (T: Lower + ?Sized) std::rc::Rc => T, - (T: Lower + ?Sized) std::sync::Arc => T, + (T: Lower + ?Sized) alloc::rc::Rc => T, + (T: Lower + ?Sized) alloc::sync::Arc => T, () String => str, (T: Lower) Vec => [T], } @@ -725,8 +726,8 @@ macro_rules! forward_string_lifts { forward_string_lifts! { Box, - std::rc::Rc, - std::sync::Arc, + alloc::rc::Rc, + alloc::sync::Arc, String, } @@ -748,8 +749,8 @@ macro_rules! forward_list_lifts { forward_list_lifts! { Box<[T]>, - std::rc::Rc<[T]>, - std::sync::Arc<[T]>, + alloc::rc::Rc<[T]>, + alloc::sync::Arc<[T]>, Vec, } @@ -1053,7 +1054,7 @@ unsafe impl Lift for char { #[inline] fn lift(_cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result { debug_assert!(matches!(ty, InterfaceType::Char)); - Ok(char::try_from(src.get_u32())?) + Ok(char::try_from(src.get_u32()).err2anyhow()?) } #[inline] @@ -1061,7 +1062,7 @@ unsafe impl Lift for char { debug_assert!(matches!(ty, InterfaceType::Char)); debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0); let bits = u32::from_le_bytes(bytes.try_into().unwrap()); - Ok(char::try_from(bits)?) + Ok(char::try_from(bits).err2anyhow()?) } } @@ -1337,18 +1338,21 @@ impl WasmStr { // Note that bounds-checking already happen in construction of `WasmStr` // so this is never expected to panic. This could theoretically be // unchecked indexing if we're feeling wild enough. - Ok(str::from_utf8(&memory[self.ptr..][..self.len])?.into()) + Ok(str::from_utf8(&memory[self.ptr..][..self.len]) + .err2anyhow()? + .into()) } fn decode_utf16<'a>(&self, memory: &'a [u8], len: usize) -> Result> { // See notes in `decode_utf8` for why this is panicking indexing. let memory = &memory[self.ptr..][..len * 2]; - Ok(std::char::decode_utf16( + Ok(core::char::decode_utf16( memory .chunks(2) .map(|chunk| u16::from_le_bytes(chunk.try_into().unwrap())), ) - .collect::>()? + .collect::>() + .err2anyhow()? .into()) } @@ -1382,7 +1386,10 @@ unsafe impl Lift for WasmStr { // FIXME: needs memory64 treatment let ptr = src[0].get_u32(); let len = src[1].get_u32(); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); + let (ptr, len) = ( + usize::try_from(ptr).err2anyhow()?, + usize::try_from(len).err2anyhow()?, + ); WasmStr::new(ptr, len, cx) } @@ -1393,7 +1400,10 @@ unsafe impl Lift for WasmStr { // FIXME: needs memory64 treatment let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()); let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); + let (ptr, len) = ( + usize::try_from(ptr).err2anyhow()?, + usize::try_from(len).err2anyhow()?, + ); WasmStr::new(ptr, len, cx) } } @@ -1530,7 +1540,7 @@ impl WasmList { Some(n) if n <= cx.memory().len() => {} _ => bail!("list pointer/length out of bounds of memory"), } - if ptr % usize::try_from(T::ALIGN32)? != 0 { + if ptr % usize::try_from(T::ALIGN32).err2anyhow()? != 0 { bail!("list pointer is not aligned") } Ok(WasmList { @@ -1686,7 +1696,10 @@ unsafe impl Lift for WasmList { // FIXME: needs memory64 treatment let ptr = src[0].get_u32(); let len = src[1].get_u32(); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); + let (ptr, len) = ( + usize::try_from(ptr).err2anyhow()?, + usize::try_from(len).err2anyhow()?, + ); WasmList::new(ptr, len, cx, elem) } @@ -1699,7 +1712,10 @@ unsafe impl Lift for WasmList { // FIXME: needs memory64 treatment let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()); let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()); - let (ptr, len) = (usize::try_from(ptr)?, usize::try_from(len)?); + let (ptr, len) = ( + usize::try_from(ptr).err2anyhow()?, + usize::try_from(len).err2anyhow()?, + ); WasmList::new(ptr, len, cx, elem) } } diff --git a/crates/wasmtime/src/runtime/component/instance.rs b/crates/wasmtime/src/runtime/component/instance.rs index b17092cbcd39..d2a1537d60b2 100644 --- a/crates/wasmtime/src/runtime/component/instance.rs +++ b/crates/wasmtime/src/runtime/component/instance.rs @@ -3,15 +3,15 @@ use crate::component::matching::InstanceType; use crate::component::{Component, ComponentNamedList, Func, Lift, Lower, ResourceType, TypedFunc}; use crate::instance::OwnedImports; use crate::linker::DefinitionType; +use crate::prelude::*; use crate::runtime::vm::component::{ComponentInstance, OwnedComponentInstance}; use crate::runtime::vm::VMFuncRef; use crate::store::{StoreOpaque, Stored}; use crate::{AsContextMut, Module, StoreContextMut}; +use alloc::sync::Arc; use anyhow::{anyhow, Context, Result}; -use std::marker; -use std::ptr::NonNull; -use std::sync::Arc; -use wasmtime_environ::prelude::IndexMap; +use core::marker; +use core::ptr::{self, NonNull}; use wasmtime_environ::{component::*, EngineOrModuleTypeIndex}; use wasmtime_environ::{EntityIndex, EntityType, Global, PrimaryMap, WasmValType}; @@ -164,7 +164,7 @@ impl InstanceData { CoreDef::InstanceFlags(idx) => { crate::runtime::vm::Export::Global(crate::runtime::vm::ExportGlobal { definition: self.state.instance_flags(*idx).as_raw(), - vmctx: std::ptr::null_mut(), + vmctx: ptr::null_mut(), global: Global { wasm_ty: WasmValType::I32, mutability: true, diff --git a/crates/wasmtime/src/runtime/component/linker.rs b/crates/wasmtime/src/runtime/component/linker.rs index 745e4b942855..59487bb65508 100644 --- a/crates/wasmtime/src/runtime/component/linker.rs +++ b/crates/wasmtime/src/runtime/component/linker.rs @@ -5,14 +5,15 @@ use crate::component::types; use crate::component::{ Component, ComponentNamedList, Instance, InstancePre, Lift, Lower, ResourceType, Val, }; +use crate::prelude::*; use crate::{AsContextMut, Engine, Module, StoreContextMut}; +use alloc::sync::Arc; use anyhow::{bail, Context, Result}; +use core::future::Future; +use core::marker; +use core::pin::Pin; +use hashbrown::hash_map::{Entry, HashMap}; use semver::Version; -use std::collections::hash_map::{Entry, HashMap}; -use std::future::Future; -use std::marker; -use std::pin::Pin; -use std::sync::Arc; use wasmtime_environ::PrimaryMap; /// A type used to instantiate [`Component`]s. @@ -641,7 +642,7 @@ impl NameMap { let (alternate_name, _version) = alternate_lookup_key(name)?; let alternate_key = strings.lookup(alternate_name)?; let (exact_key, _version) = self.alternate_lookups.get(&alternate_key)?; - self.definitions.get(&exact_key) + self.definitions.get(exact_key) } /// Inserts the `name` specified into this map. diff --git a/crates/wasmtime/src/runtime/component/matching.rs b/crates/wasmtime/src/runtime/component/matching.rs index cce569ceb97b..060c15a7581c 100644 --- a/crates/wasmtime/src/runtime/component/matching.rs +++ b/crates/wasmtime/src/runtime/component/matching.rs @@ -1,12 +1,13 @@ use crate::component::func::HostFunc; use crate::component::linker::{Definition, NameMap, Strings}; use crate::component::ResourceType; +use crate::prelude::*; use crate::runtime::vm::component::ComponentInstance; use crate::types::matching; use crate::Module; +use alloc::sync::Arc; use anyhow::{anyhow, bail, Context, Result}; -use std::any::Any; -use std::sync::Arc; +use core::any::Any; use wasmtime_environ::component::{ ComponentTypes, ResourceIndex, TypeComponentInstance, TypeDef, TypeFuncIndex, TypeModule, TypeResourceTableIndex, diff --git a/crates/wasmtime/src/runtime/component/mod.rs b/crates/wasmtime/src/runtime/component/mod.rs index 7276b5cdeb1d..3d9e4caa5c8d 100644 --- a/crates/wasmtime/src/runtime/component/mod.rs +++ b/crates/wasmtime/src/runtime/component/mod.rs @@ -137,6 +137,9 @@ pub mod __internal { pub use super::matching::InstanceType; pub use crate::map_maybe_uninit; pub use crate::store::StoreOpaque; + pub use alloc::boxed::Box; + pub use alloc::string::String; + pub use alloc::vec::Vec; pub use anyhow; #[cfg(feature = "async")] pub use async_trait::async_trait; diff --git a/crates/wasmtime/src/runtime/component/resource_table.rs b/crates/wasmtime/src/runtime/component/resource_table.rs index 4b57ce792679..1adc4be34b7d 100644 --- a/crates/wasmtime/src/runtime/component/resource_table.rs +++ b/crates/wasmtime/src/runtime/component/resource_table.rs @@ -1,6 +1,8 @@ use super::Resource; -use std::any::Any; -use std::collections::{BTreeSet, HashMap}; +use crate::prelude::*; +use alloc::collections::BTreeSet; +use core::any::Any; +use core::fmt; #[derive(Debug)] /// Errors returned by operations on `ResourceTable` @@ -16,8 +18,8 @@ pub enum ResourceTableError { HasChildren, } -impl std::fmt::Display for ResourceTableError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for ResourceTableError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Full => write!(f, "resource table has no free keys"), Self::NotPresent => write!(f, "resource not present"), @@ -26,6 +28,8 @@ impl std::fmt::Display for ResourceTableError { } } } + +#[cfg(feature = "std")] impl std::error::Error for ResourceTableError {} /// The `ResourceTable` type maps a `Resource` to its `T`. @@ -137,7 +141,7 @@ impl ResourceTable { /// Free an entry in the table, returning its [`TableEntry`]. Add the index to the free list. fn free_entry(&mut self, ix: usize) -> TableEntry { - let entry = match std::mem::replace( + let entry = match core::mem::replace( &mut self.entries[ix], Entry::Free { next: self.free_head, @@ -281,11 +285,12 @@ impl ResourceTable { } /// Zip the values of the map with mutable references to table entries corresponding to each - /// key. As the keys in the [HashMap] are unique, this iterator can give mutable references + /// key. As the keys in the `HashMap` are unique, this iterator can give mutable references /// with the same lifetime as the mutable reference to the [ResourceTable]. + #[cfg(feature = "std")] pub fn iter_entries<'a, T>( &'a mut self, - map: HashMap, + map: std::collections::HashMap, ) -> impl Iterator, T)> { map.into_iter().map(move |(k, v)| { let item = self diff --git a/crates/wasmtime/src/runtime/component/resources.rs b/crates/wasmtime/src/runtime/component/resources.rs index b2f8d08b1dcb..b223a44d7abc 100644 --- a/crates/wasmtime/src/runtime/component/resources.rs +++ b/crates/wasmtime/src/runtime/component/resources.rs @@ -1,17 +1,18 @@ use crate::component::func::{bad_type_info, desc, LiftContext, LowerContext}; use crate::component::matching::InstanceType; use crate::component::{ComponentType, Lift, Lower}; +use crate::prelude::*; use crate::runtime::vm::component::{ComponentInstance, InstanceFlags, ResourceTables}; use crate::runtime::vm::{SendSyncPtr, VMFuncRef, ValRaw}; use crate::store::{StoreId, StoreOpaque}; use crate::{AsContextMut, StoreContextMut, Trap}; use anyhow::{bail, ensure, Result}; -use std::any::TypeId; -use std::fmt; -use std::marker; -use std::mem::MaybeUninit; -use std::ptr::NonNull; -use std::sync::atomic::{AtomicU64, Ordering::Relaxed}; +use core::any::TypeId; +use core::fmt; +use core::marker; +use core::mem::MaybeUninit; +use core::ptr::NonNull; +use core::sync::atomic::{AtomicU64, Ordering::Relaxed}; use wasmtime_environ::component::{ CanonicalAbiInfo, ComponentTypes, DefinedResourceIndex, InterfaceType, ResourceIndex, TypeResourceTableIndex, diff --git a/crates/wasmtime/src/runtime/component/storage.rs b/crates/wasmtime/src/runtime/component/storage.rs index f66980cd6643..01537b42984d 100644 --- a/crates/wasmtime/src/runtime/component/storage.rs +++ b/crates/wasmtime/src/runtime/component/storage.rs @@ -1,6 +1,6 @@ use crate::ValRaw; -use std::mem::{self, MaybeUninit}; -use std::slice; +use core::mem::{self, MaybeUninit}; +use core::slice; fn assert_raw_slice_compat() { assert!(mem::size_of::() % mem::size_of::() == 0); diff --git a/crates/wasmtime/src/runtime/component/store.rs b/crates/wasmtime/src/runtime/component/store.rs index 9144761391c0..d2422043ebd0 100644 --- a/crates/wasmtime/src/runtime/component/store.rs +++ b/crates/wasmtime/src/runtime/component/store.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use crate::store::{StoreData, StoredData}; macro_rules! component_store_data { diff --git a/crates/wasmtime/src/runtime/component/types.rs b/crates/wasmtime/src/runtime/component/types.rs index a48f1d30e8e6..d6d2335bccb9 100644 --- a/crates/wasmtime/src/runtime/component/types.rs +++ b/crates/wasmtime/src/runtime/component/types.rs @@ -2,9 +2,9 @@ use crate::component::matching::InstanceType; use crate::{Engine, ExternType, FuncType}; -use std::fmt; -use std::ops::Deref; -use std::sync::Arc; +use alloc::sync::Arc; +use core::fmt; +use core::ops::Deref; use wasmtime_environ::component::{ ComponentTypes, InterfaceType, ResourceIndex, TypeComponentIndex, TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFlagsIndex, TypeFuncIndex, TypeListIndex, TypeModuleIndex, diff --git a/crates/wasmtime/src/runtime/component/values.rs b/crates/wasmtime/src/runtime/component/values.rs index f6bfd189372b..65274eb3342d 100644 --- a/crates/wasmtime/src/runtime/component/values.rs +++ b/crates/wasmtime/src/runtime/component/values.rs @@ -1,8 +1,10 @@ use crate::component::func::{desc, Lift, LiftContext, Lower, LowerContext}; use crate::component::ResourceAny; +use crate::prelude::*; use crate::ValRaw; use anyhow::{anyhow, bail, Result}; -use std::mem::MaybeUninit; +use core::mem::MaybeUninit; +use core::slice::{Iter, IterMut}; use wasmtime_component_util::{DiscriminantSize, FlagsSize}; use wasmtime_environ::component::{ CanonicalAbiInfo, InterfaceType, TypeEnum, TypeFlags, TypeListIndex, TypeOption, TypeResult, @@ -92,7 +94,7 @@ impl Val { pub(crate) fn lift( cx: &mut LiftContext<'_>, ty: InterfaceType, - src: &mut std::slice::Iter<'_, ValRaw>, + src: &mut Iter<'_, ValRaw>, ) -> Result { Ok(match ty { InterfaceType::Bool => Val::Bool(bool::lift(cx, ty, next(src))?), @@ -326,7 +328,7 @@ impl Val { &self, cx: &mut LowerContext<'_, T>, ty: InterfaceType, - dst: &mut std::slice::IterMut<'_, MaybeUninit>, + dst: &mut IterMut<'_, MaybeUninit>, ) -> Result<()> { match (ty, self) { (InterfaceType::Bool, Val::Bool(value)) => value.lower(cx, ty, next_mut(dst)), @@ -438,7 +440,9 @@ impl Val { ty: InterfaceType, offset: usize, ) -> Result<()> { - debug_assert!(offset % usize::try_from(cx.types.canonical_abi(&ty).align32)? == 0); + debug_assert!( + offset % usize::try_from(cx.types.canonical_abi(&ty).align32).err2anyhow()? == 0 + ); match (ty, self) { (InterfaceType::Bool, Val::Bool(value)) => value.store(cx, ty, offset), @@ -758,7 +762,7 @@ impl GenericVariant<'_> { fn lower( &self, cx: &mut LowerContext<'_, T>, - dst: &mut std::slice::IterMut<'_, MaybeUninit>, + dst: &mut IterMut<'_, MaybeUninit>, ) -> Result<()> { next_mut(dst).write(ValRaw::u32(self.discriminant)); @@ -816,7 +820,7 @@ fn load_list(cx: &mut LiftContext<'_>, ty: TypeListIndex, ptr: usize, len: usize Some(n) if n <= cx.memory().len() => {} _ => bail!("list pointer/length out of bounds of memory"), } - if ptr % usize::try_from(element_alignment)? != 0 { + if ptr % usize::try_from(element_alignment).err2anyhow()? != 0 { bail!("list pointer is not aligned") } @@ -871,7 +875,7 @@ fn lift_variant( cx: &mut LiftContext<'_>, flatten_count: usize, mut types: impl ExactSizeIterator>, - src: &mut std::slice::Iter<'_, ValRaw>, + src: &mut Iter<'_, ValRaw>, ) -> Result<(u32, Option>)> { let len = types.len(); let discriminant = next(src).get_u32(); @@ -898,7 +902,7 @@ fn lower_list( items: &[Val], ) -> Result<(usize, usize)> { let abi = cx.types.canonical_abi(&element_type); - let elt_size = usize::try_from(abi.size32)?; + let elt_size = usize::try_from(abi.size32).err2anyhow()?; let elt_align = abi.align32; let size = items .len() @@ -958,13 +962,11 @@ fn get_variant_discriminant<'a>( Ok((i as u32, ty)) } -fn next<'a>(src: &mut std::slice::Iter<'a, ValRaw>) -> &'a ValRaw { +fn next<'a>(src: &mut Iter<'a, ValRaw>) -> &'a ValRaw { src.next().unwrap() } -fn next_mut<'a>( - dst: &mut std::slice::IterMut<'a, MaybeUninit>, -) -> &'a mut MaybeUninit { +fn next_mut<'a>(dst: &mut IterMut<'a, MaybeUninit>) -> &'a mut MaybeUninit { dst.next().unwrap() } diff --git a/crates/wasmtime/src/runtime/coredump.rs b/crates/wasmtime/src/runtime/coredump.rs index 0ebaf5d41081..676305aa7d6c 100644 --- a/crates/wasmtime/src/runtime/coredump.rs +++ b/crates/wasmtime/src/runtime/coredump.rs @@ -1,9 +1,9 @@ -use std::{collections::HashMap, fmt}; - +use crate::prelude::*; use crate::{ store::StoreOpaque, AsContextMut, FrameInfo, Global, HeapType, Instance, Memory, Module, StoreContextMut, Val, ValType, WasmBacktrace, }; +use std::{collections::HashMap, fmt}; /// Representation of a core dump of a WebAssembly module /// diff --git a/crates/wasmtime/src/runtime/debug.rs b/crates/wasmtime/src/runtime/debug.rs index 4480c1ee7087..1585c06749cc 100644 --- a/crates/wasmtime/src/runtime/debug.rs +++ b/crates/wasmtime/src/runtime/debug.rs @@ -1,4 +1,6 @@ +use crate::prelude::*; use anyhow::{anyhow, bail, ensure, Error}; +use core::mem::size_of; use object::elf::*; use object::endian::{BigEndian, Endian, Endianness, LittleEndian}; use object::read::elf::{FileHeader, SectionHeader}; @@ -6,7 +8,6 @@ use object::{ File, NativeEndian as NE, Object, ObjectSection, ObjectSymbol, RelocationEncoding, RelocationKind, RelocationTarget, U64Bytes, }; -use std::mem::size_of; pub(crate) fn create_gdbjit_image( mut bytes: Vec, @@ -32,7 +33,7 @@ pub(crate) fn create_gdbjit_image( fn relocate_dwarf_sections(bytes: &mut [u8], code_region: (*const u8, usize)) -> Result<(), Error> { let mut relocations = Vec::new(); - let obj = File::parse(&bytes[..])?; + let obj = File::parse(&bytes[..]).err2anyhow()?; for section in obj.sections() { let section_start = match section.file_range() { Some((start, _)) => start, diff --git a/crates/wasmtime/src/runtime/externals/global.rs b/crates/wasmtime/src/runtime/externals/global.rs index c11c7d2a7a42..4623bce68bec 100644 --- a/crates/wasmtime/src/runtime/externals/global.rs +++ b/crates/wasmtime/src/runtime/externals/global.rs @@ -6,8 +6,8 @@ use crate::{ RootedGcRefImpl, Val, ValType, }; use anyhow::{bail, Context, Result}; -use std::ptr; -use std::ptr::NonNull; +use core::ptr; +use core::ptr::NonNull; use wasmtime_environ::TypeTrace; /// A WebAssembly `global` value which can be read and written to. @@ -261,7 +261,7 @@ impl Global { /// Even if the same underlying global definition is added to the /// `StoreData` multiple times and becomes multiple `wasmtime::Global`s, /// this hash key will be consistent across all of these globals. - pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl std::hash::Hash + Eq { + pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl core::hash::Hash + Eq { store[self.0].definition as usize } } diff --git a/crates/wasmtime/src/runtime/externals/table.rs b/crates/wasmtime/src/runtime/externals/table.rs index 359e61f88135..db63ca8e61f5 100644 --- a/crates/wasmtime/src/runtime/externals/table.rs +++ b/crates/wasmtime/src/runtime/externals/table.rs @@ -1,10 +1,11 @@ -use std::ptr::NonNull; - +use crate::prelude::*; use crate::runtime::vm::{self as runtime}; use crate::store::{AutoAssertNoGc, StoreData, StoreOpaque, Stored}; use crate::trampoline::generate_table_export; use crate::{AnyRef, AsContext, AsContextMut, ExternRef, Func, HeapType, Ref, TableType}; use anyhow::{anyhow, bail, Context, Result}; +use core::iter; +use core::ptr::NonNull; use runtime::{GcRootsList, SendSyncPtr}; use wasmtime_environ::TypeTrace; @@ -109,8 +110,10 @@ impl Table { let init = init.into_table_element(store, ty.element())?; unsafe { let table = Table::from_wasmtime_table(wasmtime_export, store); - let wasmtime_table = table.wasmtime_table(store, std::iter::empty()); - (*wasmtime_table).fill(store.gc_store_mut()?, 0, init, ty.minimum())?; + let wasmtime_table = table.wasmtime_table(store, iter::empty()); + (*wasmtime_table) + .fill(store.gc_store_mut()?, 0, init, ty.minimum()) + .err2anyhow()?; Ok(table) } } @@ -153,7 +156,7 @@ impl Table { /// Panics if `store` does not own this table. pub fn get(&self, mut store: impl AsContextMut, index: u32) -> Option { let mut store = AutoAssertNoGc::new(store.as_context_mut().0); - let table = self.wasmtime_table(&mut store, std::iter::once(index)); + let table = self.wasmtime_table(&mut store, iter::once(index)); unsafe { match (*table).get(store.unwrap_gc_store_mut(), index)? { runtime::TableElement::FuncRef(f) => { @@ -205,7 +208,7 @@ impl Table { let store = store.as_context_mut().0; let ty = self.ty(&store); let val = val.into_table_element(store, ty.element())?; - let table = self.wasmtime_table(store, std::iter::empty()); + let table = self.wasmtime_table(store, iter::empty()); unsafe { (*table) .set(index, val) @@ -251,7 +254,7 @@ impl Table { let store = store.as_context_mut().0; let ty = self.ty(&store); let init = init.into_table_element(store, ty.element())?; - let table = self.wasmtime_table(store, std::iter::empty()); + let table = self.wasmtime_table(store, iter::empty()); unsafe { match (*table).grow(delta, init, store)? { Some(size) => { @@ -323,7 +326,7 @@ impl Table { destination table's element type", )?; - let dst_table = dst_table.wasmtime_table(store, std::iter::empty()); + let dst_table = dst_table.wasmtime_table(store, iter::empty()); let src_range = src_index..(src_index.checked_add(len).unwrap_or(u32::MAX)); let src_table = src_table.wasmtime_table(store, src_range); unsafe { @@ -334,7 +337,8 @@ impl Table { dst_index, src_index, len, - )?; + ) + .err2anyhow()?; } Ok(()) } @@ -360,9 +364,11 @@ impl Table { let ty = self.ty(&store); let val = val.into_table_element(store, ty.element())?; - let table = self.wasmtime_table(store, std::iter::empty()); + let table = self.wasmtime_table(store, iter::empty()); unsafe { - (*table).fill(store.gc_store_mut()?, dst, val, len)?; + (*table) + .fill(store.gc_store_mut()?, dst, val, len) + .err2anyhow()?; } Ok(()) @@ -373,7 +379,7 @@ impl Table { return; } - let table = self.wasmtime_table(store, std::iter::empty()); + let table = self.wasmtime_table(store, iter::empty()); for gc_ref in unsafe { (*table).gc_refs_mut() } { if let Some(gc_ref) = gc_ref { let gc_ref = NonNull::from(gc_ref); @@ -421,7 +427,7 @@ impl Table { /// `StoreData` multiple times and becomes multiple `wasmtime::Table`s, /// this hash key will be consistent across all of these tables. #[allow(dead_code)] // Not used yet, but added for consistency. - pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl std::hash::Hash + Eq { + pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl core::hash::Hash + Eq { store[self.0].definition as usize } } diff --git a/crates/wasmtime/src/runtime/func.rs b/crates/wasmtime/src/runtime/func.rs index 79cadf450a64..3e0611766c8e 100644 --- a/crates/wasmtime/src/runtime/func.rs +++ b/crates/wasmtime/src/runtime/func.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use crate::runtime::vm::{ ExportFunction, SendSyncPtr, StoreBox, VMArrayCallHostFuncContext, VMContext, VMFuncRef, VMFunctionImport, VMNativeCallHostFuncContext, VMOpaqueContext, @@ -9,14 +10,14 @@ use crate::{ AsContext, AsContextMut, CallHook, Engine, Extern, FuncType, Instance, Module, Ref, StoreContext, StoreContextMut, Val, ValRaw, ValType, }; +use alloc::sync::Arc; use anyhow::{bail, Context as _, Error, Result}; -use std::ffi::c_void; -use std::future::Future; -use std::mem; -use std::num::NonZeroUsize; -use std::pin::Pin; -use std::ptr::{self, NonNull}; -use std::sync::Arc; +use core::ffi::c_void; +use core::future::Future; +use core::mem; +use core::num::NonZeroUsize; +use core::pin::Pin; +use core::ptr::{self, NonNull}; use wasmtime_environ::VMSharedTypeIndex; /// A reference to the abstract `nofunc` heap value. @@ -1539,7 +1540,7 @@ impl Func { /// multiple times and becomes multiple `wasmtime::Func`s, this hash key /// will be consistent across all of these functions. #[allow(dead_code)] // Not used yet, but added for consistency. - pub(crate) fn hash_key(&self, store: &mut StoreOpaque) -> impl std::hash::Hash + Eq { + pub(crate) fn hash_key(&self, store: &mut StoreOpaque) -> impl core::hash::Hash + Eq { self.vm_func_ref(store).as_ptr() as usize } } @@ -1931,7 +1932,7 @@ macro_rules! impl_host_abi { unsafe fn call(f: impl FnOnce(Self::Retptr) -> Self::Abi) -> Self { // Create space to store all the return values and then invoke // the function. - let mut space = std::mem::MaybeUninit::uninit(); + let mut space = core::mem::MaybeUninit::uninit(); let t = f(space.as_mut_ptr()); let space = space.assume_init(); @@ -2534,8 +2535,8 @@ use self::rooted::*; mod rooted { use super::HostFunc; use crate::runtime::vm::{SendSyncPtr, VMFuncRef}; - use std::ptr::NonNull; - use std::sync::Arc; + use alloc::sync::Arc; + use core::ptr::NonNull; /// A variant of a pointer-to-a-host-function used in `FuncKind::RootedHost` /// above. diff --git a/crates/wasmtime/src/runtime/func/typed.rs b/crates/wasmtime/src/runtime/func/typed.rs index 1e486c516ef5..0fa6f01bdd97 100644 --- a/crates/wasmtime/src/runtime/func/typed.rs +++ b/crates/wasmtime/src/runtime/func/typed.rs @@ -6,11 +6,11 @@ use crate::{ ValRaw, ValType, }; use anyhow::{bail, Context, Result}; -use std::marker; -use std::mem::{self, MaybeUninit}; -use std::num::NonZeroUsize; -use std::os::raw::c_void; -use std::ptr::{self, NonNull}; +use core::ffi::c_void; +use core::marker; +use core::mem::{self, MaybeUninit}; +use core::num::NonZeroUsize; +use core::ptr::{self, NonNull}; use wasmtime_environ::VMSharedTypeIndex; /// A statically typed WebAssembly function. diff --git a/crates/wasmtime/src/runtime/gc.rs b/crates/wasmtime/src/runtime/gc.rs index 3659b000172d..61ed99d8a2b6 100644 --- a/crates/wasmtime/src/runtime/gc.rs +++ b/crates/wasmtime/src/runtime/gc.rs @@ -8,7 +8,8 @@ mod disabled; #[cfg(not(feature = "gc"))] pub use disabled::*; -use std::ops::Deref; +use core::fmt; +use core::ops::Deref; /// A common trait implemented by all garbage-collected reference types. /// @@ -61,18 +62,19 @@ pub struct GcHeapOutOfMemory { inner: T, } -impl std::fmt::Debug for GcHeapOutOfMemory { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self, f) +impl fmt::Debug for GcHeapOutOfMemory { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) } } -impl std::fmt::Display for GcHeapOutOfMemory { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for GcHeapOutOfMemory { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "GC heap out of memory") } } +#[cfg(feature = "std")] impl std::error::Error for GcHeapOutOfMemory {} impl GcHeapOutOfMemory { diff --git a/crates/wasmtime/src/runtime/gc/disabled/externref.rs b/crates/wasmtime/src/runtime/gc/disabled/externref.rs index 5f7ccf66fbec..c40d97d15d29 100644 --- a/crates/wasmtime/src/runtime/gc/disabled/externref.rs +++ b/crates/wasmtime/src/runtime/gc/disabled/externref.rs @@ -2,7 +2,7 @@ use crate::runtime::vm::VMGcRef; use crate::{ store::AutoAssertNoGc, AsContextMut, GcRefImpl, Result, Rooted, StoreContext, StoreContextMut, }; -use std::any::Any; +use core::any::Any; /// Support for `externref` disabled at compile time because the `gc` cargo /// feature was not enabled. diff --git a/crates/wasmtime/src/runtime/gc/disabled/rooting.rs b/crates/wasmtime/src/runtime/gc/disabled/rooting.rs index b2f3b8eccd41..a63a6512693d 100644 --- a/crates/wasmtime/src/runtime/gc/disabled/rooting.rs +++ b/crates/wasmtime/src/runtime/gc/disabled/rooting.rs @@ -1,14 +1,16 @@ +use crate::prelude::*; use crate::runtime::vm::{GcStore, VMExternRef, VMGcRef}; use crate::{ runtime::Uninhabited, store::{AutoAssertNoGc, StoreOpaque}, AsContext, AsContextMut, GcRef, Result, RootedGcRef, }; -use std::any::Any; -use std::ffi::c_void; -use std::fmt::Debug; -use std::hash::Hash; -use std::ops::Deref; +use core::any::Any; +use core::ffi::c_void; +use core::fmt::{self, Debug}; +use core::hash::{Hash, Hasher}; +use core::marker; +use core::ops::Deref; mod sealed { use super::*; @@ -57,7 +59,7 @@ impl RootSet { /// compile time. pub struct Rooted { inner: Uninhabited, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } impl Clone for Rooted { @@ -69,7 +71,7 @@ impl Clone for Rooted { impl Copy for Rooted {} impl Debug for Rooted { - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.inner {} } } @@ -83,7 +85,7 @@ impl PartialEq for Rooted { impl Eq for Rooted {} impl Hash for Rooted { - fn hash(&self, _state: &mut H) { + fn hash(&self, _state: &mut H) { match self.inner {} } } @@ -132,7 +134,7 @@ where C: AsContextMut, { inner: Uninhabited, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } #[allow(missing_docs)] @@ -172,11 +174,11 @@ where T: GcRef, { inner: Uninhabited, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } impl Debug for ManuallyRooted { - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.inner {} } } diff --git a/crates/wasmtime/src/runtime/gc/enabled/anyref.rs b/crates/wasmtime/src/runtime/gc/enabled/anyref.rs index e430c489b4f2..946293add8b5 100644 --- a/crates/wasmtime/src/runtime/gc/enabled/anyref.rs +++ b/crates/wasmtime/src/runtime/gc/enabled/anyref.rs @@ -6,7 +6,8 @@ use crate::{ AsContext, AsContextMut, GcRefImpl, GcRootIndex, HeapType, ManuallyRooted, RefType, Result, RootSet, Rooted, ValRaw, ValType, WasmTy, I31, }; -use std::num::NonZeroU64; +use core::mem; +use core::num::NonZeroU64; /// An `anyref` GC reference. /// @@ -96,7 +97,7 @@ unsafe impl GcRefImpl for AnyRef { #[allow(private_interfaces)] fn transmute_ref(index: &GcRootIndex) -> &Self { // Safety: `AnyRef` is a newtype of a `GcRootIndex`. - let me: &Self = unsafe { std::mem::transmute(index) }; + let me: &Self = unsafe { mem::transmute(index) }; // Assert we really are just a newtype of a `GcRootIndex`. assert!(matches!( diff --git a/crates/wasmtime/src/runtime/gc/enabled/externref.rs b/crates/wasmtime/src/runtime/gc/enabled/externref.rs index 9f72af6080f8..7e389d4cb78f 100644 --- a/crates/wasmtime/src/runtime/gc/enabled/externref.rs +++ b/crates/wasmtime/src/runtime/gc/enabled/externref.rs @@ -1,5 +1,6 @@ //! Implementation of `externref` in Wasmtime. +use crate::prelude::*; use crate::runtime::vm::VMGcRef; use crate::{ store::{AutoAssertNoGc, StoreOpaque}, @@ -7,8 +8,9 @@ use crate::{ Result, RootSet, Rooted, StoreContext, StoreContextMut, ValRaw, ValType, WasmTy, }; use anyhow::Context; -use std::any::Any; -use std::num::NonZeroU64; +use core::any::Any; +use core::mem; +use core::num::NonZeroU64; /// An opaque, GC-managed reference to some host data that can be passed to /// WebAssembly. @@ -114,7 +116,7 @@ unsafe impl GcRefImpl for ExternRef { #[allow(private_interfaces)] fn transmute_ref(index: &GcRootIndex) -> &Self { // Safety: `ExternRef` is a newtype of a `GcRootIndex`. - let me: &Self = unsafe { std::mem::transmute(index) }; + let me: &Self = unsafe { mem::transmute(index) }; // Assert we really are just a newtype of a `GcRootIndex`. assert!(matches!( @@ -201,8 +203,10 @@ impl ExternRef { let gc_ref = ctx .gc_store_mut()? .alloc_externref(value) + .err2anyhow() .context("unrecoverable error when allocating new `externref`")? .map_err(|x| GcHeapOutOfMemory::::new(*x.downcast().unwrap())) + .err2anyhow() .context("failed to allocate `externref`")?; let mut ctx = AutoAssertNoGc::new(ctx); @@ -253,8 +257,10 @@ impl ExternRef { let gc_ref = ctx .gc_store_mut()? .alloc_externref(value) + .err2anyhow() .context("unrecoverable error when allocating new `externref`")? .map_err(|x| GcHeapOutOfMemory::::new(*x.downcast().unwrap())) + .err2anyhow() .context("failed to allocate `externref`")?; let mut ctx = AutoAssertNoGc::new(ctx); diff --git a/crates/wasmtime/src/runtime/gc/enabled/i31.rs b/crates/wasmtime/src/runtime/gc/enabled/i31.rs index 837430c87ecc..9d632a6f2371 100644 --- a/crates/wasmtime/src/runtime/gc/enabled/i31.rs +++ b/crates/wasmtime/src/runtime/gc/enabled/i31.rs @@ -9,6 +9,7 @@ use crate::{ store::{AutoAssertNoGc, StoreOpaque}, HeapType, RefType, Result, ValType, WasmTy, }; +use core::fmt; /// A 31-bit integer. /// @@ -76,8 +77,8 @@ use crate::{ #[derive(Clone, Copy, Default, PartialEq, Eq, Hash)] pub struct I31(crate::runtime::vm::I31); -impl std::fmt::Debug for I31 { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Debug for I31 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("I31") .field("as_u32", &self.get_u32()) .field("as_i32", &self.get_i32()) diff --git a/crates/wasmtime/src/runtime/gc/enabled/rooting.rs b/crates/wasmtime/src/runtime/gc/enabled/rooting.rs index deac3b672e9f..0a5801ed67a0 100644 --- a/crates/wasmtime/src/runtime/gc/enabled/rooting.rs +++ b/crates/wasmtime/src/runtime/gc/enabled/rooting.rs @@ -102,16 +102,20 @@ //! can. However, if you really must, consider also using an `AutoAssertNoGc` //! across the block of code that is manipulating raw GC references. +use crate::prelude::*; use crate::runtime::vm::{GcRootsList, GcStore, VMGcRef}; use crate::{ store::{AutoAssertNoGc, StoreId, StoreOpaque}, AsContext, AsContextMut, GcRef, Result, RootedGcRef, }; use anyhow::anyhow; -use std::num::NonZeroU64; -use std::{ - fmt::Debug, - hash::Hash, +use core::any; +use core::marker; +use core::mem; +use core::num::NonZeroU64; +use core::{ + fmt::{self, Debug}, + hash::{Hash, Hasher}, ops::{Deref, DerefMut}, }; use wasmtime_slab::{Id as SlabId, Slab}; @@ -196,8 +200,8 @@ pub struct GcRootIndex { const _: () = { // NB: these match the C API which should also be updated if this changes - assert!(std::mem::size_of::() == 16); - assert!(std::mem::align_of::() == 8); + assert!(mem::size_of::() == 16); + assert!(mem::align_of::() == 8); }; impl GcRootIndex { @@ -283,7 +287,7 @@ impl GcRootIndex { struct PackedIndex(u32); impl Debug for PackedIndex { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(index) = self.as_lifo() { f.debug_tuple("PackedIndex::Lifo").field(&index).finish() } else if let Some(id) = self.as_manual() { @@ -436,7 +440,7 @@ impl RootSet { // // self.lifo_roots.truncate(scope); - let mut lifo_roots = std::mem::take(&mut self.lifo_roots); + let mut lifo_roots = mem::take(&mut self.lifo_roots); for root in lifo_roots.drain(scope..) { gc_store.drop_gc_ref(root.gc_ref); } @@ -660,14 +664,14 @@ impl RootSet { #[repr(transparent)] pub struct Rooted { inner: GcRootIndex, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } impl Clone for Rooted { fn clone(&self) -> Self { Rooted { inner: self.inner, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } } } @@ -675,8 +679,8 @@ impl Clone for Rooted { impl Copy for Rooted {} impl Debug for Rooted { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let name = format!("Rooted<{}>", std::any::type_name::()); + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let name = format!("Rooted<{}>", any::type_name::()); f.debug_struct(&name).field("inner", &self.inner).finish() } } @@ -721,7 +725,7 @@ impl Rooted { let inner = roots.push_lifo_root(id, gc_ref); Rooted { inner, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } } @@ -899,7 +903,7 @@ impl Rooted { /// [`ref_hash`][crate::Rooted::ref_hash] method instead. pub fn rooted_hash(&self, state: &mut H) where - H: std::hash::Hasher, + H: Hasher, { self.inner.hash(state); } @@ -913,7 +917,7 @@ impl Rooted { /// [`rooted_hash`][crate::Rooted::rooted_hash] method instead. pub fn ref_hash(&self, store: impl AsContext, state: &mut H) -> Result<()> where - H: std::hash::Hasher, + H: Hasher, { let gc_ref = self.try_gc_ref(store.as_context().0)?; gc_ref.hash(state); @@ -1207,22 +1211,22 @@ where T: GcRef, { inner: GcRootIndex, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } const _: () = { use crate::{AnyRef, ExternRef}; // NB: these match the C API which should also be updated if this changes - assert!(std::mem::size_of::>() == 16); - assert!(std::mem::align_of::>() == 8); - assert!(std::mem::size_of::>() == 16); - assert!(std::mem::align_of::>() == 8); + assert!(mem::size_of::>() == 16); + assert!(mem::align_of::>() == 8); + assert!(mem::size_of::>() == 16); + assert!(mem::align_of::>() == 8); }; impl Debug for ManuallyRooted { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let name = format!("ManuallyRooted<{}>", std::any::type_name::()); + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let name = format!("ManuallyRooted<{}>", any::type_name::()); f.debug_struct(&name).field("inner", &self.inner).finish() } } @@ -1256,7 +1260,7 @@ where generation: 0, index: PackedIndex::new_manual(id), }, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } } @@ -1512,7 +1516,7 @@ where /// [`ref_hash`][crate::ManuallyRooted::ref_hash] method instead. pub fn rooted_hash(&self, state: &mut H) where - H: std::hash::Hasher, + H: Hasher, { self.inner.hash(state); } @@ -1526,7 +1530,7 @@ where /// [`rooted_hash`][crate::Rooted::rooted_hash] method instead. pub fn ref_hash(&self, store: impl AsContext, state: &mut H) where - H: std::hash::Hasher, + H: Hasher, { let gc_ref = self .get_gc_ref(store.as_context().0) @@ -1551,7 +1555,7 @@ where generation: b, index: PackedIndex(c), }, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } } } diff --git a/crates/wasmtime/src/runtime/instance.rs b/crates/wasmtime/src/runtime/instance.rs index 38b251954a9f..1cac5b2069f0 100644 --- a/crates/wasmtime/src/runtime/instance.rs +++ b/crates/wasmtime/src/runtime/instance.rs @@ -1,4 +1,5 @@ use crate::linker::{Definition, DefinitionType}; +use crate::prelude::*; use crate::runtime::vm::{ Imports, InstanceAllocationRequest, StorePtr, VMContext, VMFuncRef, VMFunctionImport, VMGlobalImport, VMMemoryImport, VMNativeCallFunction, VMOpaqueContext, VMTableImport, @@ -9,10 +10,10 @@ use crate::{ AsContextMut, Engine, Export, Extern, Func, Global, Memory, Module, ModuleExport, SharedMemory, StoreContext, StoreContextMut, Table, TypedFunc, }; +use alloc::sync::Arc; use anyhow::{anyhow, bail, Context, Result}; -use std::mem; -use std::ptr::NonNull; -use std::sync::Arc; +use core::mem; +use core::ptr::NonNull; use wasmparser::WasmFeatures; use wasmtime_environ::{ EntityIndex, EntityType, FuncIndex, GlobalIndex, MemoryIndex, PrimaryMap, TableIndex, TypeTrace, @@ -780,7 +781,7 @@ pub struct InstancePre { /// This is an `Arc<[T]>` for the same reason as `items`. func_refs: Arc<[VMFuncRef]>, - _marker: std::marker::PhantomData T>, + _marker: core::marker::PhantomData T>, } /// InstancePre's clone does not require T: Clone @@ -835,7 +836,7 @@ impl InstancePre { items: items.into(), host_funcs, func_refs: func_refs.into(), - _marker: std::marker::PhantomData, + _marker: core::marker::PhantomData, }) } diff --git a/crates/wasmtime/src/runtime/instantiate.rs b/crates/wasmtime/src/runtime/instantiate.rs index d37b6c1a01b0..6dc82b287aea 100644 --- a/crates/wasmtime/src/runtime/instantiate.rs +++ b/crates/wasmtime/src/runtime/instantiate.rs @@ -3,11 +3,12 @@ //! `CompiledModule` to allow compiling and instantiating to be done as separate //! steps. +use crate::prelude::*; use crate::runtime::vm::{CompiledModuleId, CompiledModuleIdAllocator, MmapVec}; use crate::{code_memory::CodeMemory, profiling_agent::ProfilingAgent}; +use alloc::sync::Arc; use anyhow::Result; -use std::str; -use std::sync::Arc; +use core::str; use wasmtime_environ::{ CompiledFunctionInfo, CompiledModuleInfo, DefinedFuncIndex, FuncIndex, FunctionLoc, FunctionName, Metadata, Module, ModuleInternedTypeIndex, PrimaryMap, StackMapInformation, diff --git a/crates/wasmtime/src/runtime/limits.rs b/crates/wasmtime/src/runtime/limits.rs index 5d0f934a5b32..e06df0b28f50 100644 --- a/crates/wasmtime/src/runtime/limits.rs +++ b/crates/wasmtime/src/runtime/limits.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use anyhow::{bail, Result}; /// Value returned by [`ResourceLimiter::instances`] default method diff --git a/crates/wasmtime/src/runtime/linker.rs b/crates/wasmtime/src/runtime/linker.rs index ff643367eeca..72c41b63880c 100644 --- a/crates/wasmtime/src/runtime/linker.rs +++ b/crates/wasmtime/src/runtime/linker.rs @@ -1,19 +1,21 @@ use crate::func::HostFunc; use crate::instance::InstancePre; +use crate::prelude::*; use crate::store::StoreOpaque; use crate::{ AsContext, AsContextMut, Caller, Engine, Extern, ExternType, Func, FuncType, ImportType, Instance, IntoFunc, Module, StoreContextMut, Val, ValRaw, ValType, }; +use alloc::sync::Arc; use anyhow::{bail, Context, Result}; -use log::warn; -use std::collections::hash_map::{Entry, HashMap}; +use core::fmt; #[cfg(feature = "async")] -use std::future::Future; -use std::marker; +use core::future::Future; +use core::marker; #[cfg(feature = "async")] -use std::pin::Pin; -use std::sync::Arc; +use core::pin::Pin; +use hashbrown::hash_map::{Entry, HashMap}; +use log::warn; /// Structure used to link wasm modules/instances together. /// @@ -1205,7 +1207,8 @@ impl Linker { let mut imports = module .imports() .map(|import| self._get_by_import(&import)) - .collect::, _>>()?; + .collect::, _>>() + .err2anyhow()?; if let Some(store) = store { for import in imports.iter_mut() { import.update_size(store); @@ -1489,8 +1492,8 @@ impl UnknownImportError { } } -impl std::fmt::Display for UnknownImportError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for UnknownImportError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "unknown import: `{}::{}` has not been defined", @@ -1499,4 +1502,5 @@ impl std::fmt::Display for UnknownImportError { } } +#[cfg(feature = "std")] impl std::error::Error for UnknownImportError {} diff --git a/crates/wasmtime/src/runtime/memory.rs b/crates/wasmtime/src/runtime/memory.rs index 45eb45c22cd0..c47703d934de 100644 --- a/crates/wasmtime/src/runtime/memory.rs +++ b/crates/wasmtime/src/runtime/memory.rs @@ -1,13 +1,15 @@ +use crate::prelude::*; use crate::runtime::vm::{RuntimeLinearMemory, VMMemoryImport}; use crate::store::{StoreData, StoreOpaque, Stored}; use crate::trampoline::generate_memory_export; use crate::Trap; use crate::{AsContext, AsContextMut, Engine, MemoryType, StoreContext, StoreContextMut}; use anyhow::{bail, Result}; -use std::cell::UnsafeCell; -use std::ops::Range; -use std::slice; -use std::time::Instant; +use core::cell::UnsafeCell; +use core::fmt; +use core::ops::Range; +use core::slice; +use core::time::Duration; use wasmtime_environ::MemoryPlan; pub use crate::runtime::vm::WaitResult; @@ -20,12 +22,13 @@ pub struct MemoryAccessError { _private: (), } -impl std::fmt::Display for MemoryAccessError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Display for MemoryAccessError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "out of bounds memory access") } } +#[cfg(feature = "std")] impl std::error::Error for MemoryAccessError {} /// A WebAssembly linear memory. @@ -580,7 +583,7 @@ impl Memory { /// Even if the same underlying memory definition is added to the /// `StoreData` multiple times and becomes multiple `wasmtime::Memory`s, /// this hash key will be consistent across all of these memories. - pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl std::hash::Hash + Eq { + pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl core::hash::Hash + Eq { store[self.0].definition as usize } } @@ -842,9 +845,8 @@ impl SharedMemory { /// the byte address `addr` specified. The `addr` specified is an index /// into this linear memory. /// - /// The optional `timeout` argument is the point in time after which the - /// calling thread is guaranteed to be woken up. Blocking will not occur - /// past this point. + /// The optional `timeout` argument is the maximum amount of time to block + /// the current thread. If not specified the thread may sleep indefinitely. /// /// This function returns one of three possible values: /// @@ -868,7 +870,7 @@ impl SharedMemory { &self, addr: u64, expected: u32, - timeout: Option, + timeout: Option, ) -> Result { self.0.atomic_wait32(addr, expected, timeout) } @@ -886,7 +888,7 @@ impl SharedMemory { &self, addr: u64, expected: u64, - timeout: Option, + timeout: Option, ) -> Result { self.0.atomic_wait64(addr, expected, timeout) } @@ -929,8 +931,8 @@ impl SharedMemory { } } -impl std::fmt::Debug for SharedMemory { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Debug for SharedMemory { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SharedMemory").finish_non_exhaustive() } } diff --git a/crates/wasmtime/src/runtime/module.rs b/crates/wasmtime/src/runtime/module.rs index 7f39308f8d33..24048e88f08f 100644 --- a/crates/wasmtime/src/runtime/module.rs +++ b/crates/wasmtime/src/runtime/module.rs @@ -1,7 +1,9 @@ +use crate::prelude::*; use crate::runtime::vm::{ CompiledModuleId, MemoryImage, MmapVec, ModuleMemoryImages, VMArrayCallFunction, VMNativeCallFunction, VMWasmCallFunction, }; +use crate::sync::OnceLock; use crate::{ code::CodeObject, code_memory::CodeMemory, @@ -11,13 +13,14 @@ use crate::{ types::{ExportType, ExternType, ImportType}, Engine, }; +use alloc::sync::Arc; use anyhow::{bail, Result}; -use once_cell::sync::OnceCell; -use std::mem; -use std::ops::Range; +use core::fmt; +use core::mem; +use core::ops::Range; +use core::ptr::NonNull; +#[cfg(feature = "std")] use std::path::Path; -use std::ptr::NonNull; -use std::sync::Arc; use wasmparser::{Parser, ValidPayload, Validator}; use wasmtime_environ::{ CompiledModuleInfo, DefinedFuncIndex, DefinedMemoryIndex, EntityIndex, HostPtr, ModuleTypes, @@ -152,7 +155,7 @@ struct ModuleInner { /// image this is a pretty expensive operation, so by deferring it this /// improves memory usage for modules that are created but may not ever be /// instantiated. - memory_images: OnceCell>, + memory_images: OnceLock>, /// Flag indicating whether this module can be serialized or not. serializable: bool, @@ -161,8 +164,8 @@ struct ModuleInner { offsets: VMOffsets, } -impl std::fmt::Debug for Module { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Debug for Module { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Module") .field("name", &self.name()) .finish_non_exhaustive() @@ -269,7 +272,7 @@ impl Module { /// # Ok(()) /// # } /// ``` - #[cfg(any(feature = "cranelift", feature = "winch"))] + #[cfg(all(feature = "std", any(feature = "cranelift", feature = "winch")))] pub fn from_file(engine: &Engine, file: impl AsRef) -> Result { crate::CodeBuilder::new(engine) .wasm_file(file.as_ref())? @@ -336,7 +339,7 @@ impl Module { /// This is because the file is mapped into memory and lazily loaded pages /// reflect the current state of the file, not necessarily the original /// state of the file. - #[cfg(any(feature = "cranelift", feature = "winch"))] + #[cfg(all(feature = "std", any(feature = "cranelift", feature = "winch")))] pub unsafe fn from_trusted_file(engine: &Engine, file: impl AsRef) -> Result { let mmap = MmapVec::from_file(file.as_ref())?; if &mmap[0..4] == b"\x7fELF" { @@ -419,6 +422,7 @@ impl Module { /// This is because the file is mapped into memory and lazily loaded pages /// reflect the current state of the file, not necessarily the origianl /// state of the file. + #[cfg(feature = "std")] pub unsafe fn deserialize_file(engine: &Engine, path: impl AsRef) -> Result { let code = engine.load_code_file(path.as_ref(), ObjectKind::Module)?; Module::from_parts(engine, code, None) @@ -441,7 +445,7 @@ impl Module { // already. let (info, types) = match info_and_types { Some((info, types)) => (info, types), - None => postcard::from_bytes(code_memory.wasmtime_info())?, + None => postcard::from_bytes(code_memory.wasmtime_info()).err2anyhow()?, }; // Register function type signatures into the engine for the lifetime @@ -483,7 +487,7 @@ impl Module { inner: Arc::new(ModuleInner { engine: engine.clone(), code, - memory_images: OnceCell::new(), + memory_images: OnceLock::new(), module, serializable, offsets, @@ -515,8 +519,8 @@ impl Module { let mut functions = Vec::new(); for payload in Parser::new(0).parse_all(binary) { - let payload = payload?; - if let ValidPayload::Func(a, b) = validator.payload(&payload)? { + let payload = payload.err2anyhow()?; + if let ValidPayload::Func(a, b) = validator.payload(&payload).err2anyhow()? { functions.push((a, b)); } if let wasmparser::Payload::Version { encoding, .. } = &payload { @@ -526,13 +530,15 @@ impl Module { } } - engine.run_maybe_parallel(functions, |(validator, body)| { - // FIXME: it would be best here to use a rayon-specific parallel - // iterator that maintains state-per-thread to share the function - // validator allocations (`Default::default` here) across multiple - // functions. - validator.into_validator(Default::default()).validate(&body) - })?; + engine + .run_maybe_parallel(functions, |(validator, body)| { + // FIXME: it would be best here to use a rayon-specific parallel + // iterator that maintains state-per-thread to share the function + // validator allocations (`Default::default` here) across multiple + // functions. + validator.into_validator(Default::default()).validate(&body) + }) + .err2anyhow()?; Ok(()) } @@ -1235,7 +1241,7 @@ impl crate::runtime::vm::ModuleRuntimeInfo for BareModuleInfo { fn type_ids(&self) -> &[VMSharedTypeIndex] { match &self.one_signature { - Some(id) => std::slice::from_ref(id), + Some(id) => core::slice::from_ref(id), None => &[], } } diff --git a/crates/wasmtime/src/runtime/module/registry.rs b/crates/wasmtime/src/runtime/module/registry.rs index 8091c9407f2e..eefe17ee61c3 100644 --- a/crates/wasmtime/src/runtime/module/registry.rs +++ b/crates/wasmtime/src/runtime/module/registry.rs @@ -3,15 +3,13 @@ use crate::code::CodeObject; #[cfg(feature = "component-model")] use crate::component::Component; +use crate::prelude::*; use crate::runtime::vm::VMWasmCallFunction; +use crate::sync::{OnceLock, RwLock}; use crate::{code_memory::CodeMemory, FrameInfo, Module, Trap}; -use once_cell::sync::Lazy; -use std::collections::btree_map::Entry; -use std::{ - collections::BTreeMap, - ptr::NonNull, - sync::{Arc, RwLock}, -}; +use alloc::collections::btree_map::{BTreeMap, Entry}; +use alloc::sync::Arc; +use core::ptr::NonNull; use wasmtime_environ::VMSharedTypeIndex; /// Used for registering modules with a store. @@ -249,7 +247,10 @@ impl LoadedCode { // it is also automatically registered with the singleton global module // registry. When a `ModuleRegistry` is destroyed then all of its entries // are removed from the global registry. -static GLOBAL_CODE: Lazy> = Lazy::new(Default::default); +fn global_code() -> &'static RwLock { + static GLOBAL_CODE: OnceLock> = OnceLock::new(); + GLOBAL_CODE.get_or_init(Default::default) +} type GlobalRegistry = BTreeMap)>; @@ -257,7 +258,7 @@ type GlobalRegistry = BTreeMap)>; /// is a wasm trap or not. pub fn get_wasm_trap(pc: usize) -> Option { let (code, text_offset) = { - let all_modules = GLOBAL_CODE.read().unwrap(); + let all_modules = global_code().read(); let (end, (start, module)) = match all_modules.range(pc..).next() { Some(info) => info, @@ -287,10 +288,7 @@ pub fn register_code(code: &Arc) { } let start = text.as_ptr() as usize; let end = start + text.len() - 1; - let prev = GLOBAL_CODE - .write() - .unwrap() - .insert(end, (start, code.clone())); + let prev = global_code().write().insert(end, (start, code.clone())); assert!(prev.is_none()); } @@ -303,7 +301,7 @@ pub fn unregister_code(code: &Arc) { return; } let end = (text.as_ptr() as usize) + text.len() - 1; - let code = GLOBAL_CODE.write().unwrap().remove(&end); + let code = global_code().write().remove(&end); assert!(code.is_some()); } diff --git a/crates/wasmtime/src/runtime/profiling.rs b/crates/wasmtime/src/runtime/profiling.rs index d732799109b4..f2a6258acd34 100644 --- a/crates/wasmtime/src/runtime/profiling.rs +++ b/crates/wasmtime/src/runtime/profiling.rs @@ -1,9 +1,9 @@ +use crate::prelude::*; use crate::runtime::vm::Backtrace; use crate::{instantiate::CompiledModule, AsContext, Module}; #[allow(unused_imports)] use anyhow::bail; use anyhow::Result; -#[cfg(feature = "profiling")] use fxprof_processed_profile::{ debugid::DebugId, CategoryHandle, Frame, FrameFlags, FrameInfo, LibraryInfo, Profile, ReferenceTimestamp, Symbol, SymbolTable, Timestamp, @@ -72,7 +72,6 @@ use wasmtime_environ::demangle_function_name_or_index; /// where they don't already have the WebAssembly module binary available this /// could theoretically lead to an undesirable information disclosure. So you /// should only include user-provided modules in profiles. -#[cfg(feature = "profiling")] #[derive(Debug)] pub struct GuestProfiler { profile: Profile, @@ -82,7 +81,6 @@ pub struct GuestProfiler { start: Instant, } -#[cfg(feature = "profiling")] impl GuestProfiler { /// Begin profiling a new guest. When this function is called, the current /// wall-clock time is recorded as the start time for the guest. @@ -189,7 +187,6 @@ impl GuestProfiler { } } -#[cfg(feature = "profiling")] fn module_symbols(name: String, compiled: &CompiledModule) -> Option { let symbols = Vec::from_iter(compiled.finished_functions().map(|(defined_idx, _)| { let loc = compiled.func_loc(defined_idx); diff --git a/crates/wasmtime/src/runtime/resources.rs b/crates/wasmtime/src/runtime/resources.rs index da0555b34a85..540f7b37b299 100644 --- a/crates/wasmtime/src/runtime/resources.rs +++ b/crates/wasmtime/src/runtime/resources.rs @@ -25,9 +25,9 @@ impl ResourcesRequired { pub(crate) fn add(&mut self, other: &ResourcesRequired) { self.num_memories += other.num_memories; self.max_initial_memory_size = - std::cmp::max(self.max_initial_memory_size, other.max_initial_memory_size); + core::cmp::max(self.max_initial_memory_size, other.max_initial_memory_size); self.num_tables += other.num_tables; self.max_initial_table_size = - std::cmp::max(self.max_initial_table_size, other.max_initial_table_size); + core::cmp::max(self.max_initial_table_size, other.max_initial_table_size); } } diff --git a/crates/wasmtime/src/runtime/stack.rs b/crates/wasmtime/src/runtime/stack.rs index d057ad2e9976..c4bfb59a7783 100644 --- a/crates/wasmtime/src/runtime/stack.rs +++ b/crates/wasmtime/src/runtime/stack.rs @@ -1,6 +1,6 @@ -use std::{ops::Range, sync::Arc}; - +use crate::prelude::*; use anyhow::Error; +use std::{ops::Range, sync::Arc}; use wasmtime_fiber::{RuntimeFiberStack, RuntimeFiberStackCreator}; /// A stack creator. Can be used to provide a stack creator to wasmtime diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs index 3f409d8b7483..599960ebdf98 100644 --- a/crates/wasmtime/src/runtime/store.rs +++ b/crates/wasmtime/src/runtime/store.rs @@ -79,6 +79,7 @@ use crate::instance::InstanceData; use crate::linker::Definition; use crate::module::{BareModuleInfo, RegisteredModuleId}; +use crate::prelude::*; use crate::runtime::vm::mpk::{self, ProtectionKey, ProtectionMask}; use crate::runtime::vm::{ Backtrace, ExportGlobal, GcHeapAllocationIndex, GcRootsList, GcStore, @@ -89,20 +90,19 @@ use crate::trampoline::VMHostGlobalContext; use crate::RootSet; use crate::{module::ModuleRegistry, Engine, Module, Trap, Val, ValRaw}; use crate::{Global, Instance, Memory, RootScope, Table}; +use alloc::sync::Arc; use anyhow::{anyhow, bail, Result}; -use once_cell::sync::OnceCell; -use std::cell::UnsafeCell; -use std::fmt; -use std::future::Future; -use std::marker; -use std::mem::{self, ManuallyDrop}; -use std::num::NonZeroU64; -use std::ops::{Deref, DerefMut}; -use std::pin::Pin; -use std::ptr; -use std::sync::atomic::AtomicU64; -use std::sync::Arc; -use std::task::{Context, Poll}; +use core::cell::UnsafeCell; +use core::fmt; +use core::future::Future; +use core::marker; +use core::mem::{self, ManuallyDrop}; +use core::num::NonZeroU64; +use core::ops::{Deref, DerefMut}; +use core::pin::Pin; +use core::ptr; +use core::sync::atomic::AtomicU64; +use core::task::{Context, Poll}; mod context; pub use self::context::*; @@ -314,7 +314,7 @@ pub struct StoreOpaque { host_globals: Vec>, // GC-related fields. - gc_store: OnceCell, + gc_store: Option, gc_roots: RootSet, gc_roots_list: GcRootsList, @@ -403,7 +403,7 @@ pub struct AutoAssertNoGc<'a> { impl<'a> AutoAssertNoGc<'a> { #[inline] pub fn new(store: &'a mut StoreOpaque) -> Self { - let entered = if let Some(gc_store) = store.gc_store.get_mut() { + let entered = if let Some(gc_store) = store.gc_store.as_mut() { gc_store.gc_heap.enter_no_gc_scope(); true } else { @@ -414,7 +414,7 @@ impl<'a> AutoAssertNoGc<'a> { } } -impl std::ops::Deref for AutoAssertNoGc<'_> { +impl core::ops::Deref for AutoAssertNoGc<'_> { type Target = StoreOpaque; #[inline] @@ -423,7 +423,7 @@ impl std::ops::Deref for AutoAssertNoGc<'_> { } } -impl std::ops::DerefMut for AutoAssertNoGc<'_> { +impl core::ops::DerefMut for AutoAssertNoGc<'_> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut *self.store @@ -487,7 +487,7 @@ impl Store { #[cfg(feature = "component-model")] num_component_instances: 0, signal_handler: None, - gc_store: OnceCell::new(), + gc_store: None, gc_roots: RootSet::default(), gc_roots_list: GcRootsList::default(), modules: ModuleRegistry::default(), @@ -557,7 +557,7 @@ impl Store { // the `Store` itself, and is a variant that we have to maintain // throughout Wasmtime. unsafe { - let traitobj = std::mem::transmute::< + let traitobj = mem::transmute::< *mut (dyn crate::runtime::vm::Store + '_), *mut (dyn crate::runtime::vm::Store + 'static), >(&mut *inner); @@ -611,7 +611,7 @@ impl Store { // there is a comment indicating this as well. unsafe { let mut inner = ManuallyDrop::take(&mut self.inner); - std::mem::forget(self); + core::mem::forget(self); ManuallyDrop::take(&mut inner.data) } } @@ -1185,10 +1185,10 @@ fn set_fuel( let interval = yield_interval.unwrap_or(NonZeroU64::MAX).get(); // If we're yielding periodically we only store the "active" amount of fuel into consumed_ptr // for the VM to use. - let injected = std::cmp::min(interval, new_fuel_amount); + let injected = core::cmp::min(interval, new_fuel_amount); // Fuel in the VM is stored as an i64, so we have to cap the amount of fuel we inject into the // VM at once to be i64 range. - let injected = std::cmp::min(injected, i64::MAX as u64); + let injected = core::cmp::min(injected, i64::MAX as u64); // Add whatever is left over after injection to the reserve for later use. *fuel_reserve = new_fuel_amount - injected; // Within the VM we increment to count fuel, so inject a negative amount. The VM will halt when @@ -1427,7 +1427,7 @@ impl StoreOpaque { for global in temp.host_globals.iter() { let export = ExportGlobal { definition: &mut (*global.get()).global as *mut _, - vmctx: std::ptr::null_mut(), + vmctx: core::ptr::null_mut(), global: (*global.get()).ty.to_wasm_type(), }; let global = Global::from_wasmtime_global(export, temp.store); @@ -1456,9 +1456,9 @@ impl StoreOpaque { #[inline(never)] pub(crate) fn allocate_gc_heap(&mut self) -> Result<()> { - assert!(self.gc_store.get_mut().is_none()); + assert!(self.gc_store.is_none()); let gc_store = allocate_gc_store(self.engine())?; - let _ = self.gc_store.set(gc_store); + self.gc_store = Some(gc_store); return Ok(()); #[cfg(feature = "gc")] @@ -1492,15 +1492,15 @@ impl StoreOpaque { #[inline] #[cfg(feature = "gc")] pub(crate) fn gc_store(&self) -> Result<&GcStore> { - match self.gc_store.get() { + match &self.gc_store { Some(gc_store) => Ok(gc_store), - None => Err(anyhow!("GC heap not initialized yet")), + None => bail!("GC heap not initialized yet"), } } #[inline] pub(crate) fn gc_store_mut(&mut self) -> Result<&mut GcStore> { - if self.gc_store.get_mut().is_none() { + if self.gc_store.is_none() { self.allocate_gc_heap()?; } Ok(self.unwrap_gc_store_mut()) @@ -1510,14 +1510,14 @@ impl StoreOpaque { #[cfg(feature = "gc")] pub(crate) fn unwrap_gc_store(&self) -> &GcStore { self.gc_store - .get() + .as_ref() .expect("attempted to access the store's GC heap before it has been allocated") } #[inline] pub(crate) fn unwrap_gc_store_mut(&mut self) -> &mut GcStore { self.gc_store - .get_mut() + .as_mut() .expect("attempted to access the store's GC heap before it has been allocated") } @@ -1533,7 +1533,7 @@ impl StoreOpaque { #[inline] pub(crate) fn exit_gc_lifo_scope(&mut self, scope: usize) { - if let Some(gc_store) = self.gc_store.get_mut() { + if let Some(gc_store) = self.gc_store.as_mut() { self.gc_roots.exit_lifo_scope(gc_store, scope); } } @@ -1541,13 +1541,13 @@ impl StoreOpaque { #[cfg(feature = "gc")] pub fn gc(&mut self) { // If the GC heap hasn't been initialized, there is nothing to collect. - if self.gc_store.get_mut().is_none() { + if self.gc_store.is_none() { return; } // Take the GC roots out of `self` so we can borrow it mutably but still // call mutable methods on `self`. - let mut roots = std::mem::take(&mut self.gc_roots_list); + let mut roots = core::mem::take(&mut self.gc_roots_list); self.trace_roots(&mut roots); self.unwrap_gc_store_mut().gc(unsafe { roots.iter() }); @@ -1589,7 +1589,7 @@ impl StoreOpaque { ); // If the GC heap hasn't been initialized, there is nothing to collect. - if self.gc_store.get_mut().is_none() { + if self.gc_store.is_none() { return; } @@ -1637,7 +1637,7 @@ impl StoreOpaque { #[cfg(feature = "gc")] fn trace_wasm_stack_roots(&mut self, gc_roots_list: &mut GcRootsList) { - use std::ptr::NonNull; + use core::ptr::NonNull; use crate::runtime::vm::{ModuleInfoLookup, SendSyncPtr}; @@ -1661,7 +1661,7 @@ impl StoreOpaque { Some(sm) => sm, None => { log::trace!("No stack map for this Wasm frame"); - return std::ops::ControlFlow::Continue(()); + return core::ops::ControlFlow::Continue(()); } }; log::trace!( @@ -1684,7 +1684,7 @@ impl StoreOpaque { continue; } - let gc_ref = unsafe { std::ptr::read(stack_slot) }; + let gc_ref = unsafe { core::ptr::read(stack_slot) }; log::trace!("Stack slot @ {stack_slot:p} = {gc_ref:#x}"); let gc_ref = VMGcRef::from_r64(gc_ref) @@ -1699,7 +1699,7 @@ impl StoreOpaque { } } - std::ops::ControlFlow::Continue(()) + core::ops::ControlFlow::Continue(()) }); log::trace!("End trace GC roots :: Wasm stack"); @@ -1933,8 +1933,12 @@ impl StoreOpaque { return fault; } - eprintln!( - "\ + cfg_if::cfg_if! { + if #[cfg(any(feature = "std", unix, windows))] { + // With the standard library a rich error can be printed here + // to stderr and the native abort path is used. + eprintln!( + "\ Wasmtime caught a segfault for a wasm program because the faulting instruction is allowed to segfault due to how linear memories are implemented. The address that was accessed, however, is not known to any linear memory in use within this @@ -1952,8 +1956,26 @@ from going any further and to alert what's going on. If this is a security issue please reach out to the Wasmtime team via its security policy at https://bytecodealliance.org/security. " - ); - std::process::abort(); + ); + std::process::abort(); + } else if #[cfg(panic = "abort")] { + // Without the standard library but with `panic=abort` then + // it's safe to panic as that's known to halt execution. For + // now avoid the above error message as well since without + // `std` it's probably best to be a bit more size-conscious. + let _ = pc; + panic!("invalid fault"); + } else { + // Without `std` and with `panic = "unwind"` there's no way to + // abort the process portably, so flag a compile time error. + // + // NB: if this becomes a problem in the future one option would + // be to extend the `capi.rs` module for no_std platforms, but + // it remains yet to be seen at this time if this is hit much. + compile_error!("either `std` or `panic=abort` must be enabled"); + None + } + } } /// Retrieve the store's protection key. @@ -2192,7 +2214,7 @@ impl StoreContextMut<'_, T> { unsafe { let _reset = Reset(self.current_poll_cx, *self.current_poll_cx); *self.current_poll_cx = - std::mem::transmute::<&mut Context<'_>, *mut Context<'static>>(cx); + core::mem::transmute::<&mut Context<'_>, *mut Context<'static>>(cx); // After that's set up we resume execution of the fiber, which // may also start the fiber for the first time. This either @@ -2361,7 +2383,7 @@ unsafe impl crate::runtime::vm::Store for StoreInner { } fn maybe_gc_store(&mut self) -> Option<&mut GcStore> { - self.gc_store.get_mut() + self.gc_store.as_mut() } fn memory_growing( @@ -2459,7 +2481,7 @@ unsafe impl crate::runtime::vm::Store for StoreInner { fn out_of_gas(&mut self) -> Result<()> { if !self.refuel() { - return Err(Trap::OutOfFuel.into()); + return Err(Trap::OutOfFuel).err2anyhow(); } #[cfg(feature = "async")] if self.fuel_yield_interval.is_some() { @@ -2473,7 +2495,7 @@ unsafe impl crate::runtime::vm::Store for StoreInner { // multiple times. let mut behavior = self.epoch_deadline_behavior.take(); let delta_result = match &mut behavior { - None => Err(Trap::Interrupt.into()), + None => Err(Trap::Interrupt).err2anyhow(), Some(callback) => callback((&mut *self).as_context_mut()).and_then(|update| { let delta = match update { UpdateDeadline::Continue(delta) => delta, diff --git a/crates/wasmtime/src/runtime/store/data.rs b/crates/wasmtime/src/runtime/store/data.rs index 319dd196a2be..54083b0cd19d 100644 --- a/crates/wasmtime/src/runtime/store/data.rs +++ b/crates/wasmtime/src/runtime/store/data.rs @@ -1,10 +1,11 @@ +use crate::prelude::*; use crate::store::StoreOpaque; use crate::{StoreContext, StoreContextMut}; -use std::fmt; -use std::marker; -use std::num::NonZeroU64; -use std::ops::{Index, IndexMut}; -use std::sync::atomic::{AtomicU64, Ordering::Relaxed}; +use core::fmt; +use core::marker; +use core::num::NonZeroU64; +use core::ops::{Index, IndexMut}; +use core::sync::atomic::{AtomicU64, Ordering::Relaxed}; // This is defined here, in a private submodule, so we can explicitly reexport // it only as `pub(crate)`. This avoids a ton of diff --git a/crates/wasmtime/src/runtime/store/func_refs.rs b/crates/wasmtime/src/runtime/store/func_refs.rs index 0f5d7eca10bd..c1b93a5ed4b8 100644 --- a/crates/wasmtime/src/runtime/store/func_refs.rs +++ b/crates/wasmtime/src/runtime/store/func_refs.rs @@ -2,8 +2,10 @@ //! trampolines. use crate::module::ModuleRegistry; +use crate::prelude::*; use crate::runtime::vm::{SendSyncPtr, VMFuncRef, VMNativeCallHostFuncContext}; -use std::{ptr::NonNull, sync::Arc}; +use alloc::sync::Arc; +use core::ptr::NonNull; /// An arena of `VMFuncRef`s. /// diff --git a/crates/wasmtime/src/runtime/trampoline.rs b/crates/wasmtime/src/runtime/trampoline.rs index 169a3ff5ee79..64bd576da338 100644 --- a/crates/wasmtime/src/runtime/trampoline.rs +++ b/crates/wasmtime/src/runtime/trampoline.rs @@ -12,15 +12,16 @@ pub(crate) use memory::MemoryCreatorProxy; use self::memory::create_memory; use self::table::create_table; use crate::module::BareModuleInfo; +use crate::prelude::*; use crate::runtime::vm::{ Imports, InstanceAllocationRequest, InstanceAllocator, OnDemandInstanceAllocator, SharedMemory, StorePtr, VMFunctionImport, }; use crate::store::{InstanceId, StoreOpaque}; use crate::{MemoryType, TableType}; +use alloc::sync::Arc; use anyhow::Result; -use std::any::Any; -use std::sync::Arc; +use core::any::Any; use wasmtime_environ::{MemoryIndex, Module, TableIndex, VMSharedTypeIndex}; fn create_handle( diff --git a/crates/wasmtime/src/runtime/trampoline/func.rs b/crates/wasmtime/src/runtime/trampoline/func.rs index e197e3f4c83a..2e4f3bb5ac06 100644 --- a/crates/wasmtime/src/runtime/trampoline/func.rs +++ b/crates/wasmtime/src/runtime/trampoline/func.rs @@ -6,7 +6,7 @@ use crate::runtime::vm::{ use crate::type_registry::RegisteredType; use crate::{code_memory::CodeMemory, Engine, FuncType, ValRaw}; use anyhow::Result; -use std::ptr::NonNull; +use core::ptr::NonNull; struct TrampolineState { func: F, @@ -54,7 +54,7 @@ unsafe extern "C" fn array_call_shim( let state = (*vmctx).host_state(); debug_assert!(state.is::>()); let state = &*(state as *const _ as *const TrampolineState); - let values_vec = std::slice::from_raw_parts_mut(values_vec, values_vec_len); + let values_vec = core::slice::from_raw_parts_mut(values_vec, values_vec_len); (state.func)(VMContext::from_opaque(caller_vmctx), values_vec) }); @@ -80,6 +80,7 @@ where F: Fn(*mut VMContext, &mut [ValRaw]) -> Result<()> + Send + Sync + 'static, { use crate::compile::finish_object; + use crate::prelude::*; use std::ptr; let mut obj = engine diff --git a/crates/wasmtime/src/runtime/trampoline/global.rs b/crates/wasmtime/src/runtime/trampoline/global.rs index 742c53f152eb..4896ffb89ec1 100644 --- a/crates/wasmtime/src/runtime/trampoline/global.rs +++ b/crates/wasmtime/src/runtime/trampoline/global.rs @@ -1,7 +1,7 @@ use crate::runtime::vm::{StoreBox, VMGlobalDefinition}; use crate::store::{AutoAssertNoGc, StoreOpaque}; use crate::{GlobalType, Mutability, Result, RootedGcRefImpl, Val}; -use std::ptr; +use core::ptr; #[repr(C)] pub struct VMHostGlobalContext { @@ -62,7 +62,7 @@ pub fn generate_global_export( store.host_globals().push(ctx); Ok(crate::runtime::vm::ExportGlobal { definition, - vmctx: std::ptr::null_mut(), + vmctx: ptr::null_mut(), global, }) } diff --git a/crates/wasmtime/src/runtime/trampoline/memory.rs b/crates/wasmtime/src/runtime/trampoline/memory.rs index d3e211956ed1..9afffeec1984 100644 --- a/crates/wasmtime/src/runtime/trampoline/memory.rs +++ b/crates/wasmtime/src/runtime/trampoline/memory.rs @@ -1,5 +1,6 @@ use crate::memory::{LinearMemory, MemoryCreator}; use crate::module::BareModuleInfo; +use crate::prelude::*; use crate::runtime::vm::mpk::ProtectionKey; use crate::runtime::vm::{ CompiledModuleId, GcHeapAllocationIndex, Imports, InstanceAllocationRequest, InstanceAllocator, @@ -9,9 +10,9 @@ use crate::runtime::vm::{ }; use crate::store::{InstanceId, StoreOpaque}; use crate::MemoryType; +use alloc::sync::Arc; use anyhow::{anyhow, Result}; -use std::ops::Range; -use std::sync::Arc; +use core::ops::Range; use wasmtime_environ::{ DefinedMemoryIndex, DefinedTableIndex, EntityIndex, HostPtr, MemoryPlan, MemoryStyle, Module, VMOffsets, WASM_PAGE_SIZE, @@ -106,7 +107,7 @@ impl RuntimeLinearMemory for LinearMemoryProxy { true } - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + fn as_any_mut(&mut self) -> &mut dyn core::any::Any { self } diff --git a/crates/wasmtime/src/runtime/trampoline/table.rs b/crates/wasmtime/src/runtime/trampoline/table.rs index 4128c8fc483a..ba8a1566aa20 100644 --- a/crates/wasmtime/src/runtime/trampoline/table.rs +++ b/crates/wasmtime/src/runtime/trampoline/table.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use crate::store::{InstanceId, StoreOpaque}; use crate::trampoline::create_handle; use crate::TableType; diff --git a/crates/wasmtime/src/runtime/trap.rs b/crates/wasmtime/src/runtime/trap.rs index 1871560ff958..86bec4bfc532 100644 --- a/crates/wasmtime/src/runtime/trap.rs +++ b/crates/wasmtime/src/runtime/trap.rs @@ -1,9 +1,10 @@ #[cfg(feature = "coredump")] use super::coredump::WasmCoreDump; +use crate::prelude::*; use crate::store::StoreOpaque; use crate::{AsContext, Module}; use anyhow::Error; -use std::fmt; +use core::fmt; use wasmtime_environ::{ demangle_function_name, demangle_function_name_or_index, EntityRef, FilePos, }; @@ -114,7 +115,7 @@ pub(crate) fn from_runtime_box( faulting_addr, trap, } => { - let mut err: Error = trap.into(); + let mut err: Error = trap.into_anyhow(); // If a fault address was present, for example with segfaults, // then simultaneously assert that it's within a known linear memory @@ -125,7 +126,7 @@ pub(crate) fn from_runtime_box( } (err, Some(pc)) } - crate::runtime::vm::TrapReason::Wasm(trap_code) => (trap_code.into(), None), + crate::runtime::vm::TrapReason::Wasm(trap_code) => (trap_code.into_anyhow(), None), }; if let Some(bt) = backtrace { diff --git a/crates/wasmtime/src/runtime/type_registry.rs b/crates/wasmtime/src/runtime/type_registry.rs index 5f222d36ef30..ecc420f20603 100644 --- a/crates/wasmtime/src/runtime/type_registry.rs +++ b/crates/wasmtime/src/runtime/type_registry.rs @@ -3,21 +3,22 @@ //! Helps implement fast indirect call signature checking, reference type //! downcasting, and etc... +use crate::prelude::*; +use crate::sync::RwLock; use crate::Engine; -use std::{ +use alloc::sync::Arc; +use core::iter; +use core::{ borrow::Borrow, - collections::{HashMap, HashSet}, - fmt::Debug, + fmt::{self, Debug}, hash::{Hash, Hasher}, ops::Range, - sync::{ - atomic::{ - AtomicUsize, - Ordering::{AcqRel, Acquire}, - }, - Arc, RwLock, + sync::atomic::{ + AtomicUsize, + Ordering::{AcqRel, Acquire}, }, }; +use hashbrown::{HashMap, HashSet}; use wasmtime_environ::{ iter_entity_range, EngineOrModuleTypeIndex, ModuleInternedTypeIndex, ModuleTypes, PrimaryMap, SecondaryMap, TypeTrace, VMSharedTypeIndex, WasmRecGroup, WasmSubType, @@ -88,7 +89,7 @@ pub struct TypeCollection { } impl Debug for TypeCollection { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let TypeCollection { engine: _, rec_groups, @@ -107,7 +108,7 @@ impl TypeCollection { pub fn new_for_module(engine: &Engine, types: &ModuleTypes) -> Self { let engine = engine.clone(); let registry = engine.signatures(); - let (rec_groups, types) = registry.0.write().unwrap().register_module_types(types); + let (rec_groups, types) = registry.0.write().register_module_types(types); let reverse_types = types.iter().map(|(k, v)| (*v, k)).collect(); Self { @@ -146,7 +147,6 @@ impl Drop for TypeCollection { .signatures() .0 .write() - .unwrap() .unregister_type_collection(self); } } @@ -178,7 +178,7 @@ pub struct RegisteredType { } impl Debug for RegisteredType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let RegisteredType { engine: _, entry: _, @@ -211,13 +211,12 @@ impl Drop for RegisteredType { .signatures() .0 .write() - .unwrap() .unregister_entry(self.entry.clone()); } } } -impl std::ops::Deref for RegisteredType { +impl core::ops::Deref for RegisteredType { type Target = WasmSubType; fn deref(&self) -> &Self::Target { @@ -258,7 +257,7 @@ impl RegisteredType { let (entry, index, ty) = { log::trace!("RegisteredType::new({ty:?})"); - let mut inner = engine.signatures().0.write().unwrap(); + let mut inner = engine.signatures().0.write(); // It shouldn't be possible for users to construct non-canonical // types via the embedding API, and the only other types they can @@ -290,7 +289,7 @@ impl RegisteredType { pub fn root(engine: &Engine, index: VMSharedTypeIndex) -> Option { let (entry, ty) = { let id = shared_type_index_to_slab_id(index); - let inner = engine.signatures().0.read().unwrap(); + let inner = engine.signatures().0.read(); let ty = inner.types.get(id)?.clone(); let entry = inner.type_to_rec_group[index].clone().unwrap(); @@ -349,10 +348,10 @@ impl RegisteredType { struct RecGroupEntry(Arc); impl Debug for RecGroupEntry { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { struct Ptr<'a, P>(&'a P); - impl Debug for Ptr<'_, P> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + impl Debug for Ptr<'_, P> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:#p}", *self.0) } } @@ -662,7 +661,7 @@ impl TypeRegistryInner { let range = ModuleInternedTypeIndex::from_bits(u32::MAX - 1) ..ModuleInternedTypeIndex::from_bits(u32::MAX); - self.register_rec_group(&map, range, std::iter::once(ty)) + self.register_rec_group(&map, range, iter::once(ty)) } /// Unregister all of a type collection's rec groups. @@ -802,7 +801,7 @@ impl TypeRegistry { /// other mechanism already keeping the type registered. pub fn borrow(&self, index: VMSharedTypeIndex) -> Option> { let id = shared_type_index_to_slab_id(index); - let inner = self.0.read().unwrap(); + let inner = self.0.read(); inner.types.get(id).cloned() } } diff --git a/crates/wasmtime/src/runtime/types.rs b/crates/wasmtime/src/runtime/types.rs index 2d17fe8651b9..a23782883472 100644 --- a/crates/wasmtime/src/runtime/types.rs +++ b/crates/wasmtime/src/runtime/types.rs @@ -1,5 +1,6 @@ +use crate::prelude::*; use anyhow::{bail, ensure, Result}; -use std::fmt::{self, Display}; +use core::fmt::{self, Display}; use wasmtime_environ::{ EngineOrModuleTypeIndex, EntityType, Global, Memory, ModuleTypes, Table, TypeTrace, VMSharedTypeIndex, WasmArrayType, WasmCompositeType, WasmFieldType, WasmFuncType, WasmHeapType, diff --git a/crates/wasmtime/src/runtime/types/matching.rs b/crates/wasmtime/src/runtime/types/matching.rs index 35e60fcad260..6cd470e88d93 100644 --- a/crates/wasmtime/src/runtime/types/matching.rs +++ b/crates/wasmtime/src/runtime/types/matching.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use crate::{linker::DefinitionType, Engine, FuncType}; use anyhow::{anyhow, bail, Result}; use wasmtime_environ::{ diff --git a/crates/wasmtime/src/runtime/unix.rs b/crates/wasmtime/src/runtime/unix.rs index f52895bea3ff..6442502b4a94 100644 --- a/crates/wasmtime/src/runtime/unix.rs +++ b/crates/wasmtime/src/runtime/unix.rs @@ -9,6 +9,7 @@ //! throughout the `wasmtime` crate with extra functionality that's only //! available on Unix. +use crate::prelude::*; use crate::{AsContextMut, Store}; /// Extensions for the [`Store`] type only available on Unix. diff --git a/crates/wasmtime/src/runtime/v128.rs b/crates/wasmtime/src/runtime/v128.rs index 9987c49a2652..287958c30067 100644 --- a/crates/wasmtime/src/runtime/v128.rs +++ b/crates/wasmtime/src/runtime/v128.rs @@ -6,8 +6,8 @@ use crate::runtime::vm::V128Abi; use crate::store::{AutoAssertNoGc, StoreOpaque}; use crate::{Result, ValRaw, ValType, WasmTy}; -use std::cmp::Ordering; -use std::fmt; +use core::cmp::Ordering; +use core::fmt; /// Representation of a 128-bit vector type, `v128`, for WebAssembly. /// diff --git a/crates/wasmtime/src/runtime/values.rs b/crates/wasmtime/src/runtime/values.rs index 63cdd6ce120b..624b8566fa37 100644 --- a/crates/wasmtime/src/runtime/values.rs +++ b/crates/wasmtime/src/runtime/values.rs @@ -5,7 +5,7 @@ use crate::{ ValType, V128, }; use anyhow::{bail, Context, Result}; -use std::ptr; +use core::ptr; pub use crate::runtime::vm::ValRaw; diff --git a/crates/wasmtime/src/runtime/vm.rs b/crates/wasmtime/src/runtime/vm.rs index 8e6f6ce7b38a..95e85777bec1 100644 --- a/crates/wasmtime/src/runtime/vm.rs +++ b/crates/wasmtime/src/runtime/vm.rs @@ -3,11 +3,11 @@ #![deny(missing_docs)] #![warn(clippy::cast_sign_loss)] +use alloc::sync::Arc; use anyhow::{Error, Result}; -use std::fmt; -use std::ptr::NonNull; -use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering}; -use std::sync::Arc; +use core::fmt; +use core::ptr::NonNull; +use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering}; use wasmtime_environ::{ DefinedFuncIndex, DefinedMemoryIndex, HostPtr, ModuleInternedTypeIndex, VMOffsets, VMSharedTypeIndex, @@ -253,7 +253,7 @@ pub fn page_size() -> usize { }; } -/// Result of [`Memory::atomic_wait32`] and [`Memory::atomic_wait64`] +/// Result of `Memory::atomic_wait32` and `Memory::atomic_wait64` #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum WaitResult { /// Indicates that a `wait` completed by being awoken by a different thread. diff --git a/crates/wasmtime/src/runtime/vm/arch/aarch64.rs b/crates/wasmtime/src/runtime/vm/arch/aarch64.rs index f3a490472f23..661641d91e5a 100644 --- a/crates/wasmtime/src/runtime/vm/arch/aarch64.rs +++ b/crates/wasmtime/src/runtime/vm/arch/aarch64.rs @@ -3,14 +3,14 @@ /// AArch64 uses vector registered which here is used with a vector type. /// Note that the specific type shouldn't matter too much but the choice /// of using a vector is the significant part. -pub type V128Abi = std::arch::aarch64::uint8x16_t; +pub type V128Abi = core::arch::aarch64::uint8x16_t; #[inline] #[allow(missing_docs)] pub fn get_stack_pointer() -> usize { let stack_pointer: usize; unsafe { - std::arch::asm!( + core::arch::asm!( "mov {}, sp", out(reg) stack_pointer, options(nostack,nomem), @@ -40,7 +40,7 @@ pub unsafe fn get_next_older_pc_from_fp(fp: usize) -> usize { // the implementation is backward-compatible and there is no duplication. // However, this instruction requires the LR register for both its input and // output. - std::arch::asm!( + core::arch::asm!( "mov lr, {pc}", "xpaclri", "mov {pc}, lr", diff --git a/crates/wasmtime/src/runtime/vm/arch/x86_64.rs b/crates/wasmtime/src/runtime/vm/arch/x86_64.rs index e1c90601b5fe..5cda5dc7f7f7 100644 --- a/crates/wasmtime/src/runtime/vm/arch/x86_64.rs +++ b/crates/wasmtime/src/runtime/vm/arch/x86_64.rs @@ -3,14 +3,14 @@ /// x86 vectors are represented with XMM registers which are represented /// with the `__m128i` type. This type is considered a vector type for /// ABI purposes which is implemented by Cranelift. -pub type V128Abi = std::arch::x86_64::__m128i; +pub type V128Abi = core::arch::x86_64::__m128i; #[inline] #[allow(missing_docs)] pub fn get_stack_pointer() -> usize { let stack_pointer: usize; unsafe { - std::arch::asm!( + core::arch::asm!( "mov {}, rsp", out(reg) stack_pointer, options(nostack,nomem), diff --git a/crates/wasmtime/src/runtime/vm/async_yield.rs b/crates/wasmtime/src/runtime/vm/async_yield.rs index 5d6a1b87fb6a..4b53f990492b 100644 --- a/crates/wasmtime/src/runtime/vm/async_yield.rs +++ b/crates/wasmtime/src/runtime/vm/async_yield.rs @@ -1,4 +1,4 @@ -use std::{ +use core::{ future::Future, pin::Pin, task::{Context, Poll}, diff --git a/crates/wasmtime/src/runtime/vm/component.rs b/crates/wasmtime/src/runtime/vm/component.rs index eff73a65b19c..7cda994bd416 100644 --- a/crates/wasmtime/src/runtime/vm/component.rs +++ b/crates/wasmtime/src/runtime/vm/component.rs @@ -10,16 +10,16 @@ use crate::runtime::vm::{ SendSyncPtr, Store, VMArrayCallFunction, VMFuncRef, VMGlobalDefinition, VMMemoryDefinition, VMNativeCallFunction, VMOpaqueContext, VMWasmCallFunction, ValRaw, }; +use alloc::alloc::Layout; +use alloc::sync::Arc; use anyhow::Result; +use core::any::Any; +use core::marker; +use core::mem; +use core::ops::Deref; +use core::ptr::{self, NonNull}; use memoffset::offset_of; use sptr::Strict; -use std::alloc::{self, Layout}; -use std::any::Any; -use std::marker; -use std::mem; -use std::ops::Deref; -use std::ptr::{self, NonNull}; -use std::sync::Arc; use wasmtime_environ::component::*; use wasmtime_environ::{HostPtr, PrimaryMap, VMSharedTypeIndex}; @@ -222,7 +222,7 @@ impl ComponentInstance { } fn vmctx(&self) -> *mut VMComponentContext { - let addr = std::ptr::addr_of!(self.vmctx); + let addr = core::ptr::addr_of!(self.vmctx); Strict::with_addr(self.vmctx_self_reference.as_ptr(), Strict::addr(addr)) } @@ -499,7 +499,7 @@ impl ComponentInstance { } /// Get the canonical ABI's `realloc` function's runtime type. - pub fn realloc_func_ty(&self) -> &Arc { + pub fn realloc_func_ty(&self) -> &Arc { self.runtime_info.realloc_func_type() } @@ -672,7 +672,7 @@ impl OwnedComponentInstance { // in the context, but to help protect against possible bugs a // zeroed allocation is done here to try to contain // use-before-initialized issues. - let ptr = alloc::alloc_zeroed(layout) as *mut ComponentInstance; + let ptr = alloc::alloc::alloc_zeroed(layout) as *mut ComponentInstance; let ptr = NonNull::new(ptr).unwrap(); ComponentInstance::new_at( @@ -768,7 +768,7 @@ impl Drop for OwnedComponentInstance { let layout = ComponentInstance::alloc_layout(&self.offsets); unsafe { ptr::drop_in_place(self.ptr.as_ptr()); - alloc::dealloc(self.ptr.as_ptr().cast(), layout); + alloc::alloc::dealloc(self.ptr.as_ptr().cast(), layout); } } } @@ -856,5 +856,5 @@ pub trait ComponentRuntimeInfo: Send + Sync + 'static { fn component_types(&self) -> &Arc; /// Get the `wasmtime::FuncType` for the canonical ABI's `realloc` function. - fn realloc_func_type(&self) -> &Arc; + fn realloc_func_type(&self) -> &Arc; } diff --git a/crates/wasmtime/src/runtime/vm/component/libcalls.rs b/crates/wasmtime/src/runtime/vm/component/libcalls.rs index 525e983b94db..7b6c05d5f78f 100644 --- a/crates/wasmtime/src/runtime/vm/component/libcalls.rs +++ b/crates/wasmtime/src/runtime/vm/component/libcalls.rs @@ -2,8 +2,8 @@ use crate::runtime::vm::component::{ComponentInstance, VMComponentContext}; use anyhow::{anyhow, Result}; -use std::cell::Cell; -use std::slice; +use core::cell::Cell; +use core::slice; use wasmtime_environ::component::TypeResourceTableIndex; const UTF16_TAG: usize = 1 << 31; @@ -189,9 +189,9 @@ mod trampolines { /// can overlap. fn assert_no_overlap(a: &[T], b: &[U]) { let a_start = a.as_ptr() as usize; - let a_end = a_start + (a.len() * std::mem::size_of::()); + let a_end = a_start + (a.len() * core::mem::size_of::()); let b_start = b.as_ptr() as usize; - let b_end = b_start + (b.len() * std::mem::size_of::()); + let b_end = b_start + (b.len() * core::mem::size_of::()); if a_start < b_start { assert!(a_end < b_start); @@ -210,7 +210,7 @@ unsafe fn utf8_to_utf8(src: *mut u8, len: usize, dst: *mut u8) -> Result<()> { let dst = slice::from_raw_parts_mut(dst, len); assert_no_overlap(src, dst); log::trace!("utf8-to-utf8 {len}"); - let src = std::str::from_utf8(src).map_err(|_| anyhow!("invalid utf8 encoding"))?; + let src = core::str::from_utf8(src).map_err(|_| anyhow!("invalid utf8 encoding"))?; dst.copy_from_slice(src.as_bytes()); Ok(()) } @@ -233,7 +233,7 @@ unsafe fn utf16_to_utf16(src: *mut u16, len: usize, dst: *mut u16) -> Result<()> /// the latin1 space. fn run_utf16_to_utf16(src: &[u16], mut dst: &mut [u16]) -> Result { let mut all_latin1 = true; - for ch in std::char::decode_utf16(src.iter().map(|i| u16::from_le(*i))) { + for ch in core::char::decode_utf16(src.iter().map(|i| u16::from_le(*i))) { let ch = ch.map_err(|_| anyhow!("invalid utf16 encoding"))?; all_latin1 = all_latin1 && u8::try_from(u32::from(ch)).is_ok(); let result = ch.encode_utf16(dst); @@ -289,7 +289,7 @@ unsafe fn utf8_to_utf16(src: *mut u8, len: usize, dst: *mut u16) -> Result Result { - let src = std::str::from_utf8(src).map_err(|_| anyhow!("invalid utf8 encoding"))?; + let src = core::str::from_utf8(src).map_err(|_| anyhow!("invalid utf8 encoding"))?; let mut amt = 0; for (i, dst) in src.encode_utf16().zip(dst) { *dst = i.to_le(); @@ -326,7 +326,7 @@ unsafe fn utf16_to_utf8( let mut src_read = 0; let mut dst_written = 0; - for ch in std::char::decode_utf16(src_iter) { + for ch in core::char::decode_utf16(src_iter) { let ch = ch.map_err(|_| anyhow!("invalid utf16 encoding"))?; // If the destination doesn't have enough space for this character diff --git a/crates/wasmtime/src/runtime/vm/component/resources.rs b/crates/wasmtime/src/runtime/vm/component/resources.rs index d0a013321a73..b11b2915a8e5 100644 --- a/crates/wasmtime/src/runtime/vm/component/resources.rs +++ b/crates/wasmtime/src/runtime/vm/component/resources.rs @@ -23,8 +23,9 @@ //! about ABI details can be found in lifting/lowering thoughout Wasmtime, //! namely in the `Resource` and `ResourceAny` types. +use crate::prelude::*; use anyhow::{bail, Result}; -use std::mem; +use core::mem; use wasmtime_environ::component::TypeResourceTableIndex; use wasmtime_environ::PrimaryMap; diff --git a/crates/wasmtime/src/runtime/vm/cow.rs b/crates/wasmtime/src/runtime/vm/cow.rs index eeacbdff4533..3fa3ddf71e23 100644 --- a/crates/wasmtime/src/runtime/vm/cow.rs +++ b/crates/wasmtime/src/runtime/vm/cow.rs @@ -1,13 +1,14 @@ //! Copy-on-write initialization support: creation of backing images for //! modules, and logic to support mapping these backing images into memory. +use crate::prelude::*; use crate::runtime::vm::sys::vm::{self, MemoryImageSource}; use crate::runtime::vm::{MmapVec, SendSyncPtr}; +use alloc::sync::Arc; use anyhow::Result; -use std::ffi::c_void; -use std::ops::Range; -use std::ptr::NonNull; -use std::sync::Arc; +use core::ffi::c_void; +use core::ops::Range; +use core::ptr::{self, NonNull}; use wasmtime_environ::{ DefinedMemoryIndex, MemoryInitialization, MemoryPlan, MemoryStyle, Module, PrimaryMap, }; @@ -100,6 +101,7 @@ impl MemoryImage { assert_eq!((data_end as u32) % page_size, 0); assert_eq!((mmap.original_offset() as u32) % page_size, 0); + #[cfg(feature = "std")] if let Some(file) = mmap.original_file() { if let Some(source) = MemoryImageSource::from_file(file) { return Ok(Some(MemoryImage { @@ -115,7 +117,7 @@ impl MemoryImage { // If `mmap` doesn't come from a file then platform-specific mechanisms // may be used to place the data in a form that's amenable to an mmap. - if let Some(source) = MemoryImageSource::from_data(data)? { + if let Some(source) = MemoryImageSource::from_data(data).err2anyhow()? { return Ok(Some(MemoryImage { source, source_offset: 0, @@ -128,17 +130,20 @@ impl MemoryImage { } unsafe fn map_at(&self, base: *mut u8) -> Result<()> { - self.source.map_at( - base.add(self.linear_memory_offset), - self.len, - self.source_offset, - )?; + self.source + .map_at( + base.add(self.linear_memory_offset), + self.len, + self.source_offset, + ) + .err2anyhow()?; Ok(()) } unsafe fn remap_as_zeros_at(&self, base: *mut u8) -> Result<()> { self.source - .remap_as_zeros_at(base.add(self.linear_memory_offset), self.len)?; + .remap_as_zeros_at(base.add(self.linear_memory_offset), self.len) + .err2anyhow()?; Ok(()) } } @@ -526,13 +531,13 @@ impl MemoryImageSlot { (keep_resident - image.linear_memory_offset).min(mem_after_image); // This is memset (1) - std::ptr::write_bytes(self.base.as_ptr(), 0u8, image.linear_memory_offset); + ptr::write_bytes(self.base.as_ptr(), 0u8, image.linear_memory_offset); // This is madvise (2) self.madvise_reset(image.linear_memory_offset, image.len)?; // This is memset (3) - std::ptr::write_bytes(self.base.as_ptr().add(image_end), 0u8, remaining_memset); + ptr::write_bytes(self.base.as_ptr().add(image_end), 0u8, remaining_memset); // This is madvise (4) self.madvise_reset( @@ -560,7 +565,7 @@ impl MemoryImageSlot { // Note that the memset may be zero bytes here. // This is memset (1) - std::ptr::write_bytes(self.base.as_ptr(), 0u8, keep_resident); + ptr::write_bytes(self.base.as_ptr(), 0u8, keep_resident); // This is madvise (2) self.madvise_reset(keep_resident, self.accessible - keep_resident)?; @@ -572,7 +577,7 @@ impl MemoryImageSlot { // the rest. None => { let size_to_memset = keep_resident.min(self.accessible); - std::ptr::write_bytes(self.base.as_ptr(), 0u8, size_to_memset); + ptr::write_bytes(self.base.as_ptr(), 0u8, size_to_memset); self.madvise_reset(size_to_memset, self.accessible - size_to_memset)?; } } @@ -586,7 +591,7 @@ impl MemoryImageSlot { if len == 0 { return Ok(()); } - vm::madvise_dontneed(self.base.as_ptr().add(base), len)?; + vm::madvise_dontneed(self.base.as_ptr().add(base), len).err2anyhow()?; Ok(()) } @@ -600,9 +605,9 @@ impl MemoryImageSlot { unsafe { let start = self.base.as_ptr().add(range.start); if readwrite { - vm::expose_existing_mapping(start, range.len())?; + vm::expose_existing_mapping(start, range.len()).err2anyhow()?; } else { - vm::hide_existing_mapping(start, range.len())?; + vm::hide_existing_mapping(start, range.len()).err2anyhow()?; } } @@ -628,7 +633,7 @@ impl MemoryImageSlot { } unsafe { - vm::erase_existing_mapping(self.base.as_ptr(), self.static_size)?; + vm::erase_existing_mapping(self.base.as_ptr(), self.static_size).err2anyhow()?; } self.image = None; diff --git a/crates/wasmtime/src/runtime/vm/export.rs b/crates/wasmtime/src/runtime/vm/export.rs index 90e8000d8185..0c87c55579e5 100644 --- a/crates/wasmtime/src/runtime/vm/export.rs +++ b/crates/wasmtime/src/runtime/vm/export.rs @@ -1,7 +1,7 @@ use crate::runtime::vm::vmcontext::{ VMContext, VMFuncRef, VMGlobalDefinition, VMMemoryDefinition, VMTableDefinition, }; -use std::ptr::NonNull; +use core::ptr::NonNull; use wasmtime_environ::{DefinedMemoryIndex, Global, MemoryPlan, TablePlan}; /// The value of an export passed from one instance to another. diff --git a/crates/wasmtime/src/runtime/vm/gc.rs b/crates/wasmtime/src/runtime/vm/gc.rs index d321e8986cd6..a208babdb0f3 100644 --- a/crates/wasmtime/src/runtime/vm/gc.rs +++ b/crates/wasmtime/src/runtime/vm/gc.rs @@ -1,5 +1,3 @@ -use std::{any::Any, num::NonZeroUsize}; - #[cfg(feature = "gc")] mod enabled; #[cfg(feature = "gc")] @@ -20,8 +18,11 @@ pub use gc_runtime::*; pub use host_data::*; pub use i31::*; +use crate::prelude::*; use crate::runtime::vm::GcHeapAllocationIndex; use anyhow::{bail, Result}; +use core::ptr; +use core::{any::Any, num::NonZeroUsize}; use wasmtime_environ::StackMap; /// Used by the runtime to lookup information about a module given a @@ -230,13 +231,13 @@ pub fn disabled_gc_heap() -> Box { } } unsafe fn vmctx_gc_heap_base(&self) -> *mut u8 { - std::ptr::null_mut() + ptr::null_mut() } unsafe fn vmctx_gc_heap_bound(&self) -> usize { 0 } unsafe fn vmctx_gc_heap_data(&self) -> *mut u8 { - std::ptr::null_mut() + ptr::null_mut() } #[cfg(feature = "pooling-allocator")] fn reset(&mut self) {} diff --git a/crates/wasmtime/src/runtime/vm/gc/disabled.rs b/crates/wasmtime/src/runtime/vm/gc/disabled.rs index 795e3fc1a6ea..2a7572a0a023 100644 --- a/crates/wasmtime/src/runtime/vm/gc/disabled.rs +++ b/crates/wasmtime/src/runtime/vm/gc/disabled.rs @@ -5,6 +5,7 @@ #![allow(missing_docs)] +use crate::prelude::*; use crate::runtime::vm::{GcHeap, GcRuntime}; use anyhow::Result; diff --git a/crates/wasmtime/src/runtime/vm/gc/enabled/drc.rs b/crates/wasmtime/src/runtime/vm/gc/enabled/drc.rs index ad79bd23149c..3ca002852bb4 100644 --- a/crates/wasmtime/src/runtime/vm/gc/enabled/drc.rs +++ b/crates/wasmtime/src/runtime/vm/gc/enabled/drc.rs @@ -42,20 +42,22 @@ //! use super::free_list::FreeList; +use crate::prelude::*; use crate::runtime::vm::{ ExternRefHostDataId, ExternRefHostDataTable, GarbageCollection, GcHeap, GcHeapObject, GcProgress, GcRootsIter, GcRuntime, Mmap, TypedGcRef, VMExternRef, VMGcHeader, VMGcRef, }; use anyhow::Result; -use std::{ +use core::ops::{Deref, DerefMut}; +use core::{ alloc::Layout, any::Any, cell::UnsafeCell, - collections::HashSet, mem, num::NonZeroUsize, ptr::{self, NonNull}, }; +use hashbrown::HashSet; use wasmtime_environ::VMGcKind; /// The deferred reference-counting (DRC) collector. @@ -105,13 +107,13 @@ impl DrcHeap { fn heap_slice(&self) -> &[UnsafeCell] { let ptr = self.heap.as_ptr().cast::>(); let len = self.heap.len(); - unsafe { std::slice::from_raw_parts(ptr, len) } + unsafe { core::slice::from_raw_parts(ptr, len) } } fn heap_slice_mut(&mut self) -> &mut [u8] { let ptr = self.heap.as_mut_ptr(); let len = self.heap.len(); - unsafe { std::slice::from_raw_parts_mut(ptr, len) } + unsafe { core::slice::from_raw_parts_mut(ptr, len) } } /// Index into this heap and get a shared reference to the `T` that `gc_ref` @@ -124,11 +126,11 @@ impl DrcHeap { where T: GcHeapObject, { - assert!(!std::mem::needs_drop::()); + assert!(!mem::needs_drop::()); let gc_ref = gc_ref.as_untyped(); let start = gc_ref.as_heap_index().unwrap().get(); let start = usize::try_from(start).unwrap(); - let len = std::mem::size_of::(); + let len = mem::size_of::(); let slice = &self.heap_slice()[start..][..len]; unsafe { &*(slice.as_ptr().cast::()) } } @@ -143,11 +145,11 @@ impl DrcHeap { where T: GcHeapObject, { - assert!(!std::mem::needs_drop::()); + assert!(!mem::needs_drop::()); let gc_ref = gc_ref.as_untyped(); let start = gc_ref.as_heap_index().unwrap().get(); let start = usize::try_from(start).unwrap(); - let len = std::mem::size_of::(); + let len = mem::size_of::(); let slice = &mut self.heap_slice_mut()[start..][..len]; unsafe { &mut *(slice.as_mut_ptr().cast::()) } } @@ -844,7 +846,7 @@ struct DebugOnly { inner: T, } -impl std::ops::Deref for DebugOnly { +impl Deref for DebugOnly { type Target = T; fn deref(&self) -> &T { @@ -859,7 +861,7 @@ impl std::ops::Deref for DebugOnly { } } -impl std::ops::DerefMut for DebugOnly { +impl DerefMut for DebugOnly { fn deref_mut(&mut self) -> &mut T { if cfg!(debug_assertions) { &mut self.inner diff --git a/crates/wasmtime/src/runtime/vm/gc/enabled/externref.rs b/crates/wasmtime/src/runtime/vm/gc/enabled/externref.rs index 3e34613085be..1c4622077830 100644 --- a/crates/wasmtime/src/runtime/vm/gc/enabled/externref.rs +++ b/crates/wasmtime/src/runtime/vm/gc/enabled/externref.rs @@ -1,4 +1,5 @@ use crate::runtime::vm::{GcHeap, GcStore, VMGcRef}; +use core::fmt; use wasmtime_environ::VMGcKind; /// A `VMGcRef` that we know points to an `externref`. @@ -14,9 +15,9 @@ use wasmtime_environ::VMGcKind; #[repr(transparent)] pub struct VMExternRef(VMGcRef); -impl std::fmt::Pointer for VMExternRef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Pointer::fmt(&self.0, f) +impl fmt::Pointer for VMExternRef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&self.0, f) } } diff --git a/crates/wasmtime/src/runtime/vm/gc/enabled/free_list.rs b/crates/wasmtime/src/runtime/vm/gc/enabled/free_list.rs index bad01b259b89..332bd60fdf1f 100644 --- a/crates/wasmtime/src/runtime/vm/gc/enabled/free_list.rs +++ b/crates/wasmtime/src/runtime/vm/gc/enabled/free_list.rs @@ -1,5 +1,8 @@ +use crate::prelude::*; +use alloc::collections::BTreeMap; use anyhow::{anyhow, ensure, Context, Result}; -use std::{alloc::Layout, collections::BTreeMap, num::NonZeroU32, ops::Bound}; +use core::cmp; +use core::{alloc::Layout, num::NonZeroU32, ops::Bound}; /// A very simple first-fit free list for use by our garbage collectors. pub(crate) struct FreeList { @@ -31,7 +34,7 @@ impl FreeList { } fn max_size(&self) -> usize { - let cap = std::cmp::min(self.capacity, usize::try_from(u32::MAX).unwrap()); + let cap = cmp::min(self.capacity, usize::try_from(u32::MAX).unwrap()); round_usize_down_to_pow2(cap.saturating_sub(ALIGN_USIZE), ALIGN_USIZE) } @@ -52,6 +55,7 @@ impl FreeList { ); let alloc_size = u32::try_from(layout.size()) + .err2anyhow() .context("requested allocation's size does not fit in a u32")?; alloc_size .checked_next_multiple_of(ALIGN_U32) diff --git a/crates/wasmtime/src/runtime/vm/gc/gc_ref.rs b/crates/wasmtime/src/runtime/vm/gc/gc_ref.rs index 952811368889..b39b70e97320 100644 --- a/crates/wasmtime/src/runtime/vm/gc/gc_ref.rs +++ b/crates/wasmtime/src/runtime/vm/gc/gc_ref.rs @@ -1,6 +1,9 @@ +use crate::prelude::*; use crate::runtime::vm::{GcHeap, GcStore, I31}; use anyhow::{Context, Result}; -use std::num::NonZeroU32; +use core::fmt; +use core::marker; +use core::num::NonZeroU32; use wasmtime_environ::{VMGcKind, VMSharedTypeIndex}; /// The common header for all objects allocated in a GC heap. @@ -98,11 +101,12 @@ impl VMGcHeader { #[cfg(test)] mod vm_gc_header_tests { use super::*; + use std::mem; #[test] fn size_align() { - assert_eq!(std::mem::size_of::(), 8); - assert_eq!(std::mem::align_of::(), 8); + assert_eq!(mem::size_of::(), 8); + assert_eq!(mem::align_of::(), 8); } } @@ -142,20 +146,20 @@ impl From> for VMGcRef { } } -impl std::fmt::LowerHex for VMGcRef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::LowerHex for VMGcRef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -impl std::fmt::UpperHex for VMGcRef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::UpperHex for VMGcRef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -impl std::fmt::Pointer for VMGcRef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Pointer for VMGcRef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:#x}", self) } } @@ -229,6 +233,7 @@ impl VMGcRef { /// type on 64-bit platforms. We should instead have a `from_r32` method. pub fn from_r64(raw: u64) -> Result> { let raw = u32::try_from(raw & (u32::MAX as u64)) + .err2anyhow() .with_context(|| format!("invalid r64: {raw:#x} cannot be converted into a u32"))?; Ok(Self::from_raw_u32(raw)) } @@ -294,7 +299,7 @@ impl VMGcRef { if T::is(gc_heap.header(&self)) { Ok(TypedGcRef { gc_ref: self, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, }) } else { Err(self) @@ -314,7 +319,7 @@ impl VMGcRef { debug_assert!(!self.is_i31()); TypedGcRef { gc_ref: self, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } } @@ -442,7 +447,7 @@ pub unsafe trait GcHeapObject: Send + Sync { #[repr(transparent)] pub struct TypedGcRef { gc_ref: VMGcRef, - _phantom: std::marker::PhantomData<*mut T>, + _phantom: marker::PhantomData<*mut T>, } impl TypedGcRef @@ -453,7 +458,7 @@ where pub fn clone(&self, gc_store: &mut GcStore) -> Self { Self { gc_ref: gc_store.clone_gc_ref(&self.gc_ref), - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } } @@ -473,7 +478,7 @@ where pub fn unchecked_copy(&self) -> Self { Self { gc_ref: self.gc_ref.unchecked_copy(), - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, } } } diff --git a/crates/wasmtime/src/runtime/vm/gc/gc_runtime.rs b/crates/wasmtime/src/runtime/vm/gc/gc_runtime.rs index b36c841d8a89..e19c1bfaaccd 100644 --- a/crates/wasmtime/src/runtime/vm/gc/gc_runtime.rs +++ b/crates/wasmtime/src/runtime/vm/gc/gc_runtime.rs @@ -1,10 +1,13 @@ //! Traits for abstracting over our different garbage collectors. +use crate::prelude::*; use crate::runtime::vm::{ ExternRefHostDataId, ExternRefHostDataTable, SendSyncPtr, VMExternRef, VMGcHeader, VMGcRef, }; use anyhow::Result; -use std::{any::Any, num::NonZeroUsize}; +use core::marker; +use core::ptr; +use core::{any::Any, num::NonZeroUsize}; /// Trait for integrating a garbage collector with the runtime. /// @@ -369,7 +372,7 @@ impl<'a> Iterator for GcRootsIter<'a> { fn next(&mut self) -> Option { let root = GcRoot { raw: self.list.0.get(self.index).copied()?, - _phantom: std::marker::PhantomData, + _phantom: marker::PhantomData, }; self.index += 1; Some(root) @@ -384,7 +387,7 @@ impl<'a> Iterator for GcRootsIter<'a> { /// `VMGcRef`'s referent during the course of a GC. pub struct GcRoot<'a> { raw: RawGcRoot, - _phantom: std::marker::PhantomData<&'a mut VMGcRef>, + _phantom: marker::PhantomData<&'a mut VMGcRef>, } impl GcRoot<'_> { @@ -400,9 +403,9 @@ impl GcRoot<'_> { #[inline] pub fn get(&self) -> VMGcRef { match self.raw { - RawGcRoot::NonStack(ptr) => unsafe { std::ptr::read(ptr.as_ptr()) }, + RawGcRoot::NonStack(ptr) => unsafe { ptr::read(ptr.as_ptr()) }, RawGcRoot::Stack(ptr) => unsafe { - let r64 = std::ptr::read(ptr.as_ptr()); + let r64 = ptr::read(ptr.as_ptr()); VMGcRef::from_r64(r64) .expect("valid r64") .expect("non-null") @@ -420,11 +423,11 @@ impl GcRoot<'_> { pub fn set(&mut self, new_ref: VMGcRef) { match self.raw { RawGcRoot::NonStack(ptr) => unsafe { - std::ptr::write(ptr.as_ptr(), new_ref); + ptr::write(ptr.as_ptr(), new_ref); }, RawGcRoot::Stack(ptr) => unsafe { let r64 = new_ref.into_r64(); - std::ptr::write(ptr.as_ptr(), r64); + ptr::write(ptr.as_ptr(), r64); }, } } diff --git a/crates/wasmtime/src/runtime/vm/gc/host_data.rs b/crates/wasmtime/src/runtime/vm/gc/host_data.rs index 13161b508fb9..4d7044c48886 100644 --- a/crates/wasmtime/src/runtime/vm/gc/host_data.rs +++ b/crates/wasmtime/src/runtime/vm/gc/host_data.rs @@ -13,7 +13,8 @@ //! less catastrophic than doing an indirect call to an attacker-controlled //! function pointer. -use std::any::Any; +use crate::prelude::*; +use core::any::Any; use wasmtime_slab::{Id, Slab}; /// Side table for each `externref`'s host data value. diff --git a/crates/wasmtime/src/runtime/vm/gc/i31.rs b/crates/wasmtime/src/runtime/vm/gc/i31.rs index 2f700fa635b8..e79ece0c3f93 100644 --- a/crates/wasmtime/src/runtime/vm/gc/i31.rs +++ b/crates/wasmtime/src/runtime/vm/gc/i31.rs @@ -1,6 +1,7 @@ //! Implementation of unboxed 31-bit integers. use super::VMGcRef; +use core::fmt; /// A 31-bit integer for use with `i31ref`. #[derive(Clone, Copy, PartialEq, Eq, Hash)] @@ -13,8 +14,8 @@ impl Default for I31 { } } -impl std::fmt::Debug for I31 { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Debug for I31 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("I31") .field("as_u32", &self.get_u32()) .field("as_i32", &self.get_i32()) diff --git a/crates/wasmtime/src/runtime/vm/instance.rs b/crates/wasmtime/src/runtime/vm/instance.rs index 687d894d2d8b..d3b3861db209 100644 --- a/crates/wasmtime/src/runtime/vm/instance.rs +++ b/crates/wasmtime/src/runtime/vm/instance.rs @@ -2,6 +2,7 @@ //! wasm module (except its callstack and register state). An //! `InstanceHandle` is a reference-counting handle for an `Instance`. +use crate::prelude::*; use crate::runtime::vm::const_expr::{ConstEvalContext, ConstExprEvaluator}; use crate::runtime::vm::export::Export; use crate::runtime::vm::memory::{Memory, RuntimeMemoryCreator}; @@ -15,16 +16,15 @@ use crate::runtime::vm::{ ExportFunction, ExportGlobal, ExportMemory, ExportTable, GcStore, Imports, ModuleRuntimeInfo, SendSyncPtr, Store, VMFunctionBody, VMGcRef, WasmFault, }; -use anyhow::Error; -use anyhow::Result; +use alloc::sync::Arc; +use anyhow::{Error, Result}; +use core::alloc::Layout; +use core::any::Any; +use core::ops::Range; +use core::ptr::NonNull; +use core::sync::atomic::AtomicU64; +use core::{mem, ptr}; use sptr::Strict; -use std::alloc::{self, Layout}; -use std::any::Any; -use std::ops::Range; -use std::ptr::NonNull; -use std::sync::atomic::AtomicU64; -use std::sync::Arc; -use std::{mem, ptr}; use wasmtime_environ::{ packed_option::ReservedValue, DataIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, ElemIndex, EntityIndex, EntityRef, EntitySet, FuncIndex, GlobalIndex, @@ -167,9 +167,9 @@ impl Instance { ) -> InstanceHandle { // The allocation must be *at least* the size required of `Instance`. let layout = Self::alloc_layout(req.runtime_info.offsets()); - let ptr = alloc::alloc(layout); + let ptr = alloc::alloc::alloc(layout); if ptr.is_null() { - alloc::handle_alloc_error(layout); + alloc::alloc::handle_alloc_error(layout); } let ptr = ptr.cast::(); @@ -191,7 +191,7 @@ impl Instance { host_state: req.host_state, vmctx_self_reference: SendSyncPtr::new(NonNull::new(ptr.add(1).cast()).unwrap()), vmctx: VMContext { - _marker: std::marker::PhantomPinned, + _marker: core::marker::PhantomPinned, }, #[cfg(feature = "wmemcheck")] wmemcheck_state: { @@ -521,7 +521,7 @@ impl Instance { // today so the `sptr` crate is used. This crate provides the extension // trait `Strict` but the method names conflict with the nightly methods // so a different syntax is used to invoke methods here. - let addr = std::ptr::addr_of!(self.vmctx); + let addr = ptr::addr_of!(self.vmctx); Strict::with_addr(self.vmctx_self_reference.as_ptr(), Strict::addr(addr)) } @@ -745,7 +745,7 @@ impl Instance { // Safety: we have a `&mut self`, so we have exclusive access // to this Instance. unsafe { - std::ptr::write(into, func_ref); + ptr::write(into, func_ref); } } @@ -859,7 +859,7 @@ impl Instance { dst, elements .iter() - .map(|idx| self.get_func_ref(*idx).unwrap_or(std::ptr::null_mut())), + .map(|idx| self.get_func_ref(*idx).unwrap_or(ptr::null_mut())), )?; } TableSegmentElements::Expressions(exprs) => { @@ -1124,7 +1124,7 @@ impl Instance { let func_index = precomputed.get(i as usize).cloned(); let func_ref = func_index .and_then(|func_index| self.get_func_ref(func_index)) - .unwrap_or(std::ptr::null_mut()); + .unwrap_or(ptr::null_mut()); self.tables[idx] .1 .set(i, TableElement::FuncRef(func_ref)) @@ -1179,7 +1179,7 @@ impl Instance { store: StorePtr, imports: Imports, ) { - assert!(std::ptr::eq(module, self.module().as_ref())); + assert!(ptr::eq(module, self.module().as_ref())); *self.vmctx_plus_offset_mut(offsets.vmctx_magic()) = VMCONTEXT_MAGIC; self.set_callee(None); diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator.rs b/crates/wasmtime/src/runtime/vm/instance/allocator.rs index f2ff6dbfc20f..3fa10e930b69 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use crate::runtime::vm::const_expr::{ConstEvalContext, ConstExprEvaluator}; use crate::runtime::vm::imports::Imports; use crate::runtime::vm::instance::{Instance, InstanceHandle}; @@ -5,8 +6,9 @@ use crate::runtime::vm::memory::Memory; use crate::runtime::vm::mpk::ProtectionKey; use crate::runtime::vm::table::Table; use crate::runtime::vm::{CompiledModuleId, ModuleRuntimeInfo, Store, VMFuncRef, VMGcRef}; +use alloc::sync::Arc; use anyhow::{bail, Result}; -use std::{alloc, any::Any, mem, ptr, sync::Arc}; +use core::{any::Any, mem, ptr}; use wasmtime_environ::{ DefinedMemoryIndex, DefinedTableIndex, HostPtr, InitMemory, MemoryInitialization, MemoryInitializer, MemoryPlan, Module, PrimaryMap, TableInitialValue, TablePlan, Trap, @@ -418,7 +420,7 @@ pub trait InstanceAllocator: InstanceAllocatorImpl { let layout = Instance::alloc_layout(handle.instance().offsets()); let ptr = handle.instance.take().unwrap(); ptr::drop_in_place(ptr.as_ptr()); - alloc::dealloc(ptr.as_ptr().cast(), layout); + alloc::alloc::dealloc(ptr.as_ptr().cast(), layout); self.decrement_core_instance_count(); } @@ -575,7 +577,7 @@ fn initialize_tables(instance: &mut Instance, module: &Module) -> Result<()> { let gc_store = unsafe { (*instance.store()).gc_store() }; let items = (0..table.size()) .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r))); - table.init_gc_refs(0, items)?; + table.init_gc_refs(0, items).err2anyhow()?; } WasmHeapTopType::Any => { @@ -583,13 +585,13 @@ fn initialize_tables(instance: &mut Instance, module: &Module) -> Result<()> { let gc_store = unsafe { (*instance.store()).gc_store() }; let items = (0..table.size()) .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r))); - table.init_gc_refs(0, items)?; + table.init_gc_refs(0, items).err2anyhow()?; } WasmHeapTopType::Func => { let funcref = raw.get_funcref().cast::(); let items = (0..table.size()).map(|_| funcref); - table.init_func(0, items)?; + table.init_func(0, items).err2anyhow()?; } } } @@ -610,14 +612,16 @@ fn initialize_tables(instance: &mut Instance, module: &Module) -> Result<()> { .eval(&mut context, &segment.offset) .expect("const expression should be valid") }; - instance.table_init_segment( - &mut const_evaluator, - segment.table_index, - &segment.elements, - start.get_u32(), - 0, - segment.elements.len(), - )?; + instance + .table_init_segment( + &mut const_evaluator, + segment.table_index, + &segment.elements, + start.get_u32(), + 0, + segment.elements.len(), + ) + .err2anyhow()?; } Ok(()) @@ -740,7 +744,7 @@ fn initialize_memories(instance: &mut Instance, module: &Module) -> Result<()> { const_evaluator: ConstExprEvaluator::default(), }); if !ok { - return Err(Trap::MemoryOutOfBounds.into()); + return Err(Trap::MemoryOutOfBounds).err2anyhow(); } Ok(()) diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/on_demand.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/on_demand.rs index bfad26f325d0..48fd1009e7be 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/on_demand.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/on_demand.rs @@ -1,13 +1,14 @@ use super::{ InstanceAllocationRequest, InstanceAllocatorImpl, MemoryAllocationIndex, TableAllocationIndex, }; +use crate::prelude::*; use crate::runtime::vm::instance::RuntimeMemoryCreator; use crate::runtime::vm::memory::{DefaultMemoryCreator, Memory}; use crate::runtime::vm::mpk::ProtectionKey; use crate::runtime::vm::table::Table; use crate::runtime::vm::CompiledModuleId; +use alloc::sync::Arc; use anyhow::Result; -use std::sync::Arc; use wasmtime_environ::{ DefinedMemoryIndex, DefinedTableIndex, HostPtr, MemoryPlan, Module, TablePlan, VMOffsets, }; diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling.rs index 6809da8d7900..6b64fde95b11 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling.rs @@ -39,21 +39,22 @@ cfg_if::cfg_if! { } } +use self::memory_pool::MemoryPool; +use self::table_pool::TablePool; use super::{ InstanceAllocationRequest, InstanceAllocatorImpl, MemoryAllocationIndex, TableAllocationIndex, }; +use crate::prelude::*; use crate::runtime::vm::{ instance::Instance, mpk::{self, MpkEnabled, ProtectionKey, ProtectionMask}, CompiledModuleId, Memory, Table, }; use anyhow::{bail, Result}; -use memory_pool::MemoryPool; use std::{ mem, sync::atomic::{AtomicU64, Ordering}, }; -use table_pool::TablePool; use wasmtime_environ::{ DefinedMemoryIndex, DefinedTableIndex, HostPtr, MemoryPlan, Module, TablePlan, Tunables, VMOffsets, diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/gc_heap_pool.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/gc_heap_pool.rs index 24331eb168c0..aa2570831fdd 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/gc_heap_pool.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/gc_heap_pool.rs @@ -1,5 +1,6 @@ use super::index_allocator::{SimpleIndexAllocator, SlotId}; use super::GcHeapAllocationIndex; +use crate::prelude::*; use crate::runtime::vm::{GcHeap, GcRuntime, PoolingInstanceAllocatorConfig, Result}; use anyhow::anyhow; use std::sync::Mutex; diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/index_allocator.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/index_allocator.rs index ffb87cf5fe05..f84fa70a1a56 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/index_allocator.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/index_allocator.rs @@ -1,5 +1,6 @@ //! Index/slot allocator policies for the pooling allocator. +use crate::prelude::*; use crate::runtime::vm::CompiledModuleId; use std::collections::hash_map::{Entry, HashMap}; use std::mem; diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/memory_pool.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/memory_pool.rs index 01f704d72dd7..6615707bb73c 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/memory_pool.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/memory_pool.rs @@ -54,6 +54,7 @@ use super::{ index_allocator::{MemoryInModule, ModuleAffinityIndexAllocator, SlotId}, MemoryAllocationIndex, }; +use crate::prelude::*; use crate::runtime::vm::mpk::{self, ProtectionKey, ProtectionMask}; use crate::runtime::vm::{ CompiledModuleId, InstanceAllocationRequest, InstanceLimits, Memory, MemoryImageSlot, Mmap, diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs index 6f30b505e4d4..9e0820327d2e 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs @@ -178,6 +178,7 @@ impl StackPool { #[cfg(test)] mod tests { use super::*; + use crate::prelude::*; use crate::runtime::vm::InstanceLimits; #[cfg(all(unix, target_pointer_width = "64", feature = "async", not(miri)))] diff --git a/crates/wasmtime/src/runtime/vm/libcalls.rs b/crates/wasmtime/src/runtime/vm/libcalls.rs index cee1f31736fc..6e27f6d2b98c 100644 --- a/crates/wasmtime/src/runtime/vm/libcalls.rs +++ b/crates/wasmtime/src/runtime/vm/libcalls.rs @@ -61,7 +61,7 @@ use crate::runtime::vm::{Instance, TrapReason, VMGcRef}; use anyhow::bail; use anyhow::Result; #[cfg(feature = "threads")] -use std::time::{Duration, Instant}; +use core::time::Duration; use wasmtime_environ::{DataIndex, ElemIndex, FuncIndex, MemoryIndex, TableIndex, Trap, Unsigned}; #[cfg(feature = "wmemcheck")] use wasmtime_wmemcheck::AccessError::{ @@ -121,7 +121,7 @@ pub mod raw { } $( #[cfg(not($attr))] - std::process::abort(); + unreachable!(); )? } @@ -365,7 +365,7 @@ unsafe fn table_get_lazy_init_func_ref( index: u32, ) -> *mut u8 { let table_index = TableIndex::from_u32(table_index); - let table = instance.get_table_with_lazy_init(table_index, std::iter::once(index)); + let table = instance.get_table_with_lazy_init(table_index, core::iter::once(index)); let gc_store = (*instance.store()).gc_store(); let elem = (*table) .get(gc_store, index) @@ -406,7 +406,7 @@ unsafe fn gc(instance: &mut Instance, gc_ref: *mut u8) -> Result<*mut u8> { } match (*instance.store()).gc(gc_ref)? { - None => Ok(std::ptr::null_mut()), + None => Ok(core::ptr::null_mut()), Some(r) => { let r64 = r.as_r64(); (*instance.store()).gc_store().expose_gc_ref_to_wasm(r); @@ -418,7 +418,7 @@ unsafe fn gc(instance: &mut Instance, gc_ref: *mut u8) -> Result<*mut u8> { // Perform a Wasm `global.get` for GC reference globals. #[cfg(feature = "gc")] unsafe fn gc_ref_global_get(instance: &mut Instance, index: u32) -> Result<*mut u8> { - use std::num::NonZeroUsize; + use core::num::NonZeroUsize; let index = wasmtime_environ::GlobalIndex::from_u32(index); let global = instance.defined_or_imported_global_ptr(index); @@ -432,7 +432,7 @@ unsafe fn gc_ref_global_get(instance: &mut Instance, index: u32) -> Result<*mut } match (*global).as_gc_ref() { - None => Ok(std::ptr::null_mut()), + None => Ok(core::ptr::null_mut()), Some(gc_ref) => { let gc_ref = gc_store.clone_gc_ref(gc_ref); let ret = usize::try_from(gc_ref.as_r64()).unwrap() as *mut u8; @@ -475,8 +475,7 @@ fn memory_atomic_wait32( expected: u32, timeout: u64, ) -> Result { - // convert timeout to Instant, before any wait happens on locking - let timeout = (timeout as i64 >= 0).then(|| Instant::now() + Duration::from_nanos(timeout)); + let timeout = (timeout as i64 >= 0).then(|| Duration::from_nanos(timeout)); let memory = MemoryIndex::from_u32(memory_index); Ok(instance .get_runtime_memory(memory) @@ -492,8 +491,7 @@ fn memory_atomic_wait64( expected: u64, timeout: u64, ) -> Result { - // convert timeout to Instant, before any wait happens on locking - let timeout = (timeout as i64 >= 0).then(|| Instant::now() + Duration::from_nanos(timeout)); + let timeout = (timeout as i64 >= 0).then(|| Duration::from_nanos(timeout)); let memory = MemoryIndex::from_u32(memory_index); Ok(instance .get_runtime_memory(memory) @@ -648,28 +646,61 @@ fn update_mem_size(instance: &mut Instance, num_pages: u32) { /// standard library generally for implementing these. #[allow(missing_docs)] pub mod relocs { + macro_rules! float_function { + (std: $std:path, core: $core:path,) => {{ + #[cfg(feature = "std")] + let func = $std; + #[cfg(not(feature = "std"))] + let func = $core; + func + }}; + } pub extern "C" fn floorf32(f: f32) -> f32 { - f.floor() + let func = float_function! { + std: f32::floor, + core: libm::floorf, + }; + func(f) } pub extern "C" fn floorf64(f: f64) -> f64 { - f.floor() + let func = float_function! { + std: f64::floor, + core: libm::floor, + }; + func(f) } pub extern "C" fn ceilf32(f: f32) -> f32 { - f.ceil() + let func = float_function! { + std: f32::ceil, + core: libm::ceilf, + }; + func(f) } pub extern "C" fn ceilf64(f: f64) -> f64 { - f.ceil() + let func = float_function! { + std: f64::ceil, + core: libm::ceil, + }; + func(f) } pub extern "C" fn truncf32(f: f32) -> f32 { - f.trunc() + let func = float_function! { + std: f32::trunc, + core: libm::truncf, + }; + func(f) } pub extern "C" fn truncf64(f: f64) -> f64 { - f.trunc() + let func = float_function! { + std: f64::trunc, + core: libm::trunc, + }; + func(f) } const TOINT_32: f32 = 1.0 / f32::EPSILON; @@ -696,7 +727,16 @@ pub mod relocs { } x } else { - (x.abs() + TOINT_32 - TOINT_32).copysign(x) + let abs = float_function! { + std: f32::abs, + core: libm::fabsf, + }; + let copysign = float_function! { + std: f32::copysign, + core: libm::copysignf, + }; + + copysign(abs(x) + TOINT_32 - TOINT_32, x) } } @@ -715,22 +755,39 @@ pub mod relocs { } x } else { - (x.abs() + TOINT_64 - TOINT_64).copysign(x) + let abs = float_function! { + std: f64::abs, + core: libm::fabs, + }; + let copysign = float_function! { + std: f64::copysign, + core: libm::copysign, + }; + + copysign(abs(x) + TOINT_64 - TOINT_64, x) } } pub extern "C" fn fmaf32(a: f32, b: f32, c: f32) -> f32 { - a.mul_add(b, c) + let func = float_function! { + std: f32::mul_add, + core: libm::fmaf, + }; + func(a, b, c) } pub extern "C" fn fmaf64(a: f64, b: f64, c: f64) -> f64 { - a.mul_add(b, c) + let func = float_function! { + std: f64::mul_add, + core: libm::fma, + }; + func(a, b, c) } // This intrinsic is only used on x86_64 platforms as an implementation of // the `pshufb` instruction when SSSE3 is not available. #[cfg(target_arch = "x86_64")] - use std::arch::x86_64::__m128i; + use core::arch::x86_64::__m128i; #[cfg(target_arch = "x86_64")] #[allow(improper_ctypes_definitions)] pub extern "C" fn x86_pshufb(a: __m128i, b: __m128i) -> __m128i { diff --git a/crates/wasmtime/src/runtime/vm/memory.rs b/crates/wasmtime/src/runtime/vm/memory.rs index 6d1a246bc765..cf84bc120cf5 100644 --- a/crates/wasmtime/src/runtime/vm/memory.rs +++ b/crates/wasmtime/src/runtime/vm/memory.rs @@ -2,17 +2,18 @@ //! //! `RuntimeLinearMemory` is to WebAssembly linear memories what `Table` is to WebAssembly tables. +use crate::prelude::*; use crate::runtime::vm::mmap::Mmap; use crate::runtime::vm::vmcontext::VMMemoryDefinition; use crate::runtime::vm::{ MemoryImage, MemoryImageSlot, SendSyncPtr, SharedMemory, Store, WaitResult, }; +use alloc::sync::Arc; use anyhow::Error; use anyhow::{bail, format_err, Result}; -use std::ops::Range; -use std::ptr::NonNull; -use std::sync::Arc; -use std::time::Instant; +use core::ops::Range; +use core::ptr::NonNull; +use core::time::Duration; use wasmtime_environ::{MemoryPlan, MemoryStyle, Trap, WASM32_MAX_PAGES, WASM64_MAX_PAGES}; const WASM_PAGE_SIZE: usize = wasmtime_environ::WASM_PAGE_SIZE as usize; @@ -152,7 +153,7 @@ pub trait RuntimeLinearMemory: Send + Sync { fn needs_init(&self) -> bool; /// Used for optional dynamic downcasting. - fn as_any_mut(&mut self) -> &mut dyn std::any::Any; + fn as_any_mut(&mut self) -> &mut dyn core::any::Any; /// Returns the range of addresses that may be reached by WebAssembly. /// @@ -349,7 +350,7 @@ impl RuntimeLinearMemory for MmapMemory { self.memory_image.is_none() } - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + fn as_any_mut(&mut self) -> &mut dyn core::any::Any { self } @@ -448,7 +449,7 @@ impl RuntimeLinearMemory for StaticMemory { !self.memory_image.has_image() } - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + fn as_any_mut(&mut self) -> &mut dyn core::any::Any { self } @@ -654,7 +655,7 @@ impl Memory { #[cfg(feature = "pooling-allocator")] pub fn unwrap_static_image(mut self) -> MemoryImageSlot { let mem = self.0.as_any_mut().downcast_mut::().unwrap(); - std::mem::replace(&mut mem.memory_image, MemoryImageSlot::dummy()) + core::mem::replace(&mut mem.memory_image, MemoryImageSlot::dummy()) } /// If the [Memory] is a [SharedMemory], unwrap it and return a clone to @@ -684,10 +685,10 @@ impl Memory { &mut self, addr: u64, expected: u32, - deadline: Option, + timeout: Option, ) -> Result { match self.0.as_any_mut().downcast_mut::() { - Some(m) => m.atomic_wait32(addr, expected, deadline), + Some(m) => m.atomic_wait32(addr, expected, timeout), None => { validate_atomic_addr(&self.vmmemory(), addr, 4, 4)?; Err(Trap::AtomicWaitNonSharedMemory) @@ -700,10 +701,10 @@ impl Memory { &mut self, addr: u64, expected: u64, - deadline: Option, + timeout: Option, ) -> Result { match self.0.as_any_mut().downcast_mut::() { - Some(m) => m.atomic_wait64(addr, expected, deadline), + Some(m) => m.atomic_wait64(addr, expected, timeout), None => { validate_atomic_addr(&self.vmmemory(), addr, 8, 8)?; Err(Trap::AtomicWaitNonSharedMemory) diff --git a/crates/wasmtime/src/runtime/vm/mmap.rs b/crates/wasmtime/src/runtime/vm/mmap.rs index 439b8205761e..7cc8409ac28c 100644 --- a/crates/wasmtime/src/runtime/vm/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/mmap.rs @@ -1,18 +1,19 @@ //! Low-level abstraction for allocating and managing zero-filled pages //! of memory. +use crate::prelude::*; use crate::runtime::vm::sys::mmap; use anyhow::{Context, Result}; -use std::fs::File; -use std::ops::Range; -use std::path::Path; -use std::sync::Arc; +use core::ops::Range; +#[cfg(feature = "std")] +use std::{fs::File, path::Path, sync::Arc}; /// A simple struct consisting of a page-aligned pointer to page-aligned /// and initially-zeroed memory and a length. #[derive(Debug)] pub struct Mmap { sys: mmap::Mmap, + #[cfg(feature = "std")] file: Option>, } @@ -34,6 +35,7 @@ impl Mmap { /// /// The memory mapping and the length of the file within the mapping are /// returned. + #[cfg(feature = "std")] pub fn from_file(path: &Path) -> Result { let (sys, file) = mmap::Mmap::from_file(path)?; Ok(Mmap { @@ -59,18 +61,21 @@ impl Mmap { if mapping_size == 0 { Ok(Mmap { sys: mmap::Mmap::new_empty(), + #[cfg(feature = "std")] file: None, }) } else if accessible_size == mapping_size { Ok(Mmap { sys: mmap::Mmap::new(mapping_size) .context(format!("mmap failed to allocate {mapping_size:#x} bytes"))?, + #[cfg(feature = "std")] file: None, }) } else { let mut result = Mmap { sys: mmap::Mmap::reserve(mapping_size) .context(format!("mmap failed to reserve {mapping_size:#x} bytes"))?, + #[cfg(feature = "std")] file: None, }; if accessible_size > 0 { @@ -114,7 +119,7 @@ impl Mmap { pub unsafe fn slice(&self, range: Range) -> &[u8] { assert!(range.start <= range.end); assert!(range.end <= self.len()); - std::slice::from_raw_parts(self.as_ptr().add(range.start), range.end - range.start) + core::slice::from_raw_parts(self.as_ptr().add(range.start), range.end - range.start) } /// Return the allocated memory as a mutable slice of u8. @@ -130,7 +135,7 @@ impl Mmap { pub unsafe fn slice_mut(&mut self, range: Range) -> &mut [u8] { assert!(range.start <= range.end); assert!(range.end <= self.len()); - std::slice::from_raw_parts_mut(self.as_mut_ptr().add(range.start), range.end - range.start) + core::slice::from_raw_parts_mut(self.as_mut_ptr().add(range.start), range.end - range.start) } /// Return the allocated memory as a pointer to u8. @@ -203,6 +208,7 @@ impl Mmap { } /// Returns the underlying file that this mmap is mapping, if present. + #[cfg(feature = "std")] pub fn original_file(&self) -> Option<&Arc> { self.file.as_ref() } diff --git a/crates/wasmtime/src/runtime/vm/mmap_vec.rs b/crates/wasmtime/src/runtime/vm/mmap_vec.rs index c39c6accb10a..05e412ab9c5a 100644 --- a/crates/wasmtime/src/runtime/vm/mmap_vec.rs +++ b/crates/wasmtime/src/runtime/vm/mmap_vec.rs @@ -1,9 +1,10 @@ +use crate::prelude::*; use crate::runtime::vm::Mmap; -use anyhow::{Context, Result}; -use std::fs::File; -use std::ops::{Deref, DerefMut, Range}; -use std::path::Path; -use std::sync::Arc; +use alloc::sync::Arc; +use anyhow::Result; +use core::ops::{Deref, DerefMut, Range}; +#[cfg(feature = "std")] +use std::{fs::File, path::Path}; /// A type akin to `Vec`, but backed by `mmap` and able to be split. /// @@ -61,7 +62,10 @@ impl MmapVec { /// then use that file to learn about its size and map the full contents /// into memory. This will return an error if the file doesn't exist or if /// it's too large to be fully mapped into memory. + #[cfg(feature = "std")] pub fn from_file(path: &Path) -> Result { + use anyhow::Context; + let mmap = Mmap::from_file(path) .with_context(|| format!("failed to create mmap for file: {}", path.display()))?; let len = mmap.len(); @@ -91,6 +95,7 @@ impl MmapVec { } /// Returns the underlying file that this mmap is mapping, if present. + #[cfg(feature = "std")] pub fn original_file(&self) -> Option<&Arc> { self.mmap.original_file() } @@ -132,7 +137,7 @@ impl DerefMut for MmapVec { // mutable access to these bytes if so desired. unsafe { let slice = - std::slice::from_raw_parts_mut(self.mmap.as_ptr().cast_mut(), self.mmap.len()); + core::slice::from_raw_parts_mut(self.mmap.as_ptr().cast_mut(), self.mmap.len()); &mut slice[self.range.clone()] } } diff --git a/crates/wasmtime/src/runtime/vm/module_id.rs b/crates/wasmtime/src/runtime/vm/module_id.rs index 3c5ed7adf193..899e8f43e50b 100644 --- a/crates/wasmtime/src/runtime/vm/module_id.rs +++ b/crates/wasmtime/src/runtime/vm/module_id.rs @@ -1,6 +1,6 @@ //! Unique IDs for modules in the runtime. -use std::{ +use core::{ num::NonZeroU64, sync::atomic::{AtomicU64, Ordering}, }; diff --git a/crates/wasmtime/src/runtime/vm/mpk/enabled.rs b/crates/wasmtime/src/runtime/vm/mpk/enabled.rs index c6bd9af345bb..504d2d3851b7 100644 --- a/crates/wasmtime/src/runtime/vm/mpk/enabled.rs +++ b/crates/wasmtime/src/runtime/vm/mpk/enabled.rs @@ -1,6 +1,7 @@ //! use super::{pkru, sys}; +use crate::prelude::*; use anyhow::{Context, Result}; use std::sync::OnceLock; diff --git a/crates/wasmtime/src/runtime/vm/mpk/mod.rs b/crates/wasmtime/src/runtime/vm/mpk/mod.rs index a5a65d3b73f2..d778c39dc6f8 100644 --- a/crates/wasmtime/src/runtime/vm/mpk/mod.rs +++ b/crates/wasmtime/src/runtime/vm/mpk/mod.rs @@ -30,7 +30,7 @@ //! the public interface. cfg_if::cfg_if! { - if #[cfg(all(target_arch = "x86_64", target_os = "linux", not(miri)))] { + if #[cfg(all(target_arch = "x86_64", target_os = "linux", feature = "std", not(miri)))] { mod enabled; mod pkru; mod sys; diff --git a/crates/wasmtime/src/runtime/vm/mpk/pkru.rs b/crates/wasmtime/src/runtime/vm/mpk/pkru.rs index acf017bece14..43751d9cd8ee 100644 --- a/crates/wasmtime/src/runtime/vm/mpk/pkru.rs +++ b/crates/wasmtime/src/runtime/vm/mpk/pkru.rs @@ -60,7 +60,7 @@ pub fn write(pkru: u32) { /// only set on Intel CPUs, so this function also checks the `CPUID` vendor /// string. pub fn has_cpuid_bit_set() -> bool { - let result = unsafe { std::arch::x86_64::__cpuid(0x07) }; + let result = unsafe { core::arch::x86_64::__cpuid(0x07) }; is_intel_cpu() && (result.ecx & 0b1000) != 0 } @@ -69,7 +69,7 @@ pub fn has_cpuid_bit_set() -> bool { pub fn is_intel_cpu() -> bool { // To read the CPU vendor string, we pass 0 in EAX and read 12 ASCII bytes // from EBX, EDX, and ECX (in that order). - let result = unsafe { std::arch::x86_64::__cpuid(0) }; + let result = unsafe { core::arch::x86_64::__cpuid(0) }; // Then we check if the vendor string matches "GenuineIntel". result.ebx == u32::from_le_bytes(*b"Genu") && result.edx == u32::from_le_bytes(*b"ineI") diff --git a/crates/wasmtime/src/runtime/vm/mpk/sys.rs b/crates/wasmtime/src/runtime/vm/mpk/sys.rs index acf503adf630..833d97c18fe7 100644 --- a/crates/wasmtime/src/runtime/vm/mpk/sys.rs +++ b/crates/wasmtime/src/runtime/vm/mpk/sys.rs @@ -74,6 +74,7 @@ pub fn pkey_mprotect(addr: usize, len: usize, prot: u32, key: u32) -> Result<()> #[cfg(test)] mod tests { use super::*; + use crate::prelude::*; #[ignore = "cannot be run when keys() has already allocated all keys"] #[test] diff --git a/crates/wasmtime/src/runtime/vm/send_sync_ptr.rs b/crates/wasmtime/src/runtime/vm/send_sync_ptr.rs index f4975fef022c..f2bb45a7a4f8 100644 --- a/crates/wasmtime/src/runtime/vm/send_sync_ptr.rs +++ b/crates/wasmtime/src/runtime/vm/send_sync_ptr.rs @@ -1,6 +1,6 @@ -use std::fmt; -use std::hash::Hash; -use std::ptr::NonNull; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::ptr::{self, NonNull}; /// A helper type in Wasmtime to store a raw pointer to `T` while automatically /// inferring the `Send` and `Sync` traits for the container based on the @@ -93,14 +93,14 @@ impl Copy for SendSyncPtr {} impl PartialEq for SendSyncPtr { #[inline] fn eq(&self, other: &SendSyncPtr) -> bool { - std::ptr::eq(self.0.as_ptr(), other.0.as_ptr()) + ptr::eq(self.0.as_ptr(), other.0.as_ptr()) } } impl Eq for SendSyncPtr {} impl Hash for SendSyncPtr { - fn hash(&self, state: &mut H) { + fn hash(&self, state: &mut H) { self.as_ptr().hash(state); } } diff --git a/crates/wasmtime/src/runtime/vm/store_box.rs b/crates/wasmtime/src/runtime/vm/store_box.rs index 00929e540a65..21ac0cdfa14e 100644 --- a/crates/wasmtime/src/runtime/vm/store_box.rs +++ b/crates/wasmtime/src/runtime/vm/store_box.rs @@ -1,3 +1,5 @@ +use crate::prelude::*; + /// A `Box` lookalike for memory that's stored in a `Store` /// /// This is intended to be quite similar to a `Box` except without the diff --git a/crates/wasmtime/src/runtime/vm/sys/custom/capi.rs b/crates/wasmtime/src/runtime/vm/sys/custom/capi.rs index 0afc7774e059..6dd0d5c24d94 100644 --- a/crates/wasmtime/src/runtime/vm/sys/custom/capi.rs +++ b/crates/wasmtime/src/runtime/vm/sys/custom/capi.rs @@ -186,4 +186,15 @@ extern "C" { /// Note that mappings created from this image are not guaranteed to be /// deallocated and/or unmapped before this is called. pub fn wasmtime_memory_image_free(image: *mut wasmtime_memory_image); + + /// Wasmtime requires a single pointer's space of TLS to be used at runtime, + /// and this function returns the current value of the TLS variable. + /// + /// This value should default to `NULL`. + pub fn wasmtime_tls_get() -> *mut u8; + + /// Sets the current TLS value for Wasmtime to the provided value. + /// + /// This value should be returned when later calling `wasmtime_tls_get`. + pub fn wasmtime_tls_set(ptr: *mut u8); } diff --git a/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs index 69d3f20aa5df..de3f6bf66b93 100644 --- a/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs @@ -1,11 +1,11 @@ use super::cvt; use crate::runtime::vm::sys::capi; use crate::runtime::vm::SendSyncPtr; -use anyhow::{bail, Result}; -use std::fs::File; -use std::ops::Range; -use std::path::Path; -use std::ptr::{self, NonNull}; +use anyhow::Result; +use core::ops::Range; +use core::ptr::{self, NonNull}; +#[cfg(feature = "std")] +use std::{fs::File, path::Path}; #[derive(Debug)] pub struct Mmap { @@ -24,7 +24,7 @@ impl Mmap { cvt(unsafe { capi::wasmtime_mmap_new(size, capi::PROT_READ | capi::PROT_WRITE, &mut ptr) })?; - let memory = std::ptr::slice_from_raw_parts_mut(ptr.cast(), size); + let memory = ptr::slice_from_raw_parts_mut(ptr.cast(), size); let memory = SendSyncPtr::new(NonNull::new(memory).unwrap()); Ok(Mmap { memory }) } @@ -32,13 +32,14 @@ impl Mmap { pub fn reserve(size: usize) -> Result { let mut ptr = ptr::null_mut(); cvt(unsafe { capi::wasmtime_mmap_new(size, 0, &mut ptr) })?; - let memory = std::ptr::slice_from_raw_parts_mut(ptr.cast(), size); + let memory = ptr::slice_from_raw_parts_mut(ptr.cast(), size); let memory = SendSyncPtr::new(NonNull::new(memory).unwrap()); Ok(Mmap { memory }) } + #[cfg(feature = "std")] pub fn from_file(_path: &Path) -> Result<(Self, File)> { - bail!("not supported on this platform"); + anyhow::bail!("not supported on this platform"); } pub fn make_accessible(&mut self, start: usize, len: usize) -> Result<()> { diff --git a/crates/wasmtime/src/runtime/vm/sys/custom/mod.rs b/crates/wasmtime/src/runtime/vm/sys/custom/mod.rs index 31de2a3cc5ad..d60c86e06c21 100644 --- a/crates/wasmtime/src/runtime/vm/sys/custom/mod.rs +++ b/crates/wasmtime/src/runtime/vm/sys/custom/mod.rs @@ -8,7 +8,7 @@ //! For more information about this see `./examples/min-platform` as well as //! `./docs/examples-minimal.md`. -use std::io; +use anyhow::{bail, Result}; pub mod capi; pub mod mmap; @@ -16,9 +16,19 @@ pub mod traphandlers; pub mod unwind; pub mod vm; -fn cvt(rc: i32) -> io::Result<()> { +fn cvt(rc: i32) -> Result<()> { match rc { 0 => Ok(()), - code => Err(io::Error::from_raw_os_error(code)), + code => bail!("os error {code}"), } } + +#[inline] +pub fn tls_get() -> *mut u8 { + unsafe { capi::wasmtime_tls_get() } +} + +#[inline] +pub fn tls_set(ptr: *mut u8) { + unsafe { capi::wasmtime_tls_set(ptr) } +} diff --git a/crates/wasmtime/src/runtime/vm/sys/custom/traphandlers.rs b/crates/wasmtime/src/runtime/vm/sys/custom/traphandlers.rs index c48f09b71fa8..493faac1a629 100644 --- a/crates/wasmtime/src/runtime/vm/sys/custom/traphandlers.rs +++ b/crates/wasmtime/src/runtime/vm/sys/custom/traphandlers.rs @@ -1,6 +1,6 @@ use crate::runtime::vm::traphandlers::{tls, TrapTest}; use crate::runtime::vm::VMContext; -use std::mem; +use core::mem; pub use crate::runtime::vm::sys::capi::{self, wasmtime_longjmp}; diff --git a/crates/wasmtime/src/runtime/vm/sys/custom/vm.rs b/crates/wasmtime/src/runtime/vm/sys/custom/vm.rs index 530f47157eb6..11534e6e9df1 100644 --- a/crates/wasmtime/src/runtime/vm/sys/custom/vm.rs +++ b/crates/wasmtime/src/runtime/vm/sys/custom/vm.rs @@ -1,12 +1,12 @@ use super::cvt; use crate::runtime::vm::sys::capi; use crate::runtime::vm::SendSyncPtr; -use std::fs::File; -use std::io; -use std::ptr::{self, NonNull}; -use std::sync::Arc; +use anyhow::Result; +use core::ptr::{self, NonNull}; +#[cfg(feature = "std")] +use std::{fs::File, sync::Arc}; -pub unsafe fn expose_existing_mapping(ptr: *mut u8, len: usize) -> io::Result<()> { +pub unsafe fn expose_existing_mapping(ptr: *mut u8, len: usize) -> Result<()> { cvt(capi::wasmtime_mprotect( ptr.cast(), len, @@ -14,23 +14,23 @@ pub unsafe fn expose_existing_mapping(ptr: *mut u8, len: usize) -> io::Result<() )) } -pub unsafe fn hide_existing_mapping(ptr: *mut u8, len: usize) -> io::Result<()> { +pub unsafe fn hide_existing_mapping(ptr: *mut u8, len: usize) -> Result<()> { cvt(capi::wasmtime_mprotect(ptr.cast(), len, 0)) } -pub unsafe fn erase_existing_mapping(ptr: *mut u8, len: usize) -> io::Result<()> { +pub unsafe fn erase_existing_mapping(ptr: *mut u8, len: usize) -> Result<()> { cvt(capi::wasmtime_mmap_remap(ptr.cast(), len, 0)) } #[cfg(feature = "pooling-allocator")] -pub unsafe fn commit_table_pages(_addr: *mut u8, _len: usize) -> io::Result<()> { +pub unsafe fn commit_table_pages(_addr: *mut u8, _len: usize) -> Result<()> { // Table pages are always READ | WRITE so there's nothing that needs to be // done here. Ok(()) } #[cfg(feature = "pooling-allocator")] -pub unsafe fn decommit_table_pages(addr: *mut u8, len: usize) -> io::Result<()> { +pub unsafe fn decommit_table_pages(addr: *mut u8, len: usize) -> Result<()> { if len == 0 { return Ok(()); } @@ -50,7 +50,7 @@ pub fn supports_madvise_dontneed() -> bool { false } -pub unsafe fn madvise_dontneed(_ptr: *mut u8, _len: usize) -> io::Result<()> { +pub unsafe fn madvise_dontneed(_ptr: *mut u8, _len: usize) -> Result<()> { unreachable!() } @@ -60,11 +60,12 @@ pub struct MemoryImageSource { } impl MemoryImageSource { + #[cfg(feature = "std")] pub fn from_file(_file: &Arc) -> Option { None } - pub fn from_data(data: &[u8]) -> io::Result> { + pub fn from_data(data: &[u8]) -> Result> { unsafe { let mut ptr = ptr::null_mut(); cvt(capi::wasmtime_memory_image_new( @@ -81,7 +82,7 @@ impl MemoryImageSource { } } - pub unsafe fn map_at(&self, base: *mut u8, len: usize, offset: u64) -> io::Result<()> { + pub unsafe fn map_at(&self, base: *mut u8, len: usize, offset: u64) -> Result<()> { assert_eq!(offset, 0); cvt(capi::wasmtime_memory_image_map_at( self.data.as_ptr(), @@ -90,7 +91,7 @@ impl MemoryImageSource { )) } - pub unsafe fn remap_as_zeros_at(&self, base: *mut u8, len: usize) -> io::Result<()> { + pub unsafe fn remap_as_zeros_at(&self, base: *mut u8, len: usize) -> Result<()> { cvt(capi::wasmtime_mmap_remap( base.cast(), len, diff --git a/crates/wasmtime/src/runtime/vm/sys/miri/mod.rs b/crates/wasmtime/src/runtime/vm/sys/miri/mod.rs index 76cf11e686ae..cf953c365a30 100644 --- a/crates/wasmtime/src/runtime/vm/sys/miri/mod.rs +++ b/crates/wasmtime/src/runtime/vm/sys/miri/mod.rs @@ -4,7 +4,21 @@ //! notably WebAssembly tests are not executed at this time (MIRI can't execute //! Cranelift-generated code). +use std::cell::Cell; + pub mod mmap; pub mod traphandlers; pub mod unwind; pub mod vm; + +std::thread_local!(static TLS: Cell<*mut u8> = const { Cell::new(std::ptr::null_mut()) }); + +#[inline] +pub fn tls_get() -> *mut u8 { + TLS.with(|p| p.get()) +} + +#[inline] +pub fn tls_set(ptr: *mut u8) { + TLS.with(|p| p.set(ptr)); +} diff --git a/crates/wasmtime/src/runtime/vm/sys/mod.rs b/crates/wasmtime/src/runtime/vm/sys/mod.rs index 841b26444603..22f371f5711d 100644 --- a/crates/wasmtime/src/runtime/vm/sys/mod.rs +++ b/crates/wasmtime/src/runtime/vm/sys/mod.rs @@ -18,16 +18,8 @@ cfg_if::cfg_if! { } else if #[cfg(unix)] { mod unix; pub use unix::*; - } else if #[cfg(wasmtime_custom_platform)] { + } else { mod custom; pub use custom::*; - } else { - compile_error!( - "Wasmtime is being compiled for a platform \ - that it does not support. If this platform is \ - one you would like to see supported you may file an \ - issue on Wasmtime's issue tracker: \ - https://github.com/bytecodealliance/wasmtime/issues/new\ - "); } } diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs index ec3b06b34f16..65c5df38697d 100644 --- a/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs @@ -1,10 +1,11 @@ +use crate::prelude::*; use crate::runtime::vm::SendSyncPtr; -use anyhow::{anyhow, Context, Result}; +use anyhow::Result; use rustix::mm::{mprotect, MprotectFlags}; -use std::fs::File; use std::ops::Range; -use std::path::Path; use std::ptr::{self, NonNull}; +#[cfg(feature = "std")] +use std::{fs::File, path::Path}; #[derive(Debug)] pub struct Mmap { @@ -25,7 +26,8 @@ impl Mmap { size, rustix::mm::ProtFlags::READ | rustix::mm::ProtFlags::WRITE, rustix::mm::MapFlags::PRIVATE, - )? + ) + .err2anyhow()? }; let memory = std::ptr::slice_from_raw_parts_mut(ptr.cast(), size); let memory = SendSyncPtr::new(NonNull::new(memory).unwrap()); @@ -39,7 +41,8 @@ impl Mmap { size, rustix::mm::ProtFlags::empty(), rustix::mm::MapFlags::PRIVATE, - )? + ) + .err2anyhow()? }; let memory = std::ptr::slice_from_raw_parts_mut(ptr.cast(), size); @@ -47,13 +50,19 @@ impl Mmap { Ok(Mmap { memory }) } + #[cfg(feature = "std")] pub fn from_file(path: &Path) -> Result<(Self, File)> { - let file = File::open(path).context("failed to open file")?; + use anyhow::Context; + + let file = File::open(path) + .err2anyhow() + .context("failed to open file")?; let len = file .metadata() + .err2anyhow() .context("failed to get file metadata")? .len(); - let len = usize::try_from(len).map_err(|_| anyhow!("file too large to map"))?; + let len = usize::try_from(len).map_err(|_| anyhow::anyhow!("file too large to map"))?; let ptr = unsafe { rustix::mm::mmap( ptr::null_mut(), @@ -63,6 +72,7 @@ impl Mmap { &file, 0, ) + .err2anyhow() .context(format!("mmap failed to allocate {:#x} bytes", len))? }; let memory = std::ptr::slice_from_raw_parts_mut(ptr.cast(), len); @@ -78,7 +88,8 @@ impl Mmap { ptr.byte_add(start).cast(), len, MprotectFlags::READ | MprotectFlags::WRITE, - )?; + ) + .err2anyhow()?; } Ok(()) @@ -122,7 +133,7 @@ impl Mmap { flags }; - mprotect(base, len, flags)?; + mprotect(base, len, flags).err2anyhow()?; Ok(()) } @@ -131,7 +142,7 @@ impl Mmap { let base = self.memory.as_ptr().byte_add(range.start).cast(); let len = range.end - range.start; - mprotect(base, len, MprotectFlags::READ)?; + mprotect(base, len, MprotectFlags::READ).err2anyhow()?; Ok(()) } diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/mod.rs b/crates/wasmtime/src/runtime/vm/sys/unix/mod.rs index f124598acf7d..92bcbc9149a0 100644 --- a/crates/wasmtime/src/runtime/vm/sys/unix/mod.rs +++ b/crates/wasmtime/src/runtime/vm/sys/unix/mod.rs @@ -3,6 +3,8 @@ //! //! This module handles Linux and macOS for example. +use core::cell::Cell; + pub mod mmap; pub mod unwind; pub mod vm; @@ -19,3 +21,15 @@ cfg_if::cfg_if! { pub use signals as traphandlers; } } + +std::thread_local!(static TLS: Cell<*mut u8> = const { Cell::new(std::ptr::null_mut()) }); + +#[inline] +pub fn tls_get() -> *mut u8 { + TLS.with(|p| p.get()) +} + +#[inline] +pub fn tls_set(ptr: *mut u8) { + TLS.with(|p| p.set(ptr)); +} diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs b/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs index 44634476e4ca..520fc673a9b0 100644 --- a/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs +++ b/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs @@ -308,7 +308,7 @@ pub fn lazy_per_thread_init() { // This thread local is purely used to register a `Stack` to get deallocated // when the thread exists. Otherwise this function is only ever called at // most once per-thread. - thread_local! { + std::thread_local! { static STACK: RefCell> = const { RefCell::new(None) }; } diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/unwind.rs b/crates/wasmtime/src/runtime/vm/sys/unix/unwind.rs index 96cd79d4637b..957dda05e26a 100644 --- a/crates/wasmtime/src/runtime/vm/sys/unix/unwind.rs +++ b/crates/wasmtime/src/runtime/vm/sys/unix/unwind.rs @@ -1,9 +1,10 @@ //! Module for System V ABI unwind registry. +use crate::prelude::*; use crate::runtime::vm::SendSyncPtr; use anyhow::Result; -use std::ptr::{self, NonNull}; -use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; +use core::ptr::{self, NonNull}; +use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; /// Represents a registration of function unwind information for System V ABI. pub struct UnwindRegistration { diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/vm.rs b/crates/wasmtime/src/runtime/vm/sys/unix/vm.rs index d0e76a14567f..ac40b24c324f 100644 --- a/crates/wasmtime/src/runtime/vm/sys/unix/vm.rs +++ b/crates/wasmtime/src/runtime/vm/sys/unix/vm.rs @@ -2,6 +2,7 @@ use rustix::fd::AsRawFd; use rustix::mm::{mmap, mmap_anonymous, mprotect, MapFlags, MprotectFlags, ProtFlags}; use std::fs::File; use std::io; +#[cfg(feature = "std")] use std::sync::Arc; pub unsafe fn expose_existing_mapping(ptr: *mut u8, len: usize) -> io::Result<()> { @@ -103,12 +104,14 @@ pub unsafe fn madvise_dontneed(ptr: *mut u8, len: usize) -> io::Result<()> { #[derive(Debug)] pub enum MemoryImageSource { + #[cfg(feature = "std")] Mmap(Arc), #[cfg(target_os = "linux")] Memfd(memfd::Memfd), } impl MemoryImageSource { + #[cfg(feature = "std")] pub fn from_file(file: &Arc) -> Option { Some(MemoryImageSource::Mmap(file.clone())) } @@ -124,6 +127,7 @@ impl MemoryImageSource { // in-memory file to represent the heap image. This anonymous // file is then used as the basis for further mmaps. + use crate::prelude::*; use std::io::{ErrorKind, Write}; // Create the memfd. It needs a name, but the documentation for @@ -139,9 +143,9 @@ impl MemoryImageSource { Err(memfd::Error::Create(err)) if err.kind() == ErrorKind::Unsupported => { return Ok(None) } - Err(e) => return Err(e.into()), + Err(e) => return Err(e.into_anyhow()), }; - memfd.as_file().write_all(data)?; + memfd.as_file().write_all(data).err2anyhow()?; // Seal the memfd's data and length. // @@ -158,21 +162,24 @@ impl MemoryImageSource { // extra-super-sure that it never changes, and because // this costs very little, we use the kernel's "seal" API // to make the memfd image permanently read-only. - memfd.add_seals(&[ - memfd::FileSeal::SealGrow, - memfd::FileSeal::SealShrink, - memfd::FileSeal::SealWrite, - memfd::FileSeal::SealSeal, - ])?; + memfd + .add_seals(&[ + memfd::FileSeal::SealGrow, + memfd::FileSeal::SealShrink, + memfd::FileSeal::SealWrite, + memfd::FileSeal::SealSeal, + ]) + .err2anyhow()?; Ok(Some(MemoryImageSource::Memfd(memfd))) } fn as_file(&self) -> &File { - match self { - MemoryImageSource::Mmap(file) => file, + match *self { + #[cfg(feature = "std")] + MemoryImageSource::Mmap(ref file) => file, #[cfg(target_os = "linux")] - MemoryImageSource::Memfd(memfd) => memfd.as_file(), + MemoryImageSource::Memfd(ref memfd) => memfd.as_file(), } } diff --git a/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs index 6dc3e61dd3d5..e9d156b48fa2 100644 --- a/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use crate::runtime::vm::SendSyncPtr; use anyhow::{anyhow, bail, Context, Result}; use std::fs::{File, OpenOptions}; @@ -69,10 +70,12 @@ impl Mmap { .access_mode(FILE_GENERIC_READ | FILE_GENERIC_EXECUTE) .share_mode(FILE_SHARE_READ) .open(path) + .err2anyhow() .context("failed to open file")?; let len = file .metadata() + .err2anyhow() .context("failed to get file metadata")? .len(); let len = usize::try_from(len).map_err(|_| anyhow!("file too large to map"))?; @@ -92,7 +95,8 @@ impl Mmap { ptr::null(), ); if mapping == 0 { - return Err(io::Error::last_os_error()).context("failed to create file mapping"); + return Err(io::Error::last_os_error().into_anyhow()) + .context("failed to create file mapping"); } // Create a view for the entire file using all our requisite @@ -109,7 +113,8 @@ impl Mmap { let err = io::Error::last_os_error(); CloseHandle(mapping); if ptr.is_null() { - return Err(err).context(format!("failed to create map view of {:#x} bytes", len)); + return Err(err.into_anyhow()) + .context(format!("failed to create map view of {:#x} bytes", len)); } let memory = std::ptr::slice_from_raw_parts_mut(ptr.cast(), len); @@ -123,7 +128,7 @@ impl Mmap { // remove the execute bit) let mut old = 0; if VirtualProtect(ret.as_mut_ptr().cast(), ret.len(), PAGE_WRITECOPY, &mut old) == 0 { - return Err(io::Error::last_os_error()) + return Err(io::Error::last_os_error().into_anyhow()) .context("failed change pages to `PAGE_READONLY`"); } diff --git a/crates/wasmtime/src/runtime/vm/sys/windows/mod.rs b/crates/wasmtime/src/runtime/vm/sys/windows/mod.rs index d055ef6926aa..0ecc7295c99b 100644 --- a/crates/wasmtime/src/runtime/vm/sys/windows/mod.rs +++ b/crates/wasmtime/src/runtime/vm/sys/windows/mod.rs @@ -1,6 +1,20 @@ //! Implementation of Wasmtime's system primitives for Windows. +use std::cell::Cell; + pub mod mmap; pub mod traphandlers; pub mod unwind; pub mod vm; + +std::thread_local!(static TLS: Cell<*mut u8> = const { Cell::new(std::ptr::null_mut()) }); + +#[inline] +pub fn tls_get() -> *mut u8 { + TLS.with(|p| p.get()) +} + +#[inline] +pub fn tls_set(ptr: *mut u8) { + TLS.with(|p| p.set(ptr)); +} diff --git a/crates/wasmtime/src/runtime/vm/table.rs b/crates/wasmtime/src/runtime/vm/table.rs index f38f9f3698d3..8f826f310f6a 100644 --- a/crates/wasmtime/src/runtime/vm/table.rs +++ b/crates/wasmtime/src/runtime/vm/table.rs @@ -4,12 +4,15 @@ #![cfg_attr(feature = "gc", allow(irrefutable_let_patterns))] +use crate::prelude::*; use crate::runtime::vm::vmcontext::{VMFuncRef, VMTableDefinition}; use crate::runtime::vm::{GcStore, SendSyncPtr, Store, VMGcRef}; use anyhow::{bail, ensure, format_err, Error, Result}; +use core::cmp; +use core::ops::Range; +use core::ptr::{self, NonNull}; +use core::slice; use sptr::Strict; -use std::ops::Range; -use std::ptr::{self, NonNull}; use wasmtime_environ::{ TablePlan, Trap, WasmHeapTopType, WasmRefType, FUNCREF_INIT_BIT, FUNCREF_MASK, }; @@ -302,7 +305,7 @@ impl Table { ); let data = SendSyncPtr::new(NonNull::slice_from_raw_parts( data.as_non_null().cast::(), - std::cmp::min(len, max), + cmp::min(len, max), )); Ok(Self::from(StaticFuncTable { data, size })) } @@ -322,7 +325,7 @@ impl Table { ); let data = SendSyncPtr::new(NonNull::slice_from_raw_parts( data.as_non_null().cast::>(), - std::cmp::min(len, max), + cmp::min(len, max), )); Ok(Self::from(StaticGcRefTable { data, size })) } @@ -705,10 +708,10 @@ impl Table { assert_eq!(self.element_type(), TableElementType::Func); match self { Self::Dynamic(DynamicTable::Func(DynamicFuncTable { elements, .. })) => unsafe { - std::slice::from_raw_parts(elements.as_ptr().cast(), elements.len()) + slice::from_raw_parts(elements.as_ptr().cast(), elements.len()) }, Self::Static(StaticTable::Func(StaticFuncTable { data, size })) => unsafe { - std::slice::from_raw_parts(data.as_ptr().cast(), usize::try_from(*size).unwrap()) + slice::from_raw_parts(data.as_ptr().cast(), usize::try_from(*size).unwrap()) }, _ => unreachable!(), } @@ -718,13 +721,10 @@ impl Table { assert_eq!(self.element_type(), TableElementType::Func); match self { Self::Dynamic(DynamicTable::Func(DynamicFuncTable { elements, .. })) => unsafe { - std::slice::from_raw_parts_mut(elements.as_mut_ptr().cast(), elements.len()) + slice::from_raw_parts_mut(elements.as_mut_ptr().cast(), elements.len()) }, Self::Static(StaticTable::Func(StaticFuncTable { data, size })) => unsafe { - std::slice::from_raw_parts_mut( - data.as_ptr().cast(), - usize::try_from(*size).unwrap(), - ) + slice::from_raw_parts_mut(data.as_ptr().cast(), usize::try_from(*size).unwrap()) }, _ => unreachable!(), } diff --git a/crates/wasmtime/src/runtime/vm/threads/parking_spot.rs b/crates/wasmtime/src/runtime/vm/threads/parking_spot.rs index 1263f651afae..fc38d71ecb02 100644 --- a/crates/wasmtime/src/runtime/vm/threads/parking_spot.rs +++ b/crates/wasmtime/src/runtime/vm/threads/parking_spot.rs @@ -11,6 +11,7 @@ #![deny(missing_docs)] +use crate::prelude::*; use crate::runtime::vm::{SendSyncPtr, WaitResult}; use std::collections::BTreeMap; use std::ptr::NonNull; @@ -304,6 +305,7 @@ impl Spot { #[cfg(test)] mod tests { use super::{ParkingSpot, Waiter}; + use crate::prelude::*; use std::sync::atomic::{AtomicU64, Ordering}; use std::thread; use std::time::{Duration, Instant}; diff --git a/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs b/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs index 4561ae45e231..5394f685566a 100644 --- a/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs +++ b/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs @@ -1,3 +1,4 @@ +use crate::prelude::*; use crate::runtime::vm::memory::{validate_atomic_addr, MmapMemory}; use crate::runtime::vm::threads::parking_spot::{ParkingSpot, Waiter}; use crate::runtime::vm::vmcontext::VMMemoryDefinition; @@ -8,7 +9,7 @@ use std::cell::RefCell; use std::ops::Range; use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; use std::sync::{Arc, RwLock}; -use std::time::Instant; +use std::time::{Duration, Instant}; use wasmtime_environ::{MemoryPlan, MemoryStyle, Trap}; /// For shared memory (and only for shared memory), this lock-version restricts @@ -126,7 +127,7 @@ impl SharedMemory { &self, addr_index: u64, expected: u32, - timeout: Option, + timeout: Option, ) -> Result { let addr = validate_atomic_addr(&self.0.def.0, addr_index, 4, 4)?; log::trace!( @@ -137,10 +138,11 @@ impl SharedMemory { assert!(std::mem::size_of::() == 4); assert!(std::mem::align_of::() <= 4); let atomic = unsafe { AtomicU32::from_ptr(addr.cast()) }; + let deadline = timeout.map(|d| Instant::now() + d); WAITER.with(|waiter| { let mut waiter = waiter.borrow_mut(); - Ok(self.0.spot.wait32(atomic, expected, timeout, &mut waiter)) + Ok(self.0.spot.wait32(atomic, expected, deadline, &mut waiter)) }) } @@ -149,7 +151,7 @@ impl SharedMemory { &self, addr_index: u64, expected: u64, - timeout: Option, + timeout: Option, ) -> Result { let addr = validate_atomic_addr(&self.0.def.0, addr_index, 8, 8)?; log::trace!( @@ -160,10 +162,11 @@ impl SharedMemory { assert!(std::mem::size_of::() == 8); assert!(std::mem::align_of::() <= 8); let atomic = unsafe { AtomicU64::from_ptr(addr.cast()) }; + let deadline = timeout.map(|d| Instant::now() + d); WAITER.with(|waiter| { let mut waiter = waiter.borrow_mut(); - Ok(self.0.spot.wait64(atomic, expected, timeout, &mut waiter)) + Ok(self.0.spot.wait64(atomic, expected, deadline, &mut waiter)) }) } } diff --git a/crates/wasmtime/src/runtime/vm/threads/shared_memory_disabled.rs b/crates/wasmtime/src/runtime/vm/threads/shared_memory_disabled.rs index 4e106d25c6d0..4b9e8b1d7800 100644 --- a/crates/wasmtime/src/runtime/vm/threads/shared_memory_disabled.rs +++ b/crates/wasmtime/src/runtime/vm/threads/shared_memory_disabled.rs @@ -1,9 +1,10 @@ #![allow(missing_docs)] +use crate::prelude::*; use crate::runtime::vm::{RuntimeLinearMemory, Store, VMMemoryDefinition, WaitResult}; use anyhow::{bail, Result}; -use std::ops::Range; -use std::time::Instant; +use core::ops::Range; +use core::time::Duration; use wasmtime_environ::{MemoryPlan, Trap}; #[derive(Clone)] @@ -46,7 +47,7 @@ impl SharedMemory { &self, _addr_index: u64, _expected: u32, - _timeout: Option, + _timeout: Option, ) -> Result { match *self {} } @@ -55,7 +56,7 @@ impl SharedMemory { &self, _addr_index: u64, _expected: u64, - _timeout: Option, + _timeout: Option, ) -> Result { match *self {} } @@ -90,7 +91,7 @@ impl RuntimeLinearMemory for SharedMemory { match *self {} } - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + fn as_any_mut(&mut self) -> &mut dyn core::any::Any { match *self {} } diff --git a/crates/wasmtime/src/runtime/vm/traphandlers.rs b/crates/wasmtime/src/runtime/vm/traphandlers.rs index 4aa02cef328e..e3b414db8024 100644 --- a/crates/wasmtime/src/runtime/vm/traphandlers.rs +++ b/crates/wasmtime/src/runtime/vm/traphandlers.rs @@ -10,13 +10,14 @@ mod coredump; #[path = "traphandlers/coredump_disabled.rs"] mod coredump; +use crate::prelude::*; use crate::runtime::vm::sys::traphandlers; use crate::runtime::vm::{Instance, VMContext, VMRuntimeLimits}; +use crate::sync::OnceLock; use anyhow::Error; -use std::cell::{Cell, UnsafeCell}; -use std::mem::MaybeUninit; -use std::ptr; -use std::sync::Once; +use core::cell::{Cell, UnsafeCell}; +use core::mem::MaybeUninit; +use core::ptr; pub use self::backtrace::Backtrace; pub use self::coredump::CoreDumpStack; @@ -35,22 +36,25 @@ pub(crate) static mut GET_WASM_TRAP: fn(usize) -> Option /// This will configure global state such as signal handlers to prepare the /// process to receive wasm traps. /// -/// This function must not only be called globally once before entering -/// WebAssembly but it must also be called once-per-thread that enters -/// WebAssembly. Currently in wasmtime's integration this function is called on -/// creation of a `Engine`. -/// -/// The `is_wasm_pc` argument is used when a trap happens to determine if a +/// The `get_wasm_trap` argument is used when a trap happens to determine if a /// program counter is the pc of an actual wasm trap or not. This is then used /// to disambiguate faults that happen due to wasm and faults that happen due to /// bugs in Rust or elsewhere. +/// +/// # Panics +/// +/// This function will panic on macOS if it is called twice or more times with +/// different values of `macos_use_mach_ports`. +/// +/// This function will also panic if the `std` feature is disabled and it's +/// called concurrently. pub fn init_traps( get_wasm_trap: fn(usize) -> Option, macos_use_mach_ports: bool, ) { - static INIT: Once = Once::new(); + static INIT: OnceLock<()> = OnceLock::new(); - INIT.call_once(|| unsafe { + INIT.get_or_init(|| unsafe { GET_WASM_TRAP = get_wasm_trap; traphandlers::platform_init(macos_use_mach_ports); }); @@ -114,7 +118,7 @@ pub unsafe fn raise_user_trap(error: Error, needs_backtrace: bool) -> ! { pub unsafe fn catch_unwind_and_longjmp(f: impl FnOnce() -> R) -> R { // With `panic=unwind` use `std::panic::catch_unwind` to catch possible // panics to rethrow. - #[cfg(panic = "unwind")] + #[cfg(all(feature = "std", panic = "unwind"))] { match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) { Ok(ret) => ret, @@ -126,7 +130,7 @@ pub unsafe fn catch_unwind_and_longjmp(f: impl FnOnce() -> R) -> R { // since it won't actually catch anything. Note that // `std::panic::catch_unwind` will technically optimize to this but having // this branch avoids using the `std::panic` module entirely. - #[cfg(not(panic = "unwind"))] + #[cfg(not(all(feature = "std", panic = "unwind")))] { f() } @@ -252,7 +256,7 @@ where backtrace, coredumpstack, })), - #[cfg(panic = "unwind")] + #[cfg(all(feature = "std", panic = "unwind"))] Err((UnwindReason::Panic(panic), _, _)) => std::panic::resume_unwind(panic), }; @@ -362,14 +366,14 @@ mod call_thread_state { pub(crate) unsafe fn pop(&self) { let prev = self.prev.replace(ptr::null()); let head = tls::raw::replace(prev); - assert!(std::ptr::eq(head, self)); + assert!(core::ptr::eq(head, self)); } } } pub use call_thread_state::*; enum UnwindReason { - #[cfg(panic = "unwind")] + #[cfg(all(feature = "std", panic = "unwind"))] Panic(Box), Trap(TrapReason), } @@ -399,7 +403,7 @@ impl CallThreadState { // hypothetical backtrace to and it doesn't really make sense to try // in the first place since this is a Rust problem rather than a // Wasm problem. - #[cfg(panic = "unwind")] + #[cfg(all(feature = "std", panic = "unwind"))] UnwindReason::Panic(_) => (None, None), // And if we are just propagating an existing trap that already has // a backtrace attached to it, then there is no need to capture a @@ -511,7 +515,7 @@ impl CallThreadState { pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { let mut state = Some(self); - std::iter::from_fn(move || { + core::iter::from_fn(move || { let this = state?; state = unsafe { this.prev().as_ref() }; Some(this) @@ -526,8 +530,8 @@ impl CallThreadState { // the caller to the trap site. pub(crate) mod tls { use super::CallThreadState; - use std::mem; - use std::ops::Range; + use core::mem; + use core::ops::Range; pub use raw::Ptr; @@ -547,32 +551,40 @@ pub(crate) mod tls { // these functions are free to be inlined. pub(super) mod raw { use super::CallThreadState; - use std::cell::Cell; - use std::ptr; + use sptr::Strict; pub type Ptr = *const CallThreadState; - // The first entry here is the `Ptr` which is what's used as part of the - // public interface of this module. The second entry is a boolean which - // allows the runtime to perform per-thread initialization if necessary - // for handling traps (e.g. setting up ports on macOS and sigaltstack on - // Unix). - thread_local!(static PTR: Cell<(Ptr, bool)> = const { Cell::new((ptr::null(), false)) }); + const _: () = { + assert!(core::mem::align_of::() > 1); + }; + + fn tls_get() -> (Ptr, bool) { + let mut initialized = false; + let p = Strict::map_addr(crate::runtime::vm::sys::tls_get(), |a| { + initialized = (a & 1) != 0; + a & !1 + }); + (p.cast(), initialized) + } + + fn tls_set(ptr: Ptr, initialized: bool) { + let encoded = Strict::map_addr(ptr, |a| a | usize::from(initialized)); + crate::runtime::vm::sys::tls_set(encoded.cast_mut().cast::()); + } #[cfg_attr(feature = "async", inline(never))] // see module docs #[cfg_attr(not(feature = "async"), inline)] pub fn replace(val: Ptr) -> Ptr { - PTR.with(|p| { - // When a new value is configured that means that we may be - // entering WebAssembly so check to see if this thread has - // performed per-thread initialization for traps. - let (prev, initialized) = p.get(); - if !initialized { - super::super::lazy_per_thread_init(); - } - p.set((val, true)); - prev - }) + // When a new value is configured that means that we may be + // entering WebAssembly so check to see if this thread has + // performed per-thread initialization for traps. + let (prev, initialized) = tls_get(); + if !initialized { + super::super::lazy_per_thread_init(); + } + tls_set(val, true); + prev } /// Eagerly initialize thread-local runtime functionality. This will be performed @@ -580,20 +592,18 @@ pub(crate) mod tls { #[cfg_attr(feature = "async", inline(never))] // see module docs #[cfg_attr(not(feature = "async"), inline)] pub fn initialize() { - PTR.with(|p| { - let (state, initialized) = p.get(); - if initialized { - return; - } - super::super::lazy_per_thread_init(); - p.set((state, true)); - }) + let (state, initialized) = tls_get(); + if initialized { + return; + } + super::super::lazy_per_thread_init(); + tls_set(state, true); } #[cfg_attr(feature = "async", inline(never))] // see module docs #[cfg_attr(not(feature = "async"), inline)] pub fn get() -> Ptr { - PTR.with(|p| p.get().0) + tls_get().0 } } @@ -617,7 +627,7 @@ pub(crate) mod tls { /// Creates new state that initially starts as null. pub fn new() -> AsyncWasmCallState { AsyncWasmCallState { - state: std::ptr::null_mut(), + state: core::ptr::null_mut(), } } @@ -646,7 +656,7 @@ pub(crate) mod tls { let ret = PreviousAsyncWasmCallState { state: raw::get() }; let mut ptr = self.state; while let Some(state) = ptr.as_ref() { - ptr = state.prev.replace(std::ptr::null_mut()); + ptr = state.prev.replace(core::ptr::null_mut()); state.push(); } ret diff --git a/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs b/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs index a33757b22ba1..cf589aaf3813 100644 --- a/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs +++ b/crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs @@ -21,12 +21,13 @@ //! exit FP and stopping once we reach the entry SP (meaning that the next older //! frame is a host frame). +use crate::prelude::*; use crate::runtime::vm::arch; use crate::runtime::vm::{ traphandlers::{tls, CallThreadState}, VMRuntimeLimits, }; -use std::ops::ControlFlow; +use core::ops::ControlFlow; /// A WebAssembly stack trace. #[derive(Debug)] @@ -109,7 +110,7 @@ impl Backtrace { // trampoline did not get a chance to save the last Wasm PC and FP, // and we need to use the plumbed-through values instead. Some((pc, fp)) => { - assert!(std::ptr::eq(limits, state.limits)); + assert!(core::ptr::eq(limits, state.limits)); (pc, fp) } // Either there is no Wasm currently on the stack, or we exited Wasm @@ -121,7 +122,7 @@ impl Backtrace { } }; - let activations = std::iter::once(( + let activations = core::iter::once(( last_wasm_exit_pc, last_wasm_exit_fp, *(*limits).last_wasm_entry_sp.get(), @@ -129,7 +130,7 @@ impl Backtrace { .chain( state .iter() - .filter(|state| std::ptr::eq(limits, state.limits)) + .filter(|state| core::ptr::eq(limits, state.limits)) .map(|state| { ( state.old_last_wasm_exit_pc(), diff --git a/crates/wasmtime/src/runtime/vm/traphandlers/coredump_enabled.rs b/crates/wasmtime/src/runtime/vm/traphandlers/coredump_enabled.rs index 21acb1224b36..6d269af67f1c 100644 --- a/crates/wasmtime/src/runtime/vm/traphandlers/coredump_enabled.rs +++ b/crates/wasmtime/src/runtime/vm/traphandlers/coredump_enabled.rs @@ -1,8 +1,7 @@ -use wasm_encoder::CoreDumpValue; - -use crate::runtime::vm::{Backtrace, VMRuntimeLimits}; - use super::CallThreadState; +use crate::prelude::*; +use crate::runtime::vm::{Backtrace, VMRuntimeLimits}; +use wasm_encoder::CoreDumpValue; /// A WebAssembly Coredump #[derive(Debug)] diff --git a/crates/wasmtime/src/runtime/vm/vmcontext.rs b/crates/wasmtime/src/runtime/vm/vmcontext.rs index f9733ba465b5..195449c42888 100644 --- a/crates/wasmtime/src/runtime/vm/vmcontext.rs +++ b/crates/wasmtime/src/runtime/vm/vmcontext.rs @@ -3,16 +3,16 @@ mod vm_host_func_context; +pub use self::vm_host_func_context::{VMArrayCallHostFuncContext, VMNativeCallHostFuncContext}; use crate::runtime::vm::{GcStore, VMGcRef}; +use core::cell::UnsafeCell; +use core::ffi::c_void; +use core::fmt; +use core::marker; +use core::mem; +use core::ptr::{self, NonNull}; +use core::sync::atomic::{AtomicUsize, Ordering}; use sptr::Strict; -use std::cell::UnsafeCell; -use std::ffi::c_void; -use std::marker; -use std::mem; -use std::ptr::{self, NonNull}; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::u32; -pub use vm_host_func_context::{VMArrayCallHostFuncContext, VMNativeCallHostFuncContext}; use wasmtime_environ::{ BuiltinFunctionIndex, DefinedMemoryIndex, Unsigned, VMSharedTypeIndex, WasmHeapTopType, WasmValType, VMCONTEXT_MAGIC, @@ -1100,8 +1100,8 @@ pub union ValRaw { // are some simple assertions about the shape of the type which are additionally // matched in C. const _: () = { - assert!(std::mem::size_of::() == 16); - assert!(std::mem::align_of::() == 8); + assert!(mem::size_of::() == 16); + assert!(mem::align_of::() == 8); }; // This type is just a bag-of-bits so it's up to the caller to figure out how @@ -1109,12 +1109,12 @@ const _: () = { unsafe impl Send for ValRaw {} unsafe impl Sync for ValRaw {} -impl std::fmt::Debug for ValRaw { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Debug for ValRaw { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { struct Hex(T); - impl std::fmt::Debug for Hex { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let bytes = std::mem::size_of::(); + impl fmt::Debug for Hex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let bytes = mem::size_of::(); let hex_digits_per_byte = 2; let hex_digits = bytes * hex_digits_per_byte; write!(f, "0x{:0width$x}", self.0, width = hex_digits) diff --git a/crates/wasmtime/src/runtime/vm/vmcontext/vm_host_func_context.rs b/crates/wasmtime/src/runtime/vm/vmcontext/vm_host_func_context.rs index 2876a37466a0..f9ad69ea63e0 100644 --- a/crates/wasmtime/src/runtime/vm/vmcontext/vm_host_func_context.rs +++ b/crates/wasmtime/src/runtime/vm/vmcontext/vm_host_func_context.rs @@ -3,8 +3,9 @@ //! Keep in sync with `wasmtime_environ::VMHostFuncOffsets`. use super::VMOpaqueContext; +use crate::prelude::*; use crate::runtime::vm::{StoreBox, VMFuncRef}; -use std::any::Any; +use core::any::Any; use wasmtime_environ::{VM_ARRAY_CALL_HOST_FUNC_MAGIC, VM_NATIVE_CALL_HOST_FUNC_MAGIC}; /// The `VM*Context` for array-call host functions. diff --git a/crates/wasmtime/src/runtime/windows.rs b/crates/wasmtime/src/runtime/windows.rs index e746d3a813ab..46022b53803a 100644 --- a/crates/wasmtime/src/runtime/windows.rs +++ b/crates/wasmtime/src/runtime/windows.rs @@ -9,6 +9,7 @@ //! throughout the `wasmtime` crate with extra functionality that's only //! available on Windows. +use crate::prelude::*; use crate::{AsContextMut, Store}; use windows_sys::Win32::System::Diagnostics::Debug::EXCEPTION_POINTERS; diff --git a/crates/wasmtime/src/sync_nostd.rs b/crates/wasmtime/src/sync_nostd.rs new file mode 100644 index 000000000000..cfc7fe27dfb8 --- /dev/null +++ b/crates/wasmtime/src/sync_nostd.rs @@ -0,0 +1,255 @@ +//! Synchronization primitives for Wasmtime for `no_std`. +//! +//! These primitives are intended for use in `no_std` contexts are are not as +//! full-featured as the `std` brethren. Namely these panic and/or return an +//! error on contention. This serves to continue to be correct in the face of +//! actual multiple threads, but if a system actually has multiple threads then +//! something will need to change in the Wasmtime crate to enable the external +//! system to perform necessary synchronization. +//! +//! In the future if these primitives are not suitable we can switch to putting +//! relevant functions in the `capi.rs` module where we basically require +//! embedders to implement them instead of doing it ourselves here. It's unclear +//! if this will be necessary, so this is the chosen starting point. +//! +//! See a brief overview of this module in `sync_std.rs` as well. + +use core::cell::UnsafeCell; +use core::mem::MaybeUninit; +use core::ops::{Deref, DerefMut}; +use core::sync::atomic::{AtomicU32, AtomicU8, Ordering}; + +pub struct OnceLock { + val: UnsafeCell>, + state: AtomicU8, +} + +unsafe impl Send for OnceLock {} +unsafe impl Sync for OnceLock {} + +const UNINITIALIZED: u8 = 0; +const INITIALIZING: u8 = 1; +const INITIALIZED: u8 = 2; + +impl OnceLock { + pub const fn new() -> OnceLock { + OnceLock { + state: AtomicU8::new(UNINITIALIZED), + val: UnsafeCell::new(MaybeUninit::uninit()), + } + } + + pub fn get_or_init(&self, f: impl FnOnce() -> T) -> &T { + if let Some(ret) = self.get() { + return ret; + } + self.try_init::<()>(|| Ok(f())).unwrap() + } + + pub fn get_or_try_init(&self, f: impl FnOnce() -> Result) -> Result<&T, E> { + if let Some(ret) = self.get() { + return Ok(ret); + } + self.try_init(f) + } + + fn get(&self) -> Option<&T> { + if self.state.load(Ordering::Acquire) == INITIALIZED { + Some(unsafe { (*self.val.get()).assume_init_ref() }) + } else { + None + } + } + + #[cold] + fn try_init(&self, f: impl FnOnce() -> Result) -> Result<&T, E> { + match self.state.compare_exchange( + UNINITIALIZED, + INITIALIZING, + Ordering::Acquire, + Ordering::Acquire, + ) { + Ok(UNINITIALIZED) => match f() { + Ok(val) => { + let ret = unsafe { &*(*self.val.get()).write(val) }; + let prev = self.state.swap(INITIALIZED, Ordering::Release); + assert_eq!(prev, INITIALIZING); + Ok(ret) + } + Err(e) => match self.state.swap(UNINITIALIZED, Ordering::Release) { + INITIALIZING => Err(e), + _ => unreachable!(), + }, + }, + Err(INITIALIZING) => panic!("concurrent initialization only allowed with `std`"), + Err(INITIALIZED) => Ok(self.get().unwrap()), + _ => unreachable!(), + } + } +} + +#[derive(Debug, Default)] +pub struct RwLock { + val: UnsafeCell, + state: AtomicU32, +} + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +impl RwLock { + pub const fn new(val: T) -> RwLock { + RwLock { + val: UnsafeCell::new(val), + state: AtomicU32::new(0), + } + } + + pub fn read(&self) -> impl Deref + '_ { + const READER_LIMIT: u32 = u32::MAX / 2; + match self + .state + .fetch_update(Ordering::Acquire, Ordering::Acquire, |x| match x { + u32::MAX => None, + n => { + let next = n + 1; + if next < READER_LIMIT { + Some(next) + } else { + None + } + } + }) { + Ok(_) => RwLockReadGuard { lock: self }, + Err(_) => panic!( + "concurrent read request while locked for writing, must use `std` to avoid panic" + ), + } + } + + pub fn write(&self) -> impl DerefMut + '_ { + match self + .state + .compare_exchange(0, u32::MAX, Ordering::Acquire, Ordering::Relaxed) + { + Ok(0) => RwLockWriteGuard { lock: self }, + _ => panic!("concurrent write request, must use `std` to avoid panicking"), + } + } +} + +struct RwLockReadGuard<'a, T> { + lock: &'a RwLock, +} + +impl Deref for RwLockReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.lock.val.get() } + } +} + +impl Drop for RwLockReadGuard<'_, T> { + fn drop(&mut self) { + self.lock.state.fetch_sub(1, Ordering::Release); + } +} + +struct RwLockWriteGuard<'a, T> { + lock: &'a RwLock, +} + +impl Deref for RwLockWriteGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.lock.val.get() } + } +} + +impl DerefMut for RwLockWriteGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.lock.val.get() } + } +} + +impl Drop for RwLockWriteGuard<'_, T> { + fn drop(&mut self) { + match self.lock.state.swap(0, Ordering::Release) { + u32::MAX => {} + _ => unreachable!(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn smoke_once_lock() { + let lock = OnceLock::new(); + assert!(lock.get().is_none()); + assert_eq!(*lock.get_or_init(|| 1), 1); + assert_eq!(*lock.get_or_init(|| 2), 1); + assert_eq!(*lock.get_or_init(|| 3), 1); + assert_eq!(lock.get_or_try_init::<()>(|| Ok(3)), Ok(&1)); + + let lock = OnceLock::new(); + assert_eq!(lock.get_or_try_init::<()>(|| Ok(3)), Ok(&3)); + assert_eq!(*lock.get_or_init(|| 1), 3); + + let lock = OnceLock::new(); + assert_eq!(lock.get_or_try_init(|| Err(())), Err(())); + assert_eq!(*lock.get_or_init(|| 1), 1); + } + + #[test] + fn smoke_rwlock() { + let lock = RwLock::new(1); + assert_eq!(*lock.read(), 1); + + let a = lock.read(); + let b = lock.read(); + assert_eq!(*a, 1); + assert_eq!(*b, 1); + drop((a, b)); + + assert_eq!(*lock.write(), 1); + + *lock.write() = 4; + assert_eq!(*lock.read(), 4); + assert_eq!(*lock.write(), 4); + + let a = lock.read(); + let b = lock.read(); + assert_eq!(*a, 4); + assert_eq!(*b, 4); + drop((a, b)); + } + + #[test] + #[should_panic(expected = "concurrent write request")] + fn rwlock_panic_read_then_write() { + let lock = RwLock::new(1); + let _a = lock.read(); + let _b = lock.write(); + } + + #[test] + #[should_panic(expected = "concurrent read request")] + fn rwlock_panic_write_then_read() { + let lock = RwLock::new(1); + let _a = lock.write(); + let _b = lock.read(); + } + + #[test] + #[should_panic(expected = "concurrent write request")] + fn rwlock_panic_write_then_write() { + let lock = RwLock::new(1); + let _a = lock.write(); + let _b = lock.write(); + } +} diff --git a/crates/wasmtime/src/sync_std.rs b/crates/wasmtime/src/sync_std.rs new file mode 100644 index 000000000000..73da271fd5cb --- /dev/null +++ b/crates/wasmtime/src/sync_std.rs @@ -0,0 +1,52 @@ +//! Synchronization primitives for Wasmtime. +//! +//! This is a small set of primitives split between std and no_std with "dummy" +//! implementation on no_std. The no_std implementations live in +//! `sync_nostd.rs`. + +use once_cell::sync::OnceCell; +use std::ops::{Deref, DerefMut}; + +/// This type is intended to mirror, and one day be implemented by, the +/// `std::sync::OnceLock` type. At this time +/// `std::sync::OnceLock::get_or_try_init` is not stable so for now this is +/// implemented with the `once_cell` crate instead. +pub struct OnceLock(OnceCell); + +impl OnceLock { + #[inline] + pub const fn new() -> OnceLock { + OnceLock(OnceCell::new()) + } + + #[inline] + pub fn get_or_init(&self, f: impl FnOnce() -> T) -> &T { + self.0.get_or_init(f) + } + + #[inline] + pub fn get_or_try_init(&self, f: impl FnOnce() -> Result) -> Result<&T, E> { + self.0.get_or_try_init(f) + } +} + +/// Small wrapper around `std::sync::RwLock` which undoes poisoning. +#[derive(Debug, Default)] +pub struct RwLock(std::sync::RwLock); + +impl RwLock { + #[inline] + pub const fn new(val: T) -> RwLock { + RwLock(std::sync::RwLock::new(val)) + } + + #[inline] + pub fn read(&self) -> impl Deref + '_ { + self.0.read().unwrap() + } + + #[inline] + pub fn write(&self) -> impl DerefMut + '_ { + self.0.write().unwrap() + } +} diff --git a/crates/wit-bindgen/Cargo.toml b/crates/wit-bindgen/Cargo.toml index 6e549ef06e3b..9c8c26c97977 100644 --- a/crates/wit-bindgen/Cargo.toml +++ b/crates/wit-bindgen/Cargo.toml @@ -16,3 +16,6 @@ anyhow = { workspace = true } heck = { workspace = true } wit-parser = { workspace = true } indexmap = { workspace = true } + +[features] +std = [] diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index 2dee30e3e237..8278f7395df3 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -1288,9 +1288,12 @@ impl<'a> InterfaceGenerator<'a> { self.push_str("write!(f, \"{:?}\", self)\n"); self.push_str("}\n"); self.push_str("}\n"); - self.push_str("impl std::error::Error for "); - self.push_str(&name); - self.push_str("{}\n"); + + if cfg!(feature = "std") { + self.push_str("impl std::error::Error for "); + self.push_str(&name); + self.push_str("{}\n"); + } } self.assert_type(id, &name); } @@ -1468,12 +1471,14 @@ impl<'a> InterfaceGenerator<'a> { self.push_str("}\n"); self.push_str("\n"); - self.push_str("impl"); - self.print_generics(lt); - self.push_str(" std::error::Error for "); - self.push_str(&name); - self.print_generics(lt); - self.push_str(" {}\n"); + if cfg!(feature = "std") { + self.push_str("impl"); + self.print_generics(lt); + self.push_str(" std::error::Error for "); + self.push_str(&name); + self.print_generics(lt); + self.push_str(" {}\n"); + } } self.assert_type(id, &name); @@ -1635,9 +1640,11 @@ impl<'a> InterfaceGenerator<'a> { self.push_str("}\n"); self.push_str("}\n"); self.push_str("\n"); - self.push_str("impl std::error::Error for "); - self.push_str(&name); - self.push_str("{}\n"); + if cfg!(feature = "std") { + self.push_str("impl std::error::Error for "); + self.push_str(&name); + self.push_str("{}\n"); + } } else { self.print_rust_enum_debug( id, @@ -1882,7 +1889,8 @@ impl<'a> InterfaceGenerator<'a> { } self.src.push_str(") |"); if self.gen.opts.async_.is_import_async(&func.name) { - self.src.push_str(" Box::new(async move { \n"); + self.src + .push_str(" wasmtime::component::__internal::Box::new(async move { \n"); } else { self.src.push_str(" { \n"); } diff --git a/crates/wit-bindgen/src/rust.rs b/crates/wit-bindgen/src/rust.rs index 7a6ba6e6e1a2..13b3967befc1 100644 --- a/crates/wit-bindgen/src/rust.rs +++ b/crates/wit-bindgen/src/rust.rs @@ -51,7 +51,7 @@ pub trait RustGenerator<'a> { } self.push_str("str"); } - TypeMode::Owned => self.push_str("String"), + TypeMode::Owned => self.push_str("wasmtime::component::__internal::String"), }, } } @@ -212,7 +212,7 @@ pub trait RustGenerator<'a> { self.push_str("]"); } TypeMode::Owned => { - self.push_str("Vec<"); + self.push_str("wasmtime::component::__internal::Vec<"); self.print_ty(ty, next_mode); self.push_str(">"); } diff --git a/examples/min-platform/embedding/wasmtime-platform.c b/examples/min-platform/embedding/wasmtime-platform.c index 22acd96ba552..b02783597aae 100644 --- a/examples/min-platform/embedding/wasmtime-platform.c +++ b/examples/min-platform/embedding/wasmtime-platform.c @@ -133,3 +133,11 @@ int wasmtime_memory_image_map_at(struct wasmtime_memory_image *image, void wasmtime_memory_image_free(struct wasmtime_memory_image *image) { abort(); } + +// Pretend that this platform doesn't have threads where storing in a static is +// ok. +static uint8_t *WASMTIME_TLS = NULL; + +uint8_t *wasmtime_tls_get() { return WASMTIME_TLS; } + +void wasmtime_tls_set(uint8_t *val) { WASMTIME_TLS = val; } diff --git a/examples/min-platform/embedding/wasmtime-platform.h b/examples/min-platform/embedding/wasmtime-platform.h index e60b0ff2d488..df8d60a0cd03 100644 --- a/examples/min-platform/embedding/wasmtime-platform.h +++ b/examples/min-platform/embedding/wasmtime-platform.h @@ -217,6 +217,21 @@ extern int32_t wasmtime_memory_image_map_at(struct wasmtime_memory_image *image, */ extern void wasmtime_memory_image_free(struct wasmtime_memory_image *image); +/** + * Wasmtime requires a single pointer's space of TLS to be used at runtime, + * and this function returns the current value of the TLS variable. + * + * This value should default to `NULL`. + */ +extern uint8_t *wasmtime_tls_get(void); + +/** + * Sets the current TLS value for Wasmtime to the provided value. + * + * This value should be returned when later calling `wasmtime_tls_get`. + */ +extern void wasmtime_tls_set(uint8_t *ptr); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/all/memory.rs b/tests/all/memory.rs index 538bd744c991..6625cf919600 100644 --- a/tests/all/memory.rs +++ b/tests/all/memory.rs @@ -1,6 +1,6 @@ use rayon::prelude::*; use std::sync::atomic::{AtomicU32, Ordering::SeqCst}; -use std::time::{Duration, Instant}; +use std::time::Duration; use wasmtime::*; fn module(engine: &Engine) -> Result { @@ -587,7 +587,7 @@ fn shared_memory_basics() -> Result<()> { assert_eq!(memory.atomic_wait64(8, 1, None), Ok(WaitResult::Mismatch)); // timeout - let near_future = Instant::now() + Duration::new(0, 100); + let near_future = Duration::new(0, 100); assert_eq!( memory.atomic_wait32(8, 0, Some(near_future)), Ok(WaitResult::TimedOut)