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(ty) => {
359                    self.add_imported_type_intrinsics(resolve, None, *ty);
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::FixedSizeList(t, len) => {
772                let index = self.metadata.fixed_size_lists.len();
773                self.metadata
774                    .fixed_size_lists
775                    .push(metadata::FixedSizeList {
776                        id,
777                        interface,
778                        name,
779                        len: *len,
780                        ty: self.lookup_ty(t),
781                    });
782                metadata::Type::FixedSizeList(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::Unknown => unreachable!(),
942        };
943        self.type_map.insert(id, result);
944    }
945
946    fn lookup_ty(&self, ty: &Type) -> metadata::Type {
947        match ty {
948            Type::U8 => metadata::Type::U8,
949            Type::U16 => metadata::Type::U16,
950            Type::U32 => metadata::Type::U32,
951            Type::U64 => metadata::Type::U64,
952            Type::S8 => metadata::Type::S8,
953            Type::S16 => metadata::Type::S16,
954            Type::S32 => metadata::Type::S32,
955            Type::S64 => metadata::Type::S64,
956            Type::F32 => metadata::Type::F32,
957            Type::F64 => metadata::Type::F64,
958            Type::Bool => metadata::Type::Bool,
959            Type::Char => metadata::Type::Char,
960            Type::String => metadata::Type::String,
961            Type::ErrorContext => metadata::Type::ErrorContext,
962            // All id-based types should already be registered via
963            // `register_type` so the hard work is already done and this is a
964            // simple lookup.
965            Type::Id(id) => self.type_map[id],
966        }
967    }
968
969    fn bindgen_world_func_import(&mut self, resolve: &Resolve, import: &WitImport<'_>) {
970        let func = import.func;
971        let mangling = self.mangling(resolve, import.interface, func, true);
972        let body = bindgen::import(
973            self,
974            resolve,
975            func,
976            mangling.import_variant(),
977            import.import_index,
978        );
979
980        let ty = if mangling.is_async() {
981            // [ cx abi_area_ptr ] -> [ status ]
982            self.define_ty([ValType::I32; 2], [ValType::I32])
983        } else {
984            // [ cx ] -> []
985            self.define_ty([ValType::I32], [])
986        };
987
988        let idx = self.define_func(&format!("adapter {}", func.name), ty, body, false);
989        let elem_index = self.push_elem(idx);
990
991        let sync_import_elem_index;
992        let async_import_elem_index;
993        let async_import_lift_results_elem_index;
994
995        if mangling.is_async() {
996            sync_import_elem_index = None;
997            async_import_elem_index = Some(elem_index);
998            let body =
999                bindgen::lift_async_import_results(self, resolve, func, mangling.import_variant());
1000            let ty = self.define_ty([ValType::I32; 2], []);
1001            let idx = self.define_func(&format!("lift results {}", func.name), ty, body, false);
1002            async_import_lift_results_elem_index = Some(self.push_elem(idx));
1003        } else {
1004            sync_import_elem_index = Some(elem_index);
1005            async_import_elem_index = None;
1006            async_import_lift_results_elem_index = None;
1007        }
1008
1009        self.metadata.import_funcs.push(metadata::ImportFunc {
1010            interface: import.interface.map(|k| resolve.name_world_key(k)),
1011            name: func.name.clone(),
1012            sync_import_elem_index,
1013            async_import_elem_index,
1014            async_import_lift_results_elem_index,
1015            args: func
1016                .params
1017                .iter()
1018                .map(|(_, ty)| self.lookup_ty(ty))
1019                .collect(),
1020            result: func.result.map(|t| self.lookup_ty(&t)),
1021            async_abi_area: self.async_import_abi_area(resolve, mangling, func),
1022        })
1023    }
1024
1025    /// Returns the `(size, align)` for the indirect params/results as necessary
1026    /// for `func` if `func` is an async function.
1027    fn async_import_abi_area(
1028        &self,
1029        resolve: &Resolve,
1030        mangling: ManglingAndAbi,
1031        func: &wit_parser::Function,
1032    ) -> Option<(usize, usize)> {
1033        if !mangling.is_async() {
1034            return None;
1035        }
1036
1037        let info = self
1038            .sizes
1039            .record(bindgen::async_import_abi_area_types(resolve, func));
1040        Some((info.size.size_wasm32(), info.align.align_wasm32()))
1041    }
1042
1043    fn bindgen_world_func_export(&mut self, resolve: &Resolve, export: &WitExport<'_>) {
1044        let func = export.func;
1045        let mangling = self.mangling(resolve, export.interface, func, false);
1046        let sig = resolve.wasm_signature(mangling.export_variant(), func);
1047        let ty = self.define_wasm_sig(sig);
1048        let name = resolve.wasm_export_name(
1049            mangling,
1050            WasmExport::Func {
1051                interface: export.interface,
1052                func,
1053                kind: WasmExportKind::Normal,
1054            },
1055        );
1056
1057        let metadata_func_index = self.metadata.export_funcs.len();
1058        let body = bindgen::export(
1059            self,
1060            resolve,
1061            func,
1062            mangling.export_variant(),
1063            metadata_func_index,
1064        );
1065        self.define_func(&name, ty, body, true);
1066
1067        let mut async_export_task_return_elem_index = None;
1068        match mangling {
1069            // For sync functions a post-return function is generated which
1070            // cleans up the `cx` argument notably but also any list allocations
1071            // and such as required.
1072            ManglingAndAbi::Standard32 | ManglingAndAbi::Legacy(LiftLowerAbi::Sync) => {
1073                let post_return_name = resolve.wasm_export_name(
1074                    mangling,
1075                    WasmExport::Func {
1076                        interface: export.interface,
1077                        func,
1078                        kind: WasmExportKind::PostReturn,
1079                    },
1080                );
1081                let post_return = bindgen::post_return(
1082                    self,
1083                    resolve,
1084                    func,
1085                    mangling.export_variant(),
1086                    metadata_func_index,
1087                );
1088                let mut sig = resolve.wasm_signature(mangling.export_variant(), func);
1089                sig.params = mem::take(&mut sig.results);
1090                let post_return_ty = self.define_wasm_sig(sig);
1091                self.define_func(&post_return_name, post_return_ty, post_return, true);
1092            }
1093
1094            // For async exports in addition to the main entrypoint a
1095            // `[callback]` function is generated which is invoked when progress
1096            // is made on this function.
1097            //
1098            // Additionally a `task.return` function is generated to be invoked
1099            // once the async export has completed.
1100            ManglingAndAbi::Legacy(LiftLowerAbi::AsyncCallback) => {
1101                let callback_name = resolve.wasm_export_name(
1102                    mangling,
1103                    WasmExport::Func {
1104                        interface: export.interface,
1105                        func,
1106                        kind: WasmExportKind::Callback,
1107                    },
1108                );
1109                // The `[callback]` function is pretty simple, just delegate to
1110                // the `wit_dylib_*` implementation with one extra contextual
1111                // argument. It's the responsibility of the implementation to
1112                // call `context.{get,set}` as appropriate.
1113                let mut callback = Function::new([]);
1114                let mut ins = callback.instructions();
1115                ins.local_get(0);
1116                ins.local_get(1);
1117                ins.local_get(2);
1118                ins.i32_const(metadata_func_index.try_into().unwrap());
1119                let export_async_callback = self.intrinsics().export_async_callback;
1120                ins.call(export_async_callback);
1121                ins.end();
1122                let callback_ty = self.define_ty([ValType::I32; 3], [ValType::I32]);
1123                self.define_func(&callback_name, callback_ty, callback, true);
1124
1125                let task_return = bindgen::task_return(
1126                    self,
1127                    resolve,
1128                    func,
1129                    mangling.export_variant(),
1130                    export.async_task_return_index.unwrap(),
1131                );
1132                let task_return_ty = self.define_ty([ValType::I32], []);
1133                let task_return = self.define_func(
1134                    &format!("task.return {}", func.name),
1135                    task_return_ty,
1136                    task_return,
1137                    false,
1138                );
1139                async_export_task_return_elem_index = Some(self.push_elem(task_return));
1140            }
1141
1142            ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => unimplemented!(),
1143        }
1144
1145        self.metadata.export_funcs.push(metadata::ExportFunc {
1146            interface: export.interface.map(|k| resolve.name_world_key(k)),
1147            name: func.name.clone(),
1148            async_export_task_return_elem_index,
1149            args: func
1150                .params
1151                .iter()
1152                .map(|(_, ty)| self.lookup_ty(ty))
1153                .collect(),
1154            result: func.result.map(|t| self.lookup_ty(&t)),
1155        })
1156    }
1157
1158    fn bindgen_world_export_resource_dtor(
1159        &mut self,
1160        resolve: &Resolve,
1161        interface: &WorldKey,
1162        resource: TypeId,
1163        index: usize,
1164    ) {
1165        let mangling = self.resource_intrinsic_mangling();
1166        let name = resolve.wasm_export_name(
1167            mangling,
1168            WasmExport::ResourceDtor {
1169                interface,
1170                resource,
1171            },
1172        );
1173        let dtor = self.intrinsics().resource_dtor;
1174        let mut func = Function::new([]);
1175        let mut ins = func.instructions();
1176        ins.i32_const(index.try_into().unwrap());
1177        ins.local_get(0);
1178        ins.call(dtor);
1179        ins.end();
1180        let ty = self.define_ty([ValType::I32], []);
1181        self.define_func(&name, ty, func, true);
1182    }
1183
1184    fn encode_metadata(&mut self) -> (u32, Vec<u8>) {
1185        let (metadata_offset, metadata, apply_relocs) =
1186            self.metadata.encode(self.table_base(), self.memory_base());
1187        if let Some(apply_relocs) = apply_relocs {
1188            let ty = self.define_ty([], []);
1189            self.define_func("__wasm_apply_data_relocs", ty, apply_relocs, true);
1190        }
1191        (metadata_offset, metadata)
1192    }
1193
1194    fn table_base(&self) -> u32 {
1195        self.table_base.unwrap()
1196    }
1197
1198    fn intrinsics(&self) -> &bindgen::WitInterpreterIntrinsics {
1199        self.intrinsics.as_ref().unwrap()
1200    }
1201
1202    fn stack_pointer(&self) -> u32 {
1203        self.stack_pointer.unwrap()
1204    }
1205
1206    fn memory_base(&self) -> u32 {
1207        self.memory_base.unwrap()
1208    }
1209
1210    fn push_elem(&mut self, elem: u32) -> u32 {
1211        let ret = self.elem_segment.len();
1212        self.elem_segment.push(elem);
1213        u32::try_from(ret).unwrap()
1214    }
1215
1216    fn finish(&mut self, metadata: &[u8]) -> Vec<u8> {
1217        // Create the element segment dynamically added to the table, if necessary.
1218        let mut elements = ElementSection::new();
1219        if !self.elem_segment.is_empty() {
1220            elements.active(
1221                Some(0),
1222                &ConstExpr::global_get(self.table_base()),
1223                Elements::Functions(Cow::Borrowed(&self.elem_segment)),
1224            );
1225        }
1226
1227        // Add a data segment for the interpreter metadata encoded data in-memory.
1228        let mut data = DataSection::new();
1229        data.active(
1230            0,
1231            &ConstExpr::global_get(self.memory_base()),
1232            metadata.iter().copied(),
1233        );
1234
1235        let mut names = NameSection::new();
1236        names.functions(&self.function_names);
1237        names.globals(&self.global_names);
1238
1239        let dylink0 = {
1240            struct MemInfo {
1241                memory_size: u32,
1242                memory_alignment: u32,
1243                table_size: u32,
1244                table_alignment: u32,
1245            }
1246
1247            let mem_info = MemInfo {
1248                memory_size: metadata.len().try_into().unwrap(),
1249                memory_alignment: 2,
1250                table_size: self.elem_segment.len().try_into().unwrap(),
1251                table_alignment: 0,
1252            };
1253
1254            let mut mem_info_subsection = Vec::new();
1255            mem_info.memory_size.encode(&mut mem_info_subsection);
1256            mem_info.memory_alignment.encode(&mut mem_info_subsection);
1257            mem_info.table_size.encode(&mut mem_info_subsection);
1258            mem_info.table_alignment.encode(&mut mem_info_subsection);
1259
1260            let mut needed_subsection = Vec::new();
1261            if let Some(name) = &self.opts.interpreter {
1262                [name.as_str()].encode(&mut needed_subsection);
1263            }
1264
1265            const WASM_DYLINK_MEM_INFO: u8 = 1;
1266            const WASM_DYLINK_NEEDED: u8 = 2;
1267
1268            let mut dylink0 = Vec::new();
1269            dylink0.push(WASM_DYLINK_MEM_INFO);
1270            mem_info_subsection.encode(&mut dylink0);
1271            if self.opts.interpreter.is_some() {
1272                dylink0.push(WASM_DYLINK_NEEDED);
1273                needed_subsection.encode(&mut dylink0);
1274            }
1275            dylink0
1276        };
1277
1278        let mut result = Module::new();
1279        result.section(&CustomSection {
1280            name: Cow::Borrowed("dylink.0"),
1281            data: Cow::Borrowed(&dylink0),
1282        });
1283        result.section(&self.types);
1284        result.section(&self.imports);
1285        result.section(&self.functions);
1286        result.section(&self.exports);
1287        if !elements.is_empty() {
1288            result.section(&elements);
1289        }
1290        result.section(&self.code);
1291        result.section(&data);
1292        result.section(&names);
1293
1294        result.finish()
1295    }
1296
1297    fn define_wasm_sig(&mut self, sig: WasmSignature) -> u32 {
1298        let ret = self.define_ty(
1299            sig.params
1300                .iter()
1301                .map(|t| self.map_wasm_type(*t))
1302                .collect::<Vec<_>>(),
1303            sig.results
1304                .iter()
1305                .map(|t| self.map_wasm_type(*t))
1306                .collect::<Vec<_>>(),
1307        );
1308        return ret;
1309    }
1310
1311    fn map_wasm_type(&self, a: WasmType) -> ValType {
1312        match a {
1313            WasmType::I32 => ValType::I32,
1314            WasmType::I64 => ValType::I64,
1315            WasmType::F32 => ValType::F32,
1316            WasmType::F64 => ValType::F64,
1317            WasmType::PointerOrI64 => ValType::I64,
1318            WasmType::Length | WasmType::Pointer => ValType::I32,
1319        }
1320    }
1321
1322    fn import_global(&mut self, module: &str, name: &str, ty: GlobalType) -> u32 {
1323        assert!(!self.imports_done);
1324        self.imports.import(module, name, ty);
1325        let ret = self.global_index;
1326        self.global_index += 1;
1327        self.global_names.append(ret, name);
1328        ret
1329    }
1330
1331    fn import_func(&mut self, module: &str, name: &str, ty: u32) -> u32 {
1332        assert!(!self.imports_done);
1333        self.imports.import(module, name, EntityType::Function(ty));
1334        let ret = self.func_index;
1335        self.func_index += 1;
1336        self.function_names.append(ret, name);
1337        ret
1338    }
1339
1340    fn define_func(&mut self, name: &str, ty: u32, body: Function, export: bool) -> u32 {
1341        assert!(self.imports_done);
1342        let ret = self.func_index;
1343        self.func_index += 1;
1344        self.functions.function(ty);
1345        self.code.function(&body);
1346        self.function_names.append(ret, name);
1347        if export {
1348            self.exports.export(name, ExportKind::Func, ret);
1349        }
1350        ret
1351    }
1352
1353    fn define_ty<P, R>(&mut self, params: P, results: R) -> u32
1354    where
1355        P: IntoIterator<Item = ValType> + Clone,
1356        P::IntoIter: ExactSizeIterator,
1357        R: IntoIterator<Item = ValType> + Clone,
1358        R::IntoIter: ExactSizeIterator,
1359    {
1360        let param_vec = params.clone().into_iter().collect::<Vec<_>>();
1361        let result_vec = results.clone().into_iter().collect::<Vec<_>>();
1362        *self
1363            .wasm_type_map
1364            .entry((param_vec, result_vec))
1365            .or_insert_with(|| {
1366                let ret = self.types.len();
1367                self.types.ty().function(params, results);
1368                ret
1369            })
1370    }
1371}
1372
1373fn imported_types_used_by_exported_interfaces(resolve: &Resolve, world: WorldId) -> LiveTypes {
1374    // First build up a set of all types used by exported interfaces which
1375    // define their own types.
1376    let mut live_export_types = LiveTypes::default();
1377    let mut exported_interfaces = HashSet::new();
1378    for (_, export) in resolve.worlds[world].exports.iter() {
1379        match export {
1380            WorldItem::Function(_) => {}
1381            WorldItem::Interface { id, .. } => {
1382                exported_interfaces.insert(*id);
1383                live_export_types.add_interface(resolve, *id)
1384            }
1385            WorldItem::Type(_) => unreachable!(),
1386        }
1387    }
1388
1389    // Using the above sets a new set is built of all types that aren't
1390    // reexported. All types used by exports, which are defined by an interface
1391    // that is NOT an export, is an imported type used by an export.
1392    let mut live_import_types = LiveTypes::default();
1393    for ty in live_export_types.iter() {
1394        if let TypeOwner::Interface(id) = resolve.types[ty].owner {
1395            if !exported_interfaces.contains(&id) {
1396                live_import_types.add_interface(resolve, id);
1397            }
1398        }
1399    }
1400
1401    live_import_types
1402}
1403
1404fn dealias(resolve: &Resolve, mut id: TypeId) -> TypeId {
1405    loop {
1406        match resolve.types[id].kind {
1407            TypeDefKind::Type(Type::Id(other)) => id = other,
1408            _ => break id,
1409        }
1410    }
1411}