Skip to content

Commit

Permalink
Add support for #![no_std] to the wasmtime crate (#8533)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
alexcrichton committed May 4, 2024
1 parent fd50e79 commit 81a8916
Show file tree
Hide file tree
Showing 147 changed files with 1,765 additions and 919 deletions.
12 changes: 2 additions & 10 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down Expand Up @@ -246,14 +246,15 @@ 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"
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"
Expand Down
2 changes: 1 addition & 1 deletion crates/c-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion crates/cli-flags/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
1 change: 1 addition & 0 deletions crates/component-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ serde_json = { workspace = true }

[features]
async = []
std = ['wasmtime-wit-bindgen/std']
32 changes: 16 additions & 16 deletions crates/component-macro/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ impl Expander for LowerExpander {
&self,
cx: &mut #internal::LowerContext<'_, T>,
ty: #internal::InterfaceType,
dst: &mut std::mem::MaybeUninit<Self::Lower>,
dst: &mut core::mem::MaybeUninit<Self::Lower>,
) -> #internal::anyhow::Result<()> {
#extract_ty
#lowers
Expand Down Expand Up @@ -677,7 +677,7 @@ impl Expander for LowerExpander {
&self,
cx: &mut #internal::LowerContext<'_, T>,
ty: #internal::InterfaceType,
dst: &mut std::mem::MaybeUninit<Self::Lower>,
dst: &mut core::mem::MaybeUninit<Self::Lower>,
) -> #internal::anyhow::Result<()> {
#extract_ty
match self {
Expand Down Expand Up @@ -1136,7 +1136,7 @@ pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
}

pub fn all() -> Self {
use std::ops::Not;
use core::ops::Not;
Self::default().not()
}

Expand All @@ -1149,63 +1149,63 @@ pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
}
}

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 {
#bitor
}
}

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 {
#bitand
}
}

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 {
#bitxor
}
}

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 {
Expand All @@ -1220,7 +1220,7 @@ pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
&self,
cx: &mut #internal::LowerContext<'_, T>,
_ty: #internal::InterfaceType,
dst: &mut std::mem::MaybeUninit<Self::Lower>,
dst: &mut core::mem::MaybeUninit<Self::Lower>,
) -> #internal::anyhow::Result<()> {
#(
self.#field_names.lower(
Expand All @@ -1245,7 +1245,7 @@ pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
#field_interface_type,
offset,
)?;
offset += std::mem::size_of_val(&self.#field_names);
offset += core::mem::size_of_val(&self.#field_names);
)*
Ok(())
}
Expand Down
16 changes: 16 additions & 0 deletions crates/component-macro/tests/codegen_no_std.rs
Original file line number Diff line number Diff line change
@@ -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);
38 changes: 30 additions & 8 deletions crates/environ/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -62,20 +62,42 @@ pub trait Err2Anyhow<T> {
fn err2anyhow(self) -> anyhow::Result<T>;
}

#[cfg(feature = "std")]
impl<T, E: Into<anyhow::Error>> Err2Anyhow<T> for Result<T, E> {
impl<T, E: IntoAnyhow> Err2Anyhow<T> for Result<T, E> {
fn err2anyhow(self) -> anyhow::Result<T> {
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<T> IntoAnyhow for T
where
T: Into<anyhow::Error>,
{
fn into_anyhow(self) -> anyhow::Error {
self.into()
}
}

#[cfg(not(feature = "std"))]
impl<T, E> Err2Anyhow<T> for Result<T, E>
impl<T> 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<T> {
self.map_err(anyhow::Error::msg)
fn into_anyhow(self) -> anyhow::Error {
anyhow::Error::msg(self)
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/wasi-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion crates/wasi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down

0 comments on commit 81a8916

Please sign in to comment.