Browse Source

Update documentation and example for no_std (#8555)

* Update Wasmtime's tier stability documentation

Move some items between tiers and add a few misc items here and there.

* Update platform support documentation

Re-word lots of this since it was originally written, link to the tiers
of support page, and rewrite the section on `no_std`.

* Update the `min-platform` example with no_std

This commit updates the preexisting `min-platform` example to no longer
require Nightly Rust and instead use the `no_std` support now added to
Wasmtime. This involved:

* Change the build process to produce a staticlib which is then manually
  converted via `cc` into a shared library for the native Linux platform.
* Compile the modules outside of the embedding and only `deserialize`
  within the embedding.
* Update the `indexmap` dependency to pick up a bug fix required in
  `no_std` mode (apparently, it fails on indexmap@2.0.0 and passes at
  2.2.6, I didn't dig much further).

This commit additionally makes the `wasmtime-platform.h` header file
generated by the example a release artifact for Wasmtime itself. The
header itself is touched up a bit by configuring some more `cbindgen`
options as well.

* Fix clippy build

prtest:full

* Review comments

* Pass gc-sections to linking the library
pull/8559/head
Alex Crichton 6 months ago
committed by GitHub
parent
commit
5054d400ba
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 43
      .github/workflows/main.yml
  2. 39
      Cargo.lock
  3. 190
      docs/stability-platform-support.md
  4. 57
      docs/stability-tiers.md
  5. 1
      examples/min-platform/.gitignore
  6. 1
      examples/min-platform/Cargo.toml
  7. 42
      examples/min-platform/build.sh
  8. 4
      examples/min-platform/embedding/Cargo.toml
  9. 18
      examples/min-platform/embedding/aarch64-unknown-unknown.json
  10. 20
      examples/min-platform/embedding/cbindgen.toml
  11. 75
      examples/min-platform/embedding/src/allocator.rs
  12. 72
      examples/min-platform/embedding/src/lib.rs
  13. 12
      examples/min-platform/embedding/src/panic.rs
  14. 22
      examples/min-platform/embedding/wasmtime-platform.h
  15. 20
      examples/min-platform/embedding/x86_64-unknown-unknown.json
  16. 63
      examples/min-platform/src/main.rs
  17. 7
      supply-chain/imports.lock

43
.github/workflows/main.yml

@ -477,16 +477,6 @@ jobs:
- run: cargo fuzz build --dev -s none --fuzz-dir ./cranelift/isle/fuzz - run: cargo fuzz build --dev -s none --fuzz-dir ./cranelift/isle/fuzz
- run: cargo fuzz build --dev -s none --fuzz-dir ./crates/environ/fuzz --features component-model - run: cargo fuzz build --dev -s none --fuzz-dir ./crates/environ/fuzz --features component-model
# Verify the "min platform" example still works.
#
# Afterwards make sure the generated header file is up to date by ensuring
# that the regeneration process didn't change anything in-tree.
- run: cargo install cbindgen --vers "^0.26" --locked
- run: rustup component add rust-src
- run: ./build.sh ./embedding/x86_64-unknown-unknown.json
working-directory: ./examples/min-platform
- run: git diff --exit-code
# common logic to cancel the entire run if this job fails # common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }} - run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request' if: failure() && github.event_name != 'pull_request'
@ -694,6 +684,38 @@ jobs:
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
# Verify the "min platform" example still works.
test-min-platform-example:
name: Test the min-platform example
needs: determine
if: needs.determine.outputs.run-full
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/install-rust
- run: cargo install cbindgen --vers "^0.26" --locked
- run: rustup target add x86_64-unknown-none
- run: ./build.sh x86_64-unknown-none
working-directory: ./examples/min-platform
# Afterwards make sure the generated header file is up to date by ensuring
# that the regeneration process didn't change anything in-tree.
- run: git diff --exit-code
# Add the `wasmtime-platform.h` file as a release artifact
- uses: actions/upload-artifact@v4
with:
name: wasmtime-platform-header
path: examples/min-platform/embedding/wasmtime-platform.h
# common logic to cancel the entire run if this job fails
- run: gh run cancel ${{ github.run_id }}
if: failure() && github.event_name != 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
build-wasmtime-target-wasm32: build-wasmtime-target-wasm32:
name: Build wasmtime-target-wasm32 name: Build wasmtime-target-wasm32
@ -915,6 +937,7 @@ jobs:
- miri - miri
- build-preview1-component-adapter - build-preview1-component-adapter
- build-wasmtime-target-wasm32 - build-wasmtime-target-wasm32
- test-min-platform-example
if: always() if: always()
steps: steps:
- name: Successful test and build - name: Successful test and build

39
Cargo.lock

@ -1347,7 +1347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
dependencies = [ dependencies = [
"fallible-iterator", "fallible-iterator",
"indexmap 2.0.0", "indexmap 2.2.6",
"stable_deref_trait", "stable_deref_trait",
] ]
@ -1363,7 +1363,7 @@ dependencies = [
"futures-sink", "futures-sink",
"futures-util", "futures-util",
"http", "http",
"indexmap 2.0.0", "indexmap 2.2.6",
"slab", "slab",
"tokio", "tokio",
"tokio-util", "tokio-util",
@ -1547,9 +1547,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.0.0" version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.14.3", "hashbrown 0.14.3",
@ -1853,6 +1853,7 @@ dependencies = [
"anyhow", "anyhow",
"libloading", "libloading",
"object 0.33.0", "object 0.33.0",
"wasmtime",
] ]
[[package]] [[package]]
@ -1927,7 +1928,7 @@ checksum = "d8dd6c0cdf9429bce006e1362bfce61fa1bfd8c898a643ed8d2b471934701d3d"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"hashbrown 0.14.3", "hashbrown 0.14.3",
"indexmap 2.0.0", "indexmap 2.2.6",
"memchr", "memchr",
] ]
@ -2890,7 +2891,7 @@ version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951" checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951"
dependencies = [ dependencies = [
"indexmap 2.0.0", "indexmap 2.2.6",
"serde", "serde",
"serde_spanned", "serde_spanned",
"toml_datetime", "toml_datetime",
@ -3253,7 +3254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fd83062c17b9f4985d438603cde0a5e8c5c8198201a6937f778b607924c7da2" checksum = "0fd83062c17b9f4985d438603cde0a5e8c5c8198201a6937f778b607924c7da2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"indexmap 2.0.0", "indexmap 2.2.6",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
@ -3269,7 +3270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84435ac34e29de6154fdb180ebbe2bdde96336f7ad0990003c43a21bd441303f" checksum = "84435ac34e29de6154fdb180ebbe2bdde96336f7ad0990003c43a21bd441303f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"indexmap 2.0.0", "indexmap 2.2.6",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
@ -3301,7 +3302,7 @@ dependencies = [
"anyhow", "anyhow",
"arbitrary", "arbitrary",
"flagset", "flagset",
"indexmap 2.0.0", "indexmap 2.2.6",
"leb128", "leb128",
"wasm-encoder 0.206.0", "wasm-encoder 0.206.0",
] ]
@ -3353,7 +3354,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708" checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708"
dependencies = [ dependencies = [
"bitflags 2.4.1", "bitflags 2.4.1",
"indexmap 2.0.0", "indexmap 2.2.6",
"semver", "semver",
] ]
@ -3366,7 +3367,7 @@ dependencies = [
"ahash", "ahash",
"bitflags 2.4.1", "bitflags 2.4.1",
"hashbrown 0.14.3", "hashbrown 0.14.3",
"indexmap 2.0.0", "indexmap 2.2.6",
"semver", "semver",
] ]
@ -3403,7 +3404,7 @@ dependencies = [
"fxprof-processed-profile", "fxprof-processed-profile",
"gimli", "gimli",
"hashbrown 0.14.3", "hashbrown 0.14.3",
"indexmap 2.0.0", "indexmap 2.2.6",
"ittapi", "ittapi",
"libc", "libc",
"libm", "libm",
@ -3658,7 +3659,7 @@ dependencies = [
"cranelift-entity", "cranelift-entity",
"env_logger", "env_logger",
"gimli", "gimli",
"indexmap 2.0.0", "indexmap 2.2.6",
"log", "log",
"object 0.33.0", "object 0.33.0",
"postcard", "postcard",
@ -3935,7 +3936,7 @@ version = "22.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"heck", "heck",
"indexmap 2.0.0", "indexmap 2.2.6",
"wit-parser 0.206.0", "wit-parser 0.206.0",
] ]
@ -4301,7 +4302,7 @@ checksum = "d8a39a15d1ae2077688213611209849cad40e9e5cccf6e61951a425850677ff3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"heck", "heck",
"indexmap 2.0.0", "indexmap 2.2.6",
"wasm-metadata 0.201.0", "wasm-metadata 0.201.0",
"wit-bindgen-core", "wit-bindgen-core",
"wit-component 0.201.0", "wit-component 0.201.0",
@ -4329,7 +4330,7 @@ checksum = "421c0c848a0660a8c22e2fd217929a0191f14476b68962afd2af89fd22e39825"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags 2.4.1", "bitflags 2.4.1",
"indexmap 2.0.0", "indexmap 2.2.6",
"log", "log",
"serde", "serde",
"serde_derive", "serde_derive",
@ -4348,7 +4349,7 @@ checksum = "81e1ae4cace3706e29a8cf1f728b792255ecdc02653b9f4130ab6cc64f435a67"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags 2.4.1", "bitflags 2.4.1",
"indexmap 2.0.0", "indexmap 2.2.6",
"log", "log",
"serde", "serde",
"serde_derive", "serde_derive",
@ -4367,7 +4368,7 @@ checksum = "196d3ecfc4b759a8573bf86a9b3f8996b304b3732e4c7de81655f875f6efdca6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"id-arena", "id-arena",
"indexmap 2.0.0", "indexmap 2.2.6",
"log", "log",
"semver", "semver",
"serde", "serde",
@ -4385,7 +4386,7 @@ checksum = "d226de4e95e052cb664d2bdad2f31d9cad5117038a3439568f078d1afd8842fe"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"id-arena", "id-arena",
"indexmap 2.0.0", "indexmap 2.2.6",
"log", "log",
"semver", "semver",
"serde", "serde",

