wasmtime/runtime/component/linker.rs
1#[cfg(feature = "component-model-async")]
2use crate::component::concurrent::Accessor;
3use crate::component::func::HostFunc;
4use crate::component::instance::RuntimeImport;
5use crate::component::matching::{InstanceType, TypeChecker};
6use crate::component::types;
7use crate::component::{
8 Component, ComponentNamedList, Instance, InstancePre, Lift, Lower, ResourceType, Val,
9};
10use crate::prelude::*;
11use crate::{AsContextMut, Engine, Module, StoreContextMut};
12use alloc::sync::Arc;
13use core::marker;
14#[cfg(feature = "component-model-async")]
15use core::pin::Pin;
16use wasmtime_environ::component::{NameMap, NameMapIntern};
17use wasmtime_environ::{Atom, PrimaryMap, StringPool};
18
19/// A type used to instantiate [`Component`]s.
20///
21/// This type is used to supply host functionality to components. Values are
22/// defined in a [`Linker`] by their import name and then components are
23/// instantiated with a [`Linker`] using the names provided for name resolution
24/// of the component's imports.
25///
26/// # Names and Semver
27///
28/// Names defined in a [`Linker`] correspond to import names in the Component
29/// Model. Names in the Component Model are allowed to be semver-qualified, for
30/// example:
31///
32/// * `wasi:cli/stdout@0.2.0`
33/// * `wasi:http/types@0.2.0-rc-2023-10-25`
34/// * `my:custom/plugin@1.0.0-pre.2`
35///
36/// These version strings are taken into account when looking up names within a
37/// [`Linker`]. You're allowed to define any number of versions within a
38/// [`Linker`] still, for example you can define `a:b/c@0.2.0`, `a:b/c@0.2.1`,
39/// and `a:b/c@0.3.0` all at the same time.
40///
41/// Specifically though when names are looked up within a linker, for example
42/// during instantiation, semver-compatible names are automatically consulted.
43/// This means that if you define `a:b/c@0.2.1` in a [`Linker`] but a component
44/// imports `a:b/c@0.2.0` then that import will resolve to the `0.2.1` version.
45///
46/// This lookup behavior relies on hosts being well-behaved when using Semver,
47/// specifically that interfaces once defined are never changed. This reflects
48/// how Semver works at the Component Model layer, and it's assumed that if
49/// versions are present then hosts are respecting this.
50///
51/// Note that this behavior goes the other direction, too. If a component
52/// imports `a:b/c@0.2.1` and the host has provided `a:b/c@0.2.0` then that
53/// will also resolve correctly. This is because if an API was defined at 0.2.0
54/// and 0.2.1 then it must be the same API.
55///
56/// This behavior is intended to make it easier for hosts to upgrade WASI and
57/// for guests to upgrade WASI. So long as the actual "meat" of the
58/// functionality is defined then it should align correctly and components can
59/// be instantiated.
60pub struct Linker<T: 'static> {
61 engine: Engine,
62 strings: StringPool,
63 map: NameMap<Atom, Definition>,
64 path: Vec<Atom>,
65 allow_shadowing: bool,
66 _marker: marker::PhantomData<fn() -> T>,
67}
68
69impl<T: 'static> Clone for Linker<T> {
70 fn clone(&self) -> Linker<T> {
71 Linker {
72 engine: self.engine.clone(),
73 strings: self.strings.clone_panic_on_oom(),
74 map: self.map.clone_panic_on_oom(),
75 path: self.path.clone(),
76 allow_shadowing: self.allow_shadowing,
77 _marker: self._marker,
78 }
79 }
80}
81
82/// Structure representing an "instance" being defined within a linker.
83///
84/// Instances do not need to be actual [`Instance`]s and instead are defined by
85/// a "bag of named items", so each [`LinkerInstance`] can further define items
86/// internally.
87pub struct LinkerInstance<'a, T: 'static> {
88 engine: &'a Engine,
89 path: &'a mut Vec<Atom>,
90 path_len: usize,
91 strings: &'a mut StringPool,
92 map: &'a mut NameMap<Atom, Definition>,
93 allow_shadowing: bool,
94 _marker: marker::PhantomData<fn() -> T>,
95}
96
97#[derive(Debug)]
98pub(crate) enum Definition {
99 Instance(NameMap<Atom, Definition>),
100 Func(Arc<HostFunc>),
101 Module(Module),
102 Resource(ResourceType, Arc<crate::func::HostFunc>),
103}
104
105impl TryClone for Definition {
106 fn try_clone(&self) -> Result<Self, OutOfMemory> {
107 Ok(match self {
108 Self::Instance(i) => Self::Instance(i.try_clone()?),
109 Self::Func(f) => Self::Func(f.try_clone()?),
110 Self::Module(m) => Self::Module(m.clone()),
111 Self::Resource(r, f) => Self::Resource(*r, f.try_clone()?),
112 })
113 }
114}
115
116impl<T: 'static> Linker<T> {
117 /// Creates a new linker for the [`Engine`] specified with no items defined
118 /// within it.
119 pub fn new(engine: &Engine) -> Linker<T> {
120 Linker {
121 engine: engine.clone(),
122 strings: StringPool::default(),
123 map: NameMap::default(),
124 allow_shadowing: false,
125 path: Vec::new(),
126 _marker: marker::PhantomData,
127 }
128 }
129
130 /// Returns the [`Engine`] this is connected to.
131 pub fn engine(&self) -> &Engine {
132 &self.engine
133 }
134
135 /// Configures whether or not name-shadowing is allowed.
136 ///
137 /// By default name shadowing is not allowed and it's an error to redefine
138 /// the same name within a linker.
139 pub fn allow_shadowing(&mut self, allow: bool) -> &mut Self {
140 self.allow_shadowing = allow;
141 self
142 }
143
144 /// Returns the "root instance" of this linker, used to define names into
145 /// the root namespace.
146 pub fn root(&mut self) -> LinkerInstance<'_, T> {
147 LinkerInstance {
148 engine: &self.engine,
149 path: &mut self.path,
150 path_len: 0,
151 strings: &mut self.strings,
152 map: &mut self.map,
153 allow_shadowing: self.allow_shadowing,
154 _marker: self._marker,
155 }
156 }
157
158 /// Returns a builder for the named instance specified.
159 ///
160 /// # Errors
161 ///
162 /// Returns an error if `name` is already defined within the linker.
163 pub fn instance(&mut self, name: &str) -> Result<LinkerInstance<'_, T>> {
164 self.root().into_instance(name)
165 }
166
167 fn typecheck<'a>(&'a self, component: &'a Component) -> Result<TypeChecker<'a>> {
168 let mut cx = TypeChecker {
169 engine: &self.engine,
170 types: component.types(),
171 strings: &self.strings,
172 imported_resources: try_new::<Arc<_>>(TryPrimaryMap::new())?,
173 };
174
175 // Walk over the component's list of import names and use that to look up
176 // the definition within this linker that it corresponds to. When found
177 // perform a typecheck against the component's expected type.
178 let env_component = component.env_component();
179 for (_idx, (name, ty)) in env_component.import_types.iter() {
180 let import = self.map.get(name, &self.strings);
181 cx.definition(&ty.ty, import).with_context(|| {
182 format!(
183 "component imports {desc} `{name}`, but \
184 a matching implementation was not found in the linker",
185 desc = ty.ty.desc()
186 )
187 })?;
188 }
189 Ok(cx)
190 }
191
192 /// Returns the [`types::Component`] corresponding to `component` with resource
193 /// types imported by it replaced using imports present in [`Self`].
194 ///
195 /// # Errors
196 ///
197 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
198 /// memory allocation fails. See the `OutOfMemory` type's documentation for
199 /// details on Wasmtime's out-of-memory handling.
200 pub fn substituted_component_type(&self, component: &Component) -> Result<types::Component> {
201 let cx = self.typecheck(&component)?;
202 Ok(types::Component::from(
203 component.ty(),
204 &InstanceType {
205 types: cx.types,
206 resources: Some(&cx.imported_resources),
207 },
208 ))
209 }
210
211 /// Performs a "pre-instantiation" to resolve the imports of the
212 /// [`Component`] specified with the items defined within this linker.
213 ///
214 /// This method will perform as much work as possible short of actually
215 /// instantiating an instance. Internally this will use the names defined
216 /// within this linker to satisfy the imports of the [`Component`] provided.
217 /// Additionally this will perform type-checks against the component's
218 /// imports against all items defined within this linker.
219 ///
220 /// Note that unlike internally in components where subtyping at the
221 /// interface-types layer is supported this is not supported here. Items
222 /// defined in this linker must match the component's imports precisely.
223 ///
224 /// # Errors
225 ///
226 /// Returns an error if this linker doesn't define a name that the
227 /// `component` imports or if a name defined doesn't match the type of the
228 /// item imported by the `component` provided.
229 ///
230 /// Returns an error if `component` was not compiled by the same
231 /// [`Engine`](crate::Engine) as this linker.
232 ///
233 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
234 /// memory allocation fails. See the `OutOfMemory` type's documentation for
235 /// details on Wasmtime's out-of-memory handling.
236 pub fn instantiate_pre(&self, component: &Component) -> Result<InstancePre<T>> {
237 ensure!(
238 Engine::same(&self.engine, component.engine()),
239 "cross-`Engine` instantiation is not currently supported"
240 );
241 let cx = self.typecheck(&component)?;
242
243 // A successful typecheck resolves all of the imported resources used by
244 // this InstancePre. We keep a clone of this table in the InstancePre
245 // so that we can construct an InstanceType for typechecking.
246 let imported_resources = cx.imported_resources.clone();
247
248 // Now that all imports are known to be defined and satisfied by this
249 // linker a list of "flat" import items (aka no instances) is created
250 // using the import map within the component created at
251 // component-compile-time.
252 let env_component = component.env_component();
253 let mut imports = TryPrimaryMap::with_capacity(env_component.imports.len())?;
254 for (idx, (import, names)) in env_component.imports.iter() {
255 let (root, _) = &env_component.import_types[*import];
256
257 // This is the flattening process where we go from a definition
258 // optionally through a list of exported names to get to the final
259 // item.
260 let mut cur = self.map.get(root, &self.strings).unwrap();
261 for name in names {
262 cur = match cur {
263 Definition::Instance(map) => map.get(&name, &self.strings).unwrap(),
264 _ => unreachable!(),
265 };
266 }
267 let import = match cur {
268 Definition::Module(m) => RuntimeImport::Module(m.clone()),
269 Definition::Func(f) => RuntimeImport::Func(f.clone()),
270 Definition::Resource(t, dtor) => RuntimeImport::Resource {
271 ty: *t,
272 dtor: dtor.clone(),
273 dtor_funcref: component.resource_drop_func_ref(dtor),
274 },
275
276 // This is guaranteed by the compilation process that "leaf"
277 // runtime imports are never instances.
278 Definition::Instance(_) => unreachable!(),
279 };
280 let i = imports.push(import)?;
281 assert_eq!(i, idx);
282 }
283 Ok(unsafe {
284 InstancePre::new_unchecked(
285 component.clone(),
286 try_new::<Arc<_>>(PrimaryMap::from(imports))?,
287 imported_resources,
288 )
289 })
290 }
291
292 /// Instantiates the [`Component`] provided into the `store` specified.
293 ///
294 /// This function will use the items defined within this [`Linker`] to
295 /// satisfy the imports of the [`Component`] provided as necessary. For more
296 /// information about this see [`Linker::instantiate_pre`] as well.
297 ///
298 /// # Errors
299 ///
300 /// Returns an error if this [`Linker`] doesn't define an import that
301 /// `component` requires or if it is of the wrong type. Additionally this
302 /// can return an error if something goes wrong during instantiation such as
303 /// a runtime trap or a runtime limit being exceeded.
304 ///
305 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
306 /// memory allocation fails. See the `OutOfMemory` type's documentation for
307 /// details on Wasmtime's out-of-memory handling.
308 pub fn instantiate(
309 &self,
310 mut store: impl AsContextMut<Data = T>,
311 component: &Component,
312 ) -> Result<Instance> {
313 let store = store.as_context_mut();
314 store.0.validate_sync_call()?;
315 self.instantiate_pre(component)?.instantiate(store)
316 }
317
318 /// Instantiates the [`Component`] provided into the `store` specified.
319 ///
320 /// This is exactly like [`Linker::instantiate`] except for [asynchronous
321 /// execution](crate#async).
322 ///
323 /// # Errors
324 ///
325 /// Returns an error if this [`Linker`] doesn't define an import that
326 /// `component` requires or if it is of the wrong type. Additionally this
327 /// can return an error if something goes wrong during instantiation such as
328 /// a runtime trap or a runtime limit being exceeded.
329 ///
330 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
331 /// memory allocation fails. See the `OutOfMemory` type's documentation for
332 /// details on Wasmtime's out-of-memory handling.
333 #[cfg(feature = "async")]
334 pub async fn instantiate_async(
335 &self,
336 store: impl AsContextMut<Data = T>,
337 component: &Component,
338 ) -> Result<Instance>
339 where
340 T: Send,
341 {
342 self.instantiate_pre(component)?
343 .instantiate_async(store)
344 .await
345 }
346
347 /// Implement any imports of the given [`Component`] with a function which traps.
348 ///
349 /// By default a [`Linker`] will error when unknown imports are encountered when instantiating a [`Component`].
350 /// This changes this behavior from an instant error to a trap that will happen if the import is called.
351 ///
352 /// # Errors
353 ///
354 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
355 /// memory allocation fails. See the `OutOfMemory` type's documentation for
356 /// details on Wasmtime's out-of-memory handling.
357 pub fn define_unknown_imports_as_traps(&mut self, component: &Component) -> Result<()> {
358 self.define_unknown_imports(component, StubKind::Trap)
359 }
360
361 /// Implement any imports of the given [`Component`] with functions which
362 /// ignore their arguments and return default values.
363 ///
364 /// By default a [`Linker`] will error when unknown imports are encountered
365 /// when instantiating a [`Component`]. This changes that behavior from an
366 /// instant error to returning defaults when the import is called. See
367 /// [`Type::default_value`](crate::component::types::Type::default_value)
368 /// for what each type defaults to.
369 ///
370 /// Values are built when the import is called, not here, as a handle's
371 /// type depends on the instance it is flowing into.
372 ///
373 /// Not every result has a default: a `future`, `stream`, or
374 /// `error-context`, or a guest-defined resource, has none. Such an import
375 /// is still defined, but traps when called rather than preventing
376 /// instantiation, so a component which never calls it can still be run.
377 ///
378 /// # Errors
379 ///
380 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
381 /// memory allocation fails. See the `OutOfMemory` type's documentation for
382 /// details on Wasmtime's out-of-memory handling.
383 pub fn define_unknown_imports_as_default_values(
384 &mut self,
385 _store: impl AsContextMut<Data = T>,
386 component: &Component,
387 ) -> Result<()> {
388 self.define_unknown_imports(component, StubKind::DefaultValue)
389 }
390
391 /// Stub out all of `component`'s undefined imports.
392 fn define_unknown_imports(&mut self, component: &Component, kind: StubKind) -> Result<()> {
393 // Recursively stub out all imports of the component.
394 use wasmtime_environ::component::{ComponentTypes, ResourceIndex, TypeDef};
395
396 fn stub_item<T>(
397 linker: &mut LinkerInstance<T>,
398 resources: &mut TryEntitySet<ResourceIndex>,
399 item_name: &str,
400 item_def: &TypeDef,
401 parent_instance: Option<&str>,
402 types: &Arc<ComponentTypes>,
403 kind: StubKind,
404 ) -> Result<()> {
405 // The first definition of a resource needs to be present, but all other future
406 // references to the same resource are aliases of the original resource definition.
407 // Once a resource is visited here all future hits on the same resource shouldn't
408 // do anything else effectively. If item_name is already defined then we'll bail
409 // out in the below matches!, and otherwise a stub will be inserted, so no matter
410 // what the first resource is defined and all others will refer to that.
411 if let TypeDef::Resource(ty) = item_def
412 && !resources.insert(types[*ty].unwrap_concrete_ty())?
413 {
414 return Ok(());
415 }
416
417 // Skip if the item isn't an instance and has already been defined in the linker.
418 if !matches!(item_def, TypeDef::ComponentInstance(_)) && linker.get(item_name).is_some()
419 {
420 return Ok(());
421 }
422
423 match item_def {
424 TypeDef::ComponentFunc(_func_idx) => {
425 let fully_qualified_name = match parent_instance {
426 Some(parent) => {
427 let mut s = TryString::new();
428 s.push_str(parent)?;
429 s.push('#')?;
430 s.push_str(item_name)?;
431 s
432 }
433 None => {
434 let mut s = TryString::new();
435 s.push_str(item_name)?;
436 s
437 }
438 };
439
440 // An `async func`-typed import can never be satisfied by
441 // `func_new` (only a sync-typed import can) — see
442 // `typecheck_async`'s doc comment. Stub it with
443 // `func_new_concurrent` instead so unsatisfied async
444 // imports can be stubbed too, not just sync
445 // ones; if concurrency support isn't enabled there's no
446 // way to stub it here, so fall through to `func_new` and
447 // let instantiation fail with that same explanatory
448 // error.
449 #[cfg(feature = "component-model-async")]
450 if types[*_func_idx].async_ && linker.engine.tunables().concurrency_support {
451 linker.func_new_concurrent(&item_name, move |accessor, ty, params, results| {
452 let fully_qualified_name = fully_qualified_name.try_clone();
453 Box::pin(async move {
454 let fully_qualified_name = fully_qualified_name?;
455 match kind {
456 StubKind::Trap => bail!(
457 "unknown import: `{fully_qualified_name}` has not been defined"
458 ),
459 StubKind::DefaultValue => accessor
460 .with(|store| fill_defaults(store, &ty, params, results))
461 .with_context(|| {
462 format_err!(
463 "unknown import: `{fully_qualified_name}` has no \
464 default value"
465 )
466 }),
467 }
468 })
469 })?;
470 return Ok(());
471 }
472
473 linker.func_new(&item_name, move |store, ty, params, results| match kind {
474 StubKind::Trap => {
475 bail!("unknown import: `{fully_qualified_name}` has not been defined")
476 }
477 StubKind::DefaultValue => fill_defaults(store, &ty, params, results)
478 .with_context(|| {
479 format_err!(
480 "unknown import: `{fully_qualified_name}` has no default value"
481 )
482 }),
483 })?;
484 }
485 TypeDef::ComponentInstance(i) => {
486 let instance = &types[*i];
487 let mut linker_instance = linker.instance(item_name)?;
488 for (export_name, export) in instance.exports.iter() {
489 stub_item(
490 &mut linker_instance,
491 resources,
492 export_name,
493 &export.ty,
494 Some(item_name),
495 types,
496 kind,
497 )?;
498 }
499 }
500 TypeDef::Resource(_) => {
501 let ty = crate::component::ResourceType::host::<()>();
502 linker.resource(item_name, ty, |_, _| Ok(()))?;
503 }
504 TypeDef::Component(_) | TypeDef::Module(_) => {
505 bail!(
506 "unable to define {} imports as {}",
507 item_def.desc(),
508 kind.desc()
509 )
510 }
511 _ => {}
512 }
513 Ok(())
514 }
515
516 let mut resources = TryEntitySet::new();
517
518 for (_, (import_name, import_type)) in &component.env_component().import_types {
519 stub_item(
520 &mut self.root(),
521 &mut resources,
522 import_name,
523 &import_type.ty,
524 None,
525 component.types(),
526 kind,
527 )?;
528 }
529 Ok(())
530 }
531}
532
533/// Which flavor of stub `Linker::define_unknown_imports` installs.
534#[derive(Copy, Clone)]
535enum StubKind {
536 /// Stubs trap when called.
537 Trap,
538 /// Stubs return default values; see
539 /// `Linker::define_unknown_imports_as_default_values`.
540 DefaultValue,
541}
542
543impl StubKind {
544 /// A human readable description, for error messages.
545 fn desc(&self) -> &'static str {
546 match self {
547 StubKind::Trap => "traps",
548 StubKind::DefaultValue => "default values",
549 }
550 }
551}
552
553/// Drop every handle within `params`.
554fn drop_params(mut store: impl AsContextMut, params: &[Val]) -> Result<()> {
555 let mut store = store.as_context_mut();
556 for param in params {
557 drop_val(store.as_context_mut(), param)?;
558 }
559 Ok(())
560}
561
562/// Drop every handle within `val`.
563fn drop_val<T>(mut store: StoreContextMut<'_, T>, val: &Val) -> Result<()> {
564 match val {
565 // Drop through the internal entry point rather than the public
566 // `resource_drop`: this runs while servicing a guest call on a fiber,
567 // where `resource_drop`'s `validate_sync_call` check would reject the
568 // drop with "cannot do blocking `call` from an async context".
569 Val::Resource(resource) => resource.resource_drop_in_guest_call(&mut store)?,
570
571 // Without `component-model-async` these are uninhabited, so there is
572 // nothing to close.
573 #[cfg(feature = "component-model-async")]
574 Val::Future(future) => future.clone().close(&mut store)?,
575 #[cfg(feature = "component-model-async")]
576 Val::Stream(stream) => stream.clone().close(&mut store)?,
577 #[cfg(not(feature = "component-model-async"))]
578 Val::Future(_) | Val::Stream(_) => {}
579
580 Val::List(vals) | Val::Tuple(vals) | Val::FixedLengthList(vals) => {
581 for val in vals {
582 drop_val(store.as_context_mut(), val)?;
583 }
584 }
585 Val::Record(fields) => {
586 for (_, val) in fields {
587 drop_val(store.as_context_mut(), val)?;
588 }
589 }
590 Val::Map(entries) => {
591 for (key, val) in entries {
592 drop_val(store.as_context_mut(), key)?;
593 drop_val(store.as_context_mut(), val)?;
594 }
595 }
596 Val::Variant(_, Some(val)) | Val::Option(Some(val)) => {
597 drop_val(store.as_context_mut(), val)?
598 }
599 Val::Result(Ok(Some(val)) | Err(Some(val))) => drop_val(store.as_context_mut(), val)?,
600
601 // Lifting an `error-context` reads its representation without taking
602 // ownership of a handle, so there is nothing to drop.
603 Val::ErrorContext(_) => {}
604
605 Val::Bool(_)
606 | Val::S8(_)
607 | Val::U8(_)
608 | Val::S16(_)
609 | Val::U16(_)
610 | Val::S32(_)
611 | Val::U32(_)
612 | Val::S64(_)
613 | Val::U64(_)
614 | Val::Float32(_)
615 | Val::Float64(_)
616 | Val::Char(_)
617 | Val::String(_)
618 | Val::Enum(_)
619 | Val::Flags(_)
620 | Val::Variant(_, None)
621 | Val::Option(None)
622 | Val::Result(Ok(None) | Err(None)) => {}
623 }
624 Ok(())
625}
626
627/// Write a default value for each of `ty`'s results into `results`, after
628/// disposing of `params`.
629///
630/// `ty` comes from the call itself rather than from the linker, so its `own`
631/// and `borrow` types are those of the instance being called, which is what
632/// makes the handles this produces pass the guest's type check.
633fn fill_defaults(
634 mut store: impl AsContextMut,
635 ty: &types::ComponentFunc,
636 params: &[Val],
637 results: &mut [Val],
638) -> Result<()> {
639 drop_params(&mut store, params)?;
640 for (slot, ty) in results.iter_mut().zip(ty.results()) {
641 *slot = ty.default_value(&mut store)?;
642 }
643 Ok(())
644}
645
646impl<T: 'static> LinkerInstance<'_, T> {
647 fn as_mut(&mut self) -> LinkerInstance<'_, T> {
648 LinkerInstance {
649 engine: self.engine,
650 path: self.path,
651 path_len: self.path_len,
652 strings: self.strings,
653 map: self.map,
654 allow_shadowing: self.allow_shadowing,
655 _marker: self._marker,
656 }
657 }
658
659 /// Defines a new host-provided function into this [`LinkerInstance`].
660 ///
661 /// This method is used to give host functions to wasm components. The
662 /// `func` provided will be callable from linked components with the type
663 /// signature dictated by `Params` and `Return`. The `Params` is a tuple of
664 /// types that will come from wasm and `Return` is a value coming from the
665 /// host going back to wasm.
666 ///
667 /// Additionally the `func` takes a
668 /// [`StoreContextMut`](crate::StoreContextMut) as its first parameter.
669 ///
670 /// Note that `func` must be an `Fn` and must also be `Send + Sync +
671 /// 'static`. Shared state within a func is typically accessed with the `T`
672 /// type parameter from [`Store<T>`](crate::Store) which is accessible
673 /// through the leading [`StoreContextMut<'_, T>`](crate::StoreContextMut)
674 /// argument which can be provided to the `func` given here.
675 ///
676 /// # Blocking / Async Behavior
677 ///
678 /// The host function `func` provided here is a blocking function from the
679 /// perspective of WebAssembly. WebAssembly, and Rust, will be blocked until
680 /// `func` completes.
681 ///
682 /// To define a function which is async on the host, but blocking to the
683 /// guest, see the [`func_wrap_async`] method.
684 ///
685 /// [`func_wrap_async`]: LinkerInstance::func_wrap_async
686 ///
687 /// # Errors
688 ///
689 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
690 /// memory allocation fails. See the `OutOfMemory` type's documentation for
691 /// details on Wasmtime's out-of-memory handling.
692 //
693 // TODO: needs more words and examples
694 pub fn func_wrap<F, Params, Return>(&mut self, name: &str, func: F) -> Result<()>
695 where
696 F: Fn(StoreContextMut<T>, Params) -> Result<Return> + Send + Sync + 'static,
697 Params: ComponentNamedList + Lift + 'static,
698 Return: ComponentNamedList + Lower + 'static,
699 {
700 self.insert(name, Definition::Func(HostFunc::func_wrap(func)?))?;
701 Ok(())
702 }
703
704 /// Defines a new host-provided async function into this [`LinkerInstance`].
705 ///
706 /// This function is similar to [`Self::func_wrap`] except it takes an async
707 /// host function instead of a blocking host function. The `F` function here
708 /// is intended to be:
709 ///
710 /// ```ignore
711 /// F: AsyncFn(StoreContextMut<'_, T>, Params) -> Result<Return>
712 /// ```
713 ///
714 /// however the returned future must be `Send` which is not possible to
715 /// bound at this time. This will be switched to an async closure once Rust
716 /// supports it.
717 ///
718 /// # Blocking / Async Behavior
719 ///
720 /// The function defined which WebAssembly calls will still appear as
721 /// blocking from the perspective of WebAssembly itself. The host, however,
722 /// can perform asynchronous operations without blocking the thread
723 /// performing a call.
724 ///
725 /// When defining host functions with this function, WebAssembly is invoked
726 /// on a separate stack within a Wasmtime-managed fiber (through the
727 /// `call_async`-style of invocation). This means that if the future
728 /// returned by `F` is not immediately ready then the fiber will be
729 /// suspended to block WebAssembly but not the host. When the future
730 /// becomes ready again the fiber will be resumed to continue execution
731 /// within WebAssembly.
732 ///
733 /// [`func_wrap_async`]: LinkerInstance::func_wrap_async
734 #[cfg(feature = "async")]
735 pub fn func_wrap_async<Params, Return, F>(&mut self, name: &str, f: F) -> Result<()>
736 where
737 F: Fn(
738 StoreContextMut<'_, T>,
739 Params,
740 ) -> Box<dyn Future<Output = Result<Return>> + Send + '_>
741 + Send
742 + Sync
743 + 'static,
744 Params: ComponentNamedList + Lift + 'static,
745 Return: ComponentNamedList + Lower + 'static,
746 {
747 self.insert(name, Definition::Func(HostFunc::func_wrap_async(f)?))?;
748 Ok(())
749 }
750
751 /// Defines a new host-provided async function into this [`LinkerInstance`].
752 ///
753 /// This function defines a host function available to call from
754 /// WebAssembly. WebAssembly may additionally make multiple invocations of
755 /// this function concurrently all at the same time. This function requires
756 /// the [`Config::wasm_component_model_async`] feature to be enabled.
757 ///
758 /// The function `f` provided will be invoked when called by WebAssembly.
759 /// WebAssembly components may then call `f` multiple times while previous
760 /// invocations of `f` are already running. Additionally while `f` is
761 /// running other host functions may be invoked.
762 ///
763 /// The `F` function here is intended to be:
764 ///
765 /// ```ignore
766 /// F: AsyncFn(&Accessor<T>, Params) -> Result<Return>
767 /// ```
768 ///
769 /// however the returned future must be `Send` which is not possible to
770 /// bound at this time. This will be switched to an async closure once Rust
771 /// supports it.
772 ///
773 /// The closure `f` is provided an [`Accessor`] which can be used to acquire
774 /// temporary, blocking, access to a [`StoreContextMut`] (through
775 /// [`Access`](crate::component::Access]). This models how a store is not
776 /// available to `f` across `await` points but it is temporarily available
777 /// while actively being polled.
778 ///
779 /// # Blocking / Async Behavior
780 ///
781 /// Unlike [`Self::func_wrap`] and [`Self::func_wrap_async`] this function
782 /// is asynchronous even from the perspective of guest WebAssembly. This
783 /// means that if `f` is not immediately resolved then the call from
784 /// WebAssembly will still return immediately (assuming it was lowered with
785 /// `async`). The closure `f` should not block the current thread and
786 /// should only perform blocking via `async` meaning that `f` won't block
787 /// either WebAssembly nor the host.
788 ///
789 /// Note that WebAssembly components can lower host functions both with and
790 /// without `async`. That means that even if a host function is defined in
791 /// the "concurrent" mode here a guest may still lower it synchronously. In
792 /// this situation Wasmtime will manage blocking the guest while the closure
793 /// `f` provided here completes. If a guest lowers this function with
794 /// `async`, though, then no blocking will happen.
795 ///
796 /// [`Config::wasm_component_model_async`]: crate::Config::wasm_component_model_async
797 /// [`func_wrap_async`]: LinkerInstance::func_wrap_async
798 #[cfg(feature = "component-model-async")]
799 pub fn func_wrap_concurrent<Params, Return, F>(&mut self, name: &str, f: F) -> Result<()>
800 where
801 T: 'static,
802 F: Fn(&Accessor<T>, Params) -> Pin<Box<dyn Future<Output = Result<Return>> + Send + '_>>
803 + Send
804 + Sync
805 + 'static,
806 Params: ComponentNamedList + Lift + 'static,
807 Return: ComponentNamedList + Lower + 'static,
808 {
809 if !self.engine.tunables().concurrency_support {
810 bail!("concurrent host functions require `Config::concurrency_support`");
811 }
812 self.insert(name, Definition::Func(HostFunc::func_wrap_concurrent(f)?))?;
813 Ok(())
814 }
815
816 /// Define a new host-provided function using dynamically typed values.
817 ///
818 /// The `name` provided is the name of the function to define and the
819 /// `func` provided is the host-defined closure to invoke when this
820 /// function is called.
821 ///
822 /// This function is the "dynamic" version of defining a host function as
823 /// compared to [`LinkerInstance::func_wrap`]. With
824 /// [`LinkerInstance::func_wrap`] a function's type is statically known but
825 /// with this method the `func` argument's type isn't known ahead of time.
826 /// That means that `func` can be by imported component so long as it's
827 /// imported as a matching name.
828 ///
829 /// Type information will be available at execution time, however. For
830 /// example when `func` is invoked the second argument, a `&[Val]` list,
831 /// contains [`Val`] entries that say what type they are. Additionally the
832 /// third argument, `&mut [Val]`, is the expected number of results. Note
833 /// that the expected types of the results cannot be learned during the
834 /// execution of `func`. Learning that would require runtime introspection
835 /// of a component.
836 ///
837 /// Return values, stored in the third argument of `&mut [Val]`, are
838 /// type-checked at runtime to ensure that they have the appropriate type.
839 /// A trap will be raised if they do not have the right type.
840 ///
841 /// # Examples
842 ///
843 /// ```
844 /// use wasmtime::{Store, Engine};
845 /// use wasmtime::component::{Component, Linker, Val};
846 ///
847 /// # fn main() -> wasmtime::Result<()> {
848 /// let engine = Engine::default();
849 /// let component = Component::new(
850 /// &engine,
851 /// r#"
852 /// (component
853 /// (import "thunk" (func $thunk))
854 /// (import "is-even" (func $is-even (param "x" u32) (result bool)))
855 ///
856 /// (core module $m
857 /// (import "" "thunk" (func $thunk))
858 /// (import "" "is-even" (func $is-even (param i32) (result i32)))
859 ///
860 /// (func (export "run")
861 /// call $thunk
862 ///
863 /// (call $is-even (i32.const 1))
864 /// if unreachable end
865 ///
866 /// (call $is-even (i32.const 2))
867 /// i32.eqz
868 /// if unreachable end
869 /// )
870 /// )
871 /// (core func $thunk (canon lower (func $thunk)))
872 /// (core func $is-even (canon lower (func $is-even)))
873 /// (core instance $i (instantiate $m
874 /// (with "" (instance
875 /// (export "thunk" (func $thunk))
876 /// (export "is-even" (func $is-even))
877 /// ))
878 /// ))
879 ///
880 /// (func (export "run") (canon lift (core func $i "run")))
881 /// )
882 /// "#,
883 /// )?;
884 ///
885 /// let mut linker = Linker::<()>::new(&engine);
886 ///
887 /// // Sample function that takes no arguments.
888 /// linker.root().func_new("thunk", |_store, _ty, params, results| {
889 /// assert!(params.is_empty());
890 /// assert!(results.is_empty());
891 /// println!("Look ma, host hands!");
892 /// Ok(())
893 /// })?;
894 ///
895 /// // This function takes one argument and returns one result.
896 /// linker.root().func_new("is-even", |_store, _ty, params, results| {
897 /// assert_eq!(params.len(), 1);
898 /// let param = match params[0] {
899 /// Val::U32(n) => n,
900 /// _ => panic!("unexpected type"),
901 /// };
902 ///
903 /// assert_eq!(results.len(), 1);
904 /// results[0] = Val::Bool(param % 2 == 0);
905 /// Ok(())
906 /// })?;
907 ///
908 /// let mut store = Store::new(&engine, ());
909 /// let instance = linker.instantiate(&mut store, &component)?;
910 /// let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
911 /// run.call(&mut store, ())?;
912 /// # Ok(())
913 /// # }
914 /// ```
915 ///
916 /// # Errors
917 ///
918 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
919 /// memory allocation fails. See the `OutOfMemory` type's documentation for
920 /// details on Wasmtime's out-of-memory handling.
921 pub fn func_new(
922 &mut self,
923 name: &str,
924 func: impl Fn(StoreContextMut<'_, T>, types::ComponentFunc, &[Val], &mut [Val]) -> Result<()>
925 + Send
926 + Sync
927 + 'static,
928 ) -> Result<()> {
929 self.insert(name, Definition::Func(HostFunc::func_new(func)?))?;
930 Ok(())
931 }
932
933 /// Define a new host-provided async function using dynamic types.
934 ///
935 /// As [`Self::func_wrap_async`] is a dual of [`Self::func_wrap`], this
936 /// function is the dual of [`Self::func_new`].
937 ///
938 /// For documentation on blocking behavior see [`Self::func_wrap_async`].
939 #[cfg(feature = "async")]
940 pub fn func_new_async<F>(&mut self, name: &str, func: F) -> Result<()>
941 where
942 F: for<'a> Fn(
943 StoreContextMut<'a, T>,
944 types::ComponentFunc,
945 &'a [Val],
946 &'a mut [Val],
947 ) -> Box<dyn Future<Output = Result<()>> + Send + 'a>
948 + Send
949 + Sync
950 + 'static,
951 {
952 self.insert(name, Definition::Func(HostFunc::func_new_async(func)?))?;
953 Ok(())
954 }
955
956 /// Define a new host-provided async function using dynamic types.
957 ///
958 /// As [`Self::func_wrap_concurrent`] is a dual of [`Self::func_wrap`], this
959 /// function is the dual of [`Self::func_new`].
960 ///
961 /// For documentation on async/blocking behavior see
962 /// [`Self::func_wrap_concurrent`].
963 #[cfg(feature = "component-model-async")]
964 pub fn func_new_concurrent<F>(&mut self, name: &str, f: F) -> Result<()>
965 where
966 T: 'static,
967 F: for<'a> Fn(
968 &'a Accessor<T>,
969 types::ComponentFunc,
970 &'a [Val],
971 &'a mut [Val],
972 ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>
973 + Send
974 + Sync
975 + 'static,
976 {
977 if !self.engine.tunables().concurrency_support {
978 bail!("concurrent host functions require `Config::concurrency_support`");
979 }
980 self.insert(name, Definition::Func(HostFunc::func_new_concurrent(f)?))?;
981 Ok(())
982 }
983
984 /// Defines a [`Module`] within this instance.
985 ///
986 /// This can be used to provide a core wasm [`Module`] as an import to a
987 /// component. The [`Module`] provided is saved within the linker for the
988 /// specified `name` in this instance.
989 ///
990 /// # Errors
991 ///
992 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
993 /// memory allocation fails. See the `OutOfMemory` type's documentation for
994 /// details on Wasmtime's out-of-memory handling.
995 pub fn module(&mut self, name: &str, module: &Module) -> Result<()> {
996 self.insert(name, Definition::Module(module.clone()))?;
997 Ok(())
998 }
999
1000 /// Defines a new resource of a given [`ResourceType`] in this linker.
1001 ///
1002 /// This function is used to specify resources defined in the host.
1003 ///
1004 /// The `name` argument is the name to define the resource within this
1005 /// linker.
1006 ///
1007 /// The `dtor` provided is a destructor that will get invoked when an owned
1008 /// version of this resource is destroyed from the guest. Note that this
1009 /// destructor is not called when a host-owned resource is destroyed as it's
1010 /// assumed the host knows how to handle destroying its own resources.
1011 ///
1012 /// The `dtor` closure is provided the store state as the first argument
1013 /// along with the representation of the resource that was just destroyed.
1014 ///
1015 /// [`Resource<U>`]: crate::component::Resource
1016 ///
1017 /// # Errors
1018 ///
1019 /// The provided `dtor` closure returns an error if something goes wrong
1020 /// when a guest calls the `dtor` to drop a `Resource<T>` such as
1021 /// a runtime trap or a runtime limit being exceeded.
1022 ///
1023 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
1024 /// memory allocation fails. See the `OutOfMemory` type's documentation for
1025 /// details on Wasmtime's out-of-memory handling.
1026 pub fn resource(
1027 &mut self,
1028 name: &str,
1029 ty: ResourceType,
1030 dtor: impl Fn(StoreContextMut<'_, T>, u32) -> Result<()> + Send + Sync + 'static,
1031 ) -> Result<()> {
1032 let dtor = try_new::<Arc<_>>(crate::func::HostFunc::wrap(
1033 &self.engine,
1034 move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| dtor(cx.as_context_mut(), param),
1035 )?)?;
1036 self.insert(name, Definition::Resource(ty, dtor))?;
1037 Ok(())
1038 }
1039
1040 /// Identical to [`Self::resource`], except that it takes an async destructor.
1041 #[cfg(feature = "async")]
1042 pub fn resource_async<F>(&mut self, name: &str, ty: ResourceType, dtor: F) -> Result<()>
1043 where
1044 T: Send,
1045 F: Fn(StoreContextMut<'_, T>, u32) -> Box<dyn Future<Output = Result<()>> + Send + '_>
1046 + Send
1047 + Sync
1048 + 'static,
1049 {
1050 let dtor = try_new::<Arc<_>>(crate::func::HostFunc::wrap_async(
1051 &self.engine,
1052 move |cx: crate::Caller<'_, T>, (param,): (u32,)| dtor(cx.into(), param),
1053 )?)?;
1054 self.insert(name, Definition::Resource(ty, dtor))?;
1055 Ok(())
1056 }
1057
1058 /// Identical to [`Self::resource`], except that it takes a concurrent destructor.
1059 #[cfg(feature = "component-model-async")]
1060 pub fn resource_concurrent<F>(&mut self, name: &str, ty: ResourceType, dtor: F) -> Result<()>
1061 where
1062 T: Send + 'static,
1063 F: Fn(&Accessor<T>, u32) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>>
1064 + Send
1065 + Sync
1066 + 'static,
1067 {
1068 if !self.engine.tunables().concurrency_support {
1069 bail!("concurrent host functions require `Config::concurrency_support`");
1070 }
1071 // TODO: This isn't really concurrent -- it requires exclusive access to
1072 // the store for the duration of the call, preventing guest code from
1073 // running until it completes. We should make it concurrent and clean
1074 // up the implementation to avoid using e.g. `Accessor::new` and
1075 // `tls::set` directly.
1076 let dtor = Arc::new(dtor);
1077 let dtor = Arc::new(crate::func::HostFunc::wrap_async(
1078 &self.engine,
1079 move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| {
1080 let dtor = dtor.clone();
1081 Box::new(async move {
1082 let mut store = cx.as_context_mut();
1083 let accessor =
1084 &Accessor::new(crate::store::StoreToken::new(store.as_context_mut()));
1085 let mut future = core::pin::pin!(dtor(accessor, param));
1086 core::future::poll_fn(|cx| {
1087 crate::component::concurrent::tls::set(store.0, || future.as_mut().poll(cx))
1088 })
1089 .await
1090 })
1091 },
1092 )?);
1093 self.insert(name, Definition::Resource(ty, dtor))?;
1094 Ok(())
1095 }
1096
1097 /// Defines a nested instance within this instance.
1098 ///
1099 /// This can be used to describe arbitrarily nested levels of instances
1100 /// within a linker to satisfy nested instance exports of components.
1101 pub fn instance(&mut self, name: &str) -> Result<LinkerInstance<'_, T>> {
1102 self.as_mut().into_instance(name)
1103 }
1104
1105 /// Same as [`LinkerInstance::instance`] except with different lifetime
1106 /// parameters.
1107 pub fn into_instance(mut self, name: &str) -> Result<Self> {
1108 let atom = self.strings.intern(name)?;
1109
1110 // If this item is already an instance then don't stomp over it with a
1111 // new empty instance (or fail due to shadowing being disallowed).
1112 // Instead continue through to below to explicitly allow re-opening an
1113 // instance multiple times over separate API calls.
1114 //
1115 // If this item isn't defined, or is defined as anything other than an
1116 // instance, however, the insert a fresh new instance and see what
1117 // happens as a result.
1118 match self.map.raw_get_mut(&atom) {
1119 Some(Definition::Instance(_)) => {}
1120 _ => {
1121 self.insert(name, Definition::Instance(NameMap::default()))?;
1122 }
1123 }
1124 self.map = match self.map.raw_get_mut(&atom) {
1125 Some(Definition::Instance(map)) => map,
1126 _ => unreachable!(),
1127 };
1128 self.path.truncate(self.path_len);
1129 self.path.push(atom);
1130 self.path_len += 1;
1131 Ok(self)
1132 }
1133
1134 fn insert(&mut self, name: &str, item: Definition) -> Result<Atom> {
1135 self.map
1136 .insert(name, self.strings, self.allow_shadowing, item)
1137 }
1138
1139 fn get(&self, name: &str) -> Option<&Definition> {
1140 self.map.get(name, self.strings)
1141 }
1142}