1use 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
51pub(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 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 let mut object = engine.compiler().object(ObjectKind::Module)?;
91 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#[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, )?;
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#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
201struct CompileKey {
202 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 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#[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 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 #[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 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 const MAX_SYMBOL_LEN: usize = 96;
413
414 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 fn compile(self, engine: &Engine) -> Result<UnlinkedCompileOutputs> {
536 let compiler = engine.compiler();
537
538 let mut raw_outputs = engine.run_maybe_parallel(self.inputs, |f| f(compiler))?;
540
541 compile_required_builtins(engine, &mut raw_outputs)?;
546
547 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 outputs: BTreeMap<u32, Vec<CompileOutput>>,
603}
604
605impl UnlinkedCompileOutputs {
606 fn pre_link(self) -> (Vec<(String, Box<dyn Any + Send>)>, FunctionIndices) {
609 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 compiled_func_index_to_module: HashMap<usize, StaticModuleIndex>,
662
663 wasm_function_infos: HashMap<CompileKey, WasmFunctionInfo>,
665
666 indices: BTreeMap<u32, BTreeMap<CompileKey, CompiledFunction<usize>>>,
668}
669
670impl FunctionIndices {
671 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 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 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 self.indices
740 .remove(&CompileKey::WASM_TO_BUILTIN_TRAMPOLINE_KIND);
741
742 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 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 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 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#[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 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}