1use 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
52pub(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 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 let mut object = engine.compiler().object(ObjectKind::Module)?;
97 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#[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, )?;
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#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
214struct CompileKey {
215 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 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#[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 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 #[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 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 const MAX_SYMBOL_LEN: usize = 96;
427
428 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 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 let mut raw_outputs = engine.run_maybe_parallel(self.inputs, |f| f(compiler))?;
580
581 compile_required_builtins(engine, &mut raw_outputs)?;
586
587 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 outputs: BTreeMap<u32, Vec<CompileOutput>>,
642}
643
644impl UnlinkedCompileOutputs {
645 fn pre_link(self) -> PreLinkOutput {
648 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
711struct PreLinkOutput {
713 needs_gc_heap: bool,
715 compiled_funcs: Vec<(String, Box<dyn Any + Send>)>,
718 indices: FunctionIndices,
721}
722
723#[derive(Default)]
724struct FunctionIndices {
725 compiled_func_index_to_module: HashMap<usize, StaticModuleIndex>,
728
729 start_srclocs: HashMap<CompileKey, FilePos>,
731
732 indices: BTreeMap<u32, BTreeMap<CompileKey, CompiledFunction<usize>>>,
734}
735
736impl FunctionIndices {
737 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 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 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 self.indices
806 .remove(&CompileKey::WASM_TO_BUILTIN_TRAMPOLINE_KIND);
807
808 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 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 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 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#[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 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}