near_vm_engine_universal/
engine.rs

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