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