190
docs/stability-platform-support.md

@ -1,139 +1,81 @@
# Platform Support # Platform Support
The `wasmtime` project is a configurable and lightweight runtime for WebAssembly This page is intended to give a high-level overview of Wasmtime's platform
which has a number of ways it can be configured. Not all features are supported support along with some aspirations of Wasmtime. For more details see the
on all platforms, but it is intended that `wasmtime` can run in some capacity on documentation on [tiers of stability](./stability-tiers.md) which has specific
almost all platforms! The matrix of what's being tested, what works, and what's information about what's supported in Wasmtime on a per-matrix-combination
supported where is evolving over time, and this document hopes to capture a basis.
snapshot of what the current state of the world looks like.
Wasmtime strives to support hardware that anyone wants to run WebAssembly on.
All features of `wasmtime` should work on the following platforms: Maintainers of Wasmtime support a number of "major" platforms themselves but
porting work may be required to support platforms that maintainers are not
* Linux x86\_64 themselves familiar with. Out-of-the box Wasmtime supports:
* Linux aarch64
* macOS x86\_64 * Linux x86\_64, aarch64, s390x, and riscv64
* macOS x86\_64, aarch64
* Windows x86\_64 * Windows x86\_64
For more detailed information about supported platforms, please check out the Other platforms such as Android, iOS, and the BSD family of OSes are not
sections below! built-in yet. PRs for porting are welcome and maintainers are happy to add more
entries to the CI matrix for these platforms.
## JIT compiler support ## Compiler Support
The JIT compiler, backed by Cranelift, supports the x86\_64 and aarch64 Cranelift supports x86\_64, aarch64, s390x, and riscv64. No 32-bit platform is
architectures at this time. Support for at least ARM and x86 is planned as well. currently supported. Building a new backend for Cranelift is a relatively large
undertaking which maintainers are willing to help with but it's recommended to
reach out to Cranelift maintainers first to discuss this.
Usage of the JIT compiler will require a host operating system which supports Winch supports x86\_64. The aarch64 backend is in development. Winch is built on
creating executable memory pages on-the-fly. In Rust terms this generally means Cranelift's support for emitting instructions so Winch's possible backend list
that `std` needs to be supported on this platform. is currently limited to what Cranelift supports.
Usage of the Cranelift or Winch requires a host operating system which supports
creating executable memory pages on-the-fly. Support for statically linking in a
single precompiled module is not supported at this time.
Both Cranelift and Winch can be used either in AOT or JIT mode. In AOT mode one
process precompiles a module/component and then loads it into another process.
In JIT mode this is all done within the same process.
Neither Cranelift nor Winch support tiering at this time in the sense of having
a WebAssembly module start from a Winch compilation and automatically switch to
a Cranelift compilation. Modules are either entirely compiled with Winch or
Cranelift.
## Interpreter support ## Interpreter support
At this time `wasmtime` does not have a mode in which it simply interprets At this time `wasmtime` does not have a mode in which it simply interprets
WebAssembly code. It is planned to add support for an interpreter, however, and WebAssembly code. It is desired to add support for an interpreter, however, and
this will have minimal system dependencies. It is planned that the system will this will have minimal system dependencies. It is planned that the system will
need to support some form of dynamic memory allocation, but other than that not need to support some form of dynamic memory allocation, but other than that not
much else will be needed. much else will be needed.
## What about `#[no_std]`? ## Support for `#![no_std]`
The `wasmtime` project does not currently use `#[no_std]` for its crates, but The `wasmtime` crate supports being build on no\_std platforms in Rust, but
this is not because it won't support it! For information on building Wasmtime only for a subset of its compile-time Cargo features. Currently supported
for a custom target see [the minimal build Cargo features are:
documentation](./examples-minimal.md). Please [open an
issue](https://github.com/bytecodealliance/wasmtime/issues/new) on the * `runtime`
`wasmtime` repository to request support for a specific platform. * `gc`
* `component-model`
This is a common question we are asked, however, so to provide some more context
on why Wasmtime is the way it is, here's some responses to frequent points This notably does not include the `default` feature which means that when
raised about `#![no_std]`: depending on Wasmtime you'll need to specify `default-features = false`. This
also notably does not include Cranelift or Winch at this time meaning that
* **What if my platform doesn't have `std`?** - For platforms without support no\_std platforms must be used in AOT mode where the module is precompiled
for the Rust standard library the JIT compiler of Wasmtime often won't run on elsewhere.
the platform as well. The JIT compiler requires `mmap` (or an equivalent), and
presence of `mmap` often implies presence of a libc which means Rust's `std` Wasmtime's support for no\_std requires the embedder to implement the equivalent
library works. of a C header file to indicate how to perform basic OS operations such as
allocating virtual memory. This API can be found as `wasmtime-platform.h` in
Cargo's [`-Z build-std` feature][zbuild-std] feature is also intended to help Wasmtime's release artifacts or at
easily build the standard library for all platforms. With this feature you can `examples/min-platform/embedding/wasmtime-platform.h` in the source tree. Note
recompile the standard library (using Nightly Rust for now) with a [custom that this API is not guaranteed to be stable at this time, it'll need to be
target specification][custom-target] if necessary. Additionally the intention updated when Wasmtime is updated.
at this time is to get `std` building for all platforms, regardless of what
the platform actually supports. This change is taking time to implement, but Wasmtime's runtime will use the symbols defined in this file meaning that if
[rust-lang/rust#74033] is an example of this support growing over time. they're not defined then a link-time error will be generated. Embedders are
required to implement these functions in accordance with their documentation to
We're also interested in running Wasmtime without a JIT compiler in the enable Wasmtime to run on custom platforms.
future, but that is not implemented at this time. Implementing this will
require a lot more work than tagging crates `#![no_std]`. The Wasmtime
developers are also very interested in supporting as many targets as possible,
so if Wasmtime doesn't work on your platform yet we'd love to learn why and
what we can do to support that platform, but the conversation here is
typically more nuanced than simply making `wasmtime` compile without `std`.
* **Doesn't `#![no_std]` have smaller binary sizes?** - There's a lot of factors
that affect binary size in Rust. Compilation options are a huge one but beyond
that idioms and libraries linked matter quite a lot as well. Code is not
inherently large when using `std` instead of `core`, it's just that often code
using `std` has more dependencies (like `std::thread`) which requires code to
bind. Code size improvements can be made to code using `std` and `core`
equally, and switching to `#![no_std]` is not a silver bullet for compile
sizes.
* **The patch to switch to `#![no_std]` is small, why not accept it?** - PRs to
switch to `#![no_std]` are often relatively small or don't impact too many
parts of the system. There's a lot more to developing a `#![no_std]`
WebAssembly runtime than switching a few crates, however. Maintaining a
`#![no_std]` library over time has a number of costs associated with it:
* Rust has no stable way to diagnose `no_std` errors in an otherwise `std`
build, which means that to support this feature it must be tested on CI with
a `no_std` target. This is costly in terms of CI time, CI maintenance, and
developers having to do extra builds to avoid CI errors. Note that this
isn't *more* costly than any other platform supported by Wasmtime, but it's
a cost nonetheless.
* Idioms in `#![no_std]` are quite different than normal Rust code. You'll
import from different crates (`core` instead of `std`) and data structures
have to all be manually imported from `alloc`. These idioms are difficult to
learn for newcomers to the project and are not well documented in the
ecosystem. This cost of development and maintenance is not unique to
Wasmtime but in general affects the `#![no_std]` ecosystem at large,
unfortunately.
* Currently Wasmtime does not have a target use case which requires
`#![no_std]` support, so it's hard to justify these costs of development.
We're very interested in supporting as many use cases and targets as
possible, but the decision to support a target needs to take into account
the costs associated so we can plan accordingly. Effectively we need to have
a goal in mind instead of taking on the costs of `#![no_std]` blindly.
* At this time it's not clear whether `#![no_std]` will be needed long-term,
so eating short-term costs may not pay off in the long run. Features like
Cargo's [`-Z build-std`][zbuild-std] may mean that `#![no_std]` is less and
less necessary over time.
* **How can Wasmtime support `#![no_std]` if it uses X?** - Wasmtime as-is today
is not suitable for many `#![no_std]` contexts. For example it might use
`mmap` for allocating JIT code memory, leverage threads for caching, or use
thread locals when calling into JIT code. These features are difficult to
support in their full fidelity on all platforms, but the Wasmtime developers
are very much aware of this! Wasmtime is intended to be configurable where
many of these features are compile-time or runtime options. For example caches
can be disabled, JITs can be removed and replaced with interpreters, or users
could provide a callback to allocate memory instead of using the OS.
This is sort of a long-winded way of saying that Wasmtime on the surface may
today look like it won't support `#![no_std]`, but this is almost always
simply a matter of time and development priorities rather than a fundamental
reason why Wasmtime *couldn't* support `#![no_std]`.
Note that at this time these guidelines apply not only to Wasmtime but also to
some of its dependencies developed by the Bytecode Alliance such as the
[wasm-tools repository](https://github.com/bytecodealliance/wasm-tools). These
projects don't have the same runtime requirements as Wasmtime (e.g. `wasmparser`
doesn't need `mmap`), but we're following the same guidelines above at this
time. Patches to add `#![no_std]`, while possibly small, incur many of the same
costs and also have an unclear longevity as features like [`-Z
build-std`][zbuild-std] evolve.
[zbuild-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
[custom-target]: https://doc.rust-lang.org/rustc/targets/custom.html
[rust-lang/rust#74033]: https://github.com/rust-lang/rust/pull/74033

57
docs/stability-tiers.md

@ -25,8 +25,7 @@ For explanations of what each tier means see below.
| Target | `x86_64-apple-darwin` | | Target | `x86_64-apple-darwin` |
| Target | `x86_64-pc-windows-msvc` | | Target | `x86_64-pc-windows-msvc` |
| Target | `x86_64-unknown-linux-gnu` | | Target | `x86_64-unknown-linux-gnu` |
| WASI Proposal | `wasi_snapshot_preview1` | | Compiler Backend | Cranelift |
| WASI Proposal | `wasi_unstable` |
| WebAssembly Proposal | [`mutable-globals`] | | WebAssembly Proposal | [`mutable-globals`] |
| WebAssembly Proposal | [`sign-extension-ops`] | | WebAssembly Proposal | [`sign-extension-ops`] |
| WebAssembly Proposal | [`nontrapping-float-to-int-conversion`] | | WebAssembly Proposal | [`nontrapping-float-to-int-conversion`] |
@ -34,6 +33,19 @@ For explanations of what each tier means see below.
| WebAssembly Proposal | [`bulk-memory`] | | WebAssembly Proposal | [`bulk-memory`] |
| WebAssembly Proposal | [`reference-types`] | | WebAssembly Proposal | [`reference-types`] |
| WebAssembly Proposal | [`simd`] | | WebAssembly Proposal | [`simd`] |
| WebAssembly Proposal | [`component-model`] |
| WebAssembly Proposal | [`relaxed-simd`] |
| WebAssembly Proposal | [`multi-memory`] |
| WebAssembly Proposal | [`threads`] |
| WebAssembly Proposal | [`tail-call`] |
| WASI Proposal | [`wasi-io`] |
| WASI Proposal | [`wasi-clocks`] |
| WASI Proposal | [`wasi-filesystem`] |
| WASI Proposal | [`wasi-random`] |
| WASI Proposal | [`wasi-sockets`] |
| WASI Proposal | [`wasi-http`] |
| WASI Proposal | `wasi_snapshot_preview1` |
| WASI Proposal | `wasi_unstable` |
[`mutable-globals`]: https://github.com/WebAssembly/mutable-global/blob/master/proposals/mutable-global/Overview.md [`mutable-globals`]: https://github.com/WebAssembly/mutable-global/blob/master/proposals/mutable-global/Overview.md
[`sign-extension-ops`]: https://github.com/WebAssembly/spec/blob/master/proposals/sign-extension-ops/Overview.md [`sign-extension-ops`]: https://github.com/WebAssembly/spec/blob/master/proposals/sign-extension-ops/Overview.md
@ -42,58 +54,51 @@ For explanations of what each tier means see below.
[`bulk-memory`]: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md [`bulk-memory`]: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md
[`reference-types`]: https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md [`reference-types`]: https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md
[`simd`]: https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md [`simd`]: https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md
[`wasi-clocks`]: https://github.com/WebAssembly/wasi-clocks
[`wasi-filesystem`]: https://github.com/WebAssembly/wasi-filesystem
[`wasi-io`]: https://github.com/WebAssembly/wasi-io
[`wasi-random`]: https://github.com/WebAssembly/wasi-random
[`wasi-sockets`]: https://github.com/WebAssembly/wasi-sockets
[`wasi-http`]: https://github.com/WebAssembly/wasi-http
[`tail-call`]: https://github.com/WebAssembly/tail-call/blob/main/proposals/tail-call/Overview.md
#### Tier 2 #### Tier 2
| Category | Description | Missing Tier 1 Requirements | | Category | Description | Missing Tier 1 Requirements |
|----------------------|----------------------------|-----------------------------| |----------------------|----------------------------|-----------------------------|
| Target | `aarch64-unknown-linux-gnu`| Continuous fuzzing | | Target | `aarch64-unknown-linux-gnu`| Continuous fuzzing |
| Target | `aarch64-apple-darwin` | Continuous fuzzing |
| Target | `s390x-unknown-linux-gnu` | Continuous fuzzing | | Target | `s390x-unknown-linux-gnu` | Continuous fuzzing |
| Target | `x86_64-pc-windows-gnu` | Clear owner of the target | | Target | `x86_64-pc-windows-gnu` | Clear owner of the target |
| Target | Support for `#![no_std]` | Support beyond CI checks |
| Compiler Backend | Winch on x86\_64 | Consenus on moving to Tier 1 |
| WebAssembly Proposal | [`memory64`] | Unstable wasm proposal | | WebAssembly Proposal | [`memory64`] | Unstable wasm proposal |
| WebAssembly Proposal | [`multi-memory`] | Unstable wasm proposal |
| WebAssembly Proposal | [`threads`] | Unstable wasm proposal |
| WebAssembly Proposal | [`component-model`] | Unstable wasm proposal |
| WebAssembly Proposal | [`tail-call`] | Unstable wasm proposal, performance work |
| WebAssembly Proposal | [`relaxed-simd`] | Unstable wasm proposal |
| WebAssembly Proposal | [`function-references`] | Unstable wasm proposal | | WebAssembly Proposal | [`function-references`] | Unstable wasm proposal |
| WASI Proposal | [`wasi-io`] | Unstable WASI proposal |
| WASI Proposal | [`wasi-clocks`] | Unstable WASI proposal |
| WASI Proposal | [`wasi-filesystem`] | Unstable WASI proposal |
| WASI Proposal | [`wasi-random`] | Unstable WASI proposal |
| WASI Proposal | [`wasi-poll`] | Unstable WASI proposal |
[`memory64`]: https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md [`memory64`]: https://github.com/WebAssembly/memory64/blob/master/proposals/memory64/Overview.md
[`multi-memory`]: https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md [`multi-memory`]: https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md
[`threads`]: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md [`threads`]: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md
[`component-model`]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md [`component-model`]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md
[`tail-call`]: https://github.com/WebAssembly/tail-call/blob/main/proposals/tail-call/Overview.md
[`relaxed-simd`]: https://github.com/WebAssembly/relaxed-simd/blob/main/proposals/relaxed-simd/Overview.md [`relaxed-simd`]: https://github.com/WebAssembly/relaxed-simd/blob/main/proposals/relaxed-simd/Overview.md
[`function-references`]: https://github.com/WebAssembly/function-references/blob/main/proposals/function-references/Overview.md [`function-references`]: https://github.com/WebAssembly/function-references/blob/main/proposals/function-references/Overview.md
[`wasi-clocks`]: https://github.com/WebAssembly/wasi-clocks
[`wasi-filesystem`]: https://github.com/WebAssembly/wasi-filesystem
[`wasi-io`]: https://github.com/WebAssembly/wasi-io
[`wasi-random`]: https://github.com/WebAssembly/wasi-random
[`wasi-poll`]: https://github.com/WebAssembly/wasi-poll
#### Tier 3 #### Tier 3
| Category | Description | Missing Tier 2 Requirements | | Category | Description | Missing Tier 2 Requirements |
|----------------------|-----------------------------------|-----------------------------| |----------------------|-----------------------------------|-----------------------------|
| Target | `aarch64-apple-darwin` | CI testing |
| Target | `aarch64-pc-windows-msvc` | CI testing, unwinding, full-time maintainer | | Target | `aarch64-pc-windows-msvc` | CI testing, unwinding, full-time maintainer |
| Target | `riscv64gc-unknown-linux-gnu` | full-time maintainer | | Target | `riscv64gc-unknown-linux-gnu` | full-time maintainer |
| Target | `wasm32-wasi` [^3] | Supported but not tested |
| Compiler Backend | Winch on aarch64 | finished implementation |
| WebAssembly Proposal | [`gc`] | Complete implementation |
| WASI Proposal | [`wasi-nn`] | More expansive CI testing | | WASI Proposal | [`wasi-nn`] | More expansive CI testing |
| WASI Proposal | [`wasi-threads`] | More CI, unstable proposal | | WASI Proposal | [`wasi-threads`] | More CI, unstable proposal |
| WASI Proposal | [`wasi-sockets`] | Complete implementation |
| WASI Proposal | [`wasi-http`] | Complete implementation |
| *misc* | Non-Wasmtime Cranelift usage [^1] | CI testing, full-time maintainer | | *misc* | Non-Wasmtime Cranelift usage [^1] | CI testing, full-time maintainer |
| *misc* | DWARF debugging [^2] | CI testing, full-time maintainer, improved quality | | *misc* | DWARF debugging [^2] | CI testing, full-time maintainer, improved quality |
[`wasi-sockets`]: https://github.com/WebAssembly/wasi-sockets
[`wasi-nn`]: https://github.com/WebAssembly/wasi-nn [`wasi-nn`]: https://github.com/WebAssembly/wasi-nn
[`wasi-threads`]: https://github.com/WebAssembly/wasi-threads [`wasi-threads`]: https://github.com/WebAssembly/wasi-threads
[`wasi-http`]: https://github.com/WebAssembly/wasi-http [`gc`]: https://github.com/WebAssembly/gc
[^1]: This is intended to encompass features that Cranelift supports as a [^1]: This is intended to encompass features that Cranelift supports as a
general-purpose code generator such as integer value types other than `i32` and general-purpose code generator such as integer value types other than `i32` and
@ -108,6 +113,10 @@ support is currently best-effort. Additionally there are known shortcomings
and bugs. At this time there's no developer time to improve the situation here and bugs. At this time there's no developer time to improve the situation here
as well. as well.
[^3]: Wasmtime's `cranelift` and `winch` features can be compiled to WebAssembly
but not the `runtime` feature at this time. This means that
Wasmtime-compiled-to-wasm can itself compile wasm but cannot execute wasm.
#### Unsupported features and platforms #### Unsupported features and platforms
While this is not an exhaustive list, Wasmtime does not currently have support While this is not an exhaustive list, Wasmtime does not currently have support
@ -118,7 +127,6 @@ features to figure out how best to implement them and at least move them to Tier
3 above. 3 above.
* Target: ARM 32-bit * Target: ARM 32-bit
* Target: WebAssembly (compiling Wasmtime to WebAssembly itself)
* Target: [FreeBSD](https://github.com/bytecodealliance/wasmtime/issues/5499) * Target: [FreeBSD](https://github.com/bytecodealliance/wasmtime/issues/5499)
* Target: [NetBSD/OpenBSD](https://github.com/bytecodealliance/wasmtime/issues/6962) * Target: [NetBSD/OpenBSD](https://github.com/bytecodealliance/wasmtime/issues/6962)
* Target: [i686 (32-bit Intel targets)](https://github.com/bytecodealliance/wasmtime/issues/1980) * Target: [i686 (32-bit Intel targets)](https://github.com/bytecodealliance/wasmtime/issues/1980)
@ -131,7 +139,6 @@ features to figure out how best to implement them and at least move them to Tier
* [WebAssembly proposal: `exception-handling`](https://github.com/WebAssembly/exception-handling) * [WebAssembly proposal: `exception-handling`](https://github.com/WebAssembly/exception-handling)
* [WebAssembly proposal: `extended-const`](https://github.com/WebAssembly/extended-const) * [WebAssembly proposal: `extended-const`](https://github.com/WebAssembly/extended-const)
* [WebAssembly proposal: `flexible-vectors`](https://github.com/WebAssembly/flexible-vectors) * [WebAssembly proposal: `flexible-vectors`](https://github.com/WebAssembly/flexible-vectors)
* [WebAssembly proposal: `gc`](https://github.com/WebAssembly/gc)
* [WebAssembly proposal: `memory-control`](https://github.com/WebAssembly/memory-control) * [WebAssembly proposal: `memory-control`](https://github.com/WebAssembly/memory-control)
* [WebAssembly proposal: `stack-switching`](https://github.com/WebAssembly/stack-switching) * [WebAssembly proposal: `stack-switching`](https://github.com/WebAssembly/stack-switching)
* [WASI proposal: `proxy-wasm`](https://github.com/proxy-wasm/spec) * [WASI proposal: `proxy-wasm`](https://github.com/proxy-wasm/spec)

1
examples/min-platform/.gitignore

@ -1 +1,2 @@
libwasmtime-platform.so libwasmtime-platform.so
libembedding.so

1
examples/min-platform/Cargo.toml

@ -12,3 +12,4 @@ workspace = true
anyhow = { workspace = true, features = ['std'] } anyhow = { workspace = true, features = ['std'] }
libloading = "0.8" libloading = "0.8"
object = { workspace = true, features = ['std'] } object = { workspace = true, features = ['std'] }
wasmtime = { workspace = true, features = ['cranelift', 'wat'] }

42
examples/min-platform/build.sh

@ -4,14 +4,14 @@
# the embedding itself as well as the example host which will run it. # the embedding itself as well as the example host which will run it.
# #
# This script takes a single argument which is a path to a Rust target json # This script takes a single argument which is a path to a Rust target json
# file. Examples are provided in `embedding/*.json`. # file. Example targets are `x86_64-unknown-none` or `aarch64-unknown-none`.
# #
# This script must be executed with the current-working-directory as # This script must be executed with the current-working-directory as
# `examples/min-platform`. # `examples/min-platform`.
target=$1 target=$1
if [ "$target" = "" ]; then if [ "$target" = "" ]; then
echo "Usage: $0 <target-json-file>" echo "Usage: $0 <target>"
exit 1 exit 1
fi fi
@ -26,30 +26,28 @@ set -ex
# #
# which ensures that Rust & C agree on types and such. # which ensures that Rust & C agree on types and such.
cbindgen ../../crates/wasmtime/src/runtime/vm/sys/custom/capi.rs \ cbindgen ../../crates/wasmtime/src/runtime/vm/sys/custom/capi.rs \
--lang C \ --config embedding/cbindgen.toml > embedding/wasmtime-platform.h
--cpp-compat > embedding/wasmtime-platform.h
clang -shared -O2 -o libwasmtime-platform.so ./embedding/wasmtime-platform.c \ clang -shared -O2 -o libwasmtime-platform.so ./embedding/wasmtime-platform.c \
-D_GNU_SOURCE -D_GNU_SOURCE
# Next the embedding itself is built. Points of note here: # Next the embedding itself is built.
# #
# * `RUSTC_BOOTSTRAP_SYNTHETIC_TARGET=1` - this "fools" the Rust standard # Note that this builds the embedding as a static library, here
# library to falling back to an "unsupported" implementation of primitives by # `libembedding.a`. This embedding is then turned into a dynamic library for the
# default but without marking the standard library as requiring # host platform using `cc` afterwards. The `*-unknown-none` targets themselves
# `feature(restricted_std)`. This is probably something that should be # don't support dynamic libraries so this is a bit of a dance to get around the
# coordinated with upstream rust-lang/rust and get better support. # fact that we're pretending this examples in't being compiled for linux.
# * `--cfg=wasmtime_custom_platform` - this flag indicates to Wasmtime that the cargo build \
# minimal platform support is being opted into. --manifest-path embedding/Cargo.toml \
# * `-Zbuild-std=std,panic_abort` - this is a nightly Cargo feature to build the --target $target \
# Rust standard library from source. --release
# cc \
# The final artifacts will be placed in Cargo's standard target directory. -Wl,--gc-sections \
RUSTC_BOOTSTRAP_SYNTHETIC_TARGET=1 \ -Wl,--whole-archive \
RUSTFLAGS="--cfg=wasmtime_custom_platform" \ ../../target/$target/release/libembedding.a \
cargo build -Zbuild-std=std,panic_abort \ -Wl,--no-whole-archive \
--manifest-path embedding/Cargo.toml \ -shared \
--target $target \ -o libembedding.so
--release
# The final step here is running the host, in the current directory, which will # The final step here is running the host, in the current directory, which will
# load the embedding and execute it. # load the embedding and execute it.

4
examples/min-platform/embedding/Cargo.toml

@ -14,12 +14,12 @@ anyhow = { workspace = true }
# Note that default-features of wasmtime are disabled and only those required # Note that default-features of wasmtime are disabled and only those required
# are enabled, in this case compilation is done in the guest from the wasm text # are enabled, in this case compilation is done in the guest from the wasm text
# format so `cranelift` and `wat` are enabled. # format so `cranelift` and `wat` are enabled.
wasmtime = { workspace = true, features = ['cranelift', 'wat', 'runtime'] } wasmtime = { workspace = true, features = ['runtime'] }
# Memory allocator used in this example (not required, however) # Memory allocator used in this example (not required, however)
dlmalloc = "0.2.4" dlmalloc = "0.2.4"
[lib] [lib]
crate-type = ['cdylib'] crate-type = ['staticlib']
test = false test = false
doctest = false doctest = false

18
examples/min-platform/embedding/aarch64-unknown-unknown.json

@ -1,18 +0,0 @@
{
"arch": "aarch64",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
"dynamic-linking": true,
"has-thread-local": true,
"is-builtin": false,
"llvm-target": "aarch64-unknown-linux-gnu",
"max-atomic-width": 64,
"os": "minwasmtime",
"position-independent-executables": true,
"panic-strategy": "abort",
"frame-pointer": "always",
"relro-level": "full",
"stack-probes": {
"kind": "inline"
},
"target-pointer-width": "64"
}

20
examples/min-platform/embedding/cbindgen.toml

@ -0,0 +1,20 @@
language = "C"
include_guard = "_WASMTIME_PLATFORM_H"
include_version = true
cpp_compat = true
header = """
// Platform support for Wasmtime's `no_std` build.
//
// This header file is what Wasmtime will rely on when it does not otherwise
// have support for the native platform. This can happen with `no_std` binaries
// for example where the traditional Unix-or-Windows implementation is not
// suitable.
//
// Embedders are expected to implement the symbols defined in this header file.
// These symbols can be defined either in C/C++ or in Rust (using
// `#[no_mangle]`).
//
// Some more information about this header can additionally be found at
// <https://docs.wasmtime.dev/stability-platform-support.html>.
"""

75
examples/min-platform/embedding/src/allocator.rs

@ -12,10 +12,15 @@
//! and the `GlobalAlloc for T` trait impl. This should be used when hooking //! and the `GlobalAlloc for T` trait impl. This should be used when hooking
//! up to an allocator elsewhere in the system. //! up to an allocator elsewhere in the system.
use alloc::alloc::{GlobalAlloc, Layout};
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::ptr;
use core::sync::atomic::{
AtomicBool,
Ordering::{Acquire, Release},
};
use dlmalloc::Dlmalloc; use dlmalloc::Dlmalloc;
use std::alloc::{GlobalAlloc, Layout};
use std::ptr;
use std::sync::Mutex;
#[global_allocator] #[global_allocator]
static MALLOC: MyGlobalDmalloc = MyGlobalDmalloc { static MALLOC: MyGlobalDmalloc = MyGlobalDmalloc {
@ -26,36 +31,33 @@ struct MyGlobalDmalloc {
dlmalloc: Mutex<Dlmalloc<MyAllocator>>, dlmalloc: Mutex<Dlmalloc<MyAllocator>>,
} }
unsafe impl Send for MyGlobalDmalloc {}
unsafe impl Sync for MyGlobalDmalloc {}
struct MyAllocator; struct MyAllocator;
unsafe impl GlobalAlloc for MyGlobalDmalloc { unsafe impl GlobalAlloc for MyGlobalDmalloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
self.dlmalloc self.dlmalloc
.lock() .try_lock()
.unwrap() .unwrap()
.malloc(layout.size(), layout.align()) .malloc(layout.size(), layout.align())
} }
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
self.dlmalloc self.dlmalloc
.lock() .try_lock()
.unwrap() .unwrap()
.calloc(layout.size(), layout.align()) .calloc(layout.size(), layout.align())
} }
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
self.dlmalloc self.dlmalloc
.lock() .try_lock()
.unwrap() .unwrap()
.realloc(ptr, layout.size(), layout.align(), new_size) .realloc(ptr, layout.size(), layout.align(), new_size)
} }
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.dlmalloc self.dlmalloc
.lock() .try_lock()
.unwrap() .unwrap()
.free(ptr, layout.size(), layout.align()) .free(ptr, layout.size(), layout.align())
} }
@ -84,7 +86,7 @@ unsafe impl dlmalloc::Allocator for MyAllocator {
} }
fn remap(&self, _ptr: *mut u8, _old: usize, _new: usize, _can_move: bool) -> *mut u8 { fn remap(&self, _ptr: *mut u8, _old: usize, _new: usize, _can_move: bool) -> *mut u8 {
std::ptr::null_mut() core::ptr::null_mut()
} }
fn free_part(&self, _ptr: *mut u8, _old: usize, _new: usize) -> bool { fn free_part(&self, _ptr: *mut u8, _old: usize, _new: usize) -> bool {
@ -110,3 +112,54 @@ unsafe impl dlmalloc::Allocator for MyAllocator {
unsafe { wasmtime_page_size() } unsafe { wasmtime_page_size() }
} }
} }
// Simple mutex which only supports `try_lock` at this time. This would probably
// be replaced with a "real" mutex in a "real" embedding.
struct Mutex<T> {
data: UnsafeCell<T>,
locked: AtomicBool,
}
unsafe impl<T: Send> Send for Mutex<T> {}
unsafe impl<T: Send> Sync for Mutex<T> {}
impl<T> Mutex<T> {
const fn new(val: T) -> Mutex<T> {
Mutex {
data: UnsafeCell::new(val),
locked: AtomicBool::new(false),
}
}
fn try_lock(&self) -> Option<impl DerefMut<Target = T> + '_> {
if self.locked.swap(true, Acquire) {
None
} else {
Some(MutexGuard { lock: self })
}
}
}
struct MutexGuard<'a, T> {
lock: &'a Mutex<T>,
}
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.data.get() }
}
}
impl<T> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.data.get() }
}
}
impl<T> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
self.lock.locked.store(false, Release);
}
}

