Skip to content

Commit eb833bc

Browse files
feat: improve nightly feature detection, reorganize cargo features
Signed-off-by: Henry <mail@henrygressmann.de>
1 parent b67755c commit eb833bc

14 files changed

Lines changed: 124 additions & 59 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Added WebAssembly threads support, including atomic wait/notify and cross-store shared memory with `MemoryShared`.
1313
- Added new `Memory::data` and `Memory::data_mut` methods for direct access to linear memory.
14-
- Added several internal methods to support a future c-api crate
14+
- Added an experimental C API in `tinywasm-c-api`.
15+
- Added parse-time resource limits and configurable fuel checkpoints.
16+
- Added `nightly` to enable all supported nightly optimizations, with automatic compiler capability detection.
1517

16-
### Removed
18+
### Breaking Changes
1719

18-
- Removed `resume_with_time_budget`. Use `resume_with_fuel` and check application deadlines between resumes.
20+
- Renamed the `simd-x86` Cargo feature to `simd-intrinsics`.
21+
- Enabled `nightly` and `simd-intrinsics` by default. `full` is unchanged.
22+
- Removed `resume_with_time_budget`. Use `resume_with_fuel` and application-managed deadlines.
23+
- Stack limits now enforce `StackConfig::max_size` even when the allocation has spare capacity.
24+
- Changed public bytecode/module types and the `.twasm` format. Regenerate archives created with 0.11.0.
1925

2026
### Fixed
2127

‎Cargo.lock‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎README.md‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
## Why `tinywasm`?
66

77
- **Tiny**: Small by design, while still passing the full WebAssembly 3.0 core test suite.
8-
- **Portable**: Runs anywhere Rust can target, supports `no_std`, has minimal dependencies[^dependencies], and can itself compile to WebAssembly.
9-
- **Safe by default**: Written entirely in safe Rust[^unsafe].
8+
- **Portable**: Runs anywhere Rust can target, supports `no_std`, has minimal dependencies[^dependencies]
9+
- **Safe**: Written entirely in safe Rust[^unsafe].
1010

