wasmer_engine_universal/
engine.rs

1//! Universal compilation.
2
3use crate::executable::{unrkyv, UniversalExecutableRef};
4use crate::{CodeMemory, UniversalArtifact, UniversalExecutable};
5use rkyv::de::deserializers::SharedDeserializeMap;
6use std::collections::BTreeMap;
7use std::convert::TryFrom;
8use std::sync::{Arc, Mutex};
9#[cfg(feature = "compiler")]
10use wasmer_compiler::Compiler;
11use wasmer_compiler::{
12    CompileError, CustomSectionProtection, CustomSectionRef, FunctionBodyRef, JumpTable,
13    SectionIndex, Target,
14};
15use wasmer_engine::{Engine, EngineId};
16use wasmer_types::entity::{EntityRef, PrimaryMap};
17use wasmer_types::{
18    DataInitializer, ExportIndex, Features, FunctionIndex, FunctionType, FunctionTypeRef,
19    GlobalInit, GlobalType, ImportCounts, ImportIndex, LocalFunctionIndex, LocalGlobalIndex,
20    MemoryIndex, SignatureIndex, TableIndex,
21};
22use wasmer_vm::{
23    FuncDataRegistry, FunctionBodyPtr, SectionBodyPtr, SignatureRegistry, Tunables,
24    VMCallerCheckedAnyfunc, VMFuncRef, VMFunctionBody, VMImportType, VMLocalFunction, VMOffsets,
25    VMSharedSignatureIndex, VMTrampoline,
26};
27
28/// A WebAssembly `Universal` Engine.
29#[derive(Clone)]
30pub struct UniversalEngine {
31    inner: Arc<Mutex<UniversalEngineInner>>,
32    /// The target for the compiler
33    target: Arc<Target>,
34    engine_id: EngineId,
35}
36
37impl UniversalEngine {
38    /// Create a new `UniversalEngine` with the given config
39    #[cfg(feature = "compiler")]
40    pub fn new(compiler: Box<dyn Compiler>, target: Target, features: Features) -> Self {
41        Self {
42            inner: Arc::new(Mutex::new(UniversalEngineInner {
43                compiler: Some(compiler),
44                code_memory: vec![],
45                signatures: SignatureRegistry::new(),
46                func_data: Arc::new(FuncDataRegistry::new()),
47                features,
48            })),
49            target: Arc::new(target),
50            engine_id: EngineId::default(),
51        }
52    }
53
54    /// Create a headless `UniversalEngine`
55    ///
56    /// A headless engine is an engine without any compiler attached.
57    /// This is useful for assuring a minimal runtime for running
58    /// WebAssembly modules.
59    ///
60    /// For example, for running in IoT devices where compilers are very
61    /// expensive, or also to optimize startup speed.
62    ///
63    /// # Important
64    ///
65    /// Headless engines can't compile or validate any modules,
66    /// they just take already processed Modules (via `Module::serialize`).
67    pub fn headless() -> Self {
68        Self {
69            inner: Arc::new(Mutex::new(UniversalEngineInner {
70                #[cfg(feature = "compiler")]
71                compiler: None,
72                code_memory: vec![],
73                signatures: SignatureRegistry::new(),
74                func_data: Arc::new(FuncDataRegistry::new()),
75                features: Features::default(),
76            })),
77            target: Arc::new(Target::default()),
78            engine_id: EngineId::default(),
79        }
80    }
81
82    pub(crate) fn inner(&self) -> std::sync::MutexGuard<'_, UniversalEngineInner> {
83        self.inner.lock().unwrap()
84    }
85
86    pub(crate) fn inner_mut(&self) -> std::sync::MutexGuard<'_, UniversalEngineInner> {
87        self.inner.lock().unwrap()
88    }
89
90    /// Compile a WebAssembly binary
91    #[cfg(feature = "compiler")]
92    pub fn compile_universal(
93        &self,
94        binary: &[u8],
95        tunables: &dyn Tunables,
96    ) -> Result<crate::UniversalExecutable, CompileError> {
97        let inner_engine = self.inner_mut();
98        let features = inner_engine.features();
99        let compiler = inner_engine.compiler()?;
100        let environ = wasmer_compiler::ModuleEnvironment::new();
101        let translation = environ.translate(binary).map_err(CompileError::Wasm)?;
102
103        let memory_styles: PrimaryMap<wasmer_types::MemoryIndex, _> = translation
104            .module
105            .memories
106            .values()
107            .map(|memory_type| tunables.memory_style(memory_type))
108            .collect();
109        let table_styles: PrimaryMap<wasmer_types::TableIndex, _> = translation
110            .module
111            .tables
112            .values()
113            .map(|table_type| tunables.table_style(table_type))
114            .collect();
115
116        // Compile the Module
117        let compile_info = wasmer_compiler::CompileModuleInfo {
118            module: Arc::new(translation.module),
119            features: features.clone(),
120            memory_styles,
121            table_styles,
122        };
123        let compilation = compiler.compile_module(
124            &self.target(),
125            &compile_info,
126            // SAFETY: Calling `unwrap` is correct since
127            // `environ.translate()` above will write some data into
128            // `module_translation_state`.
129            translation.module_translation_state.as_ref().unwrap(),
130            translation.function_body_inputs,
131        )?;
132        let function_call_trampolines = compilation.get_function_call_trampolines();
133        let dynamic_function_trampolines = compilation.get_dynamic_function_trampolines();
134        let data_initializers = translation
135            .data_initializers
136            .iter()
137            .map(wasmer_types::OwnedDataInitializer::new)
138            .collect();
139
140        let frame_infos = compilation.get_frame_info();
141        Ok(crate::UniversalExecutable {
142            function_bodies: compilation.get_function_bodies(),
143            function_relocations: compilation.get_relocations(),
144            function_jt_offsets: compilation.get_jt_offsets(),
145            function_frame_info: frame_infos,
146            function_call_trampolines,
147            dynamic_function_trampolines,
148            custom_sections: compilation.get_custom_sections(),
149            custom_section_relocations: compilation.get_custom_section_relocations(),
150            debug: compilation.get_debug(),
151            trampolines: compilation.get_trampolines(),
152            compile_info,
153            data_initializers,
154            cpu_features: self.target().cpu_features().as_u64(),
155        })
156    }
157
158    /// Load a [`UniversalExecutable`](crate::UniversalExecutable) with this engine.
159    pub fn load_universal_executable(
160        &self,
161        executable: &UniversalExecutable,
162    ) -> Result<UniversalArtifact, CompileError> {
163        let info = &executable.compile_info;
164        let module = &info.module;
165        let local_memories = (module.import_counts.memories as usize..module.memories.len())
166            .map(|idx| {
167                let idx = MemoryIndex::new(idx);
168                (module.memories[idx], info.memory_styles[idx].clone())
169            })
170            .collect();
171        let local_tables = (module.import_counts.tables as usize..module.tables.len())
172            .map(|idx| {
173                let idx = TableIndex::new(idx);
174                (module.tables[idx], info.table_styles[idx].clone())
175            })
176            .collect();
177        let local_globals: Vec<(GlobalType, GlobalInit)> = module
178            .globals
179            .iter()
180            .skip(module.import_counts.globals as usize)
181            .enumerate()
182            .map(|(idx, (_, t))| {
183                let init = module.global_initializers[LocalGlobalIndex::new(idx)];
184                (*t, init)
185            })
186            .collect();
187        let mut inner_engine = self.inner_mut();
188
189        let local_functions = executable.function_bodies.iter().map(|(_, b)| b.into());
190        let function_call_trampolines = &executable.function_call_trampolines;
191        let dynamic_function_trampolines = &executable.dynamic_function_trampolines;
192        let signatures = module
193            .signatures
194            .iter()
195            .map(|(_, sig)| inner_engine.signatures.register(sig.into()))
196            .collect::<PrimaryMap<SignatureIndex, _>>()
197            .into_boxed_slice();
198        let (functions, trampolines, dynamic_trampolines, custom_sections) = inner_engine
199            .allocate(
200                local_functions,
201                function_call_trampolines.iter().map(|(_, b)| b.into()),
202                dynamic_function_trampolines.iter().map(|(_, b)| b.into()),
203                executable.custom_sections.iter().map(|(_, s)| s.into()),
204                |idx: LocalFunctionIndex| {
205                    let func_idx = module.import_counts.function_index(idx);
206                    let sig_idx = module.functions[func_idx];
207                    (sig_idx, signatures[sig_idx])
208                },
209            )?;
210        let imports = module
211            .imports
212            .iter()
213            .map(|((module_name, field, idx), entity)| wasmer_vm::VMImport {
214                module: String::from(module_name),
215                field: String::from(field),
216                import_no: *idx,
217                ty: match entity {
218                    ImportIndex::Function(i) => {
219                        let sig_idx = module.functions[*i];
220                        VMImportType::Function {
221                            sig: signatures[sig_idx],
222                            static_trampoline: trampolines[sig_idx],
223                        }
224                    }
225                    ImportIndex::Table(i) => VMImportType::Table(module.tables[*i]),
226                    &ImportIndex::Memory(i) => {
227                        let ty = module.memories[i];
228                        VMImportType::Memory(ty, info.memory_styles[i].clone())
229                    }
230                    ImportIndex::Global(i) => VMImportType::Global(module.globals[*i]),
231                },
232            })
233            .collect();
234
235        let function_relocations = executable.function_relocations.iter();
236        let section_relocations = executable.custom_section_relocations.iter();
237        crate::link_module(
238            &functions,
239            |func_idx, jt_idx| executable.function_jt_offsets[func_idx][jt_idx],
240            function_relocations.map(|(i, rs)| (i, rs.iter().cloned())),
241            &custom_sections,
242            section_relocations.map(|(i, rs)| (i, rs.iter().cloned())),
243            &executable.trampolines,
244        );
245
246        // Make all code loaded executable.
247        inner_engine.publish_compiled_code();
248        if let Some(ref d) = executable.debug {
249            unsafe {
250                // TODO: safety comment
251                inner_engine.publish_eh_frame(std::slice::from_raw_parts(
252                    *custom_sections[d.eh_frame],
253                    executable.custom_sections[d.eh_frame].bytes.len(),
254                ))?;
255            }
256        }
257        let exports = module
258            .exports
259            .iter()
260            .map(|(s, i)| (s.clone(), i.clone()))
261            .collect::<BTreeMap<String, ExportIndex>>();
262
263        Ok(UniversalArtifact {
264            engine: self.clone(),
265            import_counts: module.import_counts,
266            start_function: module.start_function,
267            vmoffsets: VMOffsets::for_host().with_module_info(&*module),
268            imports,
269            dynamic_function_trampolines: dynamic_trampolines.into_boxed_slice(),
270            functions: functions.into_boxed_slice(),
271            exports,
272            signatures,
273            local_memories,
274            data_segments: executable.data_initializers.clone(),
275            passive_data: module.passive_data.clone(),
276            local_tables,
277            element_segments: module.table_initializers.clone(),
278            passive_elements: module.passive_elements.clone(),
279            local_globals,
280        })
281    }
282
283    /// Load a [`UniversalExecutableRef`](crate::UniversalExecutableRef) with this engine.
284    pub fn load_universal_executable_ref(
285        &self,
286        executable: &UniversalExecutableRef,
287    ) -> Result<UniversalArtifact, CompileError> {
288        let info = &executable.compile_info;
289        let module = &info.module;
290        let import_counts: ImportCounts = unrkyv(&module.import_counts);
291        let local_memories = (import_counts.memories as usize..module.memories.len())
292            .map(|idx| {
293                let idx = MemoryIndex::new(idx);
294                let mty = &module.memories[&idx];
295                (unrkyv(mty), unrkyv(&info.memory_styles[&idx]))
296            })
297            .collect();
298        let local_tables = (import_counts.tables as usize..module.tables.len())
299            .map(|idx| {
300                let idx = TableIndex::new(idx);
301                let tty = &module.tables[&idx];
302                (unrkyv(tty), unrkyv(&info.table_styles[&idx]))
303            })
304            .collect();
305        let local_globals: Vec<(GlobalType, GlobalInit)> = module
306            .globals
307            .iter()
308            .skip(import_counts.globals as _)
309            .enumerate()
310            .map(|(idx, (_, t))| {
311                let init = unrkyv(&module.global_initializers[&LocalGlobalIndex::new(idx)]);
312                (*t, init)
313            })
314            .collect();
315
316        let passive_data =
317            rkyv::Deserialize::deserialize(&module.passive_data, &mut SharedDeserializeMap::new())
318                .map_err(|_| CompileError::Validate("could not deserialize passive data".into()))?;
319        let data_segments = executable.data_initializers.iter();
320        let data_segments = data_segments
321            .map(|s| DataInitializer::from(s).into())
322            .collect();
323        let element_segments = unrkyv(&module.table_initializers);
324        let passive_elements: BTreeMap<wasmer_types::ElemIndex, Box<[FunctionIndex]>> =
325            unrkyv(&module.passive_elements);
326
327        let import_counts: ImportCounts = unrkyv(&module.import_counts);
328        let mut inner_engine = self.inner_mut();
329
330        let local_functions = executable.function_bodies.iter().map(|(_, b)| b.into());
331        let call_trampolines = executable.function_call_trampolines.iter();
332        let dynamic_trampolines = executable.dynamic_function_trampolines.iter();
333        let signatures = module
334            .signatures
335            .values()
336            .map(|sig| inner_engine.signatures.register(sig.into()))
337            .collect::<PrimaryMap<SignatureIndex, _>>()
338            .into_boxed_slice();
339        let (functions, trampolines, dynamic_trampolines, custom_sections) = inner_engine
340            .allocate(
341                local_functions,
342                call_trampolines.map(|(_, b)| b.into()),
343                dynamic_trampolines.map(|(_, b)| b.into()),
344                executable.custom_sections.iter().map(|(_, s)| s.into()),
345                |idx: LocalFunctionIndex| {
346                    let func_idx = import_counts.function_index(idx);
347                    let sig_idx = module.functions[&func_idx];
348                    (sig_idx, signatures[sig_idx])
349                },
350            )?;
351        let imports = {
352            module
353                .imports
354                .iter()
355                .map(|((module_name, field, idx), entity)| wasmer_vm::VMImport {
356                    module: String::from(module_name.as_str()),
357                    field: String::from(field.as_str()),
358                    import_no: *idx,
359                    ty: match entity {
360                        ImportIndex::Function(i) => {
361                            let sig_idx = module.functions[i];
362                            VMImportType::Function {
363                                sig: signatures[sig_idx],
364                                static_trampoline: trampolines[sig_idx],
365                            }
366                        }
367                        ImportIndex::Table(i) => VMImportType::Table(unrkyv(&module.tables[i])),
368                        ImportIndex::Memory(i) => {
369                            let ty = unrkyv(&module.memories[i]);
370                            VMImportType::Memory(ty, unrkyv(&info.memory_styles[i]))
371                        }
372                        ImportIndex::Global(i) => VMImportType::Global(unrkyv(&module.globals[i])),
373                    },
374                })
375                .collect()
376        };
377
378        let function_relocations = executable.function_relocations.iter();
379        let section_relocations = executable.custom_section_relocations.iter();
380        crate::link_module(
381            &functions,
382            |func_idx, jt_idx| {
383                let func_idx = rkyv::Archived::<LocalFunctionIndex>::new(func_idx.index());
384                let jt_idx = rkyv::Archived::<JumpTable>::new(jt_idx.index());
385                executable.function_jt_offsets[&func_idx][&jt_idx]
386            },
387            function_relocations.map(|(i, r)| (i, r.iter().map(unrkyv))),
388            &custom_sections,
389            section_relocations.map(|(i, r)| (i, r.iter().map(unrkyv))),
390            &unrkyv(&executable.trampolines),
391        );
392
393        // Make all code compiled thus far executable.
394        inner_engine.publish_compiled_code();
395        if let rkyv::option::ArchivedOption::Some(ref d) = executable.debug {
396            unsafe {
397                // TODO: safety comment
398                let s = CustomSectionRef::from(&executable.custom_sections[&d.eh_frame]);
399                inner_engine.publish_eh_frame(std::slice::from_raw_parts(
400                    *custom_sections[unrkyv(&d.eh_frame)],
401                    s.bytes.len(),
402                ))?;
403            }
404        }
405        let exports = module
406            .exports
407            .iter()
408            .map(|(s, i)| (unrkyv(s), unrkyv(i)))
409            .collect::<BTreeMap<String, ExportIndex>>();
410        Ok(UniversalArtifact {
411            engine: self.clone(),
412            import_counts,
413            start_function: unrkyv(&module.start_function),
414            vmoffsets: VMOffsets::for_host().with_archived_module_info(&*module),
415            imports,
416            dynamic_function_trampolines: dynamic_trampolines.into_boxed_slice(),
417            functions: functions.into_boxed_slice(),
418            exports,
419            signatures,
420            local_memories,
421            data_segments,
422            passive_data,
423            local_tables,
424            element_segments,
425            passive_elements,
426            local_globals,
427        })
428    }
429}
430
431impl Engine for UniversalEngine {
432    /// The target
433    fn target(&self) -> &Target {
434        &self.target
435    }
436
437    /// Register a signature
438    fn register_signature(&self, func_type: FunctionTypeRef<'_>) -> VMSharedSignatureIndex {
439        self.inner().signatures.register(func_type)
440    }
441
442    fn register_function_metadata(&self, func_data: VMCallerCheckedAnyfunc) -> VMFuncRef {
443        self.inner().func_data().register(func_data)
444    }
445
446    /// Lookup a signature
447    fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
448        self.inner().signatures.lookup(sig).cloned()
449    }
450
451    /// Validates a WebAssembly module
452    fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {
453        self.inner().validate(binary)
454    }
455
456    #[cfg(not(feature = "compiler"))]
457    fn compile(
458        &self,
459        binary: &[u8],
460        tunables: &dyn Tunables,
461    ) -> Result<Box<dyn wasmer_engine::Executable>, CompileError> {
462        return Err(CompileError::Codegen(
463            "The UniversalEngine is operating in headless mode, so it can not compile Modules."
464                .to_string(),
465        ));
466    }
467
468    /// Compile a WebAssembly binary
469    #[cfg(feature = "compiler")]
470    fn compile(
471        &self,
472        binary: &[u8],
473        tunables: &dyn Tunables,
474    ) -> Result<Box<dyn wasmer_engine::Executable>, CompileError> {
475        self.compile_universal(binary, tunables)
476            .map(|ex| Box::new(ex) as _)
477    }
478
479    fn load(
480        &self,
481        executable: &(dyn wasmer_engine::Executable),
482    ) -> Result<Arc<dyn wasmer_vm::Artifact>, CompileError> {
483        executable.load(self)
484    }
485
486    fn id(&self) -> &EngineId {
487        &self.engine_id
488    }
489
490    fn cloned(&self) -> Arc<dyn Engine + Send + Sync> {
491        Arc::new(self.clone())
492    }
493}
494
495/// The inner contents of `UniversalEngine`
496pub struct UniversalEngineInner {
497    /// The compiler
498    #[cfg(feature = "compiler")]
499    compiler: Option<Box<dyn Compiler>>,
500    /// The features to compile the Wasm module with
501    features: Features,
502    /// The code memory is responsible of publishing the compiled
503    /// functions to memory.
504    code_memory: Vec<CodeMemory>,
505    /// The signature registry is used mainly to operate with trampolines
506    /// performantly.
507    pub(crate) signatures: SignatureRegistry,
508    /// The backing storage of `VMFuncRef`s. This centralized store ensures that 2
509    /// functions with the same `VMCallerCheckedAnyfunc` will have the same `VMFuncRef`.
510    /// It also guarantees that the `VMFuncRef`s stay valid until the engine is dropped.
511    func_data: Arc<FuncDataRegistry>,
512}
513
514impl UniversalEngineInner {
515    /// Gets the compiler associated to this engine.
516    #[cfg(feature = "compiler")]
517    pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
518        if self.compiler.is_none() {
519            return Err(CompileError::Codegen("The UniversalEngine is operating in headless mode, so it can only execute already compiled Modules.".to_string()));
520        }
521        Ok(&**self.compiler.as_ref().unwrap())
522    }
523
524    /// Validate the module
525    #[cfg(feature = "compiler")]
526    pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> {
527        self.compiler()?.validate_module(self.features(), data)
528    }
529
530    /// Validate the module
531    #[cfg(not(feature = "compiler"))]
532    pub fn validate<'data>(&self, _data: &'data [u8]) -> Result<(), CompileError> {
533        Err(CompileError::Validate(
534            "The UniversalEngine is not compiled with compiler support, which is required for validating"
535                .to_string(),
536        ))
537    }
538
539    /// The Wasm features
540    pub fn features(&self) -> &Features {
541        &self.features
542    }
543
544    /// Allocate compiled functions into memory
545    #[allow(clippy::type_complexity)]
546    pub(crate) fn allocate<'a>(
547        &mut self,
548        local_functions: impl ExactSizeIterator<Item = FunctionBodyRef<'a>>,
549        call_trampolines: impl ExactSizeIterator<Item = FunctionBodyRef<'a>>,
550        dynamic_trampolines: impl ExactSizeIterator<Item = FunctionBodyRef<'a>>,
551        custom_sections: impl ExactSizeIterator<Item = CustomSectionRef<'a>>,
552        function_signature: impl Fn(LocalFunctionIndex) -> (SignatureIndex, VMSharedSignatureIndex),
553    ) -> Result<
554        (
555            PrimaryMap<LocalFunctionIndex, VMLocalFunction>,
556            PrimaryMap<SignatureIndex, VMTrampoline>,
557            PrimaryMap<FunctionIndex, FunctionBodyPtr>,
558            PrimaryMap<SectionIndex, SectionBodyPtr>,
559        ),
560        CompileError,
561    > {
562        let code_memory = &mut self.code_memory;
563        let function_count = local_functions.len();
564        let call_trampoline_count = call_trampolines.len();
565        let function_bodies = call_trampolines
566            .chain(local_functions)
567            .chain(dynamic_trampolines)
568            .collect::<Vec<_>>();
569
570        // TOOD: this shouldn't be necessary....
571        let mut section_types = Vec::with_capacity(custom_sections.len());
572        let mut executable_sections = Vec::new();
573        let mut data_sections = Vec::new();
574        for section in custom_sections {
575            if let CustomSectionProtection::ReadExecute = section.protection {
576                executable_sections.push(section);
577            } else {
578                data_sections.push(section);
579            }
580            section_types.push(section.protection);
581        }
582        code_memory.push(CodeMemory::new());
583        let code_memory = self.code_memory.last_mut().expect("infallible");
584
585        let (mut allocated_functions, allocated_executable_sections, allocated_data_sections) =
586            code_memory
587                .allocate(
588                    function_bodies.as_slice(),
589                    executable_sections.as_slice(),
590                    data_sections.as_slice(),
591                )
592                .map_err(|message| {
593                    CompileError::Resource(format!(
594                        "failed to allocate memory for functions: {}",
595                        message
596                    ))
597                })?;
598
599        let mut allocated_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
600            PrimaryMap::new();
601        for ptr in allocated_functions
602            .drain(0..call_trampoline_count)
603            .map(|slice| slice.as_ptr())
604        {
605            // TODO: What in damnation have you done?! – Bannon
606            let trampoline =
607                unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
608            allocated_function_call_trampolines.push(trampoline);
609        }
610
611        let allocated_functions_result = allocated_functions
612            .drain(0..function_count)
613            .enumerate()
614            .map(|(index, slice)| -> Result<_, CompileError> {
615                let index = LocalFunctionIndex::new(index);
616                let (sig_idx, sig) = function_signature(index);
617                Ok(VMLocalFunction {
618                    body: FunctionBodyPtr(slice.as_ptr()),
619                    length: u32::try_from(slice.len()).map_err(|_| {
620                        CompileError::Codegen("function body length exceeds 4GiB".into())
621                    })?,
622                    signature: sig,
623                    trampoline: allocated_function_call_trampolines[sig_idx],
624                })
625            })
626            .collect::<Result<PrimaryMap<LocalFunctionIndex, _>, _>>()?;
627
628        let allocated_dynamic_function_trampolines = allocated_functions
629            .drain(..)
630            .map(|slice| FunctionBodyPtr(slice.as_ptr()))
631            .collect::<PrimaryMap<FunctionIndex, _>>();
632
633        let mut exec_iter = allocated_executable_sections.iter();
634        let mut data_iter = allocated_data_sections.iter();
635        let allocated_custom_sections = section_types
636            .into_iter()
637            .map(|protection| {
638                SectionBodyPtr(
639                    if protection == CustomSectionProtection::ReadExecute {
640                        exec_iter.next()
641                    } else {
642                        data_iter.next()
643                    }
644                    .unwrap()
645                    .as_ptr(),
646                )
647            })
648            .collect::<PrimaryMap<SectionIndex, _>>();
649
650        Ok((
651            allocated_functions_result,
652            allocated_function_call_trampolines,
653            allocated_dynamic_function_trampolines,
654            allocated_custom_sections,
655        ))
656    }
657
658    /// Make memory containing compiled code executable.
659    pub(crate) fn publish_compiled_code(&mut self) {
660        self.code_memory.last_mut().unwrap().publish();
661    }
662
663    /// Register DWARF-type exception handling information associated with the code.
664    pub(crate) fn publish_eh_frame(&mut self, eh_frame: &[u8]) -> Result<(), CompileError> {
665        self.code_memory
666            .last_mut()
667            .unwrap()
668            .unwind_registry_mut()
669            .publish(eh_frame)
670            .map_err(|e| {
671                CompileError::Resource(format!("Error while publishing the unwind code: {}", e))
672            })?;
673        Ok(())
674    }
675
676    /// Shared func metadata registry.
677    pub(crate) fn func_data(&self) -> &Arc<FuncDataRegistry> {
678        &self.func_data
679    }
680}