72
examples/min-platform/embedding/src/lib.rs

@ -1,12 +1,35 @@
#![no_std]
#[macro_use]
extern crate alloc;
use anyhow::Result; use anyhow::Result;
use wasmtime::{Engine, Instance, Linker, Module, Store}; use wasmtime::{Engine, Instance, Linker, Module, Store};
mod allocator; mod allocator;
mod panic;
/// Entrypoint of this embedding.
///
/// This takes a number of parameters which are the precompiled module AOT
/// images that are run for each of the various tests below. The first parameter
/// is also where to put an error string, if any, if anything fails.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn run(buf: *mut u8, size: usize) -> usize { pub unsafe extern "C" fn run(
let buf = std::slice::from_raw_parts_mut(buf, size); error_buf: *mut u8,
match run_result() { error_size: usize,
smoke_module: *const u8,
smoke_size: usize,
simple_add_module: *const u8,
simple_add_size: usize,
simple_host_fn_module: *const u8,
simple_host_fn_size: usize,
) -> usize {
let buf = core::slice::from_raw_parts_mut(error_buf, error_size);
let smoke = core::slice::from_raw_parts(smoke_module, smoke_size);
let simple_add = core::slice::from_raw_parts(simple_add_module, simple_add_size);
let simple_host_fn = core::slice::from_raw_parts(simple_host_fn_module, simple_host_fn_size);
match run_result(smoke, simple_add, simple_host_fn) {
Ok(()) => 0, Ok(()) => 0,
Err(e) => { Err(e) => {
let msg = format!("{e:?}"); let msg = format!("{e:?}");
@ -17,50 +40,37 @@ pub unsafe extern "C" fn run(buf: *mut u8, size: usize) -> usize {
} }
} }
fn run_result() -> Result<()> { fn run_result(
smoke()?; smoke_module: &[u8],
simple_add()?; simple_add_module: &[u8],
simple_host_fn()?; simple_host_fn_module: &[u8],
) -> Result<()> {
smoke(smoke_module)?;
simple_add(simple_add_module)?;
simple_host_fn(simple_host_fn_module)?;
Ok(()) Ok(())
} }
fn smoke() -> Result<()> { fn smoke(module: &[u8]) -> Result<()> {
let engine = Engine::default(); let engine = Engine::default();
let module = Module::new(&engine, "(module)")?; let module = unsafe { Module::deserialize(&engine, module)? };
Instance::new(&mut Store::new(&engine, ()), &module, &[])?; Instance::new(&mut Store::new(&engine, ()), &module, &[])?;
Ok(()) Ok(())
} }
fn simple_add() -> Result<()> { fn simple_add(module: &[u8]) -> Result<()> {
let engine = Engine::default(); let engine = Engine::default();
let module = Module::new( let module = unsafe { Module::deserialize(&engine, module)? };
&engine,
r#"
(module
(func (export "add") (param i32 i32) (result i32)
(i32.add (local.get 0) (local.get 1)))
)
"#,
)?;
let mut store = Store::new(&engine, ()); let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?; let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
let func = instance.get_typed_func::<(u32, u32), u32>(&mut store, "add")?; let func = instance.get_typed_func::<(u32, u32), u32>(&mut store, "add")?;
assert_eq!(func.call(&mut store, (2, 3))?, 5); assert_eq!(func.call(&mut store, (2, 3))?, 5);
Ok(()) Ok(())
} }
fn simple_host_fn() -> Result<()> { fn simple_host_fn(module: &[u8]) -> Result<()> {
let engine = Engine::default(); let engine = Engine::default();
let module = Module::new( let module = unsafe { Module::deserialize(&engine, module)? };
&engine,
r#"
(module
(import "host" "multiply" (func $multiply (param i32 i32) (result i32)))
(func (export "add_and_mul") (param i32 i32 i32) (result i32)
(i32.add (call $multiply (local.get 0) (local.get 1)) (local.get 2)))
)
"#,
)?;
let mut linker = Linker::<()>::new(&engine); let mut linker = Linker::<()>::new(&engine);
linker.func_wrap("host", "multiply", |a: u32, b: u32| a.saturating_mul(b))?; linker.func_wrap("host", "multiply", |a: u32, b: u32| a.saturating_mul(b))?;
let mut store = Store::new(&engine, ()); let mut store = Store::new(&engine, ());

12
examples/min-platform/embedding/src/panic.rs

@ -0,0 +1,12 @@
#![cfg(not(unix))] // gets `cargo clippy` working
use core::panic::PanicInfo;
#[panic_handler]
fn handler(_info: &PanicInfo) -> ! {
// NB: should ideally print something here but for this example this is left
// out. A more complete embedding would likely turn `info` into a
// stack-allocated string and then pass that as a message to the outer
// system to get printed and trigger a failure.
loop {}
}

22
examples/min-platform/embedding/wasmtime-platform.h

@ -1,3 +1,23 @@
// Platform support for Wasmtime's `no_std` build.
//
// This header file is what Wasmtime will rely on when it does not otherwise
// have support for the native platform. This can happen with `no_std` binaries
// for example where the traditional Unix-or-Windows implementation is not
// suitable.
//
// Embedders are expected to implement the symbols defined in this header file.
// These symbols can be defined either in C/C++ or in Rust (using
// `#[no_mangle]`).
//
// Some more information about this header can additionally be found at
// <https://docs.wasmtime.dev/stability-platform-support.html>.
#ifndef _WASMTIME_PLATFORM_H
#define _WASMTIME_PLATFORM_H
/* Generated with cbindgen:0.26.0 */
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -235,3 +255,5 @@ extern void wasmtime_tls_set(uint8_t *ptr);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif // __cplusplus #endif // __cplusplus
#endif /* _WASMTIME_PLATFORM_H */

20
examples/min-platform/embedding/x86_64-unknown-unknown.json

@ -1,20 +0,0 @@
{
"arch": "x86_64",
"cpu": "x86-64",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"features": "+sse4.2,+avx,+fma,+popcnt",
"dynamic-linking": true,
"has-thread-local": true,
"is-builtin": false,
"llvm-target": "x86_64-unknown-linux-gnu",
"max-atomic-width": 64,
"os": "minwasmtime",
"position-independent-executables": true,
"panic-strategy": "abort",
"frame-pointer": "always",
"relro-level": "full",
"stack-probes": {
"kind": "inline"
},
"target-pointer-width": "64"
}

63
examples/min-platform/src/main.rs

@ -11,16 +11,15 @@ fn main() -> Result<()> {
use libloading::os::unix::{Library, Symbol, RTLD_GLOBAL, RTLD_NOW}; use libloading::os::unix::{Library, Symbol, RTLD_GLOBAL, RTLD_NOW};
use object::{Object, ObjectSymbol, SymbolKind}; use object::{Object, ObjectSymbol, SymbolKind};
use std::io::Write; use std::io::Write;
use std::path::Path; use wasmtime::{Config, Engine};
let target = std::env::args().nth(1).unwrap(); let target = std::env::args().nth(1).unwrap();
let target = Path::new(&target).file_stem().unwrap().to_str().unwrap();
// Path to the artifact which is the build of the embedding. // Path to the artifact which is the build of the embedding.
// //
// In this example this is a dynamic library intended to be run on Linux. // In this example this is a dynamic library intended to be run on Linux.
// Note that this is just an example of an artifact and custom build // Note that this is just an example of an artifact and custom build
// processes can produce different kinds of artifacts. // processes can produce different kinds of artifacts.
let lib = format!("../../target/{target}/release/libembedding.so"); let lib = format!("./libembedding.so");
let binary = std::fs::read(&lib)?; let binary = std::fs::read(&lib)?;
let object = object::File::parse(&binary[..])?; let object = object::File::parse(&binary[..])?;
@ -47,6 +46,34 @@ fn main() -> Result<()> {
} }
} }
// Precompile modules for the embedding. Right now Wasmtime in no_std mode
// does not have support for Cranelift meaning that AOT mode must be used.
// Modules are compiled here and then given to the embedding via the `run`
// function below.
//
// Note that `Config::target` is used here to enable cross-compilation.
let mut config = Config::new();
config.target(&target)?;
let engine = Engine::new(&config)?;
let smoke = engine.precompile_module(b"(module)")?;
let simple_add = engine.precompile_module(
br#"
(module
(func (export "add") (param i32 i32) (result i32)
(i32.add (local.get 0) (local.get 1)))
)
"#,
)?;
let simple_host_fn = engine.precompile_module(
br#"
(module
(import "host" "multiply" (func $multiply (param i32 i32) (result i32)))
(func (export "add_and_mul") (param i32 i32 i32) (result i32)
(i32.add (call $multiply (local.get 0) (local.get 1)) (local.get 2)))
)
"#,
)?;
// Next is an example of running this embedding, which also serves as test // Next is an example of running this embedding, which also serves as test
// that basic functionality actually works. // that basic functionality actually works.
// //
@ -70,13 +97,33 @@ fn main() -> Result<()> {
Library::open(Some("./libwasmtime-platform.so"), RTLD_NOW | RTLD_GLOBAL)?; Library::open(Some("./libwasmtime-platform.so"), RTLD_NOW | RTLD_GLOBAL)?;
let lib = Library::new(&lib)?; let lib = Library::new(&lib)?;
let run: Symbol<extern "C" fn(*mut u8, usize) -> usize> = lib.get(b"run")?; let run: Symbol<
extern "C" fn(
*mut u8,
usize,
*const u8,
usize,
*const u8,
usize,
*const u8,
usize,
) -> usize,
> = lib.get(b"run")?;
let mut buf = Vec::with_capacity(1024); let mut error_buf = Vec::with_capacity(1024);
let len = run(buf.as_mut_ptr(), buf.capacity()); let len = run(
buf.set_len(len); error_buf.as_mut_ptr(),
error_buf.capacity(),
smoke.as_ptr(),
smoke.len(),
simple_add.as_ptr(),
simple_add.len(),
simple_host_fn.as_ptr(),
simple_host_fn.len(),
);
error_buf.set_len(len);
std::io::stderr().write_all(&buf).unwrap(); std::io::stderr().write_all(&error_buf).unwrap();
} }
Ok(()) Ok(())
} }

7
supply-chain/imports.lock

@ -1129,6 +1129,13 @@ user-id = 539
user-login = "cuviper" user-login = "cuviper"
user-name = "Josh Stone" user-name = "Josh Stone"
[[publisher.indexmap]]
version = "2.2.6"
when = "2024-03-23"
user-id = 539
user-login = "cuviper"
user-name = "Josh Stone"
[[publisher.io-extras]] [[publisher.io-extras]]
version = "0.18.1" version = "0.18.1"
when = "2023-12-01" when = "2023-12-01"

Loading…
Cancel
Save