Skip to content

Commit 8c422a2

Browse files
alexcrichtonbongjunj
authored andcommitted
Change how wasm features/gc support work in Config (bytecodealliance#11463)
This commit aims to address bytecodealliance#11450 in complementary but somewhat orthogonal ways. First a new `Config::gc_support` option is added which is hooked up to the CLI as `-Wgc-support`. This option controls the wasmparser-internal `GC_TYPES` feature. Its default value, like before, is `cfg!(feature = "gc")` and additionally enabling it requires the `gc` crate feature to be enabled. This commit then additionally updates how wasm features are processed during validating a deserialized module to only require enabled features to be enabled in the host. Previously modules that disabled a feature but the feature was enabled in the host would fail to deserialize. All WebAssembly proposals are additive, however, so it's always ok to disable a feature and then load it into a module that enables the wasm proposal. Closes bytecodealliance#11450
1 parent d041d93 commit 8c422a2

File tree

3 files changed

+39
-68
lines changed

3 files changed

+39
-68
lines changed

crates/cli-flags/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,8 @@ wasmtime_option_group! {
403403
pub exceptions: Option<bool>,
404404
/// DEPRECATED: Configure support for the legacy exceptions proposal.
405405
pub legacy_exceptions: Option<bool>,
406+
/// Whether or not any GC infrastructure in Wasmtime is enabled or not.
407+
pub gc_support: Option<bool>,
406408
}
407409

408410
enum Wasm {
@@ -990,6 +992,10 @@ impl CommonOptions {
990992
true => err,
991993
}
992994

995+
if let Some(enable) = self.wasm.gc_support {
996+
config.gc_support(enable);
997+
}
998+
993999
Ok(config)
9941000
}
9951001

crates/wasmtime/src/config.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2226,11 +2226,14 @@ impl Config {
22262226
if self.max_wasm_stack == 0 {
22272227
bail!("max_wasm_stack size cannot be zero");
22282228
}
2229-
#[cfg(not(feature = "wmemcheck"))]
2230-
if self.wmemcheck {
2229+
if !cfg!(feature = "wmemcheck") && self.wmemcheck {
22312230
bail!("wmemcheck (memory checker) was requested but is not enabled in this build");
22322231
}
22332232

2233+
if !cfg!(feature = "gc") && features.gc_types() {
2234+
bail!("support for GC was disabled at compile time")
2235+
}
2236+
22342237
let mut tunables = Tunables::default_for_target(&self.compiler_target())?;
22352238

22362239
// If no target is explicitly specified then further refine `tunables`
@@ -2675,6 +2678,20 @@ impl Config {
26752678
self.tunables.signals_based_traps = Some(enable);
26762679
self
26772680
}
2681+
2682+
/// Enable/disable GC support in Wasmtime entirely.
2683+
///
2684+
/// This flag can be used to gate whether GC infrastructure is enabled or
2685+
/// initialized in Wasmtime at all. Wasmtime's GC implementation is required
2686+
/// for the [`Self::wasm_gc`] proposal, [`Self::wasm_function_references`],
2687+
/// and [`Self::wasm_exceptions`] at this time. None of those proposal can
2688+
/// be enabled without also having this option enabled.
2689+
///
2690+
/// This option defaults to whether the crate `gc` feature is enabled or
2691+
/// not.
2692+
pub fn gc_support(&mut self, enable: bool) -> &mut Self {
2693+
self.wasm_feature(WasmFeatures::GC_TYPES, enable)
2694+
}
26782695
}
26792696

26802697
impl Default for Config {

crates/wasmtime/src/engine/serialization.rs

Lines changed: 14 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -376,76 +376,29 @@ impl Metadata<'_> {
376376
Ok(())
377377
}
378378

379-
fn check_cfg_bool(
380-
cfg: bool,
381-
cfg_str: &str,
382-
found: bool,
383-
expected: bool,
384-
feature: impl fmt::Display,
385-
) -> Result<()> {
386-
if cfg {
387-
Self::check_bool(found, expected, feature)
388-
} else {
389-
assert!(!expected);
390-
ensure!(
391-
!found,
392-
"Module was compiled with {feature} but support in the host \
393-
was disabled at compile time because the `{cfg_str}` Cargo \
394-
feature was not enabled",
395-
);
396-
Ok(())
397-
}
398-
}
399-
400379
fn check_features(&mut self, other: &wasmparser::WasmFeatures) -> Result<()> {
401380
let module_features = wasmparser::WasmFeatures::from_bits_truncate(self.features);
402-
let difference = *other ^ module_features;
403-
for (name, flag) in difference.iter_names() {
404-
let found = module_features.contains(flag);
405-
let expected = other.contains(flag);
406-
// Give a slightly more specialized error message for the `GC_TYPES`
407-
// feature which isn't actually part of wasm itself but is gated by
408-
// compile-time crate features.
409-
if flag == wasmparser::WasmFeatures::GC_TYPES {
410-
Self::check_cfg_bool(
411-
cfg!(feature = "gc"),
412-
"gc",
413-
found,
414-
expected,
415-
WasmFeature(name),
416-
)?;
417-
} else {
418-
Self::check_bool(found, expected, WasmFeature(name))?;
419-
}
420-
}
421-
422-
return Ok(());
423-
424-
struct WasmFeature<'a>(&'a str);
425-
426-
impl fmt::Display for WasmFeature<'_> {
427-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
428-
write!(f, "support for WebAssembly feature `")?;
429-
for c in self.0.chars().map(|c| c.to_lowercase()) {
430-
write!(f, "{c}")?;
431-
}
432-
write!(f, "`")?;
433-
Ok(())
434-
}
381+
let missing_features = (*other & module_features) ^ module_features;
382+
for (name, _) in missing_features.iter_names() {
383+
let name = name.to_ascii_lowercase();
384+
bail!(
385+
"Module was compiled with support for WebAssembly feature \
386+
`{name}` but it is not enabled for the host",
387+
);
435388
}
389+
Ok(())
436390
}
437391

438392
fn check_collector(
439393
module: Option<wasmtime_environ::Collector>,
440394
host: Option<wasmtime_environ::Collector>,
441395
) -> Result<()> {
442396
match (module, host) {
443-
(None, None) => Ok(()),
397+
// If the module doesn't require GC support it doesn't matter
398+
// whether the host has GC support enabled or not.
399+
(None, _) => Ok(()),
444400
(Some(module), Some(host)) if module == host => Ok(()),
445401

446-
(None, Some(_)) => {
447-
bail!("module was compiled without GC but GC is enabled in the host")
448-
}
449402
(Some(_), None) => {
450403
bail!("module was compiled with GC however GC is disabled in the host")
451404
}
@@ -647,14 +600,9 @@ Caused by:
647600
let mut metadata = Metadata::new(&engine);
648601
metadata.features &= !wasmparser::WasmFeatures::THREADS.bits();
649602

650-
match metadata.check_compatible(&engine) {
651-
Ok(_) => unreachable!(),
652-
Err(e) => assert_eq!(
653-
e.to_string(),
654-
"Module was compiled without support for WebAssembly feature \
655-
`threads` but it is enabled for the host"
656-
),
657-
}
603+
// If a feature is disabled in the module and enabled in the host,
604+
// that's always ok.
605+
metadata.check_compatible(&engine)?;
658606

659607
let mut config = Config::new();
660608
config.wasm_threads(false);

0 commit comments

Comments
 (0)