diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index a2d5124003..a2aff6b262 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -352,6 +352,7 @@ pub struct Config { pub(crate) async_support: bool, pub(crate) deserialize_check_wasmtime_version: bool, pub(crate) parallel_compilation: bool, + pub(crate) paged_memory_initialization: bool, } impl Config { @@ -375,6 +376,8 @@ impl Config { async_support: false, deserialize_check_wasmtime_version: true, parallel_compilation: true, + // Default to paged memory initialization when using uffd on linux + paged_memory_initialization: cfg!(all(target_os = "linux", feature = "uffd")), }; #[cfg(compiler)] { @@ -984,6 +987,27 @@ impl Config { self } + /// Sets whether or not an attempt is made to initialize linear memories by page. + /// + /// This setting is `false` by default and Wasmtime initializes linear memories + /// by copying individual data segments from the compiled module. + /// + /// Setting this to `true` will cause compilation to attempt to organize the + /// data segments into WebAssembly pages and linear memories are initialized by + /// copying each page rather than individual data segments. + /// + /// Modules that import a memory or have data segments that use a global base + /// will continue to be initialized by copying each data segment individually. + /// + /// When combined with the `uffd` feature on Linux, this will allow Wasmtime + /// to delay initialization of a linear memory page until it is accessed + /// for the first time during WebAssembly execution; this may improve + /// instantiation performance as a result. + pub fn paged_memory_initialization(&mut self, value: bool) -> &mut Self { + self.paged_memory_initialization = value; + self + } + /// Configures the maximum size, in bytes, where a linear memory is /// considered static, above which it'll be considered dynamic. /// @@ -1329,6 +1353,7 @@ impl Clone for Config { async_stack_size: self.async_stack_size, deserialize_check_wasmtime_version: self.deserialize_check_wasmtime_version, parallel_compilation: self.parallel_compilation, + paged_memory_initialization: self.paged_memory_initialization, } } } diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs index d68b3b81b4..a786007885 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -380,7 +380,7 @@ impl Module { // If configured, attempt to use paged memory initialization // instead of the default mode of memory initialization - if cfg!(all(feature = "uffd", target_os = "linux")) { + if engine.config().paged_memory_initialization { translation.try_paged_init(); } diff --git a/tests/all/instance.rs b/tests/all/instance.rs index 3ba16eee11..32a2b706a2 100644 --- a/tests/all/instance.rs +++ b/tests/all/instance.rs @@ -32,6 +32,29 @@ fn initializes_linear_memory() -> Result<()> { Ok(()) } +#[test] +fn initializes_linear_memory_paged() -> Result<()> { + let wat = r#" + (module + (memory (export "memory") 2) + (data (i32.const 0) "Hello World!") + )"#; + + let mut config = Config::new(); + config.paged_memory_initialization(true); + + let module = Module::new(&Engine::new(&config)?, wat)?; + + let mut store = Store::new(module.engine(), ()); + let instance = Instance::new(&mut store, &module, &[])?; + let memory = instance.get_memory(&mut store, "memory").unwrap(); + + let mut bytes = [0; 12]; + memory.read(&store, 0, &mut bytes)?; + assert_eq!(bytes, "Hello World!".as_bytes()); + Ok(()) +} + #[test] fn linear_memory_limits() -> Result<()> { // this test will allocate 4GB of virtual memory space, and may not work in