wasmtime/
compile.rs

1//! Wasm compilation orchestration.
2//!
3//! It works roughly like this:
4//!
5//! * We walk over the Wasm module/component and make a list of all the things
6//!   we need to compile. This is a `CompileInputs`.
7//!
8//! * The `CompileInputs::compile` method compiles each of these in parallel,
9//!   producing a `UnlinkedCompileOutputs`. This is an unlinked set of compiled
10//!   functions, bucketed by type of function.
11//!
12//! * The `UnlinkedCompileOutputs::pre_link` method re-arranges the compiled
13//!   functions into a flat list. This is the order we will place them within
14//!   the ELF file, so we must also keep track of all the functions' indices
15//!   within this list, because we will need them for resolving
16//!   relocations. These indices are kept track of in the resulting
17//!   `FunctionIndices`.
18//!
19//! * The `FunctionIndices::link_and_append_code` method appends the functions
20//!   to the given ELF file and resolves relocations. It produces an `Artifacts`
21//!   which contains the data needed at runtime to find and call Wasm
22//!   functions. It is up to the caller to serialize the relevant parts of the
23//!   `Artifacts` into the ELF file.
24
25use crate::hash_map::HashMap;
26use crate::hash_set::HashSet;
27use crate::prelude::*;
28use crate::Engine;
29use std::{
30    any::Any,
31    borrow::Cow,
32    collections::{btree_map, BTreeMap, BTreeSet},
33    mem,
34};
35
36#[cfg(feature = "component-model")]
37use wasmtime_environ::component::Translator;
38use wasmtime_environ::{
39    BuiltinFunctionIndex, CompiledFunctionInfo, CompiledModuleInfo, Compiler, DefinedFuncIndex,
40    FinishedObject, FunctionBodyData, ModuleEnvironment, ModuleInternedTypeIndex,
41    ModuleTranslation, ModuleTypes, ModuleTypesBuilder, ObjectKind, PrimaryMap, RelocationTarget,
42    StaticModuleIndex, WasmFunctionInfo,
43};
44
45mod code_builder;
46pub use self::code_builder::{CodeBuilder, CodeHint, HashedEngineCompileEnv};
47
48#[cfg(feature = "runtime")]
49mod runtime;
50
51/// Converts an input binary-encoded WebAssembly module to compilation
52/// artifacts and type information.
53///
54/// This is where compilation actually happens of WebAssembly modules and
55/// translation/parsing/validation of the binary input occurs. The binary
56/// artifact represented in the `MmapVec` returned here is an in-memory ELF
57/// file in an owned area of virtual linear memory where permissions (such
58/// as the executable bit) can be applied.
59///
60/// Additionally compilation returns an `Option` here which is always
61/// `Some`, notably compiled metadata about the module in addition to the
62/// type information found within.
63pub(crate) fn build_artifacts<T: FinishedObject>(
64    engine: &Engine,
65    wasm: &[u8],
66    dwarf_package: Option<&[u8]>,
67    obj_state: &T::State,
68) -> Result<(T, Option<(CompiledModuleInfo, ModuleTypes)>)> {
69    let tunables = engine.tunables();
70
71    // First a `ModuleEnvironment` is created which records type information
72    // about the wasm module. This is where the WebAssembly is parsed and
73    // validated. Afterwards `types` will have all the type information for
74    // this module.
75    let mut parser = wasmparser::Parser::new(0);
76    let mut validator = wasmparser::Validator::new_with_features(engine.features());
77    parser.set_features(*validator.features());
78    let mut types = ModuleTypesBuilder::new(&validator);
79    let mut translation = ModuleEnvironment::new(tunables, &mut validator, &mut types)
80        .translate(parser, wasm)
81        .context("failed to parse WebAssembly module")?;
82    let functions = mem::take(&mut translation.function_body_inputs);
83
84    let compile_inputs = CompileInputs::for_module(&types, &translation, functions);
85    let unlinked_compile_outputs = compile_inputs.compile(engine)?;
86    let (compiled_funcs, function_indices) = unlinked_compile_outputs.pre_link();
87
88    // Emplace all compiled functions into the object file with any other
89    // sections associated with code as well.
90    let mut object = engine.compiler().object(ObjectKind::Module)?;
91    // Insert `Engine` and type-level information into the compiled
92    // artifact so if this module is deserialized later it contains all
93    // information necessary.
94    //
95    // Note that `append_compiler_info` and `append_types` here in theory
96    // can both be skipped if this module will never get serialized.
97    // They're only used during deserialization and not during runtime for
98    // the module itself. Currently there's no need for that, however, so
99    // it's left as an exercise for later.
100    engine.append_compiler_info(&mut object);
101    engine.append_bti(&mut object);
102
103    let (mut object, compilation_artifacts) = function_indices.link_and_append_code(
104        &types,
105        object,
106        engine,
107        compiled_funcs,
108        std::iter::once(translation).collect(),
109        dwarf_package,
110    )?;
111
112    let info = compilation_artifacts.unwrap_as_module_info();
113    let types = types.finish();
114    object.serialize_info(&(&info, &types));
115    let result = T::finish_object(object, obj_state)?;
116
117    Ok((result, Some((info, types))))
118}
119
120/// Performs the compilation phase for a component, translating and
121/// validating the provided wasm binary to machine code.
122///
123/// This method will compile all nested core wasm binaries in addition to
124/// any necessary extra functions required for operation with components.
125/// The output artifact here is the serialized object file contained within
126/// an owned mmap along with metadata about the compilation itself.
127#[cfg(feature = "component-model")]
128pub(crate) fn build_component_artifacts<T: FinishedObject>(
129    engine: &Engine,
130    binary: &[u8],
131    _dwarf_package: Option<&[u8]>,
132    obj_state: &T::State,
133) -> Result<(T, Option<wasmtime_environ::component::ComponentArtifacts>)> {
134    use wasmtime_environ::component::{
135        CompiledComponentInfo, ComponentArtifacts, ComponentTypesBuilder,
136    };
137    use wasmtime_environ::ScopeVec;
138
139    let tunables = engine.tunables();
140    let compiler = engine.compiler();
141
142    let scope = ScopeVec::new();
143    let mut validator = wasmparser::Validator::new_with_features(engine.features());
144    let mut types = ComponentTypesBuilder::new(&validator);
145    let (component, mut module_translations) =
146        Translator::new(tunables, &mut validator, &mut types, &scope)
147            .translate(binary)
148            .context("failed to parse WebAssembly module")?;
149
150    let compile_inputs = CompileInputs::for_component(
151        engine,
152        &types,
153        &component,
154        module_translations.iter_mut().map(|(i, translation)| {
155            let functions = mem::take(&mut translation.function_body_inputs);
156            (i, &*translation, functions)
157        }),
158    );
159    let unlinked_compile_outputs = compile_inputs.compile(&engine)?;
160
161    let (compiled_funcs, function_indices) = unlinked_compile_outputs.pre_link();
162
163    let mut object = compiler.object(ObjectKind::Component)?;
164    engine.append_compiler_info(&mut object);
165    engine.append_bti(&mut object);
166
167    let (mut object, compilation_artifacts) = function_indices.link_and_append_code(
168        types.module_types_builder(),
169        object,
170        engine,
171        compiled_funcs,
172        module_translations,
173        None, // TODO: Support dwarf packages for components.
174    )?;
175    let (types, ty) = types.finish(&component.component);
176
177    let info = CompiledComponentInfo {
178        component: component.component,
179        trampolines: compilation_artifacts.trampolines,
180        resource_drop_wasm_to_array_trampoline: compilation_artifacts
181            .resource_drop_wasm_to_array_trampoline,
182    };
183    let artifacts = ComponentArtifacts {
184        info,
185        ty,
186        types,
187        static_modules: compilation_artifacts.modules,
188    };
189    object.serialize_info(&artifacts);
190
191    let result = T::finish_object(object, obj_state)?;
192    Ok((result, Some(artifacts)))
193}
194
195type CompileInput<'a> = Box<dyn FnOnce(&dyn Compiler) -> Result<CompileOutput> + Send + 'a>;
196
197/// A sortable, comparable key for a compilation output.
198///
199/// Two `u32`s to align with `cranelift_codegen::ir::UserExternalName`.
200#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
201struct CompileKey {
202    // The namespace field is bitpacked like:
203    //
204    //     [ kind:i3 module:i29 ]
205    namespace: u32,
206
207    index: u32,
208}
209
210impl CompileKey {
211    const KIND_BITS: u32 = 3;
212    const KIND_OFFSET: u32 = 32 - Self::KIND_BITS;
213    const KIND_MASK: u32 = ((1 << Self::KIND_BITS) - 1) << Self::KIND_OFFSET;
214
215    fn kind(&self) -> u32 {
216        self.namespace & Self::KIND_MASK
217    }
218
219    fn module(&self) -> StaticModuleIndex {
220        StaticModuleIndex::from_u32(self.namespace & !Self::KIND_MASK)
221    }
222
223    const WASM_FUNCTION_KIND: u32 = Self::new_kind(0);
224    const ARRAY_TO_WASM_TRAMPOLINE_KIND: u32 = Self::new_kind(1);
225    const WASM_TO_ARRAY_TRAMPOLINE_KIND: u32 = Self::new_kind(2);
226    const WASM_TO_BUILTIN_TRAMPOLINE_KIND: u32 = Self::new_kind(3);
227
228    const fn new_kind(kind: u32) -> u32 {
229        assert!(kind < (1 << Self::KIND_BITS));
230        kind << Self::KIND_OFFSET
231    }
232
233    // NB: more kinds in the other `impl` block.
234
235    fn wasm_function(module: StaticModuleIndex, index: DefinedFuncIndex) -> Self {
236        debug_assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
237        Self {
238            namespace: Self::WASM_FUNCTION_KIND | module.as_u32(),
239            index: index.as_u32(),
240        }
241    }
242
243    fn array_to_wasm_trampoline(module: StaticModuleIndex, index: DefinedFuncIndex) -> Self {
244        debug_assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
245        Self {
246            namespace: Self::ARRAY_TO_WASM_TRAMPOLINE_KIND | module.as_u32(),
247            index: index.as_u32(),
248        }
249    }
250
251    fn wasm_to_array_trampoline(index: ModuleInternedTypeIndex) -> Self {
252        Self {
253            namespace: Self::WASM_TO_ARRAY_TRAMPOLINE_KIND,
254            index: index.as_u32(),
255        }
256    }
257
258    fn wasm_to_builtin_trampoline(index: BuiltinFunctionIndex) -> Self {
259        Self {
260            namespace: Self::WASM_TO_BUILTIN_TRAMPOLINE_KIND,
261            index: index.index(),
262        }
263    }
264}
265
266#[cfg(feature = "component-model")]
267impl CompileKey {
268    const TRAMPOLINE_KIND: u32 = Self::new_kind(4);
269    const RESOURCE_DROP_WASM_TO_ARRAY_KIND: u32 = Self::new_kind(5);
270
271    fn trampoline(index: wasmtime_environ::component::TrampolineIndex) -> Self {
272        Self {
273            namespace: Self::TRAMPOLINE_KIND,
274            index: index.as_u32(),
275        }
276    }
277
278    fn resource_drop_wasm_to_array_trampoline() -> Self {
279        Self {
280            namespace: Self::RESOURCE_DROP_WASM_TO_ARRAY_KIND,
281            index: 0,
282        }
283    }
284}
285
286#[derive(Clone, Copy)]
287enum CompiledFunction<T> {
288    Function(T),
289    #[cfg(feature = "component-model")]
290    AllCallFunc(wasmtime_environ::component::AllCallFunc<T>),
291}
292
293impl<T> CompiledFunction<T> {
294    fn unwrap_function(self) -> T {
295        match self {
296            Self::Function(f) => f,
297            #[cfg(feature = "component-model")]
298            Self::AllCallFunc(_) => panic!("CompiledFunction::unwrap_function"),
299        }
300    }
301
302    #[cfg(feature = "component-model")]
303    fn unwrap_all_call_func(self) -> wasmtime_environ::component::AllCallFunc<T> {
304        match self {
305            Self::AllCallFunc(f) => f,
306            Self::Function(_) => panic!("CompiledFunction::unwrap_all_call_func"),
307        }
308    }
309}
310
311#[cfg(feature = "component-model")]
312impl<T> From<wasmtime_environ::component::AllCallFunc<T>> for CompiledFunction<T> {
313    fn from(f: wasmtime_environ::component::AllCallFunc<T>) -> Self {
314        Self::AllCallFunc(f)
315    }
316}
317
318struct CompileOutput {
319    key: CompileKey,
320    symbol: String,
321    function: CompiledFunction<Box<dyn Any + Send>>,
322    info: Option<WasmFunctionInfo>,
323}
324
325/// The collection of things we need to compile for a Wasm module or component.
326#[derive(Default)]
327struct CompileInputs<'a> {
328    inputs: Vec<CompileInput<'a>>,
329}
330
331impl<'a> CompileInputs<'a> {
332    fn push_input(&mut self, f: impl FnOnce(&dyn Compiler) -> Result<CompileOutput> + Send + 'a) {
333        self.inputs.push(Box::new(f));
334    }
335
336    /// Create the `CompileInputs` for a core Wasm module.
337    fn for_module(
338        types: &'a ModuleTypesBuilder,
339        translation: &'a ModuleTranslation<'a>,
340        functions: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'a>>,
341    ) -> Self {
342        let mut ret = CompileInputs { inputs: vec![] };
343
344        let module_index = StaticModuleIndex::from_u32(0);
345        ret.collect_inputs_in_translations(types, [(module_index, translation, functions)]);
346
347        ret
348    }
349
350    /// Create a `CompileInputs` for a component.
351    #[cfg(feature = "component-model")]
352    fn for_component(
353        engine: &'a Engine,
354        types: &'a wasmtime_environ::component::ComponentTypesBuilder,
355        component: &'a wasmtime_environ::component::ComponentTranslation,
356        module_translations: impl IntoIterator<
357            Item = (
358                StaticModuleIndex,
359                &'a ModuleTranslation<'a>,
360                PrimaryMap<DefinedFuncIndex, FunctionBodyData<'a>>,
361            ),
362        >,
363    ) -> Self {
364        let mut ret = CompileInputs { inputs: vec![] };
365
366        ret.collect_inputs_in_translations(types.module_types_builder(), module_translations);
367        let tunables = engine.tunables();
368
369        for (idx, trampoline) in component.trampolines.iter() {
370            ret.push_input(move |compiler| {
371                Ok(CompileOutput {
372                    key: CompileKey::trampoline(idx),
373                    symbol: trampoline.symbol_name(),
374                    function: compiler
375                        .component_compiler()
376                        .compile_trampoline(component, types, idx, tunables)
377                        .with_context(|| format!("failed to compile {}", trampoline.symbol_name()))?
378                        .into(),
379                    info: None,
380                })
381            });
382        }
383
384        // If there are any resources defined within this component, the
385        // signature for `resource.drop` is mentioned somewhere, and the
386        // wasm-to-native trampoline for `resource.drop` hasn't been created yet
387        // then insert that here. This is possibly required by destruction of
388        // resources from the embedder and otherwise won't be explicitly
389        // requested through initializers above or such.
390        if component.component.num_resources > 0 {
391            if let Some(sig) = types.find_resource_drop_signature() {
392                ret.push_input(move |compiler| {
393                    let symbol = "resource_drop_trampoline".to_string();
394                    let trampoline = compiler
395                        .compile_wasm_to_array_trampoline(types[sig].unwrap_func())
396                        .with_context(|| format!("failed to compile `{symbol}`"))?;
397                    Ok(CompileOutput {
398                        key: CompileKey::resource_drop_wasm_to_array_trampoline(),
399                        function: CompiledFunction::Function(trampoline),
400                        symbol,
401                        info: None,
402                    })
403                });
404            }
405        }
406
407        ret
408    }
409
410    fn clean_symbol(name: &str) -> Cow<str> {
411        /// Maximum length of symbols generated in objects.
412        const MAX_SYMBOL_LEN: usize = 96;
413
414        // Just to be on the safe side, filter out characters that could
415        // pose issues to tools such as "perf" or "objdump".  To avoid
416        // having to update a list of allowed characters for each different
417        // language that compiles to Wasm, allows only graphic ASCII
418        // characters; replace runs of everything else with a "?".
419        let bad_char = |c: char| !c.is_ascii_graphic();
420        if name.chars().any(bad_char) {
421            let mut last_char_seen = '\u{0000}';
422            Cow::Owned(
423                name.chars()
424                    .map(|c| if bad_char(c) { '?' } else { c })
425                    .filter(|c| {
426                        let skip = last_char_seen == '?' && *c == '?';
427                        last_char_seen = *c;
428                        !skip
429                    })
430                    .take(MAX_SYMBOL_LEN)
431                    .collect::<String>(),
432            )
433        } else if name.len() <= MAX_SYMBOL_LEN {
434            Cow::Borrowed(&name[..])
435        } else {
436            Cow::Borrowed(&name[..MAX_SYMBOL_LEN])
437        }
438    }
439
440    fn collect_inputs_in_translations(
441        &mut self,
442        types: &'a ModuleTypesBuilder,
443        translations: impl IntoIterator<
444            Item = (
445                StaticModuleIndex,
446                &'a ModuleTranslation<'a>,
447                PrimaryMap<DefinedFuncIndex, FunctionBodyData<'a>>,
448            ),
449        >,
450    ) {
451        for (module, translation, functions) in translations {
452            for (def_func_index, func_body) in functions {
453                self.push_input(move |compiler| {
454                    let func_index = translation.module.func_index(def_func_index);
455                    let symbol = match translation
456                        .debuginfo
457                        .name_section
458                        .func_names
459                        .get(&func_index)
460                    {
461                        Some(name) => format!(
462                            "wasm[{}]::function[{}]::{}",
463                            module.as_u32(),
464                            func_index.as_u32(),
465                            Self::clean_symbol(&name)
466                        ),
467                        None => format!(
468                            "wasm[{}]::function[{}]",
469                            module.as_u32(),
470                            func_index.as_u32()
471                        ),
472                    };
473                    let (info, function) = compiler
474                        .compile_function(translation, def_func_index, func_body, types)
475                        .with_context(|| format!("failed to compile: {symbol}"))?;
476
477                    Ok(CompileOutput {
478                        key: CompileKey::wasm_function(module, def_func_index),
479                        symbol,
480                        function: CompiledFunction::Function(function),
481                        info: Some(info),
482                    })
483                });
484
485                let func_index = translation.module.func_index(def_func_index);
486                if translation.module.functions[func_index].is_escaping() {
487                    self.push_input(move |compiler| {
488                        let func_index = translation.module.func_index(def_func_index);
489                        let symbol = format!(
490                            "wasm[{}]::array_to_wasm_trampoline[{}]",
491                            module.as_u32(),
492                            func_index.as_u32()
493                        );
494                        let trampoline = compiler
495                            .compile_array_to_wasm_trampoline(translation, types, def_func_index)
496                            .with_context(|| format!("failed to compile: {symbol}"))?;
497                        Ok(CompileOutput {
498                            key: CompileKey::array_to_wasm_trampoline(module, def_func_index),
499                            symbol,
500                            function: CompiledFunction::Function(trampoline),
501                            info: None,
502                        })
503                    });
504                }
505            }
506        }
507
508        let mut trampoline_types_seen = HashSet::new();
509        for (_func_type_index, trampoline_type_index) in types.trampoline_types() {
510            let is_new = trampoline_types_seen.insert(trampoline_type_index);
511            if !is_new {
512                continue;
513            }
514            let trampoline_func_ty = types[trampoline_type_index].unwrap_func();
515            self.push_input(move |compiler| {
516                let symbol = format!(
517                    "signatures[{}]::wasm_to_array_trampoline",
518                    trampoline_type_index.as_u32()
519                );
520                let trampoline = compiler
521                    .compile_wasm_to_array_trampoline(trampoline_func_ty)
522                    .with_context(|| format!("failed to compile: {symbol}"))?;
523                Ok(CompileOutput {
524                    key: CompileKey::wasm_to_array_trampoline(trampoline_type_index),
525                    function: CompiledFunction::Function(trampoline),
526                    symbol,
527                    info: None,
528                })
529            });
530        }
531    }
532
533    /// Compile these `CompileInput`s (maybe in parallel) and return the
534    /// resulting `UnlinkedCompileOutput`s.
535    fn compile(self, engine: &Engine) -> Result<UnlinkedCompileOutputs> {
536        let compiler = engine.compiler();
537
538        // Compile each individual input in parallel.
539        let mut raw_outputs = engine.run_maybe_parallel(self.inputs, |f| f(compiler))?;
540
541        // Now that all functions have been compiled see if any
542        // wasmtime-builtin functions are necessary. If so those need to be
543        // collected and then those trampolines additionally need to be
544        // compiled.
545        compile_required_builtins(engine, &mut raw_outputs)?;
546
547        // Bucket the outputs by kind.
548        let mut outputs: BTreeMap<u32, Vec<CompileOutput>> = BTreeMap::new();
549        for output in raw_outputs {
550            outputs.entry(output.key.kind()).or_default().push(output);
551        }
552
553        Ok(UnlinkedCompileOutputs { outputs })
554    }
555}
556
557fn compile_required_builtins(engine: &Engine, raw_outputs: &mut Vec<CompileOutput>) -> Result<()> {
558    let compiler = engine.compiler();
559    let mut builtins = HashSet::new();
560    let mut new_inputs: Vec<CompileInput<'_>> = Vec::new();
561
562    let compile_builtin = |builtin: BuiltinFunctionIndex| {
563        Box::new(move |compiler: &dyn Compiler| {
564            let symbol = format!("wasmtime_builtin_{}", builtin.name());
565            Ok(CompileOutput {
566                key: CompileKey::wasm_to_builtin_trampoline(builtin),
567                function: CompiledFunction::Function(
568                    compiler
569                        .compile_wasm_to_builtin(builtin)
570                        .with_context(|| format!("failed to compile `{symbol}`"))?,
571                ),
572                symbol,
573                info: None,
574            })
575        })
576    };
577
578    for output in raw_outputs.iter() {
579        let f = match &output.function {
580            CompiledFunction::Function(f) => f,
581            #[cfg(feature = "component-model")]
582            CompiledFunction::AllCallFunc(_) => continue,
583        };
584        for reloc in compiler.compiled_function_relocation_targets(&**f) {
585            match reloc {
586                RelocationTarget::Builtin(i) => {
587                    if builtins.insert(i) {
588                        new_inputs.push(compile_builtin(i));
589                    }
590                }
591                _ => {}
592            }
593        }
594    }
595    raw_outputs.extend(engine.run_maybe_parallel(new_inputs, |c| c(compiler))?);
596    Ok(())
597}
598
599#[derive(Default)]
600struct UnlinkedCompileOutputs {
601    // A map from kind to `CompileOutput`.
602    outputs: BTreeMap<u32, Vec<CompileOutput>>,
603}
604
605impl UnlinkedCompileOutputs {
606    /// Flatten all our functions into a single list and remember each of their
607    /// indices within it.
608    fn pre_link(self) -> (Vec<(String, Box<dyn Any + Send>)>, FunctionIndices) {
609        // The order the functions end up within `compiled_funcs` is the order
610        // that they will be laid out in the ELF file, so try and group hot and
611        // cold functions together as best we can. However, because we bucket by
612        // kind, we shouldn't have any issues with, e.g., cold trampolines
613        // appearing in between hot Wasm functions.
614        let mut compiled_funcs = vec![];
615        let mut indices = FunctionIndices::default();
616        for x in self.outputs.into_iter().flat_map(|(_kind, xs)| xs) {
617            let index = match x.function {
618                CompiledFunction::Function(f) => {
619                    let index = compiled_funcs.len();
620                    compiled_funcs.push((x.symbol, f));
621                    CompiledFunction::Function(index)
622                }
623                #[cfg(feature = "component-model")]
624                CompiledFunction::AllCallFunc(f) => {
625                    let array_call = compiled_funcs.len();
626                    compiled_funcs.push((format!("{}_array_call", x.symbol), f.array_call));
627                    let wasm_call = compiled_funcs.len();
628                    compiled_funcs.push((format!("{}_wasm_call", x.symbol), f.wasm_call));
629                    CompiledFunction::AllCallFunc(wasmtime_environ::component::AllCallFunc {
630                        array_call,
631                        wasm_call,
632                    })
633                }
634            };
635
636            if x.key.kind() == CompileKey::WASM_FUNCTION_KIND
637                || x.key.kind() == CompileKey::ARRAY_TO_WASM_TRAMPOLINE_KIND
638            {
639                indices
640                    .compiled_func_index_to_module
641                    .insert(index.unwrap_function(), x.key.module());
642                if let Some(info) = x.info {
643                    indices.wasm_function_infos.insert(x.key, info);
644                }
645            }
646
647            indices
648                .indices
649                .entry(x.key.kind())
650                .or_default()
651                .insert(x.key, index);
652        }
653        (compiled_funcs, indices)
654    }
655}
656
657#[derive(Default)]
658struct FunctionIndices {
659    // A reverse map from an index in `compiled_funcs` to the
660    // `StaticModuleIndex` for that function.
661    compiled_func_index_to_module: HashMap<usize, StaticModuleIndex>,
662
663    // A map from Wasm functions' compile keys to their infos.
664    wasm_function_infos: HashMap<CompileKey, WasmFunctionInfo>,
665
666    // The index of each compiled function, bucketed by compile key kind.
667    indices: BTreeMap<u32, BTreeMap<CompileKey, CompiledFunction<usize>>>,
668}
669
670impl FunctionIndices {
671    /// Link the compiled functions together, resolving relocations, and append
672    /// them to the given ELF file.
673    fn link_and_append_code<'a>(
674        mut self,
675        types: &ModuleTypesBuilder,
676        mut obj: object::write::Object<'static>,
677        engine: &'a Engine,
678        compiled_funcs: Vec<(String, Box<dyn Any + Send>)>,
679        translations: PrimaryMap<StaticModuleIndex, ModuleTranslation<'_>>,
680        dwarf_package_bytes: Option<&[u8]>,
681    ) -> Result<(wasmtime_environ::ObjectBuilder<'a>, Artifacts)> {
682        // Append all the functions to the ELF file.
683        //
684        // The result is a vector parallel to `compiled_funcs` where
685        // `symbol_ids_and_locs[i]` is the symbol ID and function location of
686        // `compiled_funcs[i]`.
687        let compiler = engine.compiler();
688        let tunables = engine.tunables();
689        let symbol_ids_and_locs = compiler.append_code(
690            &mut obj,
691            &compiled_funcs,
692            &|caller_index: usize, callee: RelocationTarget| match callee {
693                RelocationTarget::Wasm(callee_index) => {
694                    let module = self
695                        .compiled_func_index_to_module
696                        .get(&caller_index)
697                        .copied()
698                        .expect("should only reloc inside wasm function callers");
699                    let def_func_index = translations[module]
700                        .module
701                        .defined_func_index(callee_index)
702                        .unwrap();
703                    self.indices[&CompileKey::WASM_FUNCTION_KIND]
704                        [&CompileKey::wasm_function(module, def_func_index)]
705                        .unwrap_function()
706                }
707                RelocationTarget::Builtin(builtin) => self.indices
708                    [&CompileKey::WASM_TO_BUILTIN_TRAMPOLINE_KIND]
709                    [&CompileKey::wasm_to_builtin_trampoline(builtin)]
710                    .unwrap_function(),
711                RelocationTarget::HostLibcall(_) | RelocationTarget::PulleyHostcall(_) => {
712                    unreachable!("relocation is resolved at runtime, not compile time");
713                }
714            },
715        )?;
716
717        // If requested, generate and add DWARF information.
718        if tunables.generate_native_debuginfo {
719            compiler.append_dwarf(
720                &mut obj,
721                &translations,
722                &|module, func| {
723                    let bucket = &self.indices[&CompileKey::WASM_FUNCTION_KIND];
724                    let i = bucket[&CompileKey::wasm_function(module, func)].unwrap_function();
725                    (symbol_ids_and_locs[i].0, &*compiled_funcs[i].1)
726                },
727                dwarf_package_bytes,
728                tunables,
729            )?;
730        }
731
732        let mut obj = wasmtime_environ::ObjectBuilder::new(obj, tunables);
733        let mut artifacts = Artifacts::default();
734
735        // Remove this as it's not needed by anything below and we'll debug
736        // assert `self.indices` is empty, so this is acknowledgement that this
737        // is a pure runtime implementation detail and not needed in any
738        // metadata generated below.
739        self.indices
740            .remove(&CompileKey::WASM_TO_BUILTIN_TRAMPOLINE_KIND);
741
742        // Finally, build our binary artifacts that map things like `FuncIndex`
743        // to a function location and all of that using the indices we saved
744        // earlier and the function locations we just received after appending
745        // the code.
746
747        let mut wasm_functions = self
748            .indices
749            .remove(&CompileKey::WASM_FUNCTION_KIND)
750            .unwrap_or_default()
751            .into_iter()
752            .peekable();
753
754        fn wasm_functions_for_module(
755            wasm_functions: &mut std::iter::Peekable<
756                btree_map::IntoIter<CompileKey, CompiledFunction<usize>>,
757            >,
758            module: StaticModuleIndex,
759        ) -> impl Iterator<Item = (CompileKey, CompiledFunction<usize>)> + '_ {
760            std::iter::from_fn(move || {
761                let (key, _) = wasm_functions.peek()?;
762                if key.module() == module {
763                    wasm_functions.next()
764                } else {
765                    None
766                }
767            })
768        }
769
770        let mut array_to_wasm_trampolines = self
771            .indices
772            .remove(&CompileKey::ARRAY_TO_WASM_TRAMPOLINE_KIND)
773            .unwrap_or_default();
774
775        // NB: unlike the above maps this is not emptied out during iteration
776        // since each module may reach into different portions of this map.
777        let wasm_to_array_trampolines = self
778            .indices
779            .remove(&CompileKey::WASM_TO_ARRAY_TRAMPOLINE_KIND)
780            .unwrap_or_default();
781
782        artifacts.modules = translations
783            .into_iter()
784            .map(|(module, mut translation)| {
785                // If configured attempt to use static memory initialization which
786                // can either at runtime be implemented as a single memcpy to
787                // initialize memory or otherwise enabling virtual-memory-tricks
788                // such as mmap'ing from a file to get copy-on-write.
789                if engine.tunables().memory_init_cow {
790                    let align = compiler.page_size_align();
791                    let max_always_allowed = engine.config().memory_guaranteed_dense_image_size;
792                    translation.try_static_init(align, max_always_allowed);
793                }
794
795                // Attempt to convert table initializer segments to
796                // FuncTable representation where possible, to enable
797                // table lazy init.
798                if engine.tunables().table_lazy_init {
799                    translation.try_func_table_init();
800                }
801
802                let funcs: PrimaryMap<DefinedFuncIndex, CompiledFunctionInfo> =
803                    wasm_functions_for_module(&mut wasm_functions, module)
804                        .map(|(key, wasm_func_index)| {
805                            let wasm_func_index = wasm_func_index.unwrap_function();
806                            let wasm_func_loc = symbol_ids_and_locs[wasm_func_index].1;
807                            let wasm_func_info = self.wasm_function_infos.remove(&key).unwrap();
808
809                            let array_to_wasm_trampoline = array_to_wasm_trampolines
810                                .remove(&CompileKey::array_to_wasm_trampoline(
811                                    key.module(),
812                                    DefinedFuncIndex::from_u32(key.index),
813                                ))
814                                .map(|x| symbol_ids_and_locs[x.unwrap_function()].1);
815
816                            CompiledFunctionInfo {
817                                wasm_func_info,
818                                wasm_func_loc,
819                                array_to_wasm_trampoline,
820                            }
821                        })
822                        .collect();
823
824                let unique_and_sorted_trampoline_sigs = translation
825                    .module
826                    .types
827                    .iter()
828                    .map(|(_, ty)| ty.unwrap_module_type_index())
829                    .filter(|idx| types[*idx].is_func())
830                    .map(|idx| types.trampoline_type(idx))
831                    .collect::<BTreeSet<_>>();
832                let wasm_to_array_trampolines = unique_and_sorted_trampoline_sigs
833                    .iter()
834                    .map(|idx| {
835                        let trampoline = types.trampoline_type(*idx);
836                        let key = CompileKey::wasm_to_array_trampoline(trampoline);
837                        let compiled = wasm_to_array_trampolines[&key];
838                        (*idx, symbol_ids_and_locs[compiled.unwrap_function()].1)
839                    })
840                    .collect();
841
842                obj.append(translation, funcs, wasm_to_array_trampolines)
843            })
844            .collect::<Result<PrimaryMap<_, _>>>()?;
845
846        #[cfg(feature = "component-model")]
847        {
848            artifacts.trampolines = self
849                .indices
850                .remove(&CompileKey::TRAMPOLINE_KIND)
851                .unwrap_or_default()
852                .into_iter()
853                .map(|(_id, x)| x.unwrap_all_call_func().map(|i| symbol_ids_and_locs[i].1))
854                .collect();
855            let map = self
856                .indices
857                .remove(&CompileKey::RESOURCE_DROP_WASM_TO_ARRAY_KIND)
858                .unwrap_or_default();
859            assert!(map.len() <= 1);
860            artifacts.resource_drop_wasm_to_array_trampoline = map
861                .into_iter()
862                .next()
863                .map(|(_id, x)| symbol_ids_and_locs[x.unwrap_function()].1);
864        }
865
866        debug_assert!(
867            self.indices.is_empty(),
868            "Should have processed all compile outputs"
869        );
870
871        Ok((obj, artifacts))
872    }
873}
874
875/// The artifacts necessary for finding and calling Wasm functions at runtime,
876/// to be serialized into an ELF file.
877#[derive(Default)]
878struct Artifacts {
879    modules: PrimaryMap<StaticModuleIndex, CompiledModuleInfo>,
880    #[cfg(feature = "component-model")]
881    trampolines: PrimaryMap<
882        wasmtime_environ::component::TrampolineIndex,
883        wasmtime_environ::component::AllCallFunc<wasmtime_environ::FunctionLoc>,
884    >,
885    #[cfg(feature = "component-model")]
886    resource_drop_wasm_to_array_trampoline: Option<wasmtime_environ::FunctionLoc>,
887}
888
889impl Artifacts {
890    /// Assuming this compilation was for a single core Wasm module, get the
891    /// resulting `CompiledModuleInfo`.
892    fn unwrap_as_module_info(self) -> CompiledModuleInfo {
893        assert_eq!(self.modules.len(), 1);
894        #[cfg(feature = "component-model")]
895        assert!(self.trampolines.is_empty());
896        self.modules.into_iter().next().unwrap().1
897    }
898}