wasmtime_environ/
fact.rs

1//! Wasmtime's Fused Adapter Compiler of Trampolines (FACT)
2//!
3//! This module contains a compiler which emits trampolines to implement fused
4//! adapters for the component model. A fused adapter is when a core wasm
5//! function is lifted from one component instance and then lowered into another
6//! component instance. This communication between components is well-defined by
7//! the spec and ends up creating what's called a "fused adapter".
8//!
9//! Adapters are currently implemented with WebAssembly modules. This submodule
10//! will generate a core wasm binary which contains the adapters specified
11//! during compilation. The actual wasm is then later processed by standard
12//! paths in Wasmtime to create native machine code and runtime representations
13//! of modules.
14//!
15//! Note that identification of precisely what goes into an adapter module is
16//! not handled in this file, instead that's all done in `translate/adapt.rs`.
17//! Otherwise this module is only responsible for taking a set of adapters and
18//! their imports and then generating a core wasm module to implement all of
19//! that.
20
21use crate::component::dfg::CoreDef;
22use crate::component::{
23    Adapter, AdapterOptions as AdapterOptionsDfg, ComponentTypesBuilder, FlatType, InterfaceType,
24    RuntimeComponentInstanceIndex, StringEncoding, Transcode, TypeFuncIndex,
25};
26use crate::fact::transcode::Transcoder;
27use crate::{EntityRef, FuncIndex, GlobalIndex, MemoryIndex, PrimaryMap};
28use crate::{ModuleInternedTypeIndex, prelude::*};
29use std::collections::HashMap;
30use wasm_encoder::*;
31
32mod core_types;
33mod signature;
34mod trampoline;
35mod transcode;
36
37/// Fixed parameter types for the `prepare_call` built-in function.
38///
39/// Note that `prepare_call` also takes a variable number of parameters in
40/// addition to these, determined by the signature of the function for which
41/// we're generating an adapter.
42pub static PREPARE_CALL_FIXED_PARAMS: &[ValType] = &[
43    ValType::FUNCREF, // start
44    ValType::FUNCREF, // return
45    ValType::I32,     // caller_instance
46    ValType::I32,     // callee_instance
47    ValType::I32,     // task_return_type
48    ValType::I32,     // callee_async
49    ValType::I32,     // string_encoding
50    ValType::I32,     // result_count_or_max_if_async
51];
52
53/// Representation of an adapter module.
54pub struct Module<'a> {
55    /// Whether or not debug code is inserted into the adapters themselves.
56    debug: bool,
57    /// Type information from the creator of this `Module`
58    types: &'a ComponentTypesBuilder,
59
60    /// Core wasm type section that's incrementally built
61    core_types: core_types::CoreTypes,
62
63    /// Core wasm import section which is built as adapters are inserted. Note
64    /// that imports here are intern'd to avoid duplicate imports of the same
65    /// item.
66    core_imports: ImportSection,
67    /// Final list of imports that this module ended up using, in the same order
68    /// as the imports in the import section.
69    imports: Vec<Import>,
70    /// Intern'd imports and what index they were assigned. Note that this map
71    /// covers all the index spaces for imports, not just one.
72    imported: HashMap<CoreDef, usize>,
73    /// Intern'd transcoders and what index they were assigned.
74    imported_transcoders: HashMap<Transcoder, FuncIndex>,
75
76    /// Cached versions of imported trampolines for working with resources.
77    imported_resource_transfer_own: Option<FuncIndex>,
78    imported_resource_transfer_borrow: Option<FuncIndex>,
79    imported_resource_enter_call: Option<FuncIndex>,
80    imported_resource_exit_call: Option<FuncIndex>,
81
82    // Cached versions of imported trampolines for working with the async ABI.
83    imported_async_start_calls: HashMap<(Option<FuncIndex>, Option<FuncIndex>), FuncIndex>,
84
85    // Cached versions of imported trampolines for working with `stream`s,
86    // `future`s, and `error-context`s.
87    imported_future_transfer: Option<FuncIndex>,
88    imported_stream_transfer: Option<FuncIndex>,
89    imported_error_context_transfer: Option<FuncIndex>,
90
91    imported_check_blocking: Option<FuncIndex>,
92
93    imported_trap: Option<FuncIndex>,
94
95    // Current status of index spaces from the imports generated so far.
96    imported_funcs: PrimaryMap<FuncIndex, Option<CoreDef>>,
97    imported_memories: PrimaryMap<MemoryIndex, CoreDef>,
98    imported_globals: PrimaryMap<GlobalIndex, CoreDef>,
99
100    funcs: PrimaryMap<FunctionId, Function>,
101    helper_funcs: HashMap<Helper, FunctionId>,
102    helper_worklist: Vec<(FunctionId, Helper)>,
103
104    exports: Vec<(u32, String)>,
105}
106
107struct AdapterData {
108    /// Export name of this adapter
109    name: String,
110    /// Options specified during the `canon lift` operation
111    lift: AdapterOptions,
112    /// Options specified during the `canon lower` operation
113    lower: AdapterOptions,
114    /// The core wasm function that this adapter will be calling (the original
115    /// function that was `canon lift`'d)
116    callee: FuncIndex,
117    /// FIXME(#4185) should be plumbed and handled as part of the new reentrance
118    /// rules not yet implemented here.
119    called_as_export: bool,
120}
121
122/// Configuration options which apply at the "global adapter" level.
123///
124/// These options are typically unique per-adapter and generally aren't needed
125/// when translating recursive types within an adapter.
126struct AdapterOptions {
127    instance: RuntimeComponentInstanceIndex,
128    /// The ascribed type of this adapter.
129    ty: TypeFuncIndex,
130    /// The global that represents the instance flags for where this adapter
131    /// came from.
132    flags: GlobalIndex,
133    /// The configured post-return function, if any.
134    post_return: Option<FuncIndex>,
135    /// Other, more general, options configured.
136    options: Options,
137}
138
139#[derive(PartialEq, Eq, Hash, Copy, Clone)]
140/// Linear memory.
141struct LinearMemoryOptions {
142    /// Whether or not the `memory` field, if present, is a 64-bit memory.
143    memory64: bool,
144    /// An optionally-specified memory where values may travel through for
145    /// types like lists.
146    memory: Option<MemoryIndex>,
147    /// An optionally-specified function to be used to allocate space for
148    /// types such as strings as they go into a module.
149    realloc: Option<FuncIndex>,
150}
151
152impl LinearMemoryOptions {
153    fn ptr(&self) -> ValType {
154        if self.memory64 {
155            ValType::I64
156        } else {
157            ValType::I32
158        }
159    }
160
161    fn ptr_size(&self) -> u8 {
162        if self.memory64 { 8 } else { 4 }
163    }
164}
165
166/// The data model for objects passed through an adapter.
167#[derive(PartialEq, Eq, Hash, Copy, Clone)]
168enum DataModel {
169    Gc {},
170    LinearMemory(LinearMemoryOptions),
171}
172
173impl DataModel {
174    #[track_caller]
175    fn unwrap_memory(&self) -> &LinearMemoryOptions {
176        match self {
177            DataModel::Gc {} => panic!("`unwrap_memory` on GC"),
178            DataModel::LinearMemory(opts) => opts,
179        }
180    }
181}
182
183/// This type is split out of `AdapterOptions` and is specifically used to
184/// deduplicate translation functions within a module. Consequently this has
185/// as few fields as possible to minimize the number of functions generated
186/// within an adapter module.
187#[derive(PartialEq, Eq, Hash, Copy, Clone)]
188struct Options {
189    /// The encoding that strings use from this adapter.
190    string_encoding: StringEncoding,
191    callback: Option<FuncIndex>,
192    async_: bool,
193    core_type: ModuleInternedTypeIndex,
194    data_model: DataModel,
195}
196
197/// Representation of a "helper function" which may be generated as part of
198/// generating an adapter trampoline.
199///
200/// Helper functions are created when inlining the translation for a type in its
201/// entirety would make a function excessively large. This is currently done via
202/// a simple fuel/cost heuristic based on the type being translated but may get
203/// fancier over time.
204#[derive(Copy, Clone, PartialEq, Eq, Hash)]
205struct Helper {
206    /// Metadata about the source type of what's being translated.
207    src: HelperType,
208    /// Metadata about the destination type which is being translated to.
209    dst: HelperType,
210}
211
212/// Information about a source or destination type in a `Helper` which is
213/// generated.
214#[derive(Copy, Clone, PartialEq, Eq, Hash)]
215struct HelperType {
216    /// The concrete type being translated.
217    ty: InterfaceType,
218    /// The configuration options (memory, etc) for the adapter.
219    opts: Options,
220    /// Where the type is located (either the stack or in memory)
221    loc: HelperLocation,
222}
223
224/// Where a `HelperType` is located, dictating the signature of the helper
225/// function.
226#[derive(Copy, Clone, PartialEq, Eq, Hash)]
227enum HelperLocation {
228    /// Located on the stack in wasm locals.
229    Stack,
230    /// Located in linear memory as configured by `opts`.
231    Memory,
232    /// Located in a GC struct field.
233    #[expect(dead_code, reason = "CM+GC is still WIP")]
234    StructField,
235    /// Located in a GC array element.
236    #[expect(dead_code, reason = "CM+GC is still WIP")]
237    ArrayElement,
238}
239
240impl<'a> Module<'a> {
241    /// Creates an empty module.
242    pub fn new(types: &'a ComponentTypesBuilder, debug: bool) -> Module<'a> {
243        Module {
244            debug,
245            types,
246            core_types: Default::default(),
247            core_imports: Default::default(),
248            imported: Default::default(),
249            imports: Default::default(),
250            imported_transcoders: Default::default(),
251            imported_funcs: PrimaryMap::new(),
252            imported_memories: PrimaryMap::new(),
253            imported_globals: PrimaryMap::new(),
254            funcs: PrimaryMap::new(),
255            helper_funcs: HashMap::new(),
256            helper_worklist: Vec::new(),
257            imported_resource_transfer_own: None,
258            imported_resource_transfer_borrow: None,
259            imported_resource_enter_call: None,
260            imported_resource_exit_call: None,
261            imported_async_start_calls: HashMap::new(),
262            imported_future_transfer: None,
263            imported_stream_transfer: None,
264            imported_error_context_transfer: None,
265            imported_check_blocking: None,
266            imported_trap: None,
267            exports: Vec::new(),
268        }
269    }
270
271    /// Registers a new adapter within this adapter module.
272    ///
273    /// The `name` provided is the export name of the adapter from the final
274    /// module, and `adapter` contains all metadata necessary for compilation.
275    pub fn adapt(&mut self, name: &str, adapter: &Adapter) {
276        // Import any items required by the various canonical options
277        // (memories, reallocs, etc)
278        let mut lift = self.import_options(adapter.lift_ty, &adapter.lift_options);
279        let lower = self.import_options(adapter.lower_ty, &adapter.lower_options);
280
281        // Lowering options are not allowed to specify post-return as per the
282        // current canonical abi specification.
283        assert!(adapter.lower_options.post_return.is_none());
284
285        // Import the core wasm function which was lifted using its appropriate
286        // signature since the exported function this adapter generates will
287        // call the lifted function.
288        let signature = self.types.signature(&lift);
289        let ty = self
290            .core_types
291            .function(&signature.params, &signature.results);
292        let callee = self.import_func("callee", name, ty, adapter.func.clone());
293
294        // Handle post-return specifically here where we have `core_ty` and the
295        // results of `core_ty` are the parameters to the post-return function.
296        lift.post_return = adapter.lift_options.post_return.as_ref().map(|func| {
297            let ty = self.core_types.function(&signature.results, &[]);
298            self.import_func("post_return", name, ty, func.clone())
299        });
300
301        // This will internally create the adapter as specified and append
302        // anything necessary to `self.funcs`.
303        trampoline::compile(
304            self,
305            &AdapterData {
306                name: name.to_string(),
307                lift,
308                lower,
309                callee,
310                // FIXME(#4185) should be plumbed and handled as part of the new
311                // reentrance rules not yet implemented here.
312                called_as_export: true,
313            },
314        );
315
316        while let Some((result, helper)) = self.helper_worklist.pop() {
317            trampoline::compile_helper(self, result, helper);
318        }
319    }
320
321    fn import_options(&mut self, ty: TypeFuncIndex, options: &AdapterOptionsDfg) -> AdapterOptions {
322        let AdapterOptionsDfg {
323            instance,
324            string_encoding,
325            post_return: _, // handled above
326            callback,
327            async_,
328            core_type,
329            data_model,
330            cancellable,
331        } = options;
332        assert!(!cancellable);
333
334        let flags = self.import_global(
335            "flags",
336            &format!("instance{}", instance.as_u32()),
337            GlobalType {
338                val_type: ValType::I32,
339                mutable: true,
340                shared: false,
341            },
342            CoreDef::InstanceFlags(*instance),
343        );
344
345        let data_model = match data_model {
346            crate::component::DataModel::Gc {} => DataModel::Gc {},
347            crate::component::DataModel::LinearMemory {
348                memory,
349                memory64,
350                realloc,
351            } => {
352                let memory = memory.as_ref().map(|memory| {
353                    self.import_memory(
354                        "memory",
355                        &format!("m{}", self.imported_memories.len()),
356                        MemoryType {
357                            minimum: 0,
358                            maximum: None,
359                            shared: false,
360                            memory64: *memory64,
361                            page_size_log2: None,
362                        },
363                        memory.clone().into(),
364                    )
365                });
366                let realloc = realloc.as_ref().map(|func| {
367                    let ptr = if *memory64 {
368                        ValType::I64
369                    } else {
370                        ValType::I32
371                    };
372                    let ty = self.core_types.function(&[ptr, ptr, ptr, ptr], &[ptr]);
373                    self.import_func(
374                        "realloc",
375                        &format!("f{}", self.imported_funcs.len()),
376                        ty,
377                        func.clone(),
378                    )
379                });
380                DataModel::LinearMemory(LinearMemoryOptions {
381                    memory64: *memory64,
382                    memory,
383                    realloc,
384                })
385            }
386        };
387
388        let callback = callback.as_ref().map(|func| {
389            let ty = self
390                .core_types
391                .function(&[ValType::I32, ValType::I32, ValType::I32], &[ValType::I32]);
392            self.import_func(
393                "callback",
394                &format!("f{}", self.imported_funcs.len()),
395                ty,
396                func.clone(),
397            )
398        });
399
400        AdapterOptions {
401            instance: *instance,
402            ty,
403            flags,
404            post_return: None,
405            options: Options {
406                string_encoding: *string_encoding,
407                callback,
408                async_: *async_,
409                core_type: *core_type,
410                data_model,
411            },
412        }
413    }
414
415    fn import_func(&mut self, module: &str, name: &str, ty: u32, def: CoreDef) -> FuncIndex {
416        self.import(module, name, EntityType::Function(ty), def, |m| {
417            &mut m.imported_funcs
418        })
419    }
420
421    fn import_global(
422        &mut self,
423        module: &str,
424        name: &str,
425        ty: GlobalType,
426        def: CoreDef,
427    ) -> GlobalIndex {
428        self.import(module, name, EntityType::Global(ty), def, |m| {
429            &mut m.imported_globals
430        })
431    }
432
433    fn import_memory(
434        &mut self,
435        module: &str,
436        name: &str,
437        ty: MemoryType,
438        def: CoreDef,
439    ) -> MemoryIndex {
440        self.import(module, name, EntityType::Memory(ty), def, |m| {
441            &mut m.imported_memories
442        })
443    }
444
445    fn import<K: EntityRef, V: From<CoreDef>>(
446        &mut self,
447        module: &str,
448        name: &str,
449        ty: EntityType,
450        def: CoreDef,
451        map: impl FnOnce(&mut Self) -> &mut PrimaryMap<K, V>,
452    ) -> K {
453        if let Some(prev) = self.imported.get(&def) {
454            return K::new(*prev);
455        }
456        let idx = map(self).push(def.clone().into());
457        self.core_imports.import(module, name, ty);
458        self.imported.insert(def.clone(), idx.index());
459        self.imports.push(Import::CoreDef(def));
460        idx
461    }
462
463    fn import_transcoder(&mut self, transcoder: transcode::Transcoder) -> FuncIndex {
464        *self
465            .imported_transcoders
466            .entry(transcoder)
467            .or_insert_with(|| {
468                // Add the import to the core wasm import section...
469                let name = transcoder.name();
470                let ty = transcoder.ty(&mut self.core_types);
471                self.core_imports.import("transcode", &name, ty);
472
473                // ... and also record the metadata for what this import
474                // corresponds to.
475                let from = self.imported_memories[transcoder.from_memory].clone();
476                let to = self.imported_memories[transcoder.to_memory].clone();
477                self.imports.push(Import::Transcode {
478                    op: transcoder.op,
479                    from,
480                    from64: transcoder.from_memory64,
481                    to,
482                    to64: transcoder.to_memory64,
483                });
484
485                self.imported_funcs.push(None)
486            })
487    }
488
489    fn import_simple(
490        &mut self,
491        module: &str,
492        name: &str,
493        params: &[ValType],
494        results: &[ValType],
495        import: Import,
496        get: impl Fn(&mut Self) -> &mut Option<FuncIndex>,
497    ) -> FuncIndex {
498        self.import_simple_get_and_set(
499            module,
500            name,
501            params,
502            results,
503            import,
504            |me| *get(me),
505            |me, v| *get(me) = Some(v),
506        )
507    }
508
509    fn import_simple_get_and_set(
510        &mut self,
511        module: &str,
512        name: &str,
513        params: &[ValType],
514        results: &[ValType],
515        import: Import,
516        get: impl Fn(&mut Self) -> Option<FuncIndex>,
517        set: impl Fn(&mut Self, FuncIndex),
518    ) -> FuncIndex {
519        if let Some(idx) = get(self) {
520            return idx;
521        }
522        let ty = self.core_types.function(params, results);
523        let ty = EntityType::Function(ty);
524        self.core_imports.import(module, name, ty);
525
526        self.imports.push(import);
527        let idx = self.imported_funcs.push(None);
528        set(self, idx);
529        idx
530    }
531
532    /// Import a host built-in function to set up a subtask for a sync-lowered
533    /// import call to an async-lifted export.
534    ///
535    /// Given that the callee may exert backpressure before the host can copy
536    /// the parameters, the adapter must use this function to set up the subtask
537    /// and stash the parameters as part of that subtask until any backpressure
538    /// has cleared.
539    fn import_prepare_call(
540        &mut self,
541        suffix: &str,
542        params: &[ValType],
543        memory: Option<MemoryIndex>,
544    ) -> FuncIndex {
545        let ty = self.core_types.function(
546            &PREPARE_CALL_FIXED_PARAMS
547                .iter()
548                .copied()
549                .chain(params.iter().copied())
550                .collect::<Vec<_>>(),
551            &[],
552        );
553        self.core_imports.import(
554            "sync",
555            &format!("[prepare-call]{suffix}"),
556            EntityType::Function(ty),
557        );
558        let import = Import::PrepareCall {
559            memory: memory.map(|v| self.imported_memories[v].clone()),
560        };
561        self.imports.push(import);
562        self.imported_funcs.push(None)
563    }
564
565    /// Import a host built-in function to start a subtask for a sync-lowered
566    /// import call to an async-lifted export.
567    ///
568    /// This call with block until the subtask has produced result(s) via the
569    /// `task.return` intrinsic.
570    ///
571    /// Note that this could potentially be combined with the `sync-prepare`
572    /// built-in into a single built-in function that does both jobs.  However,
573    /// we've kept them separate to allow a future optimization where the caller
574    /// calls the callee directly rather than using `sync-start` to have the host
575    /// do it.
576    fn import_sync_start_call(
577        &mut self,
578        suffix: &str,
579        callback: Option<FuncIndex>,
580        results: &[ValType],
581    ) -> FuncIndex {
582        let ty = self
583            .core_types
584            .function(&[ValType::FUNCREF, ValType::I32], results);
585        self.core_imports.import(
586            "sync",
587            &format!("[start-call]{suffix}"),
588            EntityType::Function(ty),
589        );
590        let import = Import::SyncStartCall {
591            callback: callback
592                .map(|callback| self.imported_funcs.get(callback).unwrap().clone().unwrap()),
593        };
594        self.imports.push(import);
595        self.imported_funcs.push(None)
596    }
597
598    /// Import a host built-in function to start a subtask for an async-lowered
599    /// import call to an async- or sync-lifted export.
600    ///
601    /// Note that this could potentially be combined with the `async-prepare`
602    /// built-in into a single built-in function that does both jobs.  However,
603    /// we've kept them separate to allow a future optimization where the caller
604    /// calls the callee directly rather than using `async-start` to have the
605    /// host do it.
606    fn import_async_start_call(
607        &mut self,
608        suffix: &str,
609        callback: Option<FuncIndex>,
610        post_return: Option<FuncIndex>,
611    ) -> FuncIndex {
612        self.import_simple_get_and_set(
613            "async",
614            &format!("[start-call]{suffix}"),
615            &[ValType::FUNCREF, ValType::I32, ValType::I32, ValType::I32],
616            &[ValType::I32],
617            Import::AsyncStartCall {
618                callback: callback
619                    .map(|callback| self.imported_funcs.get(callback).unwrap().clone().unwrap()),
620                post_return: post_return.map(|post_return| {
621                    self.imported_funcs
622                        .get(post_return)
623                        .unwrap()
624                        .clone()
625                        .unwrap()
626                }),
627            },
628            |me| {
629                me.imported_async_start_calls
630                    .get(&(callback, post_return))
631                    .copied()
632            },
633            |me, v| {
634                assert!(
635                    me.imported_async_start_calls
636                        .insert((callback, post_return), v)
637                        .is_none()
638                )
639            },
640        )
641    }
642
643    fn import_future_transfer(&mut self) -> FuncIndex {
644        self.import_simple(
645            "future",
646            "transfer",
647            &[ValType::I32; 3],
648            &[ValType::I32],
649            Import::FutureTransfer,
650            |me| &mut me.imported_future_transfer,
651        )
652    }
653
654    fn import_stream_transfer(&mut self) -> FuncIndex {
655        self.import_simple(
656            "stream",
657            "transfer",
658            &[ValType::I32; 3],
659            &[ValType::I32],
660            Import::StreamTransfer,
661            |me| &mut me.imported_stream_transfer,
662        )
663    }
664
665    fn import_error_context_transfer(&mut self) -> FuncIndex {
666        self.import_simple(
667            "error-context",
668            "transfer",
669            &[ValType::I32; 3],
670            &[ValType::I32],
671            Import::ErrorContextTransfer,
672            |me| &mut me.imported_error_context_transfer,
673        )
674    }
675
676    fn import_resource_transfer_own(&mut self) -> FuncIndex {
677        self.import_simple(
678            "resource",
679            "transfer-own",
680            &[ValType::I32, ValType::I32, ValType::I32],
681            &[ValType::I32],
682            Import::ResourceTransferOwn,
683            |me| &mut me.imported_resource_transfer_own,
684        )
685    }
686
687    fn import_resource_transfer_borrow(&mut self) -> FuncIndex {
688        self.import_simple(
689            "resource",
690            "transfer-borrow",
691            &[ValType::I32, ValType::I32, ValType::I32],
692            &[ValType::I32],
693            Import::ResourceTransferBorrow,
694            |me| &mut me.imported_resource_transfer_borrow,
695        )
696    }
697
698    fn import_resource_enter_call(&mut self) -> FuncIndex {
699        self.import_simple(
700            "resource",
701            "enter-call",
702            &[],
703            &[],
704            Import::ResourceEnterCall,
705            |me| &mut me.imported_resource_enter_call,
706        )
707    }
708
709    fn import_resource_exit_call(&mut self) -> FuncIndex {
710        self.import_simple(
711            "resource",
712            "exit-call",
713            &[],
714            &[],
715            Import::ResourceExitCall,
716            |me| &mut me.imported_resource_exit_call,
717        )
718    }
719
720    fn import_check_blocking(&mut self) -> FuncIndex {
721        self.import_simple(
722            "async",
723            "check-blocking",
724            &[],
725            &[],
726            Import::CheckBlocking,
727            |me| &mut me.imported_check_blocking,
728        )
729    }
730
731    fn import_trap(&mut self) -> FuncIndex {
732        self.import_simple(
733            "runtime",
734            "trap",
735            &[ValType::I32],
736            &[],
737            Import::Trap,
738            |me| &mut me.imported_trap,
739        )
740    }
741
742    fn translate_helper(&mut self, helper: Helper) -> FunctionId {
743        *self.helper_funcs.entry(helper).or_insert_with(|| {
744            // Generate a fresh `Function` with a unique id for what we're about to
745            // generate.
746            let ty = helper.core_type(self.types, &mut self.core_types);
747            let id = self.funcs.push(Function::new(None, ty));
748            self.helper_worklist.push((id, helper));
749            id
750        })
751    }
752
753    /// Encodes this module into a WebAssembly binary.
754    pub fn encode(&mut self) -> Vec<u8> {
755        // Build the function/export sections of the wasm module in a first pass
756        // which will assign a final `FuncIndex` to all functions defined in
757        // `self.funcs`.
758        let mut funcs = FunctionSection::new();
759        let mut exports = ExportSection::new();
760        let mut id_to_index = PrimaryMap::<FunctionId, FuncIndex>::new();
761        for (id, func) in self.funcs.iter() {
762            assert!(func.filled_in);
763            let idx = FuncIndex::from_u32(self.imported_funcs.next_key().as_u32() + id.as_u32());
764            let id2 = id_to_index.push(idx);
765            assert_eq!(id2, id);
766
767            funcs.function(func.ty);
768
769            if let Some(name) = &func.export {
770                exports.export(name, ExportKind::Func, idx.as_u32());
771            }
772        }
773        for (idx, name) in &self.exports {
774            exports.export(name, ExportKind::Func, *idx);
775        }
776
777        // With all functions numbered the fragments of the body of each
778        // function can be assigned into one final adapter function.
779        let mut code = CodeSection::new();
780        for (_, func) in self.funcs.iter() {
781            let mut body = Vec::new();
782
783            // Encode all locals used for this function
784            func.locals.len().encode(&mut body);
785            for (count, ty) in func.locals.iter() {
786                count.encode(&mut body);
787                ty.encode(&mut body);
788            }
789
790            // Then encode each "chunk" of a body which may have optional traps
791            // specified within it. Traps get offset by the current length of
792            // the body and otherwise our `Call` instructions are "relocated"
793            // here to the final function index.
794            for chunk in func.body.iter() {
795                match chunk {
796                    Body::Raw(code) => {
797                        body.extend_from_slice(code);
798                    }
799                    Body::Call(id) => {
800                        Instruction::Call(id_to_index[*id].as_u32()).encode(&mut body);
801                    }
802                    Body::RefFunc(id) => {
803                        Instruction::RefFunc(id_to_index[*id].as_u32()).encode(&mut body);
804                    }
805                }
806            }
807            code.raw(&body);
808        }
809
810        let mut result = wasm_encoder::Module::new();
811        result.section(&self.core_types.section);
812        result.section(&self.core_imports);
813        result.section(&funcs);
814        result.section(&exports);
815        result.section(&code);
816        result.finish()
817    }
818
819    /// Returns the imports that were used, in order, to create this adapter
820    /// module.
821    pub fn imports(&self) -> &[Import] {
822        &self.imports
823    }
824}
825
826/// Possible imports into an adapter module.
827#[derive(Clone)]
828pub enum Import {
829    /// A definition required in the configuration of an `Adapter`.
830    CoreDef(CoreDef),
831    /// A transcoding function from the host to convert between string encodings.
832    Transcode {
833        /// The transcoding operation this performs.
834        op: Transcode,
835        /// The memory being read
836        from: CoreDef,
837        /// Whether or not `from` is a 64-bit memory
838        from64: bool,
839        /// The memory being written
840        to: CoreDef,
841        /// Whether or not `to` is a 64-bit memory
842        to64: bool,
843    },
844    /// Transfers an owned resource from one table to another.
845    ResourceTransferOwn,
846    /// Transfers a borrowed resource from one table to another.
847    ResourceTransferBorrow,
848    /// Sets up entry metadata for a borrow resources when a call starts.
849    ResourceEnterCall,
850    /// Tears down a previous entry and handles checking borrow-related
851    /// metadata.
852    ResourceExitCall,
853    /// An intrinsic used by FACT-generated modules to begin a call involving
854    /// an async-lowered import and/or an async-lifted export.
855    PrepareCall {
856        /// The memory used to verify that the memory specified for the
857        /// `task.return` that is called at runtime (if any) matches the one
858        /// specified in the lifted export.
859        memory: Option<CoreDef>,
860    },
861    /// An intrinsic used by FACT-generated modules to complete a call involving
862    /// a sync-lowered import and async-lifted export.
863    SyncStartCall {
864        /// The callee's callback function, if any.
865        callback: Option<CoreDef>,
866    },
867    /// An intrinsic used by FACT-generated modules to complete a call involving
868    /// an async-lowered import function.
869    AsyncStartCall {
870        /// The callee's callback function, if any.
871        callback: Option<CoreDef>,
872
873        /// The callee's post-return function, if any.
874        post_return: Option<CoreDef>,
875    },
876    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
877    /// ownership of a `future`.
878    FutureTransfer,
879    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
880    /// ownership of a `stream`.
881    StreamTransfer,
882    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
883    /// ownership of an `error-context`.
884    ErrorContextTransfer,
885    /// An intrinsic used by FACT-generated modules to check whether an
886    /// async-typed function may be called via a sync lower.
887    CheckBlocking,
888    /// An intrinsic for trapping the instance with a specific trap code.
889    Trap,
890}
891
892impl Options {
893    fn flat_types<'a>(
894        &self,
895        ty: &InterfaceType,
896        types: &'a ComponentTypesBuilder,
897    ) -> Option<&'a [FlatType]> {
898        let flat = types.flat_types(ty)?;
899        match self.data_model {
900            DataModel::Gc {} => todo!("CM+GC"),
901            DataModel::LinearMemory(mem_opts) => Some(if mem_opts.memory64 {
902                flat.memory64
903            } else {
904                flat.memory32
905            }),
906        }
907    }
908}
909
910/// Temporary index which is not the same as `FuncIndex`.
911///
912/// This represents the nth generated function in the adapter module where the
913/// final index of the function is not known at the time of generation since
914/// more imports may be discovered (specifically string transcoders).
915#[derive(Debug, Copy, Clone, PartialEq, Eq)]
916struct FunctionId(u32);
917cranelift_entity::entity_impl!(FunctionId);
918
919/// A generated function to be added to an adapter module.
920///
921/// At least one function is created per-adapter and depending on the type
922/// hierarchy multiple functions may be generated per-adapter.
923struct Function {
924    /// Whether or not the `body` has been finished.
925    ///
926    /// Functions are added to a `Module` before they're defined so this is used
927    /// to assert that the function was in fact actually filled in by the
928    /// time we reach `Module::encode`.
929    filled_in: bool,
930
931    /// The type signature that this function has, as an index into the core
932    /// wasm type index space of the generated adapter module.
933    ty: u32,
934
935    /// The locals that are used by this function, organized by the number of
936    /// types of each local.
937    locals: Vec<(u32, ValType)>,
938
939    /// If specified, the export name of this function.
940    export: Option<String>,
941
942    /// The contents of the function.
943    ///
944    /// See `Body` for more information, and the `Vec` here represents the
945    /// concatenation of all the `Body` fragments.
946    body: Vec<Body>,
947}
948
949/// Representation of a fragment of the body of a core wasm function generated
950/// for adapters.
951///
952/// This variant comes in one of two flavors:
953///
954/// 1. First a `Raw` variant is used to contain general instructions for the
955///    wasm function. This is populated by `Compiler::instruction` primarily.
956///
957/// 2. A `Call` instruction variant for a `FunctionId` where the final
958///    `FuncIndex` isn't known until emission time.
959///
960/// The purpose of this representation is the `Body::Call` variant. This can't
961/// be encoded as an instruction when it's generated due to not knowing the
962/// final index of the function being called. During `Module::encode`, however,
963/// all indices are known and `Body::Call` is turned into a final
964/// `Instruction::Call`.
965///
966/// One other possible representation in the future would be to encode a `Call`
967/// instruction with a 5-byte leb to fill in later, but for now this felt
968/// easier to represent. A 5-byte leb may be more efficient at compile-time if
969/// necessary, however.
970enum Body {
971    Raw(Vec<u8>),
972    Call(FunctionId),
973    RefFunc(FunctionId),
974}
975
976impl Function {
977    fn new(export: Option<String>, ty: u32) -> Function {
978        Function {
979            filled_in: false,
980            ty,
981            locals: Vec::new(),
982            export,
983            body: Vec::new(),
984        }
985    }
986}
987
988impl Helper {
989    fn core_type(
990        &self,
991        types: &ComponentTypesBuilder,
992        core_types: &mut core_types::CoreTypes,
993    ) -> u32 {
994        let mut params = Vec::new();
995        let mut results = Vec::new();
996        // The source type being translated is always pushed onto the
997        // parameters first, either a pointer for memory or its flat
998        // representation.
999        self.src.push_flat(&mut params, types);
1000
1001        // The destination type goes into the parameter list if it's from
1002        // memory or otherwise is the result of the function itself for a
1003        // stack-based representation.
1004        match self.dst.loc {
1005            HelperLocation::Stack => self.dst.push_flat(&mut results, types),
1006            HelperLocation::Memory => params.push(self.dst.opts.data_model.unwrap_memory().ptr()),
1007            HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
1008        }
1009
1010        core_types.function(&params, &results)
1011    }
1012}
1013
1014impl HelperType {
1015    fn push_flat(&self, dst: &mut Vec<ValType>, types: &ComponentTypesBuilder) {
1016        match self.loc {
1017            HelperLocation::Stack => {
1018                for ty in self.opts.flat_types(&self.ty, types).unwrap() {
1019                    dst.push((*ty).into());
1020                }
1021            }
1022            HelperLocation::Memory => {
1023                dst.push(self.opts.data_model.unwrap_memory().ptr());
1024            }
1025            HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
1026        }
1027    }
1028}