Update memfd support with a runtime toggle (#3778)
This commit updates the `memfd` support in Wasmtime to have a runtime toggle as to whether it's used or not. The compile-time feature gating `memfd` support is now also re-enabled by default, but the new runtime switch is still disabled-by-default. Additionally this commit updates our fuzz oracle to turn on/off the memfd flag to re-enable fuzzing with memfd on oss-fuzz.
This commit is contained in:
@@ -96,6 +96,7 @@ default = [
|
|||||||
"wasmtime/parallel-compilation",
|
"wasmtime/parallel-compilation",
|
||||||
"wasi-nn",
|
"wasi-nn",
|
||||||
"pooling-allocator",
|
"pooling-allocator",
|
||||||
|
"memfd",
|
||||||
]
|
]
|
||||||
jitdump = ["wasmtime/jitdump"]
|
jitdump = ["wasmtime/jitdump"]
|
||||||
vtune = ["wasmtime/vtune"]
|
vtune = ["wasmtime/vtune"]
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ pub struct WasmtimeConfig {
|
|||||||
pub(crate) consume_fuel: bool,
|
pub(crate) consume_fuel: bool,
|
||||||
memory_config: MemoryConfig,
|
memory_config: MemoryConfig,
|
||||||
force_jump_veneers: bool,
|
force_jump_veneers: bool,
|
||||||
|
memfd: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Arbitrary, Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Arbitrary, Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
@@ -99,7 +100,8 @@ impl Config {
|
|||||||
.cranelift_nan_canonicalization(self.wasmtime.canonicalize_nans)
|
.cranelift_nan_canonicalization(self.wasmtime.canonicalize_nans)
|
||||||
.cranelift_opt_level(self.wasmtime.opt_level.to_wasmtime())
|
.cranelift_opt_level(self.wasmtime.opt_level.to_wasmtime())
|
||||||
.interruptable(self.wasmtime.interruptable)
|
.interruptable(self.wasmtime.interruptable)
|
||||||
.consume_fuel(self.wasmtime.consume_fuel);
|
.consume_fuel(self.wasmtime.consume_fuel)
|
||||||
|
.memfd(self.wasmtime.memfd);
|
||||||
|
|
||||||
// If the wasm-smith-generated module use nan canonicalization then we
|
// If the wasm-smith-generated module use nan canonicalization then we
|
||||||
// don't need to enable it, but if it doesn't enable it already then we
|
// don't need to enable it, but if it doesn't enable it already then we
|
||||||
|
|||||||
@@ -51,7 +51,16 @@ wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync" }
|
|||||||
maintenance = { status = "actively-developed" }
|
maintenance = { status = "actively-developed" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ['async', 'cache', 'wat', 'jitdump', 'parallel-compilation', 'cranelift', 'pooling-allocator']
|
default = [
|
||||||
|
'async',
|
||||||
|
'cache',
|
||||||
|
'wat',
|
||||||
|
'jitdump',
|
||||||
|
'parallel-compilation',
|
||||||
|
'cranelift',
|
||||||
|
'pooling-allocator',
|
||||||
|
'memfd',
|
||||||
|
]
|
||||||
|
|
||||||
# An on-by-default feature enabling runtime compilation of WebAssembly modules
|
# An on-by-default feature enabling runtime compilation of WebAssembly modules
|
||||||
# with the Cranelift compiler. Cranelift is the default compilation backend of
|
# with the Cranelift compiler. Cranelift is the default compilation backend of
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ pub struct Config {
|
|||||||
pub(crate) module_version: ModuleVersionStrategy,
|
pub(crate) module_version: ModuleVersionStrategy,
|
||||||
pub(crate) parallel_compilation: bool,
|
pub(crate) parallel_compilation: bool,
|
||||||
pub(crate) paged_memory_initialization: bool,
|
pub(crate) paged_memory_initialization: bool,
|
||||||
|
pub(crate) memfd: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@@ -129,6 +130,7 @@ impl Config {
|
|||||||
parallel_compilation: true,
|
parallel_compilation: true,
|
||||||
// Default to paged memory initialization when using uffd on linux
|
// Default to paged memory initialization when using uffd on linux
|
||||||
paged_memory_initialization: cfg!(all(target_os = "linux", feature = "uffd")),
|
paged_memory_initialization: cfg!(all(target_os = "linux", feature = "uffd")),
|
||||||
|
memfd: false,
|
||||||
};
|
};
|
||||||
#[cfg(compiler)]
|
#[cfg(compiler)]
|
||||||
{
|
{
|
||||||
@@ -1170,6 +1172,33 @@ impl Config {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configures whether `memfd`, if supported, will be used to initialize
|
||||||
|
/// applicable module memories.
|
||||||
|
///
|
||||||
|
/// This is a Linux-specific feature since `memfd` is only supported on
|
||||||
|
/// Linux. Support for this is also enabled by default at compile time but
|
||||||
|
/// is otherwise disabled at runtime by default. This feature needs to be
|
||||||
|
/// enabled to `true` for support to be used.
|
||||||
|
///
|
||||||
|
/// Also note that even if this feature is enabled it may not be applicable
|
||||||
|
/// to all memories in all wasm modules. At this time memories must meet
|
||||||
|
/// specific criteria to be memfd-initialized:
|
||||||
|
///
|
||||||
|
/// * Only memories defined in the module can be initialized this way.
|
||||||
|
/// * Data segments for memory must use statically known offsets.
|
||||||
|
/// * Data segments for memory must all be in-bounds.
|
||||||
|
///
|
||||||
|
/// If all of the above applies, this setting is enabled, and the current
|
||||||
|
/// platform is Linux the `memfd` will be used to efficiently initialize
|
||||||
|
/// linear memories with `mmap` to avoid copying data from initializers into
|
||||||
|
/// linear memory.
|
||||||
|
#[cfg(feature = "memfd")]
|
||||||
|
#[cfg_attr(nightlydoc, doc(cfg(feature = "memfd")))]
|
||||||
|
pub fn memfd(&mut self, memfd: bool) -> &mut Self {
|
||||||
|
self.memfd = memfd;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn build_allocator(&self) -> Result<Box<dyn InstanceAllocator>> {
|
pub(crate) fn build_allocator(&self) -> Result<Box<dyn InstanceAllocator>> {
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
let stack_size = self.async_stack_size;
|
let stack_size = self.async_stack_size;
|
||||||
@@ -1239,6 +1268,7 @@ impl Clone for Config {
|
|||||||
module_version: self.module_version.clone(),
|
module_version: self.module_version.clone(),
|
||||||
parallel_compilation: self.parallel_compilation,
|
parallel_compilation: self.parallel_compilation,
|
||||||
paged_memory_initialization: self.paged_memory_initialization,
|
paged_memory_initialization: self.paged_memory_initialization,
|
||||||
|
memfd: self.memfd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -275,6 +275,21 @@
|
|||||||
//! all architectures for both the JIT compiler and the `wasmtime compile` CLI
|
//! all architectures for both the JIT compiler and the `wasmtime compile` CLI
|
||||||
//! command.
|
//! command.
|
||||||
//!
|
//!
|
||||||
|
//! * `pooling-allocator` - Enabled by default, this feature adds support for
|
||||||
|
//! the pooling allocation strategy enabled via
|
||||||
|
//! [`Config::allocation_strategy`]. The pooling allocator can enable more
|
||||||
|
//! efficient reuse of resources for high-concurrency and
|
||||||
|
//! high-instantiation-count scenarios.
|
||||||
|
//!
|
||||||
|
//! * `memfd` - Enabled by default, this feature builds in support for a
|
||||||
|
//! Linux-specific feature of creating a `memfd` where applicable for a
|
||||||
|
//! [`Module`]'s initial memory. This makes instantiation much faster by
|
||||||
|
//! `mmap`-ing the initial memory image into place instead of copying memory
|
||||||
|
//! into place, allowing sharing pages that end up only getting read and
|
||||||
|
//! otherwise using copy-on-write for efficient initialization of memory. Note
|
||||||
|
//! that this is simply compile-time support and this must also be enabled at
|
||||||
|
//! run-time via [`Config::memfd`].
|
||||||
|
//!
|
||||||
//! ## Examples
|
//! ## Examples
|
||||||
//!
|
//!
|
||||||
//! In addition to the examples below be sure to check out the [online embedding
|
//! In addition to the examples below be sure to check out the [online embedding
|
||||||
|
|||||||
@@ -724,6 +724,9 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn memfds(&self) -> Result<Option<&Arc<ModuleMemFds>>> {
|
pub(crate) fn memfds(&self) -> Result<Option<&Arc<ModuleMemFds>>> {
|
||||||
|
if !self.engine().config().memfd {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
Ok(self
|
Ok(self
|
||||||
.inner
|
.inner
|
||||||
.memfds
|
.memfds
|
||||||
|
|||||||
Reference in New Issue
Block a user