Skip to content

Commit 9d94576

Browse files
authored
Make component linker allocations fallible (#13083)
* Make component linker allocations fallible * Address review feedback
1 parent 6734861 commit 9d94576

4 files changed

Lines changed: 60 additions & 63 deletions

File tree

crates/environ/src/component/names.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::collections::TryCow;
22
use crate::error::{Result, bail};
3-
use crate::prelude::*;
3+
use crate::{Atom, StringPool, prelude::*};
44
use alloc::sync::Arc;
55
use core::borrow::Borrow;
66
use core::hash::Hash;
@@ -263,6 +263,19 @@ impl NameMapIntern for NameMapNoIntern {
263263
}
264264
}
265265

266+
impl NameMapIntern for StringPool {
267+
type Key = Atom;
268+
type BorrowedKey = Atom;
269+
270+
fn intern(&mut self, string: &str) -> Result<Atom, OutOfMemory> {
271+
self.insert(string)
272+
}
273+
274+
fn lookup(&self, string: &str) -> Option<TryCow<'_, Atom>> {
275+
self.get_atom(string).map(TryCow::Owned)
276+
}
277+
}
278+
266279
/// Determines a version-based "alternate lookup key" for the `name` specified.
267280
///
268281
/// Some examples are:

crates/wasmtime/src/runtime/component/func/host.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,22 +76,22 @@ impl HostFunc {
7676
///
7777
/// Note that if `asyncness` is mistaken then that'll result in panics
7878
/// in Wasmtime, but not memory unsafety.
79-
fn new<T, F, P, R>(asyncness: Asyncness, func: F) -> Arc<HostFunc>
79+
fn new<T, F, P, R>(asyncness: Asyncness, func: F) -> Result<Arc<HostFunc>>
8080
where
8181
T: 'static,
8282
R: Send + Sync + 'static,
8383
F: HostFn<T, P, R> + Send + Sync + 'static,
8484
{
85-
Arc::new(HostFunc {
85+
Ok(try_new::<Arc<_>>(HostFunc {
8686
entrypoint: F::cabi_entrypoint,
8787
typecheck: F::typecheck,
88-
func: Box::new(func),
88+
func: try_new::<Box<_>>(func)?,
8989
asyncness,
90-
})
90+
})?)
9191
}
9292

9393
/// Equivalent for `Linker::func_wrap`
94-
pub(crate) fn func_wrap<T, F, P, R>(func: F) -> Arc<HostFunc>
94+
pub(crate) fn func_wrap<T, F, P, R>(func: F) -> Result<Arc<HostFunc>>
9595
where
9696
T: 'static,
9797
F: Fn(StoreContextMut<T>, P) -> Result<R> + Send + Sync + 'static,
@@ -108,7 +108,7 @@ impl HostFunc {
108108

109109
/// Equivalent for `Linker::func_wrap_async`
110110
#[cfg(feature = "async")]
111-
pub(crate) fn func_wrap_async<T, F, P, R>(func: F) -> Arc<HostFunc>
111+
pub(crate) fn func_wrap_async<T, F, P, R>(func: F) -> Result<Arc<HostFunc>>
112112
where
113113
T: 'static,
114114
F: Fn(StoreContextMut<'_, T>, P) -> Box<dyn Future<Output = Result<R>> + Send + '_>
@@ -132,7 +132,7 @@ impl HostFunc {
132132

133133
/// Equivalent for `Linker::func_wrap_concurrent`
134134
#[cfg(feature = "component-model-async")]
135-
pub(crate) fn func_wrap_concurrent<T, F, P, R>(func: F) -> Arc<HostFunc>
135+
pub(crate) fn func_wrap_concurrent<T, F, P, R>(func: F) -> Result<Arc<HostFunc>>
136136
where
137137
T: 'static,
138138
F: Fn(&Accessor<T>, P) -> Pin<Box<dyn Future<Output = Result<R>> + Send + '_>>
@@ -155,7 +155,7 @@ impl HostFunc {
155155
}
156156

157157
/// Equivalent of `Linker::func_new`
158-
pub(crate) fn func_new<T, F>(func: F) -> Arc<HostFunc>
158+
pub(crate) fn func_new<T, F>(func: F) -> Result<Arc<HostFunc>>
159159
where
160160
T: 'static,
161161
F: Fn(StoreContextMut<'_, T>, ComponentFunc, &[Val], &mut [Val]) -> Result<()>
@@ -177,7 +177,7 @@ impl HostFunc {
177177

178178
/// Equivalent of `Linker::func_new_async`
179179
#[cfg(feature = "async")]
180-
pub(crate) fn func_new_async<T, F>(func: F) -> Arc<HostFunc>
180+
pub(crate) fn func_new_async<T, F>(func: F) -> Result<Arc<HostFunc>>
181181
where
182182
T: 'static,
183183
F: for<'a> Fn(
@@ -209,7 +209,7 @@ impl HostFunc {
209209

210210
/// Equivalent of `Linker::func_new_concurrent`
211211
#[cfg(feature = "component-model-async")]
212-
pub(crate) fn func_new_concurrent<T, F>(func: F) -> Arc<HostFunc>
212+
pub(crate) fn func_new_concurrent<T, F>(func: F) -> Result<Arc<HostFunc>>
213213
where
214214
T: 'static,
215215
F: for<'a> Fn(

crates/wasmtime/src/runtime/component/linker.rs

Lines changed: 32 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,14 @@ use crate::component::types;
77
use crate::component::{
88
Component, ComponentNamedList, Instance, InstancePre, Lift, Lower, ResourceType, Val,
99
};
10-
use crate::hash_map::HashMap;
1110
use crate::prelude::*;
1211
use crate::{AsContextMut, Engine, Module, StoreContextMut};
1312
use alloc::sync::Arc;
1413
use core::marker;
1514
#[cfg(feature = "component-model-async")]
1615
use core::pin::Pin;
17-
use wasmtime_environ::PrimaryMap;
18-
use wasmtime_environ::collections::TryCow;
19-
use wasmtime_environ::component::{NameMap, NameMapIntern};
16+
use wasmtime_environ::component::NameMap;
17+
use wasmtime_environ::{Atom, PrimaryMap, StringPool};
2018

2119
/// A type used to instantiate [`Component`]s.
2220
///
@@ -61,9 +59,9 @@ use wasmtime_environ::component::{NameMap, NameMapIntern};
6159
/// be instantiated.
6260
pub struct Linker<T: 'static> {
6361
engine: Engine,
64-
strings: Strings,
65-
map: NameMap<usize, Definition>,
66-
path: Vec<usize>,
62+
strings: StringPool,
63+
map: NameMap<Atom, Definition>,
64+
path: Vec<Atom>,
6765
allow_shadowing: bool,
6866
_marker: marker::PhantomData<fn() -> T>,
6967
}
@@ -72,7 +70,7 @@ impl<T: 'static> Clone for Linker<T> {
7270
fn clone(&self) -> Linker<T> {
7371
Linker {
7472
engine: self.engine.clone(),
75-
strings: self.strings.clone(),
73+
strings: self.strings.clone_panic_on_oom(),
7674
map: self.map.clone_panic_on_oom(),
7775
path: self.path.clone(),
7876
allow_shadowing: self.allow_shadowing,
@@ -81,30 +79,24 @@ impl<T: 'static> Clone for Linker<T> {
8179
}
8280
}
8381

84-
#[derive(Clone, Default)]
85-
pub struct Strings {
86-
string2idx: HashMap<Arc<str>, usize>,
87-
strings: Vec<Arc<str>>,
88-
}
89-
9082
/// Structure representing an "instance" being defined within a linker.
9183
///
9284
/// Instances do not need to be actual [`Instance`]s and instead are defined by
9385
/// a "bag of named items", so each [`LinkerInstance`] can further define items
9486
/// internally.
9587
pub struct LinkerInstance<'a, T: 'static> {
9688
engine: &'a Engine,
97-
path: &'a mut Vec<usize>,
89+
path: &'a mut Vec<Atom>,
9890
path_len: usize,
99-
strings: &'a mut Strings,
100-
map: &'a mut NameMap<usize, Definition>,
91+
strings: &'a mut StringPool,
92+
map: &'a mut NameMap<Atom, Definition>,
10193
allow_shadowing: bool,
10294
_marker: marker::PhantomData<fn() -> T>,
10395
}
10496

10597
#[derive(Debug)]
10698
pub(crate) enum Definition {
107-
Instance(NameMap<usize, Definition>),
99+
Instance(NameMap<Atom, Definition>),
108100
Func(Arc<HostFunc>),
109101
Module(Module),
110102
Resource(ResourceType, Arc<crate::func::HostFunc>),
@@ -127,7 +119,7 @@ impl<T: 'static> Linker<T> {
127119
pub fn new(engine: &Engine) -> Linker<T> {
128120
Linker {
129121
engine: engine.clone(),
130-
strings: Strings::default(),
122+
strings: StringPool::default(),
131123
map: NameMap::default(),
132124
allow_shadowing: false,
133125
path: Vec::new(),
@@ -345,9 +337,20 @@ impl<T: 'static> Linker<T> {
345337

346338
match item_def {
347339
TypeDef::ComponentFunc(_) => {
348-
let fully_qualified_name = parent_instance
349-
.map(|parent| format!("{parent}#{item_name}"))
350-
.unwrap_or_else(|| item_name.to_owned());
340+
let fully_qualified_name = match parent_instance {
341+
Some(parent) => {
342+
let mut s = TryString::new();
343+
s.push_str(parent)?;
344+
s.push('#')?;
345+
s.push_str(item_name)?;
346+
s
347+
}
348+
None => {
349+
let mut s = TryString::new();
350+
s.push_str(item_name)?;
351+
s
352+
}
353+
};
351354
linker.func_new(&item_name, move |_, _, _, _| {
352355
bail!("unknown import: `{fully_qualified_name}` has not been defined")
353356
})?;
@@ -438,7 +441,7 @@ impl<T: 'static> LinkerInstance<'_, T> {
438441
Params: ComponentNamedList + Lift + 'static,
439442
Return: ComponentNamedList + Lower + 'static,
440443
{
441-
self.insert(name, Definition::Func(HostFunc::func_wrap(func)))?;
444+
self.insert(name, Definition::Func(HostFunc::func_wrap(func)?))?;
442445
Ok(())
443446
}
444447

@@ -485,7 +488,7 @@ impl<T: 'static> LinkerInstance<'_, T> {
485488
Params: ComponentNamedList + Lift + 'static,
486489
Return: ComponentNamedList + Lower + 'static,
487490
{
488-
self.insert(name, Definition::Func(HostFunc::func_wrap_async(f)))?;
491+
self.insert(name, Definition::Func(HostFunc::func_wrap_async(f)?))?;
489492
Ok(())
490493
}
491494

@@ -550,7 +553,7 @@ impl<T: 'static> LinkerInstance<'_, T> {
550553
if !self.engine.tunables().concurrency_support {
551554
bail!("concurrent host functions require `Config::concurrency_support`");
552555
}
553-
self.insert(name, Definition::Func(HostFunc::func_wrap_concurrent(f)))?;
556+
self.insert(name, Definition::Func(HostFunc::func_wrap_concurrent(f)?))?;
554557
Ok(())
555558
}
556559

@@ -661,7 +664,7 @@ impl<T: 'static> LinkerInstance<'_, T> {
661664
+ Sync
662665
+ 'static,
663666
) -> Result<()> {
664-
self.insert(name, Definition::Func(HostFunc::func_new(func)))?;
667+
self.insert(name, Definition::Func(HostFunc::func_new(func)?))?;
665668
Ok(())
666669
}
667670

@@ -684,7 +687,7 @@ impl<T: 'static> LinkerInstance<'_, T> {
684687
+ Sync
685688
+ 'static,
686689
{
687-
self.insert(name, Definition::Func(HostFunc::func_new_async(func)))?;
690+
self.insert(name, Definition::Func(HostFunc::func_new_async(func)?))?;
688691
Ok(())
689692
}
690693

@@ -712,7 +715,7 @@ impl<T: 'static> LinkerInstance<'_, T> {
712715
if !self.engine.tunables().concurrency_support {
713716
bail!("concurrent host functions require `Config::concurrency_support`");
714717
}
715-
self.insert(name, Definition::Func(HostFunc::func_new_concurrent(f)))?;
718+
self.insert(name, Definition::Func(HostFunc::func_new_concurrent(f)?))?;
716719
Ok(())
717720
}
718721

@@ -841,7 +844,7 @@ impl<T: 'static> LinkerInstance<'_, T> {
841844
Ok(self)
842845
}
843846

844-
fn insert(&mut self, name: &str, item: Definition) -> Result<usize> {
847+
fn insert(&mut self, name: &str, item: Definition) -> Result<Atom> {
845848
self.map
846849
.insert(name, self.strings, self.allow_shadowing, item)
847850
}
@@ -850,23 +853,3 @@ impl<T: 'static> LinkerInstance<'_, T> {
850853
self.map.get(name, self.strings)
851854
}
852855
}
853-
854-
impl NameMapIntern for Strings {
855-
type Key = usize;
856-
type BorrowedKey = usize;
857-
858-
fn intern(&mut self, string: &str) -> Result<usize, OutOfMemory> {
859-
if let Some(idx) = self.string2idx.get(string) {
860-
return Ok(*idx);
861-
}
862-
let string: Arc<str> = string.into();
863-
let idx = self.strings.len();
864-
self.strings.push(string.clone());
865-
self.string2idx.insert(string, idx);
866-
Ok(idx)
867-
}
868-
869-
fn lookup(&self, string: &str) -> Option<TryCow<'_, usize>> {
870-
self.string2idx.get(string).copied().map(TryCow::Owned)
871-
}
872-
}

crates/wasmtime/src/runtime/component/matching.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::Module;
22
use crate::component::ResourceType;
33
use crate::component::func::HostFunc;
4-
use crate::component::linker::{Definition, Strings};
4+
use crate::component::linker::Definition;
55
use crate::component::types::{FutureType, StreamType};
66
use crate::runtime::vm::component::ComponentInstance;
77
use crate::types::matching;
@@ -13,11 +13,12 @@ use wasmtime_environ::component::{
1313
TypeStreamTableIndex,
1414
};
1515
use wasmtime_environ::prelude::TryPrimaryMap;
16+
use wasmtime_environ::{Atom, StringPool};
1617

1718
pub struct TypeChecker<'a> {
1819
pub engine: &'a Engine,
1920
pub types: &'a Arc<ComponentTypes>,
20-
pub strings: &'a Strings,
21+
pub strings: &'a StringPool,
2122
pub imported_resources: Arc<TryPrimaryMap<ResourceIndex, ResourceType>>,
2223
}
2324

@@ -147,7 +148,7 @@ impl TypeChecker<'_> {
147148
fn instance(
148149
&mut self,
149150
expected: &TypeComponentInstance,
150-
actual: Option<&NameMap<usize, Definition>>,
151+
actual: Option<&NameMap<Atom, Definition>>,
151152
) -> Result<()> {
152153
// Like modules, every export in the expected type must be present in
153154
// the actual type. It's ok, though, to have extra exports in the actual

0 commit comments

Comments
 (0)