Skip to main content

wit_dylib/
lib.rs

1use std::borrow::Cow;
2use std::collections::{HashMap, HashSet};
3use std::mem;
4use wasm_encoder::{
5    CodeSection, ConstExpr, CustomSection, DataSection, ElementSection, Elements, Encode,
6    EntityType, ExportKind, ExportSection, Function, FunctionSection, GlobalType, ImportSection,
7    MemoryType, Module, NameMap, NameSection, RefType, TableType, TypeSection, ValType,
8};
9use wit_parser::abi::{WasmSignature, WasmType};
10use wit_parser::{
11    Handle, LiftLowerAbi, LiveTypes, ManglingAndAbi, Resolve, ResourceIntrinsic, SizeAlign, Type,
12    TypeDefKind, TypeId, TypeOwner, WasmExport, WasmExportKind, WasmImport, WorldId, WorldItem,
13    WorldKey,
14};
15
16mod async_;
17mod bindgen;
18pub mod metadata;
19pub use crate::async_::AsyncFilterSet;
20pub use crate::metadata::Metadata;
21
22pub const C_HEADER: &'static str = include_str!("../wit_dylib.h");
23
24#[derive(Default, Clone, Debug)]
25#[cfg_attr(feature = "clap", derive(clap::Parser))]
26pub struct DylibOpts {
27    /// The interpreter name to insert into the `WASM_DYLINK_NEEDED` section
28    /// encoded as `dylink.0`.
29    #[cfg_attr(feature = "clap", clap(long, value_name = "name"))]
30    pub interpreter: Option<String>,
31
32    #[cfg_attr(feature = "clap", clap(flatten))]
33    pub async_: AsyncFilterSet,
34
35    /// Where the stack pointer is located in the ABI of the generated dylib.
36    ///
37    /// For WASIp2-and-prior the `global` option should be used, and for
38    /// WASIp3-and-later the `task-context` option should be used.
39    #[cfg_attr(
40        feature = "clap",
41        clap(long, value_name = "loc", default_value = "global")
42    )]
43    pub stack_pointer: StackPointer,
44}
45
46#[derive(Default, Clone, Debug)]
47#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
48pub enum StackPointer {
49    #[default]
50    Global,
51    TaskContext,
52}
53
54pub fn create(
55    resolve: &Resolve,
56    world_id: WorldId,
57    opts: Option<&mut DylibOpts>,
58) -> anyhow::Result<Vec<u8>> {
59    Ok(create_with_metadata(resolve, world_id, opts)?.0)
60}
61
62pub fn create_with_metadata(
63    resolve: &Resolve,
64    world_id: WorldId,
65    mut opts: Option<&mut DylibOpts>,
66) -> anyhow::Result<(Vec<u8>, Metadata)> {
67    let mut adapter = Adapter::default();
68    if let Some(opts) = &mut opts {
69        adapter.opts = opts.clone();
70    }
71    let result = adapter.encode(resolve, world_id)?;
72    if let Some(opts) = &mut opts {
73        **opts = adapter.opts;
74    }
75    Ok((result, adapter.metadata))
76}
77
78#[derive(Default)]
79struct Adapter {
80    types: TypeSection,
81    wasm_type_map: HashMap<(Vec<ValType>, Vec<ValType>), u32>,
82    imports: ImportSection,
83    imports_done: bool,
84    global_index: u32,
85    table_base: Option<u32>,
86    memory_base: Option<u32>,
87    stack_pointer: Option<ImportedStackPointer>,
88    func_index: u32,
89    functions: FunctionSection,
90    exports: ExportSection,
91    code: CodeSection,
92    global_names: NameMap,
93    function_names: NameMap,
94    metadata: Metadata,
95    type_map: HashMap<TypeId, metadata::Type>,
96    resource_map: HashMap<TypeId, usize>,
97    export_resource_map: HashMap<TypeId, usize>,
98    intrinsics: Option<bindgen::WitInterpreterIntrinsics>,
99    sizes: SizeAlign,
100    opts: DylibOpts,
101
102    /// Contents of the element segment of this module, which will start at
103    /// `__table_base`.
104    ///
105    /// Elements of this list are function indices in this module which will be
106    /// placed into the element segment.
107    elem_segment: Vec<u32>,
108}
109
110#[derive(Copy, Clone)]
111enum ImportedStackPointer {
112    Global(u32),
113    TaskContext { get: u32, set: u32 },
114}
115
116#[derive(Default)]
117struct Imports<'a> {
118    wit_imports: Vec<WitImport<'a>>,
119    wit_exports: Vec<WitExport<'a>>,
120}
121
122struct WitImport<'a> {
123    interface: Option<&'a WorldKey>,
124    func: &'a wit_parser::Function,
125    import_index: u32,
126}
127
128struct WitExport<'a> {
129    interface: Option<&'a WorldKey>,
130    func: &'a wit_parser::Function,
131    async_task_return_index: Option<u32>,
132}
133
134/// Represents data for a given `stream<T>` or `future<T>` as referenced by an
135/// imported or exported function by way of its parameter list or result.
136struct PayloadData {
137    /// `{stream|future}.new` import
138    new_elem_index: u32,
139    /// `{stream|future}.read` import
140    read_elem_index: u32,
141    /// `{stream|future}.write` import
142    write_elem_index: u32,
143    /// `{stream|future}.cancel-read` import
144    cancel_read_elem_index: u32,
145    /// `{stream|future}.cancel-write` import
146    cancel_write_elem_index: u32,
147    /// `{stream|future}.drop-readable` import
148    drop_readable_elem_index: u32,
149    /// `{stream|future}.drop-writable` import
150    drop_writable_elem_index: u32,
151    /// Position of this `stream<T>` or `future<T>` in the function's signature
152    /// relative to any other `stream`s or `future`s.  See
153    /// `wit_parser::Function::find_futures_and_streams` for details.
154    ordinal: usize,
155    /// Name of the function with the signature in which this `stream<T>` or
156    /// `future<T>` was found.
157    function: String,
158}
159
160impl Adapter {
161    pub fn encode(&mut self, resolve: &Resolve, world_id: WorldId) -> anyhow::Result<Vec<u8>> {
162        self.sizes.fill(resolve)?;
163
164        // First define all imports that will go into the wasm module since
165        // they're required to be first in their index spaces anyway. This will
166        // import intrinsics necessary for exported resources, for example, as
167        // well.
168        let imports = self.add_imports(resolve, world_id);
169
170        let mut payload_data = HashMap::new();
171        self.collect_payload_data(resolve, world_id, &mut payload_data);
172
173        self.imports_done = true;
174
175        // Ensure that `cabi_realloc` is reexported from our module to indicate
176        // that our module's allocations are routed through the same
177        // `cabi_realloc` we're importing.
178        let cabi_realloc = self.intrinsics().cabi_realloc;
179        self.exports
180            .export("cabi_realloc", ExportKind::Func, cabi_realloc);
181
182        // Generate/add metadata for all functions that are either imported or
183        // exported.
184        self.bindgen_world(resolve, world_id, &imports, &payload_data);
185
186        // Now that all functions have been learned about the metadata data
187        // segment can be finalized and emitted. Here this additionally invokes
188        // the interpreter initialization function as part of a ctor to ensure
189        // that the interpreter is aware of where metadata ended up in linear
190        // memory.
191        let (metadata_offset, metadata) = self.encode_metadata();
192        let mut ctor = Function::new([]);
193        ctor.instructions().i32_const(metadata_offset as i32);
194        ctor.instructions().global_get(self.memory_base());
195        ctor.instructions().i32_add();
196        ctor.instructions().call(self.intrinsics().initialize);
197        ctor.instructions().end();
198        let ty = self.define_ty([], []);
199        self.define_func("__wasm_call_ctors", ty, ctor, true);
200
201        Ok(self.finish(&metadata))
202    }
203
204    fn mangling(
205        &mut self,
206        resolve: &Resolve,
207        interface: Option<&WorldKey>,
208        func: &wit_parser::Function,
209        is_import: bool,
210    ) -> ManglingAndAbi {
211        let abi = if self
212            .opts
213            .async_
214            .is_async(resolve, interface, func, is_import)
215        {
216            LiftLowerAbi::AsyncCallback
217        } else {
218            LiftLowerAbi::Sync
219        };
220        ManglingAndAbi::Legacy(abi)
221    }
222
223    fn resource_intrinsic_mangling(&mut self) -> ManglingAndAbi {
224        ManglingAndAbi::Legacy(LiftLowerAbi::Sync)
225    }
226
227    /// Scan the specified function for any `stream` or `future` types in the
228    /// parameter list or result, importing the necessary intrinsics for each
229    /// one found and inserting them into `data` for later reference.
230    fn collect_payload_data_for_func(
231        &mut self,
232        resolve: &Resolve,
233        interface: Option<&WorldKey>,
234        func: &wit_parser::Function,
235        prefix: &str,
236        data: &mut HashMap<TypeId, PayloadData>,
237    ) {
238        let mut make = |arg_count, kind, ordinal| {
239            let module = format!(
240                "{prefix}{}",
241                interface
242                    .map(|name| resolve.name_world_key(name))
243                    .unwrap_or_else(|| "$root".into())
244            );
245            let function = func.name.clone();
246
247            let import = |me: &mut Self, prefix, name, params, results| {
248                let ty = me.define_ty(params, results);
249                let import = me.import_func(
250                    &module,
251                    &format!("{prefix}[{kind}-{name}-{ordinal}]{function}"),
252                    ty,
253                );
254                me.push_elem(import)
255            };
256
257            let new_elem_index = import(self, "", "new", vec![], vec![ValType::I64]);
258            let read_elem_index = import(
259                self,
260                "[async-lower]",
261                "read",
262                vec![ValType::I32; arg_count],
263                vec![ValType::I32],
264            );
265            let write_elem_index = import(
266                self,
267                "[async-lower]",
268                "write",
269                vec![ValType::I32; arg_count],
270                vec![ValType::I32],
271            );
272            let cancel_read_elem_index = import(
273                self,
274                "",
275                "cancel-read",
276                vec![ValType::I32],
277                vec![ValType::I32],
278            );
279            let cancel_write_elem_index = import(
280                self,
281                "",
282                "cancel-write",
283                vec![ValType::I32],
284                vec![ValType::I32],
285            );
286            let drop_readable_elem_index =
287                import(self, "", "drop-readable", vec![ValType::I32], vec![]);
288            let drop_writable_elem_index =
289                import(self, "", "drop-writable", vec![ValType::I32], vec![]);
290
291            PayloadData {
292                new_elem_index,
293                read_elem_index,
294                write_elem_index,
295                cancel_read_elem_index,
296                cancel_write_elem_index,
297                drop_readable_elem_index,
298                drop_writable_elem_index,
299                ordinal,
300                function,
301            }
302        };
303
304        for (ordinal, ty) in func
305            .find_futures_and_streams(resolve)
306            .into_iter()
307            .enumerate()
308        {
309            match &resolve.types[ty].kind {
310                TypeDefKind::Future(_) => {
311                    data.entry(ty).or_insert_with(|| make(2, "future", ordinal))
312                }
313                TypeDefKind::Stream(_) => {
314                    data.entry(ty).or_insert_with(|| make(3, "stream", ordinal))
315                }
316                _ => unreachable!(),
317            };
318        }
319    }
320
321    fn collect_payload_data(
322        &mut self,
323        resolve: &Resolve,
324        world_id: WorldId,
325        data: &mut HashMap<TypeId, PayloadData>,
326    ) {
327        let world = &resolve.worlds[world_id];
328
329        for (key, import) in world.imports.iter() {
330            match import {
331                WorldItem::Interface { id, .. } => {
332                    for (_, func) in resolve.interfaces[*id].functions.iter() {
333                        self.collect_payload_data_for_func(resolve, Some(key), func, "", data);
334                    }
335                }
336                WorldItem::Type { .. } => {}
337                WorldItem::Function(func) => {
338                    self.collect_payload_data_for_func(resolve, None, func, "", data);
339                }
340            }
341        }
342
343        for (key, export) in world.exports.iter() {
344            match export {
345                WorldItem::Interface { id, .. } => {
346                    for (_, func) in resolve.interfaces[*id].functions.iter() {
347                        self.collect_payload_data_for_func(
348                            resolve,
349                            Some(key),
350                            func,
351                            "[export]",
352                            data,
353                        );
354                    }
355                }
356                WorldItem::Type { .. } => unreachable!(),
357                WorldItem::Function(func) => {
358                    self.collect_payload_data_for_func(resolve, None, func, "[export]", data);
359                }
360            }
361        }
362    }
363
364    fn add_imports<'a>(&mut self, resolve: &'a Resolve, world_id: WorldId) -> Imports<'a> {
365        let mut ret = Imports::default();
366        let world = &resolve.worlds[world_id];
367
368        // First up import everything from the interpreter itself that we're
369        // going to possibly need.
370        self.intrinsics = Some(bindgen::WitInterpreterIntrinsics::new(self));
371
372        // Generate function imports for all world imports, in addition to
373        // intrinsics for all resources imported as well. This will additionally
374        // populate the `Imports` return value with all functions that were
375        // found.
376        for (interface, import) in world.imports.iter() {
377            match import {
378                WorldItem::Interface { id, .. } => {
379                    for (_, func) in resolve.interfaces[*id].functions.iter() {
380                        self.add_imported_func(resolve, Some(interface), func, &mut ret);
381                    }
382                    for (_, ty) in resolve.interfaces[*id].types.iter() {
383                        self.add_imported_type_intrinsics(resolve, Some(interface), *ty);
384                    }
385                }
386                WorldItem::Type { id, .. } => {
387                    self.add_imported_type_intrinsics(resolve, None, *id);
388                }
389                WorldItem::Function(func) => {
390                    self.add_imported_func(resolve, None, func, &mut ret);
391                }
392            }
393        }
394
395        // Exported resources need to have intrinsics imported for manipulation,
396        // so do so here.
397        for (name, export) in world.exports.iter() {
398            match export {
399                WorldItem::Function(func) => {
400                    self.add_imported_func_intrinsics_for_export(resolve, None, func, &mut ret);
401                }
402                WorldItem::Interface { id: export, .. } => {
403                    for (_, ty) in resolve.interfaces[*export].types.iter() {
404                        self.add_imported_type_intrinsics_for_export(resolve, Some(name), *ty);
405                    }
406                    for (_, func) in resolve.interfaces[*export].functions.iter() {
407                        self.add_imported_func_intrinsics_for_export(
408                            resolve,
409                            Some(name),
410                            func,
411                            &mut ret,
412                        );
413                    }
414                }
415                WorldItem::Type { .. } => unreachable!(),
416            }
417        }
418
419        let const_i32_global = GlobalType {
420            val_type: ValType::I32,
421            mutable: false,
422            shared: false,
423        };
424        let mut_i32_global = GlobalType {
425            val_type: ValType::I32,
426            mutable: true,
427            shared: false,
428        };
429
430        self.table_base = Some(self.import_global("env", "__table_base", const_i32_global));
431        self.memory_base = Some(self.import_global("env", "__memory_base", const_i32_global));
432        self.stack_pointer = Some(match self.opts.stack_pointer {
433            StackPointer::Global => ImportedStackPointer::Global(self.import_global(
434                "env",
435                "__stack_pointer",
436                mut_i32_global,
437            )),
438            StackPointer::TaskContext => {
439                let get_ty = self.define_ty([], [ValType::I32]);
440                let set_ty = self.define_ty([ValType::I32], []);
441                ImportedStackPointer::TaskContext {
442                    get: self.import_func("$root", "[context-get-0]", get_ty),
443                    set: self.import_func("$root", "[context-set-0]", set_ty),
444                }
445            }
446        });
447
448        self.imports.import(
449            "env",
450            "memory",
451            EntityType::Memory(MemoryType {
452                minimum: 0,
453                maximum: None,
454                memory64: false,
455                shared: false,
456                page_size_log2: None,
457            }),
458        );
459
460        self.imports.import(
461            "env",
462            "__indirect_function_table",
463            EntityType::Table(TableType {
464                element_type: RefType::FUNCREF,
465                minimum: 0,
466                maximum: None,
467                table64: false,
468                shared: false,
469            }),
470        );
471        ret
472    }
473
474    fn add_imported_func<'a>(
475        &mut self,
476        resolve: &'a Resolve,
477        interface: Option<&'a WorldKey>,
478        func: &'a wit_parser::Function,
479        imports: &mut Imports<'a>,
480    ) {
481        let mangling = self.mangling(resolve, interface, func, true);
482        let (module, name) =
483            resolve.wasm_import_name(mangling, WasmImport::Func { interface, func });
484        let sig = resolve.wasm_signature(mangling.import_variant(), func);
485        let ty = self.define_wasm_sig(sig);
486        let import_index = self.import_func(&module, &name, ty);
487        imports.wit_imports.push(WitImport {
488            func,
489            interface,
490            import_index,
491        });
492    }
493
494    fn add_imported_type_intrinsics<'a>(
495        &mut self,
496        resolve: &Resolve,
497        interface: Option<&'a WorldKey>,
498        id: TypeId,
499    ) {
500        let mangling = self.resource_intrinsic_mangling();
501        let ty = &resolve.types[id];
502        match ty.kind {
503            TypeDefKind::Resource => {
504                let (module, name) = resolve.wasm_import_name(
505                    mangling,
506                    WasmImport::ResourceIntrinsic {
507                        interface,
508                        resource: id,
509                        intrinsic: ResourceIntrinsic::ImportedDrop,
510                    },
511                );
512                let core_ty = self.define_ty([ValType::I32], []);
513                let drop = self.import_func(&module, &name, core_ty);
514                let drop_elem_index = self.push_elem(drop);
515                let resource_index = self.metadata.resources.len();
516                self.metadata.resources.push(metadata::Resource {
517                    id,
518                    interface: interface.map(|i| resolve.name_world_key(i)),
519                    name: ty.name.clone().unwrap(),
520                    drop_elem_index,
521                    new_elem_index: None,
522                    rep_elem_index: None,
523                });
524                let prev = self.resource_map.insert(id, resource_index);
525                assert!(prev.is_none());
526            }
527
528            // No other types with intrinsics at this time (futures/streams are
529            // relative to where they show up in function types).
530            _ => {}
531        }
532    }
533
534    fn add_imported_type_intrinsics_for_export<'a>(
535        &mut self,
536        resolve: &Resolve,
537        interface: Option<&'a WorldKey>,
538        id: TypeId,
539    ) {
540        let ty = &resolve.types[id];
541        let mangling = self.resource_intrinsic_mangling();
542        match ty.kind {
543            TypeDefKind::Resource => {
544                let drop_ty = self.define_ty([ValType::I32], []);
545                let new_rep_ty = self.define_ty([ValType::I32], [ValType::I32]);
546
547                let mut import = |ty, intrinsic| {
548                    let (module, name) = resolve.wasm_import_name(
549                        mangling,
550                        WasmImport::ResourceIntrinsic {
551                            interface,
552                            resource: id,
553                            intrinsic,
554                        },
555                    );
556                    self.import_func(&module, &name, ty)
557                };
558
559                let drop = import(drop_ty, ResourceIntrinsic::ExportedDrop);
560                let new = import(new_rep_ty, ResourceIntrinsic::ExportedNew);
561                let rep = import(new_rep_ty, ResourceIntrinsic::ExportedRep);
562
563                let drop_elem_index = self.push_elem(drop);
564                let new_elem_index = Some(self.push_elem(new));
565                let rep_elem_index = Some(self.push_elem(rep));
566
567                let resource_index = self.metadata.resources.len();
568                self.metadata.resources.push(metadata::Resource {
569                    id,
570                    interface: interface.map(|i| resolve.name_world_key(i)),
571                    name: ty.name.clone().unwrap(),
572                    drop_elem_index,
573                    new_elem_index,
574                    rep_elem_index,
575                });
576
577                // Note that this populates an `export_resource_map` instead of
578                // `resource_map` to ensure that if an interface is both
579                // imported and exported that we don't clobber the import
580                // version here. The clobber here happens later when bindings
581                // are generated for exports.
582                let prev = self.export_resource_map.insert(id, resource_index);
583                assert!(prev.is_none());
584            }
585
586            // No other types with intrinsics at this time (futures/streams
587            // relative to where they are in a function).
588            _ => {}
589        }
590    }
591
592    /// Adds `task.return` imports for async functions, and appends all
593    /// functions to `ret.wit_exports`.
594    fn add_imported_func_intrinsics_for_export<'a>(
595        &mut self,
596        resolve: &Resolve,
597        interface: Option<&'a WorldKey>,
598        func: &'a wit_parser::Function,
599        ret: &mut Imports<'a>,
600    ) {
601        let mangling = self.mangling(resolve, interface, func, false);
602        let async_task_return_index = if mangling.is_async() {
603            let (module, name, sig) =
604                func.task_return_import(resolve, interface, mangling.mangling());
605            let ty = self.define_wasm_sig(sig);
606            Some(self.import_func(&module, &name, ty))
607        } else {
608            None
609        };
610        ret.wit_exports.push(WitExport {
611            interface,
612            func,
613            async_task_return_index,
614        });
615    }
616
617    fn bindgen_world(
618        &mut self,
619        resolve: &Resolve,
620        world_id: WorldId,
621        imports: &Imports<'_>,
622        payload_data: &HashMap<TypeId, PayloadData>,
623    ) {
624        let world = &resolve.worlds[world_id];
625
626        // Build up a map for all types of all imports. This pushes all type
627        // information into the metadata section that the interpreter will end
628        // up learning about.
629        let mut import_types = LiveTypes::default();
630        let mut interface_names = HashMap::new();
631        for (interface, import) in world.imports.iter() {
632            import_types.add_world_item(resolve, import);
633            if let WorldItem::Interface { id, .. } = import {
634                interface_names.insert(*id, interface);
635            }
636        }
637        for (_, export) in world.exports.iter() {
638            match export {
639                WorldItem::Function(func) => import_types.add_func(resolve, func),
640                WorldItem::Interface { .. } => {}
641                WorldItem::Type { .. } => unreachable!(),
642            }
643        }
644        for ty in import_types.iter() {
645            let key = match resolve.types[ty].owner {
646                TypeOwner::Interface(id) => Some(interface_names[&id]),
647                _ => None,
648            };
649            self.register_type(resolve, key, ty, payload_data);
650        }
651
652        // Using the populated type map for imports generate functions to invoke
653        // these imports. Also generate exported functions in the world since
654        // they use imported types as well.
655        for import in imports.wit_imports.iter() {
656            self.bindgen_world_func_import(resolve, import);
657        }
658        for export in imports.wit_exports.iter().filter(|i| i.interface.is_none()) {
659            self.bindgen_world_func_export(resolve, export);
660        }
661
662        // Next handle exported interfaces. This is a bit tricky since an
663        // interface can be both exported and imported. To handle that first the
664        // `type_map` set is pruned to only include imported types required, and
665        // then all exported types are added. Export types skip over all
666        // types present in `self.type_map`, though, since those are already
667        // retained from imports.
668        let to_keep = imported_types_used_by_exported_interfaces(resolve, world_id);
669        self.type_map.retain(|id, _| to_keep.contains(*id));
670        let mut exported_types = LiveTypes::default();
671        let mut export_names = HashMap::new();
672        for (interface, import) in world.exports.iter() {
673            if let WorldItem::Interface { id, .. } = import {
674                exported_types.add_world_item(resolve, import);
675                export_names.insert(*id, interface);
676            }
677        }
678        for (ty, index) in mem::take(&mut self.export_resource_map) {
679            self.resource_map.insert(ty, index);
680        }
681        for ty in exported_types.iter() {
682            if self.type_map.contains_key(&ty) {
683                continue;
684            }
685            let key = match resolve.types[ty].owner {
686                TypeOwner::Interface(id) => Some(export_names[&id]),
687                _ => None,
688            };
689            self.register_type(resolve, key, ty, payload_data);
690
691            if let Some(index) = self.resource_map.get(&ty) {
692                self.bindgen_world_export_resource_dtor(resolve, key.unwrap(), ty, *index);
693            }
694        }
695
696        // With export types all in place now run bindgen for all exported
697        // functions.
698        for export in imports.wit_exports.iter().filter(|i| i.interface.is_some()) {
699            self.bindgen_world_func_export(resolve, export);
700        }
701    }
702
703    /// Push WIT type information into metadata for the interpreter.
704    ///
705    /// This will insert `id` into metadata and build up the interpreter data
706    /// structures for it. The end-result is the population of `self.type_map`
707    /// here.
708    fn register_type(
709        &mut self,
710        resolve: &Resolve,
711        key: Option<&WorldKey>,
712        id: TypeId,
713        payload_data: &HashMap<TypeId, PayloadData>,
714    ) {
715        let ty = &resolve.types[id];
716        let interface = key.map(|key| resolve.name_world_key(key));
717        let name = ty.name.clone();
718        let result = match &ty.kind {
719            TypeDefKind::Record(r) => {
720                let index = self.metadata.records.len();
721                let fields = r
722                    .fields
723                    .iter()
724                    .map(|field| (field.name.clone(), self.lookup_ty(&field.ty)))
725                    .collect();
726                self.metadata.records.push(metadata::Record {
727                    id,
728                    interface,
729                    name: name.unwrap(),
730                    fields,
731                });
732                metadata::Type::Record(index)
733            }
734            TypeDefKind::Flags(t) => {
735                let index = self.metadata.flags.len();
736                let names = t.flags.iter().map(|f| f.name.clone()).collect();
737                self.metadata.flags.push(metadata::Flags {
738                    id,
739                    interface,
740                    name: name.unwrap(),
741                    names,
742                });
743                metadata::Type::Flags(index)
744            }
745            TypeDefKind::Tuple(t) => {
746                let index = self.metadata.tuples.len();
747                let types = t.types.iter().map(|t| self.lookup_ty(t)).collect();
748                self.metadata.tuples.push(metadata::Tuple {
749                    id,
750                    interface,
751                    name,
752                    types,
753                });
754                metadata::Type::Tuple(index)
755            }
756            TypeDefKind::Variant(t) => {
757                let index = self.metadata.variants.len();
758                let cases = t
759                    .cases
760                    .iter()
761                    .map(|c| (c.name.clone(), c.ty.map(|t| self.lookup_ty(&t))))
762                    .collect();
763                self.metadata.variants.push(metadata::Variant {
764                    id,
765                    interface,
766                    name: name.unwrap(),
767                    cases,
768                });
769                metadata::Type::Variant(index)
770            }
771            TypeDefKind::Enum(t) => {
772                let index = self.metadata.enums.len();
773                let names = t.cases.iter().map(|f| f.name.clone()).collect();
774                self.metadata.enums.push(metadata::Enum {
775                    id,
776                    interface,
777                    name: name.unwrap(),
778                    names,
779                });
780                metadata::Type::Enum(index)
781            }
782            TypeDefKind::Option(t) => {
783                let index = self.metadata.options.len();
784                self.metadata.options.push(metadata::WitOption {
785                    id,
786                    interface,
787                    name,
788                    ty: self.lookup_ty(t),
789                });
790                metadata::Type::Option(index)
791            }
792            TypeDefKind::Result(t) => {
793                let index = self.metadata.results.len();
794                self.metadata.results.push(metadata::WitResult {
795                    id,
796                    interface,
797                    name,
798                    ok: t.ok.map(|t| self.lookup_ty(&t)),
799                    err: t.err.map(|t| self.lookup_ty(&t)),
800                });
801                metadata::Type::Result(index)
802            }
803            TypeDefKind::List(t) => {
804                let index = self.metadata.lists.len();
805                self.metadata.lists.push(metadata::List {
806                    id,
807                    interface,
808                    name,
809                    ty: self.lookup_ty(t),
810                });
811                metadata::Type::List(index)
812            }
813            TypeDefKind::FixedLengthList(t, len) => {
814                let index = self.metadata.fixed_length_lists.len();
815                self.metadata
816                    .fixed_length_lists
817                    .push(metadata::FixedLengthList {
818                        id,
819                        interface,
820                        name,
821                        len: *len,
822                        ty: self.lookup_ty(t),
823                    });
824                metadata::Type::FixedLengthList(index)
825            }
826            TypeDefKind::Future(t) => {
827                let index = self.metadata.futures.len();
828
829                let Some(&PayloadData {
830                    new_elem_index,
831                    read_elem_index,
832                    write_elem_index,
833                    cancel_read_elem_index,
834                    cancel_write_elem_index,
835                    drop_readable_elem_index,
836                    drop_writable_elem_index,
837                    ordinal,
838                    ref function,
839                }) = payload_data.get(&id)
840                else {
841                    // Such a type can't be used with `wit-component` currently.
842                    panic!("encountered future type not used in any function")
843                };
844
845                // Compile lift and lower functions for lifting and lowering
846                // items of this future's payload type, if applicable.
847
848                let lift_elem_index = t.map(|t| {
849                    let ty = self.define_ty([ValType::I32; 2], []);
850                    let func = bindgen::lift_payload(self, resolve, t);
851                    let func = self.define_func(
852                        &format!("[future-lift-{ordinal}]{function}"),
853                        ty,
854                        func,
855                        false,
856                    );
857                    self.push_elem(func)
858                });
859
860                let lower_elem_index = t.map(|t| {
861                    let ty = self.define_ty([ValType::I32; 2], []);
862                    let func = bindgen::lower_payload(self, resolve, t);
863                    let func = self.define_func(
864                        &format!("[future-lower-{ordinal}]{function}"),
865                        ty,
866                        func,
867                        false,
868                    );
869                    self.push_elem(func)
870                });
871
872                self.metadata.futures.push(metadata::Future {
873                    id,
874                    interface,
875                    name,
876                    ty: t.map(|t| self.lookup_ty(&t)),
877                    new_elem_index,
878                    read_elem_index,
879                    write_elem_index,
880                    cancel_read_elem_index,
881                    cancel_write_elem_index,
882                    drop_readable_elem_index,
883                    drop_writable_elem_index,
884                    lift_elem_index,
885                    lower_elem_index,
886                    abi_payload_size: t.map(|t| self.sizes.size(&t).size_wasm32()).unwrap_or(0),
887                    abi_payload_align: t.map(|t| self.sizes.align(&t).align_wasm32()).unwrap_or(1),
888                });
889                metadata::Type::Future(index)
890            }
891            TypeDefKind::Stream(t) => {
892                let index = self.metadata.streams.len();
893
894                let Some(&PayloadData {
895                    new_elem_index,
896                    read_elem_index,
897                    write_elem_index,
898                    cancel_read_elem_index,
899                    cancel_write_elem_index,
900                    drop_readable_elem_index,
901                    drop_writable_elem_index,
902                    ordinal,
903                    ref function,
904                }) = payload_data.get(&id)
905                else {
906                    // Such a type can't be used with `wit-component` currently.
907                    panic!("encountered stream type not used in any function")
908                };
909
910                // Compile lift and lower functions for lifting and lowering
911                // items of this stream's payload type, if applicable.
912                //
913                // Note that these functions operate on only a single item,
914                // meaning they must be called in a loop when reading or writing
915                // multiple items.  That saves us from having to generate a Wasm
916                // loop, and allows us to reuse the same code generators for
917                // `future`s and `stream`s, although the result might not be
918                // quite as efficient.
919
920                let lift_elem_index = t.map(|t| {
921                    let ty = self.define_ty([ValType::I32; 2], []);
922                    let func = bindgen::lift_payload(self, resolve, t);
923                    let func = self.define_func(
924                        &format!("[stream-lift-{ordinal}]{function}"),
925                        ty,
926                        func,
927                        false,
928                    );
929                    self.push_elem(func)
930                });
931
932                let lower_elem_index = t.map(|t| {
933                    let ty = self.define_ty([ValType::I32; 2], []);
934                    let func = bindgen::lower_payload(self, resolve, t);
935                    let func = self.define_func(
936                        &format!("[stream-lower-{ordinal}]{function}"),
937                        ty,
938                        func,
939                        false,
940                    );
941                    self.push_elem(func)
942                });
943
944                self.metadata.streams.push(metadata::Stream {
945                    id,
946                    interface,
947                    name,
948                    ty: t.map(|t| self.lookup_ty(&t)),
949                    new_elem_index,
950                    read_elem_index,
951                    write_elem_index,
952                    cancel_read_elem_index,
953                    cancel_write_elem_index,
954                    drop_readable_elem_index,
955                    drop_writable_elem_index,
956                    lift_elem_index,
957                    lower_elem_index,
958                    abi_payload_size: t.map(|t| self.sizes.size(&t).size_wasm32()).unwrap_or(0),
959                    abi_payload_align: t.map(|t| self.sizes.align(&t).align_wasm32()).unwrap_or(1),
960                });
961                metadata::Type::Stream(index)
962            }
963            TypeDefKind::Type(t) => {
964                let index = self.metadata.aliases.len();
965                self.metadata.aliases.push(metadata::Alias {
966                    id,
967                    interface,
968                    name: name.unwrap(),
969                    ty: self.lookup_ty(t),
970                });
971                metadata::Type::Alias(index)
972            }
973            TypeDefKind::Resource => metadata::Type::Own(self.resource_map[&id]),
974
975            // Own/Borrow handles should have already inserted the resource into
976            // `self.resource_map` so this is just a simple lookup.
977            TypeDefKind::Handle(Handle::Own(t)) => {
978                metadata::Type::Own(self.resource_map[&dealias(resolve, *t)])
979            }
980            TypeDefKind::Handle(Handle::Borrow(t)) => {
981                metadata::Type::Borrow(self.resource_map[&dealias(resolve, *t)])
982            }
983            TypeDefKind::Map(k, v) => {
984                let index = self.metadata.maps.len();
985                self.metadata.maps.push(metadata::Map {
986                    id,
987                    interface,
988                    name,
989                    key_type: self.lookup_ty(k),
990                    value_type: self.lookup_ty(v),
991                });
992                metadata::Type::Map(index)
993            }
994            TypeDefKind::Unknown => unreachable!(),
995        };
996        self.type_map.insert(id, result);
997    }
998
999    fn lookup_ty(&self, ty: &Type) -> metadata::Type {
1000        match ty {
1001            Type::U8 => metadata::Type::U8,
1002            Type::U16 => metadata::Type::U16,
1003            Type::U32 => metadata::Type::U32,
1004            Type::U64 => metadata::Type::U64,
1005            Type::S8 => metadata::Type::S8,
1006            Type::S16 => metadata::Type::S16,
1007            Type::S32 => metadata::Type::S32,
1008            Type::S64 => metadata::Type::S64,
1009            Type::F32 => metadata::Type::F32,
1010            Type::F64 => metadata::Type::F64,
1011            Type::Bool => metadata::Type::Bool,
1012            Type::Char => metadata::Type::Char,
1013            Type::String => metadata::Type::String,
1014            Type::ErrorContext => metadata::Type::ErrorContext,
1015            // All id-based types should already be registered via
1016            // `register_type` so the hard work is already done and this is a
1017            // simple lookup.
1018            Type::Id(id) => self.type_map[id],
1019        }
1020    }
1021
1022    fn bindgen_world_func_import(&mut self, resolve: &Resolve, import: &WitImport<'_>) {
1023        let func = import.func;
1024        let mangling = self.mangling(resolve, import.interface, func, true);
1025        let body = bindgen::import(
1026            self,
1027            resolve,
1028            func,
1029            mangling.import_variant(),
1030            import.import_index,
1031        );
1032
1033        let ty = if mangling.is_async() {
1034            // [ cx abi_area_ptr ] -> [ status ]
1035            self.define_ty([ValType::I32; 2], [ValType::I32])
1036        } else {
1037            // [ cx ] -> []
1038            self.define_ty([ValType::I32], [])
1039        };
1040
1041        let idx = self.define_func(&format!("adapter {}", func.name), ty, body, false);
1042        let elem_index = self.push_elem(idx);
1043
1044        let sync_import_elem_index;
1045        let async_import_elem_index;
1046        let async_import_lift_results_elem_index;
1047
1048        if mangling.is_async() {
1049            sync_import_elem_index = None;
1050            async_import_elem_index = Some(elem_index);
1051            let body =
1052                bindgen::lift_async_import_results(self, resolve, func, mangling.import_variant());
1053            let ty = self.define_ty([ValType::I32; 2], []);
1054            let idx = self.define_func(&format!("lift results {}", func.name), ty, body, false);
1055            async_import_lift_results_elem_index = Some(self.push_elem(idx));
1056        } else {
1057            sync_import_elem_index = Some(elem_index);
1058            async_import_elem_index = None;
1059            async_import_lift_results_elem_index = None;
1060        }
1061
1062        self.metadata.import_funcs.push(metadata::ImportFunc {
1063            interface: import.interface.map(|k| resolve.name_world_key(k)),
1064            name: func.name.clone(),
1065            sync_import_elem_index,
1066            async_import_elem_index,
1067            async_import_lift_results_elem_index,
1068            args: func.params.iter().map(|p| self.lookup_ty(&p.ty)).collect(),
1069            result: func.result.map(|t| self.lookup_ty(&t)),
1070            async_abi_area: self.async_import_abi_area(resolve, mangling, func),
1071        })
1072    }
1073
1074    /// Returns the `(size, align)` for the indirect params/results as necessary
1075    /// for `func` if `func` is an async function.
1076    fn async_import_abi_area(
1077        &self,
1078        resolve: &Resolve,
1079        mangling: ManglingAndAbi,
1080        func: &wit_parser::Function,
1081    ) -> Option<(usize, usize)> {
1082        if !mangling.is_async() {
1083            return None;
1084        }
1085
1086        let info = self
1087            .sizes
1088            .record(bindgen::async_import_abi_area_types(resolve, func));
1089        Some((info.size.size_wasm32(), info.align.align_wasm32()))
1090    }
1091
1092    fn bindgen_world_func_export(&mut self, resolve: &Resolve, export: &WitExport<'_>) {
1093        let func = export.func;
1094        let mangling = self.mangling(resolve, export.interface, func, false);
1095        let sig = resolve.wasm_signature(mangling.export_variant(), func);
1096        let ty = self.define_wasm_sig(sig);
1097        let name = resolve.wasm_export_name(
1098            mangling,
1099            WasmExport::Func {
1100                interface: export.interface,
1101                func,
1102                kind: WasmExportKind::Normal,
1103            },
1104        );
1105
1106        let metadata_func_index = self.metadata.export_funcs.len();
1107        let body = bindgen::export(
1108            self,
1109            resolve,
1110            func,
1111            mangling.export_variant(),
1112            metadata_func_index,
1113        );
1114        self.define_func(&name, ty, body, true);
1115
1116        let mut async_export_task_return_elem_index = None;
1117        match mangling {
1118            // For sync functions a post-return function is generated which
1119            // cleans up the `cx` argument notably but also any list allocations
1120            // and such as required.
1121            ManglingAndAbi::Standard32 | ManglingAndAbi::Legacy(LiftLowerAbi::Sync) => {
1122                let post_return_name = resolve.wasm_export_name(
1123                    mangling,
1124                    WasmExport::Func {
1125                        interface: export.interface,
1126                        func,
1127                        kind: WasmExportKind::PostReturn,
1128                    },
1129                );
1130                let post_return = bindgen::post_return(
1131                    self,
1132                    resolve,
1133                    func,
1134                    mangling.export_variant(),
1135                    metadata_func_index,
1136                );
1137                let mut sig = resolve.wasm_signature(mangling.export_variant(), func);
1138                sig.params = mem::take(&mut sig.results);
1139                let post_return_ty = self.define_wasm_sig(sig);
1140                self.define_func(&post_return_name, post_return_ty, post_return, true);
1141            }
1142
1143            // For async exports in addition to the main entrypoint a
1144            // `[callback]` function is generated which is invoked when progress
1145            // is made on this function.
1146            //
1147            // Additionally a `task.return` function is generated to be invoked
1148            // once the async export has completed.
1149            ManglingAndAbi::Legacy(LiftLowerAbi::AsyncCallback) => {
1150                let callback_name = resolve.wasm_export_name(
1151                    mangling,
1152                    WasmExport::Func {
1153                        interface: export.interface,
1154                        func,
1155                        kind: WasmExportKind::Callback,
1156                    },
1157                );
1158                // The `[callback]` function is pretty simple, just delegate to
1159                // the `wit_dylib_*` implementation with one extra contextual
1160                // argument. It's the responsibility of the implementation to
1161                // call `context.{get,set}` as appropriate.
1162                let mut callback = Function::new([]);
1163                let mut ins = callback.instructions();
1164                ins.local_get(0);
1165                ins.local_get(1);
1166                ins.local_get(2);
1167                ins.i32_const(metadata_func_index.try_into().unwrap());
1168                let export_async_callback = self.intrinsics().export_async_callback;
1169                ins.call(export_async_callback);
1170                ins.end();
1171                let callback_ty = self.define_ty([ValType::I32; 3], [ValType::I32]);
1172                self.define_func(&callback_name, callback_ty, callback, true);
1173
1174                let task_return = bindgen::task_return(
1175                    self,
1176                    resolve,
1177                    func,
1178                    mangling.export_variant(),
1179                    export.async_task_return_index.unwrap(),
1180                );
1181                let task_return_ty = self.define_ty([ValType::I32], []);
1182                let task_return = self.define_func(
1183                    &format!("task.return {}", func.name),
1184                    task_return_ty,
1185                    task_return,
1186                    false,
1187                );
1188                async_export_task_return_elem_index = Some(self.push_elem(task_return));
1189            }
1190
1191            ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => unimplemented!(),
1192        }
1193
1194        self.metadata.export_funcs.push(metadata::ExportFunc {
1195            interface: export.interface.map(|k| resolve.name_world_key(k)),
1196            name: func.name.clone(),
1197            async_export_task_return_elem_index,
1198            args: func.params.iter().map(|p| self.lookup_ty(&p.ty)).collect(),
1199            result: func.result.map(|t| self.lookup_ty(&t)),
1200        })
1201    }
1202
1203    fn bindgen_world_export_resource_dtor(
1204        &mut self,
1205        resolve: &Resolve,
1206        interface: &WorldKey,
1207        resource: TypeId,
1208        index: usize,
1209    ) {
1210        let mangling = self.resource_intrinsic_mangling();
1211        let name = resolve.wasm_export_name(
1212            mangling,
1213            WasmExport::ResourceDtor {
1214                interface,
1215                resource,
1216            },
1217        );
1218        let dtor = self.intrinsics().resource_dtor;
1219        let mut func = Function::new([]);
1220        let mut ins = func.instructions();
1221        ins.i32_const(index.try_into().unwrap());
1222        ins.local_get(0);
1223        ins.call(dtor);
1224        ins.end();
1225        let ty = self.define_ty([ValType::I32], []);
1226        self.define_func(&name, ty, func, true);
1227    }
1228
1229    fn encode_metadata(&mut self) -> (u32, Vec<u8>) {
1230        let (metadata_offset, metadata, apply_relocs) =
1231            self.metadata.encode(self.table_base(), self.memory_base());
1232        if let Some(apply_relocs) = apply_relocs {
1233            let ty = self.define_ty([], []);
1234            self.define_func("__wasm_apply_data_relocs", ty, apply_relocs, true);
1235        }
1236        (metadata_offset, metadata)
1237    }
1238
1239    fn table_base(&self) -> u32 {
1240        self.table_base.unwrap()
1241    }
1242
1243    fn intrinsics(&self) -> &bindgen::WitInterpreterIntrinsics {
1244        self.intrinsics.as_ref().unwrap()
1245    }
1246
1247    fn memory_base(&self) -> u32 {
1248        self.memory_base.unwrap()
1249    }
1250
1251    fn push_elem(&mut self, elem: u32) -> u32 {
1252        let ret = self.elem_segment.len();
1253        self.elem_segment.push(elem);
1254        u32::try_from(ret).unwrap()
1255    }
1256
1257    fn finish(&mut self, metadata: &[u8]) -> Vec<u8> {
1258        // Create the element segment dynamically added to the table, if necessary.
1259        let mut elements = ElementSection::new();
1260        if !self.elem_segment.is_empty() {
1261            elements.active(
1262                Some(0),
1263                &ConstExpr::global_get(self.table_base()),
1264                Elements::Functions(Cow::Borrowed(&self.elem_segment)),
1265            );
1266        }
1267
1268        // Add a data segment for the interpreter metadata encoded data in-memory.
1269        let mut data = DataSection::new();
1270        data.active(
1271            0,
1272            &ConstExpr::global_get(self.memory_base()),
1273            metadata.iter().copied(),
1274        );
1275
1276        let mut names = NameSection::new();
1277        names.functions(&self.function_names);
1278        names.globals(&self.global_names);
1279
1280        let dylink0 = {
1281            struct MemInfo {
1282                memory_size: u32,
1283                memory_alignment: u32,
1284                table_size: u32,
1285                table_alignment: u32,
1286            }
1287
1288            let mem_info = MemInfo {
1289                memory_size: metadata.len().try_into().unwrap(),
1290                memory_alignment: 2,
1291                table_size: self.elem_segment.len().try_into().unwrap(),
1292                table_alignment: 0,
1293            };
1294
1295            let mut mem_info_subsection = Vec::new();
1296            mem_info.memory_size.encode(&mut mem_info_subsection);
1297            mem_info.memory_alignment.encode(&mut mem_info_subsection);
1298            mem_info.table_size.encode(&mut mem_info_subsection);
1299            mem_info.table_alignment.encode(&mut mem_info_subsection);
1300
1301            let mut needed_subsection = Vec::new();
1302            if let Some(name) = &self.opts.interpreter {
1303                [name.as_str()].encode(&mut needed_subsection);
1304            }
1305
1306            const WASM_DYLINK_MEM_INFO: u8 = 1;
1307            const WASM_DYLINK_NEEDED: u8 = 2;
1308
1309            let mut dylink0 = Vec::new();
1310            dylink0.push(WASM_DYLINK_MEM_INFO);
1311            mem_info_subsection.encode(&mut dylink0);
1312            if self.opts.interpreter.is_some() {
1313                dylink0.push(WASM_DYLINK_NEEDED);
1314                needed_subsection.encode(&mut dylink0);
1315            }
1316            dylink0
1317        };
1318
1319        let mut result = Module::new();
1320        result.section(&CustomSection {
1321            name: Cow::Borrowed("dylink.0"),
1322            data: Cow::Borrowed(&dylink0),
1323        });
1324        result.section(&self.types);
1325        result.section(&self.imports);
1326        result.section(&self.functions);
1327        result.section(&self.exports);
1328        if !elements.is_empty() {
1329            result.section(&elements);
1330        }
1331        result.section(&self.code);
1332        result.section(&data);
1333        result.section(&names);
1334
1335        result.finish()
1336    }
1337
1338    fn define_wasm_sig(&mut self, sig: WasmSignature) -> u32 {
1339        let ret = self.define_ty(
1340            sig.params
1341                .iter()
1342                .map(|t| self.map_wasm_type(*t))
1343                .collect::<Vec<_>>(),
1344            sig.results
1345                .iter()
1346                .map(|t| self.map_wasm_type(*t))
1347                .collect::<Vec<_>>(),
1348        );
1349        return ret;
1350    }
1351
1352    fn map_wasm_type(&self, a: WasmType) -> ValType {
1353        match a {
1354            WasmType::I32 => ValType::I32,
1355            WasmType::I64 => ValType::I64,
1356            WasmType::F32 => ValType::F32,
1357            WasmType::F64 => ValType::F64,
1358            WasmType::PointerOrI64 => ValType::I64,
1359            WasmType::Length | WasmType::Pointer => ValType::I32,
1360        }
1361    }
1362
1363    fn import_global(&mut self, module: &str, name: &str, ty: GlobalType) -> u32 {
1364        assert!(!self.imports_done);
1365        self.imports.import(module, name, ty);
1366        let ret = self.global_index;
1367        self.global_index += 1;
1368        self.global_names.append(ret, name);
1369        ret
1370    }
1371
1372    fn import_func(&mut self, module: &str, name: &str, ty: u32) -> u32 {
1373        assert!(!self.imports_done);
1374        self.imports.import(module, name, EntityType::Function(ty));
1375        let ret = self.func_index;
1376        self.func_index += 1;
1377        self.function_names.append(ret, name);
1378        ret
1379    }
1380
1381    fn define_func(&mut self, name: &str, ty: u32, body: Function, export: bool) -> u32 {
1382        assert!(self.imports_done);
1383        let ret = self.func_index;
1384        self.func_index += 1;
1385        self.functions.function(ty);
1386        self.code.function(&body);
1387        self.function_names.append(ret, name);
1388        if export {
1389            self.exports.export(name, ExportKind::Func, ret);
1390        }
1391        ret
1392    }
1393
1394    fn define_ty<P, R>(&mut self, params: P, results: R) -> u32
1395    where
1396        P: IntoIterator<Item = ValType> + Clone,
1397        P::IntoIter: ExactSizeIterator,
1398        R: IntoIterator<Item = ValType> + Clone,
1399        R::IntoIter: ExactSizeIterator,
1400    {
1401        let param_vec = params.clone().into_iter().collect::<Vec<_>>();
1402        let result_vec = results.clone().into_iter().collect::<Vec<_>>();
1403        *self
1404            .wasm_type_map
1405            .entry((param_vec, result_vec))
1406            .or_insert_with(|| {
1407                let ret = self.types.len();
1408                self.types.ty().function(params, results);
1409                ret
1410            })
1411    }
1412}
1413
1414fn imported_types_used_by_exported_interfaces(resolve: &Resolve, world: WorldId) -> LiveTypes {
1415    // First build up a set of all types used by exported interfaces which
1416    // define their own types.
1417    let mut live_export_types = LiveTypes::default();
1418    let mut exported_interfaces = HashSet::new();
1419    for (_, export) in resolve.worlds[world].exports.iter() {
1420        match export {
1421            WorldItem::Function(_) => {}
1422            WorldItem::Interface { id, .. } => {
1423                exported_interfaces.insert(*id);
1424                live_export_types.add_interface(resolve, *id)
1425            }
1426            WorldItem::Type { .. } => unreachable!(),
1427        }
1428    }
1429
1430    // Using the above sets a new set is built of all types that aren't
1431    // reexported. All types used by exports, which are defined by an interface
1432    // that is NOT an export, is an imported type used by an export.
1433    let mut live_import_types = LiveTypes::default();
1434    for ty in live_export_types.iter() {
1435        if let TypeOwner::Interface(id) = resolve.types[ty].owner {
1436            if !exported_interfaces.contains(&id) {
1437                live_import_types.add_interface(resolve, id);
1438            }
1439        }
1440    }
1441
1442    live_import_types
1443}
1444
1445fn dealias(resolve: &Resolve, mut id: TypeId) -> TypeId {
1446    loop {
1447        match resolve.types[id].kind {
1448            TypeDefKind::Type(Type::Id(other)) => id = other,
1449            _ => break id,
1450        }
1451    }
1452}
1453
1454#[cfg(test)]
1455mod tests {
1456    use wasmparser::{Operator, Parser, Payload};
1457    use wit_parser::Resolve;
1458
1459    #[derive(Copy, Clone)]
1460    enum Which {
1461        S8,
1462        S16,
1463    }
1464
1465    #[test]
1466    fn s8_uses_signed_load() {
1467        assert!(find_signed_load(Which::S8));
1468    }
1469
1470    #[test]
1471    fn s16_uses_signed_load() {
1472        assert!(find_signed_load(Which::S16));
1473    }
1474
1475    fn find_signed_load(which: Which) -> bool {
1476        let mut resolve = Resolve::default();
1477        let ty = match which {
1478            Which::S8 => "s8",
1479            Which::S16 => "s16",
1480        };
1481        let package = resolve
1482            .push_str(
1483                "wit",
1484                &format!(
1485                    "package test:test;
1486world w {{
1487  export foo: func(v: list<{ty}>);
1488}}
1489"
1490                ),
1491            )
1492            .unwrap();
1493        let world = resolve.select_world(&[package], None).unwrap();
1494        let adapter = super::create(&resolve, world, None).unwrap();
1495        for payload in Parser::new(0).parse_all(&adapter) {
1496            match payload.unwrap() {
1497                Payload::CodeSectionEntry(body) => {
1498                    for operator in body.get_operators_reader().unwrap() {
1499                        match (operator.unwrap(), which) {
1500                            (Operator::I32Load16S { .. }, Which::S16)
1501                            | (Operator::I32Load8S { .. }, Which::S8) => return true,
1502                            _ => {}
1503                        }
1504                    }
1505                }
1506                _ => {}
1507            }
1508        }
1509        false
1510    }
1511}