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