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/// Bit flag for indicating async-lifted exports
40///
41/// This flag may be passed to the `async-start` built-in function (which is
42/// called from both async->async and async->sync adapters) to indicate that the
43/// callee is an async-lifted export.
44pub const START_FLAG_ASYNC_CALLEE: i32 = 1 << 0;
45
46/// Fixed parameter types for the `prepare_call` built-in function.
47///
48/// Note that `prepare_call` also takes a variable number of parameters in
49/// addition to these, determined by the signature of the function for which
50/// we're generating an adapter.
51pub static PREPARE_CALL_FIXED_PARAMS: &[ValType] = &[
52    ValType::FUNCREF, // start
53    ValType::FUNCREF, // return
54    ValType::I32,     // caller_instance
55    ValType::I32,     // callee_instance
56    ValType::I32,     // task_return_type
57    ValType::I32,     // string_encoding
58    ValType::I32,     // result_count_or_max_if_async
59];
60
61/// Representation of an adapter module.
62pub struct Module<'a> {
63    /// Whether or not debug code is inserted into the adapters themselves.
64    debug: bool,
65    /// Type information from the creator of this `Module`
66    types: &'a ComponentTypesBuilder,
67
68    /// Core wasm type section that's incrementally built
69    core_types: core_types::CoreTypes,
70
71    /// Core wasm import section which is built as adapters are inserted. Note
72    /// that imports here are intern'd to avoid duplicate imports of the same
73    /// item.
74    core_imports: ImportSection,
75    /// Final list of imports that this module ended up using, in the same order
76    /// as the imports in the import section.
77    imports: Vec<Import>,
78    /// Intern'd imports and what index they were assigned. Note that this map
79    /// covers all the index spaces for imports, not just one.
80    imported: HashMap<CoreDef, usize>,
81    /// Intern'd transcoders and what index they were assigned.
82    imported_transcoders: HashMap<Transcoder, FuncIndex>,
83
84    /// Cached versions of imported trampolines for working with resources.
85    imported_resource_transfer_own: Option<FuncIndex>,
86    imported_resource_transfer_borrow: Option<FuncIndex>,
87    imported_resource_enter_call: Option<FuncIndex>,
88    imported_resource_exit_call: Option<FuncIndex>,
89
90    // Cached versions of imported trampolines for working with the async ABI.
91    imported_async_start_calls: HashMap<(Option<FuncIndex>, Option<FuncIndex>), FuncIndex>,
92
93    // Cached versions of imported trampolines for working with `stream`s,
94    // `future`s, and `error-context`s.
95    imported_future_transfer: Option<FuncIndex>,
96    imported_stream_transfer: Option<FuncIndex>,
97    imported_error_context_transfer: Option<FuncIndex>,
98
99    // Current status of index spaces from the imports generated so far.
100    imported_funcs: PrimaryMap<FuncIndex, Option<CoreDef>>,
101    imported_memories: PrimaryMap<MemoryIndex, CoreDef>,
102    imported_globals: PrimaryMap<GlobalIndex, CoreDef>,
103
104    funcs: PrimaryMap<FunctionId, Function>,
105    helper_funcs: HashMap<Helper, FunctionId>,
106    helper_worklist: Vec<(FunctionId, Helper)>,
107
108    exports: Vec<(u32, String)>,
109}
110
111struct AdapterData {
112    /// Export name of this adapter
113    name: String,
114    /// Options specified during the `canon lift` operation
115    lift: AdapterOptions,
116    /// Options specified during the `canon lower` operation
117    lower: AdapterOptions,
118    /// The core wasm function that this adapter will be calling (the original
119    /// function that was `canon lift`'d)
120    callee: FuncIndex,
121    /// FIXME(#4185) should be plumbed and handled as part of the new reentrance
122    /// rules not yet implemented here.
123    called_as_export: bool,
124}
125
126/// Configuration options which apply at the "global adapter" level.
127///
128/// These options are typically unique per-adapter and generally aren't needed
129/// when translating recursive types within an adapter.
130struct AdapterOptions {
131    instance: RuntimeComponentInstanceIndex,
132    /// The ascribed type of this adapter.
133    ty: TypeFuncIndex,
134    /// The global that represents the instance flags for where this adapter
135    /// came from.
136    flags: GlobalIndex,
137    /// The configured post-return function, if any.
138    post_return: Option<FuncIndex>,
139    /// Other, more general, options configured.
140    options: Options,
141}
142
143#[derive(PartialEq, Eq, Hash, Copy, Clone)]
144/// Linear memory.
145struct LinearMemoryOptions {
146    /// Whether or not the `memory` field, if present, is a 64-bit memory.
147    memory64: bool,
148    /// An optionally-specified memory where values may travel through for
149    /// types like lists.
150    memory: Option<MemoryIndex>,
151    /// An optionally-specified function to be used to allocate space for
152    /// types such as strings as they go into a module.
153    realloc: Option<FuncIndex>,
154}
155
156impl LinearMemoryOptions {
157    fn ptr(&self) -> ValType {
158        if self.memory64 {
159            ValType::I64
160        } else {
161            ValType::I32
162        }
163    }
164
165    fn ptr_size(&self) -> u8 {
166        if self.memory64 { 8 } else { 4 }
167    }
168}
169
170/// The data model for objects passed through an adapter.
171#[derive(PartialEq, Eq, Hash, Copy, Clone)]
172enum DataModel {
173    Gc {},
174    LinearMemory(LinearMemoryOptions),
175}
176
177impl DataModel {
178    #[track_caller]
179    fn unwrap_memory(&self) -> &LinearMemoryOptions {
180        match self {
181            DataModel::Gc {} => panic!("`unwrap_memory` on GC"),
182            DataModel::LinearMemory(opts) => opts,
183        }
184    }
185}
186
187/// This type is split out of `AdapterOptions` and is specifically used to
188/// deduplicate translation functions within a module. Consequently this has
189/// as few fields as possible to minimize the number of functions generated
190/// within an adapter module.
191#[derive(PartialEq, Eq, Hash, Copy, Clone)]
192struct Options {
193    /// The encoding that strings use from this adapter.
194    string_encoding: StringEncoding,
195    callback: Option<FuncIndex>,
196    async_: bool,
197    core_type: ModuleInternedTypeIndex,
198    data_model: DataModel,
199}
200
201/// Representation of a "helper function" which may be generated as part of
202/// generating an adapter trampoline.
203///
204/// Helper functions are created when inlining the translation for a type in its
205/// entirety would make a function excessively large. This is currently done via
206/// a simple fuel/cost heuristic based on the type being translated but may get
207/// fancier over time.
208#[derive(Copy, Clone, PartialEq, Eq, Hash)]
209struct Helper {
210    /// Metadata about the source type of what's being translated.
211    src: HelperType,
212    /// Metadata about the destination type which is being translated to.
213    dst: HelperType,
214}
215
216/// Information about a source or destination type in a `Helper` which is
217/// generated.
218#[derive(Copy, Clone, PartialEq, Eq, Hash)]
219struct HelperType {
220    /// The concrete type being translated.
221    ty: InterfaceType,
222    /// The configuration options (memory, etc) for the adapter.
223    opts: Options,
224    /// Where the type is located (either the stack or in memory)
225    loc: HelperLocation,
226}
227
228/// Where a `HelperType` is located, dictating the signature of the helper
229/// function.
230#[derive(Copy, Clone, PartialEq, Eq, Hash)]
231enum HelperLocation {
232    /// Located on the stack in wasm locals.
233    Stack,
234    /// Located in linear memory as configured by `opts`.
235    Memory,
236    /// Located in a GC struct field.
237    #[expect(dead_code, reason = "CM+GC is still WIP")]
238    StructField,
239    /// Located in a GC array element.
240    #[expect(dead_code, reason = "CM+GC is still WIP")]
241    ArrayElement,
242}
243
244impl<'a> Module<'a> {
245    /// Creates an empty module.
246    pub fn new(types: &'a ComponentTypesBuilder, debug: bool) -> Module<'a> {
247        Module {
248            debug,
249            types,
250            core_types: Default::default(),
251            core_imports: Default::default(),
252            imported: Default::default(),
253            imports: Default::default(),
254            imported_transcoders: Default::default(),
255            imported_funcs: PrimaryMap::new(),
256            imported_memories: PrimaryMap::new(),
257            imported_globals: PrimaryMap::new(),
258            funcs: PrimaryMap::new(),
259            helper_funcs: HashMap::new(),
260            helper_worklist: Vec::new(),
261            imported_resource_transfer_own: None,
262            imported_resource_transfer_borrow: None,
263            imported_resource_enter_call: None,
264            imported_resource_exit_call: None,
265            imported_async_start_calls: HashMap::new(),
266            imported_future_transfer: None,
267            imported_stream_transfer: None,
268            imported_error_context_transfer: None,
269            exports: Vec::new(),
270        }
271    }
272
273    /// Registers a new adapter within this adapter module.
274    ///
275    /// The `name` provided is the export name of the adapter from the final
276    /// module, and `adapter` contains all metadata necessary for compilation.
277    pub fn adapt(&mut self, name: &str, adapter: &Adapter) {
278        // Import any items required by the various canonical options
279        // (memories, reallocs, etc)
280        let mut lift = self.import_options(adapter.lift_ty, &adapter.lift_options);
281        let lower = self.import_options(adapter.lower_ty, &adapter.lower_options);
282
283        // Lowering options are not allowed to specify post-return as per the
284        // current canonical abi specification.
285        assert!(adapter.lower_options.post_return.is_none());
286
287        // Import the core wasm function which was lifted using its appropriate
288        // signature since the exported function this adapter generates will
289        // call the lifted function.
290        let signature = self.types.signature(&lift);
291        let ty = self
292            .core_types
293            .function(&signature.params, &signature.results);
294        let callee = self.import_func("callee", name, ty, adapter.func.clone());
295
296        // Handle post-return specifically here where we have `core_ty` and the
297        // results of `core_ty` are the parameters to the post-return function.
298        lift.post_return = adapter.lift_options.post_return.as_ref().map(|func| {
299            let ty = self.core_types.function(&signature.results, &[]);
300            self.import_func("post_return", name, ty, func.clone())
301        });
302
303        // This will internally create the adapter as specified and append
304        // anything necessary to `self.funcs`.
305        trampoline::compile(
306            self,
307            &AdapterData {
308                name: name.to_string(),
309                lift,
310                lower,
311                callee,
312                // FIXME(#4185) should be plumbed and handled as part of the new
313                // reentrance rules not yet implemented here.
314                called_as_export: true,
315            },
316        );
317
318        while let Some((result, helper)) = self.helper_worklist.pop() {
319            trampoline::compile_helper(self, result, helper);
320        }
321    }
322
323    fn import_options(&mut self, ty: TypeFuncIndex, options: &AdapterOptionsDfg) -> AdapterOptions {
324        let AdapterOptionsDfg {
325            instance,
326            string_encoding,
327            post_return: _, // handled above
328            callback,
329            async_,
330            core_type,
331            data_model,
332        } = options;
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 translate_helper(&mut self, helper: Helper) -> FunctionId {
721        *self.helper_funcs.entry(helper).or_insert_with(|| {
722            // Generate a fresh `Function` with a unique id for what we're about to
723            // generate.
724            let ty = helper.core_type(self.types, &mut self.core_types);
725            let id = self.funcs.push(Function::new(None, ty));
726            self.helper_worklist.push((id, helper));
727            id
728        })
729    }
730
731    /// Encodes this module into a WebAssembly binary.
732    pub fn encode(&mut self) -> Vec<u8> {
733        // Build the function/export sections of the wasm module in a first pass
734        // which will assign a final `FuncIndex` to all functions defined in
735        // `self.funcs`.
736        let mut funcs = FunctionSection::new();
737        let mut exports = ExportSection::new();
738        let mut id_to_index = PrimaryMap::<FunctionId, FuncIndex>::new();
739        for (id, func) in self.funcs.iter() {
740            assert!(func.filled_in);
741            let idx = FuncIndex::from_u32(self.imported_funcs.next_key().as_u32() + id.as_u32());
742            let id2 = id_to_index.push(idx);
743            assert_eq!(id2, id);
744
745            funcs.function(func.ty);
746
747            if let Some(name) = &func.export {
748                exports.export(name, ExportKind::Func, idx.as_u32());
749            }
750        }
751        for (idx, name) in &self.exports {
752            exports.export(name, ExportKind::Func, *idx);
753        }
754
755        // With all functions numbered the fragments of the body of each
756        // function can be assigned into one final adapter function.
757        let mut code = CodeSection::new();
758        let mut traps = traps::TrapSection::default();
759        for (id, func) in self.funcs.iter() {
760            let mut func_traps = Vec::new();
761            let mut body = Vec::new();
762
763            // Encode all locals used for this function
764            func.locals.len().encode(&mut body);
765            for (count, ty) in func.locals.iter() {
766                count.encode(&mut body);
767                ty.encode(&mut body);
768            }
769
770            // Then encode each "chunk" of a body which may have optional traps
771            // specified within it. Traps get offset by the current length of
772            // the body and otherwise our `Call` instructions are "relocated"
773            // here to the final function index.
774            for chunk in func.body.iter() {
775                match chunk {
776                    Body::Raw(code, traps) => {
777                        let start = body.len();
778                        body.extend_from_slice(code);
779                        for (offset, trap) in traps {
780                            func_traps.push((start + offset, *trap));
781                        }
782                    }
783                    Body::Call(id) => {
784                        Instruction::Call(id_to_index[*id].as_u32()).encode(&mut body);
785                    }
786                    Body::RefFunc(id) => {
787                        Instruction::RefFunc(id_to_index[*id].as_u32()).encode(&mut body);
788                    }
789                }
790            }
791            code.raw(&body);
792            traps.append(id_to_index[id].as_u32(), func_traps);
793        }
794
795        let traps = traps.finish();
796
797        let mut result = wasm_encoder::Module::new();
798        result.section(&self.core_types.section);
799        result.section(&self.core_imports);
800        result.section(&funcs);
801        result.section(&exports);
802        result.section(&code);
803        if self.debug {
804            result.section(&CustomSection {
805                name: "wasmtime-trampoline-traps".into(),
806                data: Cow::Borrowed(&traps),
807            });
808        }
809        result.finish()
810    }
811
812    /// Returns the imports that were used, in order, to create this adapter
813    /// module.
814    pub fn imports(&self) -> &[Import] {
815        &self.imports
816    }
817}
818
819/// Possible imports into an adapter module.
820#[derive(Clone)]
821pub enum Import {
822    /// A definition required in the configuration of an `Adapter`.
823    CoreDef(CoreDef),
824    /// A transcoding function from the host to convert between string encodings.
825    Transcode {
826        /// The transcoding operation this performs.
827        op: Transcode,
828        /// The memory being read
829        from: CoreDef,
830        /// Whether or not `from` is a 64-bit memory
831        from64: bool,
832        /// The memory being written
833        to: CoreDef,
834        /// Whether or not `to` is a 64-bit memory
835        to64: bool,
836    },
837    /// Transfers an owned resource from one table to another.
838    ResourceTransferOwn,
839    /// Transfers a borrowed resource from one table to another.
840    ResourceTransferBorrow,
841    /// Sets up entry metadata for a borrow resources when a call starts.
842    ResourceEnterCall,
843    /// Tears down a previous entry and handles checking borrow-related
844    /// metadata.
845    ResourceExitCall,
846    /// An intrinsic used by FACT-generated modules to begin a call involving
847    /// an async-lowered import and/or an async-lifted export.
848    PrepareCall {
849        /// The memory used to verify that the memory specified for the
850        /// `task.return` that is called at runtime (if any) matches the one
851        /// specified in the lifted export.
852        memory: Option<CoreDef>,
853    },
854    /// An intrinsic used by FACT-generated modules to complete a call involving
855    /// a sync-lowered import and async-lifted export.
856    SyncStartCall {
857        /// The callee's callback function, if any.
858        callback: Option<CoreDef>,
859    },
860    /// An intrinsic used by FACT-generated modules to complete a call involving
861    /// an async-lowered import function.
862    AsyncStartCall {
863        /// The callee's callback function, if any.
864        callback: Option<CoreDef>,
865
866        /// The callee's post-return function, if any.
867        post_return: Option<CoreDef>,
868    },
869    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
870    /// ownership of a `future`.
871    FutureTransfer,
872    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
873    /// ownership of a `stream`.
874    StreamTransfer,
875    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
876    /// ownership of an `error-context`.
877    ErrorContextTransfer,
878}
879
880impl Options {
881    fn flat_types<'a>(
882        &self,
883        ty: &InterfaceType,
884        types: &'a ComponentTypesBuilder,
885    ) -> Option<&'a [FlatType]> {
886        let flat = types.flat_types(ty)?;
887        match self.data_model {
888            DataModel::Gc {} => todo!("CM+GC"),
889            DataModel::LinearMemory(mem_opts) => Some(if mem_opts.memory64 {
890                flat.memory64
891            } else {
892                flat.memory32
893            }),
894        }
895    }
896}
897
898/// Temporary index which is not the same as `FuncIndex`.
899///
900/// This represents the nth generated function in the adapter module where the
901/// final index of the function is not known at the time of generation since
902/// more imports may be discovered (specifically string transcoders).
903#[derive(Debug, Copy, Clone, PartialEq, Eq)]
904struct FunctionId(u32);
905cranelift_entity::entity_impl!(FunctionId);
906
907/// A generated function to be added to an adapter module.
908///
909/// At least one function is created per-adapter and depending on the type
910/// hierarchy multiple functions may be generated per-adapter.
911struct Function {
912    /// Whether or not the `body` has been finished.
913    ///
914    /// Functions are added to a `Module` before they're defined so this is used
915    /// to assert that the function was in fact actually filled in by the
916    /// time we reach `Module::encode`.
917    filled_in: bool,
918
919    /// The type signature that this function has, as an index into the core
920    /// wasm type index space of the generated adapter module.
921    ty: u32,
922
923    /// The locals that are used by this function, organized by the number of
924    /// types of each local.
925    locals: Vec<(u32, ValType)>,
926
927    /// If specified, the export name of this function.
928    export: Option<String>,
929
930    /// The contents of the function.
931    ///
932    /// See `Body` for more information, and the `Vec` here represents the
933    /// concatenation of all the `Body` fragments.
934    body: Vec<Body>,
935}
936
937/// Representation of a fragment of the body of a core wasm function generated
938/// for adapters.
939///
940/// This variant comes in one of two flavors:
941///
942/// 1. First a `Raw` variant is used to contain general instructions for the
943///    wasm function. This is populated by `Compiler::instruction` primarily.
944///    This also comes with a list of traps. and the byte offset within the
945///    first vector of where the trap information applies to.
946///
947/// 2. A `Call` instruction variant for a `FunctionId` where the final
948///    `FuncIndex` isn't known until emission time.
949///
950/// The purpose of this representation is the `Body::Call` variant. This can't
951/// be encoded as an instruction when it's generated due to not knowing the
952/// final index of the function being called. During `Module::encode`, however,
953/// all indices are known and `Body::Call` is turned into a final
954/// `Instruction::Call`.
955///
956/// One other possible representation in the future would be to encode a `Call`
957/// instruction with a 5-byte leb to fill in later, but for now this felt
958/// easier to represent. A 5-byte leb may be more efficient at compile-time if
959/// necessary, however.
960enum Body {
961    Raw(Vec<u8>, Vec<(usize, traps::Trap)>),
962    Call(FunctionId),
963    RefFunc(FunctionId),
964}
965
966impl Function {
967    fn new(export: Option<String>, ty: u32) -> Function {
968        Function {
969            filled_in: false,
970            ty,
971            locals: Vec::new(),
972            export,
973            body: Vec::new(),
974        }
975    }
976}
977
978impl Helper {
979    fn core_type(
980        &self,
981        types: &ComponentTypesBuilder,
982        core_types: &mut core_types::CoreTypes,
983    ) -> u32 {
984        let mut params = Vec::new();
985        let mut results = Vec::new();
986        // The source type being translated is always pushed onto the
987        // parameters first, either a pointer for memory or its flat
988        // representation.
989        self.src.push_flat(&mut params, types);
990
991        // The destination type goes into the parameter list if it's from
992        // memory or otherwise is the result of the function itself for a
993        // stack-based representation.
994        match self.dst.loc {
995            HelperLocation::Stack => self.dst.push_flat(&mut results, types),
996            HelperLocation::Memory => params.push(self.dst.opts.data_model.unwrap_memory().ptr()),
997            HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
998        }
999
1000        core_types.function(&params, &results)
1001    }
1002}
1003
1004impl HelperType {
1005    fn push_flat(&self, dst: &mut Vec<ValType>, types: &ComponentTypesBuilder) {
1006        match self.loc {
1007            HelperLocation::Stack => {
1008                for ty in self.opts.flat_types(&self.ty, types).unwrap() {
1009                    dst.push((*ty).into());
1010                }
1011            }
1012            HelperLocation::Memory => {
1013                dst.push(self.opts.data_model.unwrap_memory().ptr());
1014            }
1015            HelperLocation::StructField | HelperLocation::ArrayElement => todo!("CM+GC"),
1016        }
1017    }
1018}