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