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