Skip to main content

substrate_wasmtime/
linker.rs

1use crate::{
2    Extern, ExternType, Func, FuncType, GlobalType, ImportType, Instance, IntoFunc, Module, Store,
3    Trap,
4};
5use anyhow::{anyhow, bail, Context, Error, Result};
6use log::warn;
7use std::collections::hash_map::{Entry, HashMap};
8use std::rc::Rc;
9
10/// Structure used to link wasm modules/instances together.
11///
12/// This structure is used to assist in instantiating a [`Module`]. A `Linker`
13/// is a way of performing name resolution to make instantiating a module easier
14/// (as opposed to calling [`Instance::new`]). `Linker` is a name-based resolver
15/// where names are dynamically defined and then used to instantiate a
16/// [`Module`]. The goal of a `Linker` is to have a one-argument method,
17/// [`Linker::instantiate`], which takes a [`Module`] and produces an
18/// [`Instance`].  This method will automatically select all the right imports
19/// for the [`Module`] to be instantiated, and will otherwise return an error
20/// if an import isn't satisfied.
21///
22/// ## Name Resolution
23///
24/// As mentioned previously, `Linker` is a form of name resolver. It will be
25/// using the string-based names of imports on a module to attempt to select a
26/// matching item to hook up to it. This name resolution has two-levels of
27/// namespaces, a module level and a name level. Each item is defined within a
28/// module and then has its own name. This basically follows the wasm standard
29/// for modularization.
30///
31/// Names in a `Linker` can be defined twice, but only for different signatures
32/// of items. This means that every item defined in a `Linker` has a unique
33/// name/type pair. For example you can define two functions with the module
34/// name `foo` and item name `bar`, so long as they have different function
35/// signatures. Currently duplicate memories and tables are not allowed, only
36/// one-per-name is allowed.
37///
38/// Note that allowing duplicates by shadowing the previous definition can be
39/// controlled with the [`Linker::allow_shadowing`] method as well.
40pub struct Linker {
41    store: Store,
42    string2idx: HashMap<Rc<str>, usize>,
43    strings: Vec<Rc<str>>,
44    map: HashMap<ImportKey, Extern>,
45    allow_shadowing: bool,
46}
47
48#[derive(Hash, PartialEq, Eq)]
49struct ImportKey {
50    name: usize,
51    module: usize,
52    kind: ImportKind,
53}
54
55#[derive(Hash, PartialEq, Eq, Debug)]
56enum ImportKind {
57    Func(FuncType),
58    Global(GlobalType),
59    Memory,
60    Table,
61}
62
63impl Linker {
64    /// Creates a new [`Linker`].
65    ///
66    /// This function will create a new [`Linker`] which is ready to start
67    /// linking modules. All items defined in this linker and produced by this
68    /// linker will be connected with `store` and must come from the same
69    /// `store`.
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use wasmtime::{Linker, Store};
75    ///
76    /// let store = Store::default();
77    /// let mut linker = Linker::new(&store);
78    /// // ...
79    /// ```
80    pub fn new(store: &Store) -> Linker {
81        Linker {
82            store: store.clone(),
83            map: HashMap::new(),
84            string2idx: HashMap::new(),
85            strings: Vec::new(),
86            allow_shadowing: false,
87        }
88    }
89
90    /// Configures whether this [`Linker`] will shadow previous duplicate
91    /// definitions of the same signature.
92    ///
93    /// By default a [`Linker`] will disallow duplicate definitions of the same
94    /// signature. This method, however, can be used to instead allow duplicates
95    /// and have the latest definition take precedence when linking modules.
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// # use wasmtime::*;
101    /// # fn main() -> anyhow::Result<()> {
102    /// # let store = Store::default();
103    /// let mut linker = Linker::new(&store);
104    /// linker.func("", "", || {})?;
105    ///
106    /// // by default, duplicates are disallowed
107    /// assert!(linker.func("", "", || {}).is_err());
108    ///
109    /// // but shadowing can be configured to be allowed as well
110    /// linker.allow_shadowing(true);
111    /// linker.func("", "", || {})?;
112    /// # Ok(())
113    /// # }
114    /// ```
115    pub fn allow_shadowing(&mut self, allow: bool) -> &mut Linker {
116        self.allow_shadowing = allow;
117        self
118    }
119
120    /// Defines a new item in this [`Linker`].
121    ///
122    /// This method will add a new definition, by name, to this instance of
123    /// [`Linker`]. The `module` and `name` provided are what to name the
124    /// `item`.
125    ///
126    /// # Errors
127    ///
128    /// Returns an error if the `module` and `name` already identify an item
129    /// of the same type as the `item` provided and if shadowing is disallowed.
130    /// For more information see the documentation on [`Linker`].
131    ///
132    /// Also returns an error if `item` comes from a different store than this
133    /// [`Linker`] was created with.
134    ///
135    /// # Examples
136    ///
137    /// ```
138    /// # use wasmtime::*;
139    /// # fn main() -> anyhow::Result<()> {
140    /// # let store = Store::default();
141    /// let mut linker = Linker::new(&store);
142    /// let ty = GlobalType::new(ValType::I32, Mutability::Const);
143    /// let global = Global::new(&store, ty, Val::I32(0x1234))?;
144    /// linker.define("host", "offset", global)?;
145    ///
146    /// let wat = r#"
147    ///     (module
148    ///         (import "host" "offset" (global i32))
149    ///         (memory 1)
150    ///         (data (global.get 0) "foo")
151    ///     )
152    /// "#;
153    /// let module = Module::new(store.engine(), wat)?;
154    /// linker.instantiate(&module)?;
155    /// # Ok(())
156    /// # }
157    /// ```
158    pub fn define(
159        &mut self,
160        module: &str,
161        name: &str,
162        item: impl Into<Extern>,
163    ) -> Result<&mut Self> {
164        self._define(module, name, item.into())
165    }
166
167    fn _define(&mut self, module: &str, name: &str, item: Extern) -> Result<&mut Self> {
168        if !item.comes_from_same_store(&self.store) {
169            bail!("all linker items must be from the same store");
170        }
171        self.insert(module, name, item)?;
172        Ok(self)
173    }
174
175    /// Convenience wrapper to define a function import.
176    ///
177    /// This method is a convenience wrapper around [`Linker::define`] which
178    /// internally delegates to [`Func::wrap`].
179    ///
180    /// # Errors
181    ///
182    /// Returns an error if the `module` and `name` already identify an item
183    /// of the same type as the `item` provided and if shadowing is disallowed.
184    /// For more information see the documentation on [`Linker`].
185    ///
186    /// # Examples
187    ///
188    /// ```
189    /// # use wasmtime::*;
190    /// # fn main() -> anyhow::Result<()> {
191    /// # let store = Store::default();
192    /// let mut linker = Linker::new(&store);
193    /// linker.func("host", "double", |x: i32| x * 2)?;
194    /// linker.func("host", "log_i32", |x: i32| println!("{}", x))?;
195    /// linker.func("host", "log_str", |caller: Caller, ptr: i32, len: i32| {
196    ///     // ...
197    /// })?;
198    ///
199    /// let wat = r#"
200    ///     (module
201    ///         (import "host" "double" (func (param i32) (result i32)))
202    ///         (import "host" "log_i32" (func (param i32)))
203    ///         (import "host" "log_str" (func (param i32 i32)))
204    ///     )
205    /// "#;
206    /// let module = Module::new(store.engine(), wat)?;
207    /// linker.instantiate(&module)?;
208    /// # Ok(())
209    /// # }
210    /// ```
211    pub fn func<Params, Args>(
212        &mut self,
213        module: &str,
214        name: &str,
215        func: impl IntoFunc<Params, Args>,
216    ) -> Result<&mut Self> {
217        self._define(module, name, Func::wrap(&self.store, func).into())
218    }
219
220    /// Convenience wrapper to define an entire [`Instance`] in this linker.
221    ///
222    /// This function is a convenience wrapper around [`Linker::define`] which
223    /// will define all exports on `instance` into this linker. The module name
224    /// for each export is `module_name`, and the name for each export is the
225    /// name in the instance itself.
226    ///
227    /// # Errors
228    ///
229    /// Returns an error if the any item is redefined twice in this linker (for
230    /// example the same `module_name` was already defined) and shadowing is
231    /// disallowed, or if `instance` comes from a different [`Store`] than this
232    /// [`Linker`] originally was created with.
233    ///
234    /// # Examples
235    ///
236    /// ```
237    /// # use wasmtime::*;
238    /// # fn main() -> anyhow::Result<()> {
239    /// # let store = Store::default();
240    /// let mut linker = Linker::new(&store);
241    ///
242    /// // Instantiate a small instance...
243    /// let wat = r#"(module (func (export "run") ))"#;
244    /// let module = Module::new(store.engine(), wat)?;
245    /// let instance = linker.instantiate(&module)?;
246    ///
247    /// // ... and inform the linker that the name of this instance is
248    /// // `instance1`. This defines the `instance1::run` name for our next
249    /// // module to use.
250    /// linker.instance("instance1", &instance)?;
251    ///
252    /// let wat = r#"
253    ///     (module
254    ///         (import "instance1" "run" (func $instance1_run))
255    ///         (func (export "run")
256    ///             call $instance1_run
257    ///         )
258    ///     )
259    /// "#;
260    /// let module = Module::new(store.engine(), wat)?;
261    /// let instance = linker.instantiate(&module)?;
262    /// # Ok(())
263    /// # }
264    /// ```
265    pub fn instance(&mut self, module_name: &str, instance: &Instance) -> Result<&mut Self> {
266        if !Store::same(&self.store, instance.store()) {
267            bail!("all linker items must be from the same store");
268        }
269        for export in instance.exports() {
270            self.insert(module_name, export.name(), export.into_extern())?;
271        }
272        Ok(self)
273    }
274
275    /// Define automatic instantiations of a [`Module`] in this linker.
276    ///
277    /// This automatically handles [Commands and Reactors] instantiation and
278    /// initialization.
279    ///
280    /// Exported functions of a Command module may be called directly, however
281    /// instead of having a single instance which is reused for each call,
282    /// each call creates a new instance, which lives for the duration of the
283    /// call. The imports of the Command are resolved once, and reused for
284    /// each instantiation, so all dependencies need to be present at the time
285    /// when `Linker::module` is called.
286    ///
287    /// For Reactors, a single instance is created, and an initialization
288    /// function is called, and then its exports may be called.
289    ///
290    /// Ordinary modules which don't declare themselves to be either Commands
291    /// or Reactors are treated as Reactors without any initialization calls.
292    ///
293    /// [Commands and Reactors]: https://github.com/WebAssembly/WASI/blob/master/design/application-abi.md#current-unstable-abi
294    ///
295    /// # Errors
296    ///
297    /// Returns an error if the any item is redefined twice in this linker (for
298    /// example the same `module_name` was already defined) and shadowing is
299    /// disallowed, if `instance` comes from a different [`Store`] than this
300    /// [`Linker`] originally was created with, or if a Reactor initialization
301    /// function traps.
302    ///
303    /// # Examples
304    ///
305    /// ```
306    /// # use wasmtime::*;
307    /// # fn main() -> anyhow::Result<()> {
308    /// # let store = Store::default();
309    /// let mut linker = Linker::new(&store);
310    ///
311    /// // Instantiate a small instance and inform the linker that the name of
312    /// // this instance is `instance1`. This defines the `instance1::run` name
313    /// // for our next module to use.
314    /// let wat = r#"(module (func (export "run") ))"#;
315    /// let module = Module::new(store.engine(), wat)?;
316    /// linker.module("instance1", &module)?;
317    ///
318    /// let wat = r#"
319    ///     (module
320    ///         (import "instance1" "run" (func $instance1_run))
321    ///         (func (export "run")
322    ///             call $instance1_run
323    ///         )
324    ///     )
325    /// "#;
326    /// let module = Module::new(store.engine(), wat)?;
327    /// let instance = linker.instantiate(&module)?;
328    /// # Ok(())
329    /// # }
330    /// ```
331    ///
332    /// For a Command, a new instance is created for each call.
333    ///
334    /// ```
335    /// # use wasmtime::*;
336    /// # fn main() -> anyhow::Result<()> {
337    /// # let store = Store::default();
338    /// let mut linker = Linker::new(&store);
339    ///
340    /// // Create a Command that attempts to count the number of times it is run, but is
341    /// // foiled by each call getting a new instance.
342    /// let wat = r#"
343    ///     (module
344    ///         (global $counter (mut i32) (i32.const 0))
345    ///         (func (export "_start")
346    ///             (global.set $counter (i32.add (global.get $counter) (i32.const 1)))
347    ///         )
348    ///         (func (export "read_counter") (result i32)
349    ///             (global.get $counter)
350    ///         )
351    ///     )
352    /// "#;
353    /// let module = Module::new(store.engine(), wat)?;
354    /// linker.module("commander", &module)?;
355    /// let run = linker.get_default("")?.get0::<()>()?;
356    /// run()?;
357    /// run()?;
358    /// run()?;
359    ///
360    /// let wat = r#"
361    ///     (module
362    ///         (import "commander" "_start" (func $commander_start))
363    ///         (import "commander" "read_counter" (func $commander_read_counter (result i32)))
364    ///         (func (export "run") (result i32)
365    ///             call $commander_start
366    ///             call $commander_start
367    ///             call $commander_start
368    ///             call $commander_read_counter
369    ///         )
370    ///     )
371    /// "#;
372    /// let module = Module::new(store.engine(), wat)?;
373    /// linker.module("", &module)?;
374    /// let count = linker.get_one_by_name("", "run")?.into_func().unwrap().get0::<i32>()?()?;
375    /// assert_eq!(count, 0, "a Command should get a fresh instance on each invocation");
376    ///
377    /// # Ok(())
378    /// # }
379    /// ```
380    pub fn module(&mut self, module_name: &str, module: &Module) -> Result<&mut Self> {
381        match ModuleKind::categorize(module)? {
382            ModuleKind::Command => self.command(module_name, module),
383            ModuleKind::Reactor => {
384                let instance = self.instantiate(&module)?;
385
386                if let Some(export) = instance.get_export("_initialize") {
387                    if let Extern::Func(func) = export {
388                        func.get0::<()>()
389                            .and_then(|f| f().map_err(Into::into))
390                            .context("calling the Reactor initialization function")?;
391                    }
392                }
393
394                self.instance(module_name, &instance)
395            }
396        }
397    }
398
399    fn command(&mut self, module_name: &str, module: &Module) -> Result<&mut Self> {
400        for export in module.exports() {
401            if let Some(func_ty) = export.ty().func() {
402                let imports = self.compute_imports(module)?;
403                let store = self.store.clone();
404                let module = module.clone();
405                let export_name = export.name().to_owned();
406                let func = Func::new(&self.store, func_ty.clone(), move |_, params, results| {
407                    // Create a new instance for this command execution.
408                    let instance = Instance::new(&store, &module, &imports)?;
409
410                    // `unwrap()` everything here because we know the instance contains a
411                    // function export with the given name and signature because we're
412                    // iterating over the module it was instantiated from.
413                    let command_results = instance
414                        .get_export(&export_name)
415                        .unwrap()
416                        .into_func()
417                        .unwrap()
418                        .call(params)
419                        .map_err(|error| error.downcast::<Trap>().unwrap())?;
420
421                    // Copy the return values into the output slice.
422                    for (result, command_result) in
423                        results.iter_mut().zip(command_results.into_vec())
424                    {
425                        *result = command_result;
426                    }
427
428                    Ok(())
429                });
430                self.insert(module_name, export.name(), func.into())?;
431            } else if export.name() == "memory" && export.ty().memory().is_some() {
432                // Allow an exported "memory" memory for now.
433            } else if export.name() == "__indirect_function_table" && export.ty().table().is_some()
434            {
435                // Allow an exported "__indirect_function_table" table for now.
436            } else if export.name() == "table" && export.ty().table().is_some() {
437                // Allow an exported "table" table for now.
438            } else if export.name() == "__data_end" && export.ty().global().is_some() {
439                // Allow an exported "__data_end" memory for compatibility with toolchains
440                // which use --export-dynamic, which unfortunately doesn't work the way
441                // we want it to.
442                warn!("command module exporting '__data_end' is deprecated");
443            } else if export.name() == "__heap_base" && export.ty().global().is_some() {
444                // Allow an exported "__data_end" memory for compatibility with toolchains
445                // which use --export-dynamic, which unfortunately doesn't work the way
446                // we want it to.
447                warn!("command module exporting '__heap_base' is deprecated");
448            } else if export.name() == "__dso_handle" && export.ty().global().is_some() {
449                // Allow an exported "__dso_handle" memory for compatibility with toolchains
450                // which use --export-dynamic, which unfortunately doesn't work the way
451                // we want it to.
452                warn!("command module exporting '__dso_handle' is deprecated")
453            } else if export.name() == "__rtti_base" && export.ty().global().is_some() {
454                // Allow an exported "__rtti_base" memory for compatibility with
455                // AssemblyScript.
456                warn!("command module exporting '__rtti_base' is deprecated; pass `--runtime half` to the AssemblyScript compiler");
457            } else {
458                bail!("command export '{}' is not a function", export.name());
459            }
460        }
461
462        Ok(self)
463    }
464
465    /// Aliases one module's name as another.
466    ///
467    /// This method will alias all currently defined under `module` to also be
468    /// defined under the name `as_module` too.
469    ///
470    /// # Errors
471    ///
472    /// Returns an error if any shadowing violations happen while defining new
473    /// items.
474    pub fn alias(&mut self, module: &str, as_module: &str) -> Result<()> {
475        let items = self
476            .iter()
477            .filter(|(m, _, _)| *m == module)
478            .map(|(_, name, item)| (name.to_string(), item))
479            .collect::<Vec<_>>();
480        for (name, item) in items {
481            self.define(as_module, &name, item)?;
482        }
483        Ok(())
484    }
485
486    fn insert(&mut self, module: &str, name: &str, item: Extern) -> Result<()> {
487        let key = self.import_key(module, name, item.ty());
488        match self.map.entry(key) {
489            Entry::Occupied(o) if !self.allow_shadowing => bail!(
490                "import of `{}::{}` with kind {:?} defined twice",
491                module,
492                name,
493                o.key().kind,
494            ),
495            Entry::Occupied(mut o) => {
496                o.insert(item);
497            }
498            Entry::Vacant(v) => {
499                v.insert(item);
500            }
501        }
502        Ok(())
503    }
504
505    fn import_key(&mut self, module: &str, name: &str, ty: ExternType) -> ImportKey {
506        ImportKey {
507            module: self.intern_str(module),
508            name: self.intern_str(name),
509            kind: self.import_kind(ty),
510        }
511    }
512
513    fn import_kind(&self, ty: ExternType) -> ImportKind {
514        match ty {
515            ExternType::Func(f) => ImportKind::Func(f),
516            ExternType::Global(f) => ImportKind::Global(f),
517            ExternType::Memory(_) => ImportKind::Memory,
518            ExternType::Table(_) => ImportKind::Table,
519        }
520    }
521
522    fn intern_str(&mut self, string: &str) -> usize {
523        if let Some(idx) = self.string2idx.get(string) {
524            return *idx;
525        }
526        let string: Rc<str> = string.into();
527        let idx = self.strings.len();
528        self.strings.push(string.clone());
529        self.string2idx.insert(string, idx);
530        idx
531    }
532
533    /// Attempts to instantiate the `module` provided.
534    ///
535    /// This method will attempt to assemble a list of imports that correspond
536    /// to the imports required by the [`Module`] provided. This list
537    /// of imports is then passed to [`Instance::new`] to continue the
538    /// instantiation process.
539    ///
540    /// Each import of `module` will be looked up in this [`Linker`] and must
541    /// have previously been defined. If it was previously defined with an
542    /// incorrect signature or if it was not previously defined then an error
543    /// will be returned because the import can not be satisfied.
544    ///
545    /// Per the WebAssembly spec, instantiation includes running the module's
546    /// start function, if it has one (not to be confused with the `_start`
547    /// function, which is not run).
548    ///
549    /// # Errors
550    ///
551    /// This method can fail because an import may not be found, or because
552    /// instantiation itself may fail. For information on instantiation
553    /// failures see [`Instance::new`].
554    ///
555    /// # Examples
556    ///
557    /// ```
558    /// # use wasmtime::*;
559    /// # fn main() -> anyhow::Result<()> {
560    /// # let store = Store::default();
561    /// let mut linker = Linker::new(&store);
562    /// linker.func("host", "double", |x: i32| x * 2)?;
563    ///
564    /// let wat = r#"
565    ///     (module
566    ///         (import "host" "double" (func (param i32) (result i32)))
567    ///     )
568    /// "#;
569    /// let module = Module::new(store.engine(), wat)?;
570    /// linker.instantiate(&module)?;
571    /// # Ok(())
572    /// # }
573    /// ```
574    pub fn instantiate(&self, module: &Module) -> Result<Instance> {
575        let imports = self.compute_imports(module)?;
576
577        Instance::new(&self.store, module, &imports)
578    }
579
580    fn compute_imports(&self, module: &Module) -> Result<Vec<Extern>> {
581        module
582            .imports()
583            .map(|import| self.get(&import).ok_or_else(|| self.link_error(&import)))
584            .collect()
585    }
586
587    fn link_error(&self, import: &ImportType) -> Error {
588        let mut options = Vec::new();
589        for i in self.map.keys() {
590            if &*self.strings[i.module] != import.module()
591                || &*self.strings[i.name] != import.name()
592            {
593                continue;
594            }
595            options.push(format!("  * {:?}\n", i.kind));
596        }
597        if options.is_empty() {
598            return anyhow!(
599                "unknown import: `{}::{}` has not been defined",
600                import.module(),
601                import.name()
602            );
603        }
604
605        options.sort();
606
607        anyhow!(
608            "incompatible import type for `{}::{}` specified\n\
609                 desired signature was: {:?}\n\
610                 signatures available:\n\n{}",
611            import.module(),
612            import.name(),
613            import.ty(),
614            options.concat(),
615        )
616    }
617
618    /// Returns the [`Store`] that this linker is connected to.
619    pub fn store(&self) -> &Store {
620        &self.store
621    }
622
623    /// Returns an iterator over all items defined in this `Linker`, in arbitrary order.
624    ///
625    /// The iterator returned will yield 3-tuples where the first two elements
626    /// are the module name and item name for the external item, and the third
627    /// item is the item itself that is defined.
628    ///
629    /// Note that multiple `Extern` items may be defined for the same
630    /// module/name pair.
631    pub fn iter(&self) -> impl Iterator<Item = (&str, &str, Extern)> {
632        self.map.iter().map(move |(key, item)| {
633            (
634                &*self.strings[key.module],
635                &*self.strings[key.name],
636                item.clone(),
637            )
638        })
639    }
640
641    /// Looks up a value in this `Linker` which matches the `import` type
642    /// provided.
643    ///
644    /// Returns `None` if no match was found.
645    pub fn get(&self, import: &ImportType) -> Option<Extern> {
646        let key = ImportKey {
647            module: *self.string2idx.get(import.module())?,
648            name: *self.string2idx.get(import.name())?,
649            kind: self.import_kind(import.ty()),
650        };
651        self.map.get(&key).cloned()
652    }
653
654    /// Returns all items defined for the `module` and `name` pair.
655    ///
656    /// This may return an empty iterator, but it may also return multiple items
657    /// if the module/name have been defined twice.
658    pub fn get_by_name<'a: 'p, 'p>(
659        &'a self,
660        module: &'p str,
661        name: &'p str,
662    ) -> impl Iterator<Item = &'a Extern> + 'p {
663        self.map
664            .iter()
665            .filter(move |(key, _item)| {
666                &*self.strings[key.module] == module && &*self.strings[key.name] == name
667            })
668            .map(|(_, item)| item)
669    }
670
671    /// Returns the single item defined for the `module` and `name` pair.
672    ///
673    /// Unlike the similar [`Linker::get_by_name`] method this function returns
674    /// a single `Extern` item. If the `module` and `name` pair isn't defined
675    /// in this linker then an error is returned. If more than one value exists
676    /// for the `module` and `name` pairs, then an error is returned as well.
677    pub fn get_one_by_name(&self, module: &str, name: &str) -> Result<Extern> {
678        let mut items = self.get_by_name(module, name);
679        let ret = items
680            .next()
681            .ok_or_else(|| anyhow!("no item named `{}` in `{}`", name, module))?;
682        if items.next().is_some() {
683            bail!("too many items named `{}` in `{}`", name, module);
684        }
685        Ok(ret.clone())
686    }
687
688    /// Returns the "default export" of a module.
689    ///
690    /// An export with an empty string is considered to be a "default export".
691    /// "_start" is also recognized for compatibility.
692    pub fn get_default(&self, module: &str) -> Result<Func> {
693        let mut items = self.get_by_name(module, "");
694        if let Some(external) = items.next() {
695            if items.next().is_some() {
696                bail!("too many items named `` in `{}`", module);
697            }
698            if let Extern::Func(func) = external {
699                return Ok(func.clone());
700            }
701            bail!("default export in '{}' is not a function", module);
702        }
703
704        // For compatibility, also recognize "_start".
705        let mut items = self.get_by_name(module, "_start");
706        if let Some(external) = items.next() {
707            if items.next().is_some() {
708                bail!("too many items named `_start` in `{}`", module);
709            }
710            if let Extern::Func(func) = external {
711                return Ok(func.clone());
712            }
713            bail!("`_start` in '{}' is not a function", module);
714        }
715
716        // Otherwise return a no-op function.
717        Ok(Func::new(
718            &self.store,
719            FuncType::new(Vec::new().into_boxed_slice(), Vec::new().into_boxed_slice()),
720            move |_, _, _| Ok(()),
721        ))
722    }
723}
724
725/// Modules can be interpreted either as Commands or Reactors.
726enum ModuleKind {
727    /// The instance is a Command, meaning an instance is created for each
728    /// exported function and lives for the duration of the function call.
729    Command,
730
731    /// The instance is a Reactor, meaning one instance is created which
732    /// may live across multiple calls.
733    Reactor,
734}
735
736impl ModuleKind {
737    /// Determine whether the given module is a Command or a Reactor.
738    fn categorize(module: &Module) -> Result<ModuleKind> {
739        let command_start = module.get_export("_start");
740        let reactor_start = module.get_export("_initialize");
741        match (command_start, reactor_start) {
742            (Some(command_start), None) => {
743                if let Some(_) = command_start.func() {
744                    Ok(ModuleKind::Command)
745                } else {
746                    bail!("`_start` must be a function")
747                }
748            }
749            (None, Some(reactor_start)) => {
750                if let Some(_) = reactor_start.func() {
751                    Ok(ModuleKind::Reactor)
752                } else {
753                    bail!("`_initialize` must be a function")
754                }
755            }
756            (None, None) => {
757                // Module declares neither of the recognized functions, so treat
758                // it as a reactor with no initialization function.
759                Ok(ModuleKind::Reactor)
760            }
761            (Some(_), Some(_)) => {
762                // Module declares itself to be both a Command and a Reactor.
763                bail!("Program cannot be both a Command and a Reactor")
764            }
765        }
766    }
767}