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