soroban_wasmi/
linker.rs

1use crate::{
2    collections::{
3        string_interner::{InternHint, Sym as Symbol},
4        StringInterner,
5    },
6    func::{FuncEntity, HostFuncEntity, HostFuncTrampolineEntity},
7    module::{ImportName, ImportType},
8    AsContext,
9    AsContextMut,
10    Caller,
11    Engine,
12    Error,
13    Extern,
14    ExternType,
15    Func,
16    FuncType,
17    GlobalType,
18    InstancePre,
19    IntoFunc,
20    MemoryType,
21    Module,
22    TableType,
23    Val,
24};
25use core::{
26    fmt::{self, Debug, Display},
27    marker::PhantomData,
28};
29use std::{
30    collections::{btree_map::Entry, BTreeMap},
31    sync::Arc,
32    vec::Vec,
33};
34
35/// An error that may occur upon operating with [`Linker`] instances.
36#[derive(Debug)]
37pub enum LinkerError {
38    /// Encountered duplicate definitions for the same name.
39    DuplicateDefinition {
40        /// The duplicate import name of the definition.
41        import_name: ImportName,
42    },
43    /// Encountered when no definition for an import is found.
44    MissingDefinition {
45        /// The name of the import for which no definition was found.
46        name: ImportName,
47        /// The type of the import for which no definition has been found.
48        ty: ExternType,
49    },
50    /// Encountered when a definition with invalid type is found.
51    InvalidTypeDefinition {
52        /// The name of the import for which no definition was found.
53        name: ImportName,
54        /// The expected import type.
55        expected: ExternType,
56        /// The found definition type.
57        found: ExternType,
58    },
59    /// Encountered when a [`FuncType`] does not match the expected [`FuncType`].
60    FuncTypeMismatch {
61        /// The name of the import with the mismatched type.
62        name: ImportName,
63        /// The expected [`FuncType`].
64        expected: FuncType,
65        /// The mismatching [`FuncType`] found.
66        found: FuncType,
67    },
68    /// Encountered when a [`TableType`] does not match the expected [`TableType`].
69    InvalidTableSubtype {
70        /// The name of the import with the invalid [`TableType`].
71        name: ImportName,
72        /// The [`TableType`] that is supposed to be a subtype of `other`.
73        ty: TableType,
74        /// The [`TableType`] this is supposed to be a supertype of `ty`.
75        other: TableType,
76    },
77    /// Encountered when a [`MemoryType`] does not match the expected [`MemoryType`].
78    InvalidMemorySubtype {
79        /// The name of the import with the invalid [`MemoryType`].
80        name: ImportName,
81        /// The [`MemoryType`] that is supposed to be a subtype of `other`.
82        ty: MemoryType,
83        /// The [`MemoryType`] this is supposed to be a supertype of `ty`.
84        other: MemoryType,
85    },
86    /// Encountered when a [`GlobalType`] does not match the expected [`GlobalType`].
87    GlobalTypeMismatch {
88        /// The name of the import with the mismatched type.
89        name: ImportName,
90        /// The expected [`GlobalType`].
91        expected: GlobalType,
92        /// The mismatching [`GlobalType`] found.
93        found: GlobalType,
94    },
95}
96
97impl LinkerError {
98    /// Creates a new [`LinkerError`] for when an imported definition was not found.
99    fn missing_definition(import: &ImportType) -> Self {
100        Self::MissingDefinition {
101            name: import.import_name().clone(),
102            ty: import.ty().clone(),
103        }
104    }
105
106    /// Creates a new [`LinkerError`] for when an imported definition has an invalid type.
107    fn invalid_type_definition(import: &ImportType, found: &ExternType) -> Self {
108        Self::InvalidTypeDefinition {
109            name: import.import_name().clone(),
110            expected: import.ty().clone(),
111            found: found.clone(),
112        }
113    }
114
115    /// Create a new [`LinkerError`] for when a [`FuncType`] mismatched.
116    fn func_type_mismatch(name: &ImportName, expected: &FuncType, found: &FuncType) -> Self {
117        Self::FuncTypeMismatch {
118            name: name.clone(),
119            expected: expected.clone(),
120            found: found.clone(),
121        }
122    }
123
124    /// Create a new [`LinkerError`] for when a [`TableType`] `ty` unexpectedly is not a subtype of `other`.
125    fn table_type_mismatch(name: &ImportName, ty: &TableType, other: &TableType) -> Self {
126        Self::InvalidTableSubtype {
127            name: name.clone(),
128            ty: *ty,
129            other: *other,
130        }
131    }
132
133    /// Create a new [`LinkerError`] for when a [`MemoryType`] `ty` unexpectedly is not a subtype of `other`.
134    fn invalid_memory_subtype(name: &ImportName, ty: &MemoryType, other: &MemoryType) -> Self {
135        Self::InvalidMemorySubtype {
136            name: name.clone(),
137            ty: *ty,
138            other: *other,
139        }
140    }
141
142    /// Create a new [`LinkerError`] for when a [`GlobalType`] mismatched.
143    fn global_type_mismatch(name: &ImportName, expected: &GlobalType, found: &GlobalType) -> Self {
144        Self::GlobalTypeMismatch {
145            name: name.clone(),
146            expected: *expected,
147            found: *found,
148        }
149    }
150}
151
152#[cfg(feature = "std")]
153impl std::error::Error for LinkerError {}
154
155impl Display for LinkerError {
156    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157        match self {
158            Self::DuplicateDefinition { import_name } => {
159                write!(
160                    f,
161                    "encountered duplicate definition with name `{import_name}`",
162                )
163            }
164            Self::MissingDefinition { name, ty } => {
165                write!(
166                    f,
167                    "cannot find definition for import {name} with type {ty:?}",
168                )
169            }
170            Self::InvalidTypeDefinition {
171                name,
172                expected,
173                found,
174            } => {
175                write!(f, "found definition for import {name} with type {expected:?} but found type {found:?}")
176            }
177            Self::FuncTypeMismatch {
178                name,
179                expected,
180                found,
181            } => {
182                write!(
183                    f,
184                    "function type mismatch for import {name}: \
185                    expected {expected:?} but found {found:?}",
186                )
187            }
188            Self::InvalidTableSubtype { name, ty, other } => {
189                write!(
190                    f,
191                    "import {name}: table type {ty:?} is not a subtype of {other:?}"
192                )
193            }
194            Self::InvalidMemorySubtype { name, ty, other } => {
195                write!(
196                    f,
197                    "import {name}: memory type {ty:?} is not a subtype of {other:?}"
198                )
199            }
200            Self::GlobalTypeMismatch {
201                name,
202                expected,
203                found,
204            } => {
205                write!(
206                    f,
207                    "global variable type mismatch for import {name}: \
208                    expected {expected:?} but found {found:?}",
209                )
210            }
211        }
212    }
213}
214
215/// Wasm import keys.
216#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
217#[repr(transparent)]
218struct ImportKey {
219    /// Merged module and name symbols.
220    ///
221    /// Merging allows for a faster `Ord` implementation.
222    module_and_name: u64,
223}
224
225impl Debug for ImportKey {
226    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227        f.debug_struct("ImportKey")
228            .field("module", &self.module())
229            .field("name", &self.name())
230            .finish()
231    }
232}
233
234impl ImportKey {
235    /// Creates a new [`ImportKey`] from the given `module` and `name` symbols.
236    #[inline]
237    pub fn new(module: Symbol, name: Symbol) -> Self {
238        let module_and_name = u64::from(module.into_u32()) << 32 | u64::from(name.into_u32());
239        Self { module_and_name }
240    }
241
242    /// Returns the `module` [`Symbol`] of the [`ImportKey`].
243    #[inline]
244    pub fn module(&self) -> Symbol {
245        Symbol::from_u32((self.module_and_name >> 32) as u32)
246    }
247
248    /// Returns the `name` [`Symbol`] of the [`ImportKey`].
249    #[inline]
250    pub fn name(&self) -> Symbol {
251        Symbol::from_u32(self.module_and_name as u32)
252    }
253}
254
255/// A [`Linker`] definition.
256#[derive(Debug)]
257enum Definition<T> {
258    /// An external item from an [`Instance`](crate::Instance).
259    Extern(Extern),
260    /// A [`Linker`] internal host function.
261    HostFunc(HostFuncTrampolineEntity<T>),
262}
263
264impl<T> Clone for Definition<T> {
265    fn clone(&self) -> Self {
266        match self {
267            Self::Extern(definition) => Self::Extern(*definition),
268            Self::HostFunc(host_func) => Self::HostFunc(host_func.clone()),
269        }
270    }
271}
272
273impl<T> Definition<T> {
274    /// Returns the [`Extern`] item if this [`Definition`] is [`Definition::Extern`].
275    ///
276    /// Otherwise returns `None`.
277    fn as_extern(&self) -> Option<&Extern> {
278        match self {
279            Definition::Extern(item) => Some(item),
280            Definition::HostFunc(_) => None,
281        }
282    }
283
284    /// Returns the [`ExternType`] of the [`Definition`].
285    pub fn ty(&self, ctx: impl AsContext) -> ExternType {
286        match self {
287            Definition::Extern(item) => item.ty(ctx),
288            Definition::HostFunc(host_func) => ExternType::Func(host_func.func_type().clone()),
289        }
290    }
291
292    /// Returns the [`Func`] of the [`Definition`] if it is a function.
293    ///
294    /// Returns `None` otherwise.
295    ///
296    /// # Note
297    ///
298    /// - This allocates a new [`Func`] on the `ctx` if it is a [`Linker`]
299    ///   defined host function.
300    /// - This unifies handling of [`Definition::Extern(Extern::Func)`] and
301    ///   [`Definition::HostFunc`].
302    pub fn as_func(&self, mut ctx: impl AsContextMut<Data = T>) -> Option<Func> {
303        match self {
304            Definition::Extern(Extern::Func(func)) => Some(*func),
305            Definition::HostFunc(host_func) => {
306                let trampoline = ctx
307                    .as_context_mut()
308                    .store
309                    .alloc_trampoline(host_func.trampoline().clone());
310                let ty = host_func.func_type();
311                let entity = HostFuncEntity::new(ctx.as_context().engine(), ty, trampoline);
312                let func = ctx
313                    .as_context_mut()
314                    .store
315                    .inner
316                    .alloc_func(FuncEntity::Host(entity));
317                Some(func)
318            }
319            _ => None,
320        }
321    }
322}
323
324/// A linker used to define module imports and instantiate module instances.
325#[derive(Debug)]
326pub struct Linker<T> {
327    /// The underlying [`Engine`] for the [`Linker`].
328    ///
329    /// # Note
330    ///
331    /// Primarily required to define [`Linker`] owned host functions
332    //  using [`Linker::func_wrap`] and [`Linker::func_new`]. TODO: implement methods
333    engine: Engine,
334    /// Definitions shared with other [`Linker`] instances created by the same [`LinkerBuilder`].
335    ///
336    /// `None` if no [`LinkerBuilder`] was used for creation of the [`Linker`].
337    shared: Option<Arc<LinkerInner<T>>>,
338    /// Inner linker implementation details.
339    inner: LinkerInner<T>,
340}
341
342impl<T> Clone for Linker<T> {
343    fn clone(&self) -> Linker<T> {
344        Self {
345            engine: self.engine.clone(),
346            shared: self.shared.clone(),
347            inner: self.inner.clone(),
348        }
349    }
350}
351
352impl<T> Default for Linker<T> {
353    fn default() -> Self {
354        Self::new(&Engine::default())
355    }
356}
357
358impl<T> Linker<T> {
359    /// Creates a new [`Linker`].
360    pub fn new(engine: &Engine) -> Self {
361        Self {
362            engine: engine.clone(),
363            shared: None,
364            inner: LinkerInner::default(),
365        }
366    }
367
368    /// Creates a new [`LinkerBuilder`] to construct a [`Linker`].
369    pub fn build() -> LinkerBuilder<state::Constructing, T> {
370        LinkerBuilder {
371            inner: Arc::new(LinkerInner::default()),
372            marker: PhantomData,
373        }
374    }
375
376    /// Returns the underlying [`Engine`] of the [`Linker`].
377    pub fn engine(&self) -> &Engine {
378        &self.engine
379    }
380
381    /// Ensures that the `name` in `module` is undefined in the shared definitions.
382    ///
383    /// Returns `Ok` if no shared definition exists.
384    ///
385    /// # Errors
386    ///
387    /// If there exists a shared definition for `name` in `module`.
388    fn ensure_undefined(&self, module: &str, name: &str) -> Result<(), LinkerError> {
389        if let Some(shared) = &self.shared {
390            if shared.has_definition(module, name) {
391                return Err(LinkerError::DuplicateDefinition {
392                    import_name: ImportName::new(module, name),
393                });
394            }
395        }
396        Ok(())
397    }
398
399    /// Define a new item in this [`Linker`].
400    ///
401    /// # Errors
402    ///
403    /// If there already is a definition under the same name for this [`Linker`].
404    pub fn define(
405        &mut self,
406        module: &str,
407        name: &str,
408        item: impl Into<Extern>,
409    ) -> Result<&mut Self, LinkerError> {
410        self.ensure_undefined(module, name)?;
411        let key = self.inner.new_import_key(module, name);
412        self.inner.insert(key, Definition::Extern(item.into()))?;
413        Ok(self)
414    }
415
416    /// Creates a new named [`Func::new`]-style host [`Func`] for this [`Linker`].
417    ///
418    /// For more information see [`Linker::func_wrap`].
419    ///
420    /// # Errors
421    ///
422    /// If there already is a definition under the same name for this [`Linker`].
423    pub fn func_new(
424        &mut self,
425        module: &str,
426        name: &str,
427        ty: FuncType,
428        func: impl Fn(Caller<'_, T>, &[Val], &mut [Val]) -> Result<(), Error> + Send + Sync + 'static,
429    ) -> Result<&mut Self, LinkerError> {
430        self.ensure_undefined(module, name)?;
431        let func = HostFuncTrampolineEntity::new(ty, func);
432        let key = self.inner.new_import_key(module, name);
433        self.inner.insert(key, Definition::HostFunc(func))?;
434        Ok(self)
435    }
436
437    /// Creates a new named [`Func::new`]-style host [`Func`] for this [`Linker`].
438    ///
439    /// For information how to use this API see [`Func::wrap`].
440    ///
441    /// This method creates a host function for this [`Linker`] under the given name.
442    /// It is distinct in its ability to create a [`Store`] independent
443    /// host function. Host functions defined this way can be used to instantiate
444    /// instances in multiple different [`Store`] entities.
445    ///
446    /// The same applies to other [`Linker`] methods to define new [`Func`] instances
447    /// such as [`Linker::func_new`].
448    ///
449    /// In a concurrently running program, this means that these host functions
450    /// could be called concurrently if different [`Store`] entities are executing on
451    /// different threads.
452    ///
453    /// # Errors
454    ///
455    /// If there already is a definition under the same name for this [`Linker`].
456    ///
457    /// [`Store`]: crate::Store
458    pub fn func_wrap<Params, Args>(
459        &mut self,
460        module: &str,
461        name: &str,
462        func: impl IntoFunc<T, Params, Args>,
463    ) -> Result<&mut Self, LinkerError> {
464        self.ensure_undefined(module, name)?;
465        let func = HostFuncTrampolineEntity::wrap(func);
466        let key = self.inner.new_import_key(module, name);
467        self.inner.insert(key, Definition::HostFunc(func))?;
468        Ok(self)
469    }
470
471    /// Looks up a defined [`Extern`] by name in this [`Linker`].
472    ///
473    /// - Returns `None` if this name was not previously defined in this [`Linker`].
474    /// - Returns `None` if the definition is a [`Linker`] defined host function.
475    ///
476    /// # Panics
477    ///
478    /// If the [`Engine`] of this [`Linker`] and the [`Engine`] of `context` are not the same.
479    pub fn get(
480        &self,
481        context: impl AsContext<Data = T>,
482        module: &str,
483        name: &str,
484    ) -> Option<Extern> {
485        match self.get_definition(context, module, name) {
486            Some(Definition::Extern(item)) => Some(*item),
487            _ => None,
488        }
489    }
490
491    /// Looks up a [`Definition`] by name in this [`Linker`].
492    ///
493    /// Returns `None` if this name was not previously defined in this [`Linker`].
494    ///
495    /// # Panics
496    ///
497    /// If the [`Engine`] of this [`Linker`] and the [`Engine`] of `context` are not the same.
498    fn get_definition(
499        &self,
500        context: impl AsContext<Data = T>,
501        module: &str,
502        name: &str,
503    ) -> Option<&Definition<T>> {
504        assert!(Engine::same(
505            context.as_context().store.engine(),
506            self.engine()
507        ));
508        if let Some(shared) = &self.shared {
509            if let Some(item) = shared.get_definition(module, name) {
510                return Some(item);
511            }
512        }
513        self.inner.get_definition(module, name)
514    }
515
516    /// Instantiates the given [`Module`] using the definitions in the [`Linker`].
517    ///
518    /// # Panics
519    ///
520    /// If the [`Engine`] of the [`Linker`] and `context` are not the same.
521    ///
522    /// # Errors
523    ///
524    /// - If the linker does not define imports of the instantiated [`Module`].
525    /// - If any imported item does not satisfy its type requirements.
526    pub fn instantiate(
527        &self,
528        mut context: impl AsContextMut<Data = T>,
529        module: &Module,
530    ) -> Result<InstancePre, Error> {
531        assert!(Engine::same(self.engine(), context.as_context().engine()));
532        // TODO: possibly add further resource limtation here on number of externals.
533        // Not clear that user can't import the same external lots of times to inflate this.
534        let externals = module
535            .imports()
536            .map(|import| self.process_import(&mut context, import))
537            .collect::<Result<Vec<Extern>, Error>>()?;
538        module.instantiate(context, externals)
539    }
540
541    /// Processes a single [`Module`] import.
542    ///
543    /// # Panics
544    ///
545    /// If the [`Engine`] of the [`Linker`] and `context` are not the same.
546    ///
547    /// # Errors
548    ///
549    /// If the imported item does not satisfy constraints set by the [`Module`].
550    fn process_import(
551        &self,
552        mut context: impl AsContextMut<Data = T>,
553        import: ImportType,
554    ) -> Result<Extern, Error> {
555        assert!(Engine::same(self.engine(), context.as_context().engine()));
556        let import_name = import.import_name();
557        let module_name = import.module();
558        let field_name = import.name();
559        let resolved = self
560            .get_definition(context.as_context(), module_name, field_name)
561            .ok_or_else(|| LinkerError::missing_definition(&import))?;
562        let invalid_type = || LinkerError::invalid_type_definition(&import, &resolved.ty(&context));
563        match import.ty() {
564            ExternType::Func(expected_type) => {
565                let found_type = resolved
566                    .ty(&context)
567                    .func()
568                    .cloned()
569                    .ok_or_else(invalid_type)?;
570                if &found_type != expected_type {
571                    return Err(Error::from(LinkerError::func_type_mismatch(
572                        import_name,
573                        expected_type,
574                        &found_type,
575                    )));
576                }
577                let func = resolved
578                    .as_func(&mut context)
579                    .expect("already asserted that `resolved` is a function");
580                Ok(Extern::Func(func))
581            }
582            ExternType::Table(expected_type) => {
583                let table = resolved
584                    .as_extern()
585                    .copied()
586                    .and_then(Extern::into_table)
587                    .ok_or_else(invalid_type)?;
588                let found_type = table.dynamic_ty(context);
589                found_type.is_subtype_or_err(expected_type).map_err(|_| {
590                    LinkerError::table_type_mismatch(import_name, expected_type, &found_type)
591                })?;
592                Ok(Extern::Table(table))
593            }
594            ExternType::Memory(expected_type) => {
595                let memory = resolved
596                    .as_extern()
597                    .copied()
598                    .and_then(Extern::into_memory)
599                    .ok_or_else(invalid_type)?;
600                let found_type = memory.dynamic_ty(context);
601                found_type.is_subtype_or_err(expected_type).map_err(|_| {
602                    LinkerError::invalid_memory_subtype(import_name, expected_type, &found_type)
603                })?;
604                Ok(Extern::Memory(memory))
605            }
606            ExternType::Global(expected_type) => {
607                let global = resolved
608                    .as_extern()
609                    .copied()
610                    .and_then(Extern::into_global)
611                    .ok_or_else(invalid_type)?;
612                let found_type = global.ty(context);
613                if &found_type != expected_type {
614                    return Err(Error::from(LinkerError::global_type_mismatch(
615                        import_name,
616                        expected_type,
617                        &found_type,
618                    )));
619                }
620                Ok(Extern::Global(global))
621            }
622        }
623    }
624}
625
626/// Contains type states for the [`LinkerBuilder`] construction process.
627pub mod state {
628    /// Signals that the [`LinkerBuilder`] is itself under construction.
629    ///
630    /// [`LinkerBuilder`]: super::LinkerBuilder
631    pub enum Constructing {}
632
633    /// Signals that the [`LinkerBuilder`] is ready to create new [`Linker`] instances.
634    ///
635    /// [`Linker`]: super::Linker
636    /// [`LinkerBuilder`]: super::LinkerBuilder
637    pub enum Ready {}
638}
639
640/// A linker used to define module imports and instantiate module instances.
641///
642/// Create this type via the [`Linker::build`] method.
643#[derive(Debug)]
644pub struct LinkerBuilder<State, T> {
645    /// Internal linker implementation details.
646    inner: Arc<LinkerInner<T>>,
647    /// The [`LinkerBuilder`] type state.
648    marker: PhantomData<fn() -> State>,
649}
650
651impl<T> Clone for LinkerBuilder<state::Ready, T> {
652    fn clone(&self) -> Self {
653        Self {
654            inner: self.inner.clone(),
655            marker: PhantomData,
656        }
657    }
658}
659
660impl<T> LinkerBuilder<state::Ready, T> {
661    /// Finishes construction of the [`Linker`] by attaching an [`Engine`].
662    pub fn create(&self, engine: &Engine) -> Linker<T> {
663        Linker {
664            engine: engine.clone(),
665            shared: self.inner.clone().into(),
666            inner: <LinkerInner<T>>::default(),
667        }
668    }
669}
670
671impl<T> LinkerBuilder<state::Constructing, T> {
672    /// Signals that the [`LinkerBuilder`] is now ready to create new [`Linker`] instances.
673    pub fn finish(self) -> LinkerBuilder<state::Ready, T> {
674        LinkerBuilder {
675            inner: self.inner,
676            marker: PhantomData,
677        }
678    }
679
680    /// Returns an exclusive reference to the underlying [`Linker`] internals if no [`Linker`] has been built, yet.
681    ///
682    /// # Panics
683    ///
684    /// If the [`LinkerBuilder`] has already created a [`Linker`] using [`LinkerBuilder::finish`].
685    fn inner_mut(&mut self) -> &mut LinkerInner<T> {
686        Arc::get_mut(&mut self.inner).unwrap_or_else(|| {
687            unreachable!("tried to define host function in LinkerBuilder after Linker creation")
688        })
689    }
690
691    /// Creates a new named [`Func::new`]-style host [`Func`] for this [`Linker`].
692    ///
693    /// For more information see [`Linker::func_wrap`].
694    ///
695    /// # Errors
696    ///
697    /// If there already is a definition under the same name for this [`Linker`].
698    ///
699    /// # Panics
700    ///
701    /// If the [`LinkerBuilder`] has already created a [`Linker`] using [`LinkerBuilder::finish`].
702    pub fn func_new(
703        &mut self,
704        module: &str,
705        name: &str,
706        ty: FuncType,
707        func: impl Fn(Caller<'_, T>, &[Val], &mut [Val]) -> Result<(), Error> + Send + Sync + 'static,
708    ) -> Result<&mut Self, LinkerError> {
709        self.inner_mut().func_new(module, name, ty, func)?;
710        Ok(self)
711    }
712
713    /// Creates a new named [`Func::new`]-style host [`Func`] for this [`Linker`].
714    ///
715    /// For information how to use this API see [`Func::wrap`].
716    ///
717    /// This method creates a host function for this [`Linker`] under the given name.
718    /// It is distinct in its ability to create a [`Store`] independent
719    /// host function. Host functions defined this way can be used to instantiate
720    /// instances in multiple different [`Store`] entities.
721    ///
722    /// The same applies to other [`Linker`] methods to define new [`Func`] instances
723    /// such as [`Linker::func_new`].
724    ///
725    /// In a concurrently running program, this means that these host functions
726    /// could be called concurrently if different [`Store`] entities are executing on
727    /// different threads.
728    ///
729    /// # Errors
730    ///
731    /// If there already is a definition under the same name for this [`Linker`].
732    ///
733    /// [`Store`]: crate::Store
734    ///
735    /// # Panics
736    ///
737    /// If the [`LinkerBuilder`] has already created a [`Linker`] using [`LinkerBuilder::finish`].
738    pub fn func_wrap<Params, Args>(
739        &mut self,
740        module: &str,
741        name: &str,
742        func: impl IntoFunc<T, Params, Args>,
743    ) -> Result<&mut Self, LinkerError> {
744        self.inner_mut().func_wrap(module, name, func)?;
745        Ok(self)
746    }
747}
748
749/// Internal [`Linker`] implementation.
750#[derive(Debug)]
751pub struct LinkerInner<T> {
752    /// Allows to efficiently store strings and deduplicate them..
753    strings: StringInterner,
754    /// Stores the definitions given their names.
755    ///
756    /// # Dev. Note
757    ///
758    /// Benchmarks show that [`BTreeMap`] performs better than [`HashMap`]
759    /// which is why we do not use [`wasmi_collections::Map`] here.
760    ///
761    /// [`HashMap`]: std::collections::HashMap
762    definitions: BTreeMap<ImportKey, Definition<T>>,
763}
764
765impl<T> Default for LinkerInner<T> {
766    fn default() -> Self {
767        Self {
768            strings: StringInterner::default(),
769            definitions: BTreeMap::default(),
770        }
771    }
772}
773
774impl<T> Clone for LinkerInner<T> {
775    fn clone(&self) -> Self {
776        Self {
777            strings: self.strings.clone(),
778            definitions: self.definitions.clone(),
779        }
780    }
781}
782
783impl<T> LinkerInner<T> {
784    /// Returns the import key for the module name and item name.
785    fn new_import_key(&mut self, module: &str, name: &str) -> ImportKey {
786        ImportKey::new(
787            self.strings
788                .get_or_intern_with_hint(module, InternHint::LikelyExists),
789            self.strings
790                .get_or_intern_with_hint(name, InternHint::LikelyNew),
791        )
792    }
793
794    /// Returns the import key for the module name and item name.
795    fn get_import_key(&self, module: &str, name: &str) -> Option<ImportKey> {
796        Some(ImportKey::new(
797            self.strings.get(module)?,
798            self.strings.get(name)?,
799        ))
800    }
801
802    /// Resolves the module and item name of the import key if any.
803    fn resolve_import_key(&self, key: ImportKey) -> Option<(&str, &str)> {
804        let module_name = self.strings.resolve(key.module())?;
805        let item_name = self.strings.resolve(key.name())?;
806        Some((module_name, item_name))
807    }
808
809    /// Inserts the extern item under the import key.
810    ///
811    /// # Errors
812    ///
813    /// If there already is a definition for the import key for this [`Linker`].
814    fn insert(&mut self, key: ImportKey, item: Definition<T>) -> Result<(), LinkerError> {
815        match self.definitions.entry(key) {
816            Entry::Occupied(_) => {
817                let (module_name, field_name) = self
818                    .resolve_import_key(key)
819                    .unwrap_or_else(|| panic!("encountered missing import names for key {key:?}"));
820                let import_name = ImportName::new(module_name, field_name);
821                return Err(LinkerError::DuplicateDefinition { import_name });
822            }
823            Entry::Vacant(v) => {
824                v.insert(item);
825            }
826        }
827        Ok(())
828    }
829
830    /// Creates a new named [`Func::new`]-style host [`Func`] for this [`Linker`].
831    ///
832    /// For more information see [`Linker::func_wrap`].
833    ///
834    /// # Errors
835    ///
836    /// If there already is a definition under the same name for this [`Linker`].
837    pub fn func_new(
838        &mut self,
839        module: &str,
840        name: &str,
841        ty: FuncType,
842        func: impl Fn(Caller<'_, T>, &[Val], &mut [Val]) -> Result<(), Error> + Send + Sync + 'static,
843    ) -> Result<&mut Self, LinkerError> {
844        let func = HostFuncTrampolineEntity::new(ty, func);
845        let key = self.new_import_key(module, name);
846        self.insert(key, Definition::HostFunc(func))?;
847        Ok(self)
848    }
849
850    /// Creates a new named [`Func::new`]-style host [`Func`] for this [`Linker`].
851    ///
852    /// For information how to use this API see [`Func::wrap`].
853    ///
854    /// This method creates a host function for this [`Linker`] under the given name.
855    /// It is distinct in its ability to create a [`Store`] independent
856    /// host function. Host functions defined this way can be used to instantiate
857    /// instances in multiple different [`Store`] entities.
858    ///
859    /// The same applies to other [`Linker`] methods to define new [`Func`] instances
860    /// such as [`Linker::func_new`].
861    ///
862    /// In a concurrently running program, this means that these host functions
863    /// could be called concurrently if different [`Store`] entities are executing on
864    /// different threads.
865    ///
866    /// # Errors
867    ///
868    /// If there already is a definition under the same name for this [`Linker`].
869    ///
870    /// [`Store`]: crate::Store
871    pub fn func_wrap<Params, Args>(
872        &mut self,
873        module: &str,
874        name: &str,
875        func: impl IntoFunc<T, Params, Args>,
876    ) -> Result<&mut Self, LinkerError> {
877        let func = HostFuncTrampolineEntity::wrap(func);
878        let key = self.new_import_key(module, name);
879        self.insert(key, Definition::HostFunc(func))?;
880        Ok(self)
881    }
882
883    /// Looks up a [`Definition`] by name in this [`Linker`].
884    ///
885    /// Returns `None` if this name was not previously defined in this [`Linker`].
886    ///
887    /// # Panics
888    ///
889    /// If the [`Engine`] of this [`Linker`] and the [`Engine`] of `context` are not the same.
890    fn get_definition(&self, module: &str, name: &str) -> Option<&Definition<T>> {
891        let key = self.get_import_key(module, name)?;
892        self.definitions.get(&key)
893    }
894
895    /// Returns `true` if [`LinkerInner`] contains a [`Definition`] for `name` in `module`.
896    fn has_definition(&self, module: &str, name: &str) -> bool {
897        let Some(key) = self.get_import_key(module, name) else {
898            return false;
899        };
900        self.definitions.contains_key(&key)
901    }
902}
903
904#[cfg(test)]
905mod tests {
906    use crate::core::ValType;
907
908    use super::*;
909    use crate::Store;
910
911    struct HostState {
912        a: i32,
913        b: i64,
914    }
915
916    #[test]
917    fn linker_funcs_work() {
918        let engine = Engine::default();
919        let mut linker = <Linker<HostState>>::new(&engine);
920        linker
921            .func_new(
922                "host",
923                "get_a",
924                FuncType::new([], [ValType::I32]),
925                |ctx: Caller<HostState>, _params: &[Val], results: &mut [Val]| {
926                    results[0] = Val::from(ctx.data().a);
927                    Ok(())
928                },
929            )
930            .unwrap();
931        linker
932            .func_new(
933                "host",
934                "set_a",
935                FuncType::new([ValType::I32], []),
936                |mut ctx: Caller<HostState>, params: &[Val], _results: &mut [Val]| {
937                    ctx.data_mut().a = params[0].i32().unwrap();
938                    Ok(())
939                },
940            )
941            .unwrap();
942        linker
943            .func_wrap("host", "get_b", |ctx: Caller<HostState>| ctx.data().b)
944            .unwrap();
945        linker
946            .func_wrap("host", "set_b", |mut ctx: Caller<HostState>, value: i64| {
947                ctx.data_mut().b = value
948            })
949            .unwrap();
950        let a_init = 42;
951        let b_init = 77;
952        let mut store = <Store<HostState>>::new(
953            &engine,
954            HostState {
955                a: a_init,
956                b: b_init,
957            },
958        );
959        let wat = r#"
960                (module
961                    (import "host" "get_a" (func $host_get_a (result i32)))
962                    (import "host" "set_a" (func $host_set_a (param i32)))
963                    (import "host" "get_b" (func $host_get_b (result i64)))
964                    (import "host" "set_b" (func $host_set_b (param i64)))
965
966                    (func (export "wasm_get_a") (result i32)
967                        (call $host_get_a)
968                    )
969                    (func (export "wasm_set_a") (param $param i32)
970                        (call $host_set_a (local.get $param))
971                    )
972
973                    (func (export "wasm_get_b") (result i64)
974                        (call $host_get_b)
975                    )
976                    (func (export "wasm_set_b") (param $param i64)
977                        (call $host_set_b (local.get $param))
978                    )
979                )
980            "#;
981        let wasm = wat::parse_str(wat).unwrap();
982        let module = Module::new(&engine, &wasm[..]).unwrap();
983        let instance = linker
984            .instantiate(&mut store, &module)
985            .unwrap()
986            .start(&mut store)
987            .unwrap();
988
989        let wasm_get_a = instance
990            .get_typed_func::<(), i32>(&store, "wasm_get_a")
991            .unwrap();
992        let wasm_set_a = instance
993            .get_typed_func::<i32, ()>(&store, "wasm_set_a")
994            .unwrap();
995        let wasm_get_b = instance
996            .get_typed_func::<(), i64>(&store, "wasm_get_b")
997            .unwrap();
998        let wasm_set_b = instance
999            .get_typed_func::<i64, ()>(&store, "wasm_set_b")
1000            .unwrap();
1001
1002        assert_eq!(wasm_get_a.call(&mut store, ()).unwrap(), a_init);
1003        wasm_set_a.call(&mut store, 100).unwrap();
1004        assert_eq!(wasm_get_a.call(&mut store, ()).unwrap(), 100);
1005
1006        assert_eq!(wasm_get_b.call(&mut store, ()).unwrap(), b_init);
1007        wasm_set_b.call(&mut store, 200).unwrap();
1008        assert_eq!(wasm_get_b.call(&mut store, ()).unwrap(), 200);
1009    }
1010
1011    #[test]
1012    fn build_linker() {
1013        let mut builder = <Linker<()>>::build();
1014        builder
1015            .func_wrap("env", "foo", || std::println!("called foo"))
1016            .unwrap();
1017        builder
1018            .func_new(
1019                "env",
1020                "bar",
1021                FuncType::new([], []),
1022                |_caller, _params, _results| {
1023                    std::println!("called bar");
1024                    Ok(())
1025                },
1026            )
1027            .unwrap();
1028        let builder = builder.finish();
1029        for _ in 0..3 {
1030            let engine = Engine::default();
1031            let _ = builder.create(&engine);
1032        }
1033    }
1034
1035    #[test]
1036    fn linker_builder_uses() {
1037        use crate::{Engine, Linker, Module, Store};
1038        let wasm = wat::parse_str(
1039            r#"
1040            (module
1041                (import "host" "func.0" (func $host_func.0))
1042                (import "host" "func.1" (func $host_func.1))
1043                (func (export "hello")
1044                    (call $host_func.0)
1045                    (call $host_func.1)
1046                )
1047            )"#,
1048        )
1049        .unwrap();
1050        let engine = Engine::default();
1051        let mut builder = <Linker<()>>::build();
1052        builder
1053            .func_wrap("host", "func.0", |_caller: Caller<()>| ())
1054            .unwrap();
1055        builder
1056            .func_wrap("host", "func.1", |_caller: Caller<()>| ())
1057            .unwrap();
1058        let linker = builder.finish().create(&engine);
1059        let mut store = Store::new(&engine, ());
1060        let module = Module::new(&engine, &wasm[..]).unwrap();
1061        linker.instantiate(&mut store, &module).unwrap();
1062    }
1063
1064    #[test]
1065    fn linker_builder_and_linker_uses() {
1066        use crate::{Engine, Linker, Module, Store};
1067        let wasm = wat::parse_str(
1068            r#"
1069            (module
1070                (import "host" "func.0" (func $host_func.0))
1071                (import "host" "func.1" (func $host_func.1))
1072                (func (export "hello")
1073                    (call $host_func.0)
1074                    (call $host_func.1)
1075                )
1076            )"#,
1077        )
1078        .unwrap();
1079        let engine = Engine::default();
1080        let mut builder = <Linker<()>>::build();
1081        builder
1082            .func_wrap("host", "func.0", |_caller: Caller<()>| ())
1083            .unwrap();
1084        let mut linker = builder.finish().create(&engine);
1085        linker
1086            .func_wrap("host", "func.1", |_caller: Caller<()>| ())
1087            .unwrap();
1088        let mut store = Store::new(&engine, ());
1089        let module = Module::new(&engine, &wasm[..]).unwrap();
1090        linker.instantiate(&mut store, &module).unwrap();
1091    }
1092
1093    #[test]
1094    fn linker_builder_no_overwrite() {
1095        use crate::{Engine, Linker};
1096        let engine = Engine::default();
1097        let mut builder = <Linker<()>>::build();
1098        builder
1099            .func_wrap("host", "func.0", |_caller: Caller<()>| ())
1100            .unwrap();
1101        let mut linker = builder.finish().create(&engine);
1102        linker
1103            .func_wrap("host", "func.1", |_caller: Caller<()>| ())
1104            .unwrap();
1105        // The following definition won't shadow the previous 'host/func.0' func and errors instead:
1106        linker
1107            .func_wrap("host", "func.0", |_caller: Caller<()>| ())
1108            .unwrap_err();
1109    }
1110
1111    #[test]
1112    fn populate_via_imports() {
1113        use crate::{Engine, Func, Linker, Memory, MemoryType, Module, Store};
1114        let wasm = wat::parse_str(
1115            r#"
1116            (module
1117                (import "host" "hello" (func $host_hello (param i32) (result i32)))
1118                (import "env" "memory" (memory $mem 0 4096))
1119                (func (export "hello") (result i32)
1120                    (call $host_hello (i32.const 3))
1121                    (i32.const 2)
1122                    i32.add
1123                )
1124            )"#,
1125        )
1126        .unwrap();
1127        let engine = Engine::default();
1128        let mut linker = <Linker<()>>::new(&engine);
1129        let mut store = Store::new(&engine, ());
1130        let memory = Memory::new(&mut store, MemoryType::new(1, Some(4096)).unwrap()).unwrap();
1131        let module = Module::new(&engine, &wasm[..]).unwrap();
1132        linker.define("env", "memory", memory).unwrap();
1133        let func = Func::new(
1134            &mut store,
1135            FuncType::new([ValType::I32], [ValType::I32]),
1136            |_caller, _params, _results| todo!(),
1137        );
1138        linker.define("host", "hello", func).unwrap();
1139        linker.instantiate(&mut store, &module).unwrap();
1140    }
1141}