Skip to main content

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