Skip to content

Commit 17899c8

Browse files
authored
Share empty ModuleRuntimeInfos across all stores in an engine (#12409)
* Share empty `ModuleRuntimeInfo`s across all stores in an engine This avoids an `Arc`- and `Box`-allocation during `Store` creation. * Fix no-runtime build * Pin x86-64_macos build to nightly to avoid a rustc bug
1 parent 58ce6b8 commit 17899c8

File tree

7 files changed

+41
-34
lines changed

7 files changed

+41
-34
lines changed

ci/build-build-matrix.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ const array = [
4444
// On OSX all we need to do is configure our deployment target as old as
4545
// possible. For now 10.12 is the limit.
4646
"env": { "MACOSX_DEPLOYMENT_TARGET": "10.12" },
47+
// Similar to https://github.com/bytecodealliance/wasmtime/pull/12245, we
48+
// need to avoid a rustc bug that results in linker errors depending on the
49+
// order and division of code into CGUs. This is fixed on nightly but not
50+
// stable yet.
51+
"rust": "wasmtime-ci-pinned-nightly",
4752
},
4853
{
4954
"build": "aarch64-macos",

crates/wasmtime/src/engine.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub use crate::runtime::code_memory::CustomCodeMemory;
55
#[cfg(feature = "runtime")]
66
use crate::runtime::type_registry::TypeRegistry;
77
#[cfg(feature = "runtime")]
8-
use crate::runtime::vm::GcRuntime;
8+
use crate::runtime::vm::{GcRuntime, ModuleRuntimeInfo};
99
use alloc::sync::Arc;
1010
use core::ptr::NonNull;
1111
#[cfg(target_has_atomic = "64")]
@@ -66,6 +66,12 @@ struct EngineInner {
6666
/// One-time check of whether the compiler's settings, if present, are
6767
/// compatible with the native host.
6868
compatible_with_native_host: crate::sync::OnceLock<Result<(), String>>,
69+
70+
/// The canonical empty `ModuleRuntimeInfo`, so that each store doesn't need
71+
/// allocate its own copy when creating its default caller instance or GC
72+
/// heap.
73+
#[cfg(feature = "runtime")]
74+
empty_module_runtime_info: ModuleRuntimeInfo,
6975
}
7076

7177
impl core::fmt::Debug for Engine {
@@ -122,6 +128,11 @@ impl Engine {
122128
#[cfg(not(any(feature = "cranelift", feature = "winch")))]
123129
let _ = &mut tunables;
124130

131+
#[cfg(feature = "runtime")]
132+
let empty_module_runtime_info = ModuleRuntimeInfo::bare(try_new(
133+
wasmtime_environ::Module::new(wasmtime_environ::StaticModuleIndex::from_u32(0)),
134+
)?)?;
135+
125136
Ok(Engine {
126137
inner: try_new::<Arc<_>>(EngineInner {
127138
#[cfg(any(feature = "cranelift", feature = "winch"))]
@@ -150,6 +161,8 @@ impl Engine {
150161
config,
151162
tunables,
152163
features,
164+
#[cfg(feature = "runtime")]
165+
empty_module_runtime_info,
153166
})?,
154167
})
155168
}
@@ -620,6 +633,11 @@ information about this check\
620633
pub fn is_pulley(&self) -> bool {
621634
self.target().is_pulley()
622635
}
636+
637+
#[cfg(feature = "runtime")]
638+
pub(crate) fn empty_module_runtime_info(&self) -> &ModuleRuntimeInfo {
639+
&self.inner.empty_module_runtime_info
640+
}
623641
}
624642

625643
#[cfg(any(feature = "cranelift", feature = "winch"))]

crates/wasmtime/src/runtime/store.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ use crate::{Engine, Module, Val, ValRaw, module::ModuleRegistry};
107107
#[cfg(feature = "gc")]
108108
use crate::{ExnRef, Rooted};
109109
use crate::{Global, Instance, Table};
110-
use alloc::sync::Arc;
111110
use core::convert::Infallible;
112111
use core::fmt;
113112
use core::marker;
@@ -116,7 +115,6 @@ use core::num::NonZeroU64;
116115
use core::ops::{Deref, DerefMut};
117116
use core::pin::Pin;
118117
use core::ptr::NonNull;
119-
use wasmtime_environ::StaticModuleIndex;
120118
use wasmtime_environ::{DefinedGlobalIndex, DefinedTableIndex, EntityRef, PrimaryMap, TripleExt};
121119

122120
mod context;
@@ -809,14 +807,10 @@ impl<T> Store<T> {
809807
// single "default callee" for the entire `Store`. This is then used as
810808
// part of `Func::call` to guarantee that the `callee: *mut VMContext`
811809
// is never null.
812-
let module = Arc::new(wasmtime_environ::Module::new(StaticModuleIndex::from_u32(
813-
0,
814-
)));
815-
let shim = ModuleRuntimeInfo::bare(module);
816810
let allocator = OnDemandInstanceAllocator::default();
817-
811+
let info = engine.empty_module_runtime_info();
818812
allocator
819-
.validate_module(shim.env_module(), shim.offsets())
813+
.validate_module(info.env_module(), info.offsets())
820814
.unwrap();
821815

822816
unsafe {
@@ -829,7 +823,7 @@ impl<T> Store<T> {
829823
AllocateInstanceKind::Dummy {
830824
allocator: &allocator,
831825
},
832-
&shim,
826+
info,
833827
Default::default(),
834828
))
835829
.expect("failed to allocate default callee");
@@ -1934,7 +1928,7 @@ impl StoreOpaque {
19341928
store: &mut StoreOpaque,
19351929
limiter: Option<&mut StoreResourceLimiter<'_>>,
19361930
) -> Result<GcStore> {
1937-
use wasmtime_environ::{StaticModuleIndex, packed_option::ReservedValue};
1931+
use wasmtime_environ::packed_option::ReservedValue;
19381932

19391933
let engine = store.engine();
19401934
let mem_ty = engine.tunables().gc_heap_memory_type();
@@ -1946,9 +1940,7 @@ impl StoreOpaque {
19461940
// First, allocate the memory that will be our GC heap's storage.
19471941
let mut request = InstanceAllocationRequest {
19481942
id: InstanceId::reserved_value(),
1949-
runtime_info: &ModuleRuntimeInfo::bare(Arc::new(wasmtime_environ::Module::new(
1950-
StaticModuleIndex::from_u32(0),
1951-
))),
1943+
runtime_info: engine.empty_module_runtime_info(),
19521944
imports: vm::Imports::default(),
19531945
store,
19541946
limiter,

crates/wasmtime/src/runtime/trampoline/memory.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub async fn create_memory(
4141
module
4242
.exports
4343
.insert(String::new(), EntityIndex::Memory(memory_id));
44+
let info = ModuleRuntimeInfo::bare(Arc::new(module))?;
4445

4546
// We create an instance in the on-demand allocator when creating handles
4647
// associated with external objects. The configured instance allocator
@@ -57,7 +58,7 @@ pub async fn create_memory(
5758
AllocateInstanceKind::Dummy {
5859
allocator: &allocator,
5960
},
60-
&ModuleRuntimeInfo::bare(Arc::new(module)),
61+
&info,
6162
Default::default(),
6263
)
6364
.await

crates/wasmtime/src/runtime/trampoline/table.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub async fn create_table(
4343
&ModuleRuntimeInfo::bare_with_registered_type(
4444
module,
4545
table.element().clone().into_registered_type(),
46-
),
46+
)?,
4747
imports,
4848
)
4949
.await

crates/wasmtime/src/runtime/trampoline/tag.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub fn create_tag(store: &mut StoreOpaque, ty: &TagType) -> Result<InstanceId> {
4848
AllocateInstanceKind::Dummy {
4949
allocator: &allocator,
5050
},
51-
&ModuleRuntimeInfo::bare_with_registered_type(module, Some(func_ty)),
51+
&ModuleRuntimeInfo::bare_with_registered_type(module, Some(func_ty))?,
5252
imports,
5353
))
5454
}

crates/wasmtime/src/runtime/vm.rs

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ use core::pin::pin;
4444
use core::ptr::NonNull;
4545
use core::sync::atomic::{AtomicUsize, Ordering};
4646
use core::task::{Context, Poll, Waker};
47+
use wasmtime_environ::error::OutOfMemory;
4748
use wasmtime_environ::{DefinedMemoryIndex, HostPtr, VMOffsets, VMSharedTypeIndex};
4849

4950
#[cfg(feature = "gc")]
@@ -284,19 +285,8 @@ struct VMStoreRawPtr(pub NonNull<dyn VMStore>);
284285
unsafe impl Send for VMStoreRawPtr {}
285286
unsafe impl Sync for VMStoreRawPtr {}
286287

287-
/// Functionality required by this crate for a particular module. This
288-
/// is chiefly needed for lazy initialization of various bits of
289-
/// instance state.
290-
///
291-
/// When an instance is created, it holds an `Arc<dyn ModuleRuntimeInfo>`
292-
/// so that it can get to signatures, metadata on functions, memory and
293-
/// funcref-table images, etc. All of these things are ordinarily known
294-
/// by the higher-level layers of Wasmtime. Specifically, the main
295-
/// implementation of this trait is provided by
296-
/// `wasmtime::module::ModuleInner`. Since the runtime crate sits at
297-
/// the bottom of the dependence DAG though, we don't know or care about
298-
/// that; we just need some implementor of this trait for each
299-
/// allocation request.
288+
/// Functionality required by this crate for a particular module. This is
289+
/// chiefly needed for lazy initialization of various bits of instance state.
300290
#[derive(Clone)]
301291
pub enum ModuleRuntimeInfo {
302292
Module(crate::Module),
@@ -315,19 +305,20 @@ pub struct BareModuleInfo {
315305
}
316306

317307
impl ModuleRuntimeInfo {
318-
pub(crate) fn bare(module: Arc<wasmtime_environ::Module>) -> Self {
308+
pub(crate) fn bare(module: Arc<wasmtime_environ::Module>) -> Result<Self, OutOfMemory> {
319309
ModuleRuntimeInfo::bare_with_registered_type(module, None)
320310
}
321311

322312
pub(crate) fn bare_with_registered_type(
323313
module: Arc<wasmtime_environ::Module>,
324314
registered_type: Option<RegisteredType>,
325-
) -> Self {
326-
ModuleRuntimeInfo::Bare(Box::new(BareModuleInfo {
315+
) -> Result<Self, OutOfMemory> {
316+
let info = try_new(BareModuleInfo {
327317
offsets: VMOffsets::new(HostPtr, &module),
328318
module,
329319
_registered_type: registered_type,
330-
}))
320+
})?;
321+
Ok(ModuleRuntimeInfo::Bare(info))
331322
}
332323

333324
/// The underlying Module.

0 commit comments

Comments
 (0)