1111
[^dependencies]: The two main external components are [`wasmparser`](https://crates.io/crates/wasmparser) for WebAssembly parsing and validation, and [`postcard`](https://crates.io/crates/postcard) for `.twasm` archives.
1212

13-
[^unsafe]: The optional `simd-x86` feature is the only exception. It uses `unsafe` internally for selected x86 SIMD intrinsics.
13+
[^unsafe]: The `simd-intrinsics` feature uses `unsafe` internally for selected architecture-specific SIMD implementations.
1414

1515
## Installation
1616

@@ -58,11 +58,10 @@ See the [examples](./examples) directory and [documentation](https://docs.rs/tin
5858
- **`canonicalize-nans`:** Uses a [canonical NaN](https://en.wikipedia.org/wiki/NaN#Canonical_NaN) for normalized NaN results.
5959
- **`debug`:** Derives `Debug` for runtime types. Enabled by default.
6060
- **`guest-debug`:** Exposes module-internal by-index inspection APIs (`*_by_index`).
61-
- **`nightly-tail-calls`:** Uses Rust's unstable explicit tail calls for interpreter dispatch. Requires nightly Rust (recommended for maximum performance).
62-
- **`nightly-rust-preserve-none`:** Uses Rust's experimental preserve-none ABI for x86_64 and 64-bit AArch64 tail-call handlers. Requires nightly Rust (recommended for maximum performance).
63-
- **`simd-x86`:** Enables x86-specific SIMD intrinsics and uses `unsafe` internally.
61+
- **`nightly`:** Enables all supported nightly-only optimizations. Enabled by default, with compiler capability detection and a stable fallback.
62+
- **`simd-intrinsics`:** Enables architecture-specific SIMD implementations where available, using `unsafe` internally. Enabled by default. Safe Wasm SIMD remains automatic.
6463

65-
With default features disabled, `tinywasm` supports `no_std + alloc` and depends only on `libm`.
64+
With default features disabled, `tinywasm` supports `no_std + alloc` and its runtime depends only on `libm`.
6665

6766
Use [`Engine`](https://docs.rs/tinywasm/latest/tinywasm/engine/struct.Engine.html) and [`engine::Config`](https://docs.rs/tinywasm/latest/tinywasm/engine/struct.Config.html) for non-default fuel accounting, stack sizing, or GC collection thresholds. A configured `ResourceLimiter` can allow, reject, or trap memory and table allocation or growth requests, and GC object allocations.
6867

‎crates/tinywasm/Cargo.toml‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,11 @@ tinywasm-cli = { path = "../cli", features = ["tests", "wat"] }
9292
wasm-testsuite.workspace = true
9393
wat.workspace = true
9494

95+
[build-dependencies]
96+
autocfg = "1.5"
97+
9598
[features]
96-
default = ["full", "std"]
99+
default = ["full", "nightly", "simd-intrinsics", "std"]
97100
full = ["archive", "debug", "parallel-parser", "parser", "state", "validate"]
98101

99102
log = ["dep:log", "tinywasm-parser?/log"]
@@ -129,16 +132,22 @@ debug = ["tinywasm-types/debug"]
129132
# expose module-internal by-index inspection APIs for non-exported entities (for testing and debugging)
130133
guest-debug = []
131134

132-
# use explicit tail calls for interpreter dispatch (requires nightly Rust)
135+
# enable all supported nightly-only optimizations
136+
nightly = ["nightly-abort-immediate", "nightly-rust-preserve-none", "nightly-tail-calls"]
137+
138+
# abort in place on internal invariant violations in release builds when supported by the compiler
139+
nightly-abort-immediate = []
140+
141+
# use explicit tail calls for interpreter dispatch when supported by the compiler
133142
nightly-tail-calls = []
134143

135144
# use the experimental preserve-none ABI for x86_64 and 64-bit AArch64 tail-call handlers
136145
nightly-rust-preserve-none = ["nightly-tail-calls"]
137146

138-
# enable x86-specific SIMD intrinsics in Value128 (uses unsafe code)
147+
# enable architecture-specific SIMD intrinsics in Value128 (uses unsafe code internally)
139148
# note: for x86 backend selection, compile with x86-64-v3 target features
140149
# (for example: `RUSTFLAGS="-C target-cpu=x86-64-v3"`)
141-
simd-x86 = []
150+
simd-intrinsics = []
142151

143152
[lints]
144153
workspace = true

‎crates/tinywasm/build.rs‎

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,41 @@
11
use std::env;
22

3+
const TAIL_CALLS_PROBE: &str = r#"
4+
#![no_std]
5+
#![allow(incomplete_features)]
6+
#![feature(explicit_tail_calls)]
7+
8+
#[inline(never)]
9+
pub fn callee(value: u32) -> u32 { value }
10+
pub fn caller(value: u32) -> u32 { become callee(value); }
11+
"#;
12+
13+
const PRESERVE_NONE_PROBE: &str = r#"
14+
#![no_std]
15+
#![allow(incomplete_features)]
16+
#![feature(explicit_tail_calls, rust_preserve_none_cc)]
17+
18+
#[inline(never)]
19+
pub extern "rust-preserve-none" fn callee(value: u32) -> u32 { value }
20+
pub extern "rust-preserve-none" fn caller(value: u32) -> u32 { become callee(value); }
21+
"#;
22+
23+
const ABORT_IMMEDIATE_PROBE: &str = r#"
24+
#![no_std]
25+
#![feature(abort_immediate)]
26+
27+
pub fn trap() -> ! { core::process::abort_immediate() }
28+
"#;
29+
330
fn main() {
431
println!("cargo::rerun-if-changed=build.rs");
5-
println!(
6-
"cargo::rustc-check-cfg=cfg(tail_abi, values(\"Rust\", \"C-unwind\", \"sysv64-unwind\", \"rust-preserve-none\"))"
7-
);
8-
println!("cargo::rustc-check-cfg=cfg(simd_backend, values(\"generic\", \"wasm\", \"x86\"))");
32+
println!("cargo::rerun-if-env-changed=RUSTC_BOOTSTRAP");
33+
configure_simd();
34+
configure_nightly();
35+
}
36+
37+
fn configure_simd() {
38+
println!("cargo::rustc-check-cfg=cfg(tw_simd_backend, values(\"generic\", \"wasm\", \"x86\"))");
939

1040
let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("Cargo target architecture");
1141
let features = env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or_default();
@@ -14,23 +44,44 @@ fn main() {
1444
.all(|required| features.split(',').any(|enabled| enabled == *required));
1545
let simd = match arch.as_str() {
1646
"wasm32" | "wasm64" => "wasm",
17-
"x86_64" if env::var_os("CARGO_FEATURE_SIMD_X86").is_some() && x86_v3 => "x86",
47+
"x86_64" if env::var_os("CARGO_FEATURE_SIMD_INTRINSICS").is_some() && x86_v3 => "x86",
1848
_ => "generic",
1949
};
20-
println!("cargo::rustc-cfg=simd_backend={simd:?}");
50+
println!("cargo::rustc-cfg=tw_simd_backend={simd:?}");
51+
}
2152

22-
if env::var_os("CARGO_FEATURE_NIGHTLY_TAIL_CALLS").is_none() {
53+
fn configure_nightly() {
54+
println!("cargo::rustc-check-cfg=cfg(tw_abort_immediate)");
55+
println!("cargo::rustc-check-cfg=cfg(tw_tail_calls)");
56+
println!(
57+
"cargo::rustc-check-cfg=cfg(tw_tail_abi, values(\"Rust\", \"C-unwind\", \"sysv64-unwind\", \"rust-preserve-none\"))"
58+
);
59+
let mut compiler = autocfg::new();
60+
compiler.set_edition(Some("2024".into()));
61+
if env::var_os("CARGO_FEATURE_NIGHTLY_ABORT_IMMEDIATE").is_some()
62+
&& compiler.probe_raw(ABORT_IMMEDIATE_PROBE).is_ok()
63+
{
64+
println!("cargo::rustc-cfg=tw_abort_immediate");
65+
}
66+
if env::var_os("CARGO_FEATURE_NIGHTLY_TAIL_CALLS").is_none() || compiler.probe_raw(TAIL_CALLS_PROBE).is_err() {
2367
return;
2468
}
2569

70+
let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("Cargo target architecture");
2671
let width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").expect("Cargo target pointer width");
2772
let os = env::var("CARGO_CFG_TARGET_OS").expect("Cargo target OS");
28-
let preserve_none = env::var_os("CARGO_FEATURE_NIGHTLY_RUST_PRESERVE_NONE").is_some();
29-
let abi = match (arch.as_str(), width.as_str(), os.as_str(), preserve_none) {
30-
("aarch64", "32", _, _) => "C-unwind",
31-
("x86_64", _, _, true) | ("aarch64", "64", _, true) => "rust-preserve-none",
32-
("x86_64", _, "windows", _) => "sysv64-unwind",
33-
_ => "Rust",
73+
let preserve_none = env::var_os("CARGO_FEATURE_NIGHTLY_RUST_PRESERVE_NONE").is_some()
74+
&& matches!((arch.as_str(), width.as_str()), ("x86_64", "64") | ("aarch64", "64"))
75+
&& compiler.probe_raw(PRESERVE_NONE_PROBE).is_ok();
76+
let abi = if preserve_none {
77+
"rust-preserve-none"
78+
} else {
79+
match (arch.as_str(), width.as_str(), os.as_str()) {
80+
("aarch64", "32", _) => "C-unwind",
81+
("x86_64", _, "windows") => "sysv64-unwind",
82+
_ => "Rust",
83+
}
3484
};
35-
println!("cargo::rustc-cfg=tail_abi={abi:?}");
85+
println!("cargo::rustc-cfg=tw_tail_calls");
86+
println!("cargo::rustc-cfg=tw_tail_abi={abi:?}");
3687
}

‎crates/tinywasm/src/collections/stack.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl<T: Copy + Default> StackLane<T> {
4242
}
4343

4444
/// Synchronizes the unchanged live height forwarded into a tail-dispatch handler.
45-
#[cfg(feature = "nightly-tail-calls")]
45+
#[cfg(tw_tail_calls)]
4646
#[inline(always)]
4747
pub(crate) fn set_height(&mut self, height: usize) {
4848
debug_assert_eq!(height, self.top);
@@ -357,7 +357,7 @@ mod tests {
357357
}
358358
}
359359

360-
#[cfg(any(debug_assertions, not(feature = "nightly-tail-calls")))]
360+
#[cfg(any(debug_assertions, not(tw_tail_calls)))]
361361
#[test]
362362
#[should_panic(expected = "value stack index out of range")]
363363
fn get_rejects_popped_slots() {
@@ -367,7 +367,7 @@ mod tests {
367367
stack.get(0);
368368
}
369369

370-
#[cfg(any(debug_assertions, not(feature = "nightly-tail-calls")))]
370+
#[cfg(any(debug_assertions, not(tw_tail_calls)))]
371371
#[test]
372372
#[should_panic(expected = "value stack index out of range")]
373373
fn set_rejects_popped_slots() {

‎crates/tinywasm/src/interpreter/executor/dispatch_become.rs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,13 @@ macro_rules! define_tail_dispatch {
8484
};
8585
}
8686

87-
#[cfg(tail_abi = "Rust")]
87+
#[cfg(tw_tail_abi = "Rust")]
8888
instruction_handlers!(define_tail_dispatch, "Rust");
89-
#[cfg(tail_abi = "C-unwind")]
89+
#[cfg(tw_tail_abi = "C-unwind")]
9090
instruction_handlers!(define_tail_dispatch, "C-unwind");
91-
#[cfg(tail_abi = "sysv64-unwind")]
91+
#[cfg(tw_tail_abi = "sysv64-unwind")]
9292
instruction_handlers!(define_tail_dispatch, "sysv64-unwind");
93-
#[cfg(tail_abi = "rust-preserve-none")]
93+
#[cfg(tw_tail_abi = "rust-preserve-none")]
9494
instruction_handlers!(define_tail_dispatch, "rust-preserve-none");
9595

9696
impl Executor<'_> {

‎crates/tinywasm/src/interpreter/executor/mod.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ mod budget;
2323

2424
pub(crate) use budget::Budget;
2525

26-
#[cfg(not(feature = "nightly-tail-calls"))]
26+
#[cfg(not(tw_tail_calls))]
2727
mod dispatch;
28-
#[cfg(feature = "nightly-tail-calls")]
28+
#[cfg(tw_tail_calls)]
2929
mod dispatch_become;
3030

3131
const FUEL_COST_CALL_TOTAL: u32 = 5;

‎crates/tinywasm/src/interpreter/simd/instructions.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use super::super::no_std_floats::NoStdFloatExt;
1010
use core::arch::wasm32 as wasm;
1111
#[cfg(target_arch = "wasm64")]
1212
use core::arch::wasm64 as wasm;
13-
#[cfg(simd_backend = "x86")]
13+
#[cfg(tw_simd_backend = "x86")]
1414
use core::arch::x86_64 as x86;
1515

1616
impl Value128 {

‎crates/tinywasm/src/interpreter/simd/macros.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
macro_rules! simd_impl {
44
($(wasm => $wasm:block)? $(x86 => $x86:block)? generic => $generic:block) => {
55
cfg_select! {
6-
simd_backend = "wasm" => { simd_impl!(@pick_wasm $( $wasm )? ; $generic) },
7-
simd_backend = "x86" => { simd_impl!(@pick_x86 $( $x86 )? ; $generic) },
6+
tw_simd_backend = "wasm" => { simd_impl!(@pick_wasm $( $wasm )? ; $generic) },
7+
tw_simd_backend = "x86" => { simd_impl!(@pick_x86 $( $x86 )? ; $generic) },
88
_ => { $generic }
99
}
1010
};

0 commit comments

Comments
 (0)