Skip to main content

wasmer_compiler/types/
function.rs

1/*
2 * ! Remove me once rkyv generates doc-comments for fields or generates an #[allow(missing_docs)]
3 * on their own.
4 */
5#![allow(missing_docs)]
6// This file contains code from external sources.
7// Attributions: https://github.com/wasmerio/wasmer/blob/main/docs/ATTRIBUTIONS.md
8
9//! A `Compilation` contains the compiled function bodies for a WebAssembly
10//! module (`CompiledFunction`).
11
12use super::{
13    address_map::FunctionAddressMap,
14    relocation::Relocation,
15    section::{CustomSection, SectionIndex},
16    unwind::{
17        ArchivedCompiledFunctionUnwindInfo, CompiledFunctionUnwindInfo,
18        CompiledFunctionUnwindInfoLike,
19    },
20};
21use rkyv::{
22    Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize, option::ArchivedOption,
23};
24#[cfg(feature = "enable-serde")]
25use serde::{Deserialize, Serialize};
26use wasmer_types::{
27    FunctionIndex, LocalFunctionIndex, SignatureIndex, TrapInformation, entity::PrimaryMap,
28};
29
30/// The frame info for a Compiled function.
31///
32/// This structure is only used for reconstructing
33/// the frame information after a `Trap`.
34#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
35#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
36#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq, Default)]
37#[rkyv(derive(Debug))]
38pub struct CompiledFunctionFrameInfo {
39    /// The traps (in the function body).
40    ///
41    /// Code offsets of the traps MUST be in ascending order.
42    pub traps: Vec<TrapInformation>,
43
44    /// The address map.
45    pub address_map: FunctionAddressMap,
46}
47
48/// The function body.
49#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
50#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
51#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq)]
52#[rkyv(derive(Debug))]
53pub struct FunctionBody {
54    /// The function body bytes.
55    #[cfg_attr(feature = "enable-serde", serde(with = "serde_bytes"))]
56    pub body: Vec<u8>,
57
58    /// The function unwind info
59    pub unwind_info: Option<CompiledFunctionUnwindInfo>,
60}
61
62pub enum CompiledFunctionBody {
63    Rkyv(FunctionBody),
64    Elf(Vec<u8>),
65}
66
67/// Any struct that acts like a `FunctionBody`.
68#[allow(missing_docs)]
69pub trait FunctionBodyLike<'a> {
70    type UnwindInfo: CompiledFunctionUnwindInfoLike<'a>;
71
72    fn body(&'a self) -> &'a [u8];
73    fn unwind_info(&'a self) -> Option<&'a Self::UnwindInfo>;
74}
75
76impl<'a> FunctionBodyLike<'a> for FunctionBody {
77    type UnwindInfo = CompiledFunctionUnwindInfo;
78
79    fn body(&'a self) -> &'a [u8] {
80        self.body.as_ref()
81    }
82
83    fn unwind_info(&'a self) -> Option<&'a Self::UnwindInfo> {
84        self.unwind_info.as_ref()
85    }
86}
87
88impl<'a> FunctionBodyLike<'a> for ArchivedFunctionBody {
89    type UnwindInfo = ArchivedCompiledFunctionUnwindInfo;
90
91    fn body(&'a self) -> &'a [u8] {
92        self.body.as_ref()
93    }
94
95    fn unwind_info(&'a self) -> Option<&'a Self::UnwindInfo> {
96        match self.unwind_info {
97            ArchivedOption::Some(ref x) => Some(x),
98            ArchivedOption::None => None,
99        }
100    }
101}
102
103/// The result of compiling a WebAssembly function.
104///
105/// This structure only have the compiled information data
106/// (function bytecode body, relocations, traps, jump tables
107/// and unwind information).
108#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
109#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq)]
110#[rkyv(derive(Debug))]
111pub struct CompiledFunction {
112    /// The function body.
113    pub body: FunctionBody,
114
115    /// The relocations (in the body)
116    pub relocations: Vec<Relocation>,
117
118    /// The frame information.
119    pub frame_info: CompiledFunctionFrameInfo,
120
121    /// The maximum stack allocation directly connected to the function itself
122    /// if tracked (does not include any potential function calls).
123    pub maximum_stack_usage: Option<usize>,
124}
125
126/// The compiled functions map (index in the Wasm -> function)
127pub type Functions = PrimaryMap<LocalFunctionIndex, CompiledFunction>;
128
129/// The custom sections for a Compilation.
130pub type CustomSections = PrimaryMap<SectionIndex, CustomSection>;
131
132/// The unwinding information for this Compilation.
133///
134/// It is used for retrieving the unwind information once an exception
135/// happens.
136/// In the future this structure may also hold other information useful
137/// for debugging.
138#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
139#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
140#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, PartialEq, Eq, Clone, Default)]
141#[rkyv(derive(Debug), compare(PartialEq))]
142pub struct UnwindInfo {
143    /// The section index in the [`Compilation`] that corresponds to the exception frames.
144    /// [Learn
145    /// more](https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html).
146    pub eh_frame: Option<SectionIndex>,
147    pub compact_unwind: Option<SectionIndex>,
148}
149
150impl UnwindInfo {
151    /// Creates a `Dwarf` struct with the corresponding indices for its sections
152    pub fn new(eh_frame: SectionIndex) -> Self {
153        Self {
154            eh_frame: Some(eh_frame),
155            compact_unwind: None,
156        }
157    }
158
159    pub fn new_cu(compact_unwind: SectionIndex) -> Self {
160        Self {
161            eh_frame: None,
162            compact_unwind: Some(compact_unwind),
163        }
164    }
165}
166
167/// The GOT - Global Offset Table - for this Compilation.
168///
169/// The GOT is but a list of pointers to objects (functions, data, sections..); in our context the
170/// GOT is represented simply as a custom section.
171#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
172#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
173#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, PartialEq, Eq, Clone, Default)]
174#[rkyv(derive(Debug))]
175pub struct GOT {
176    /// The section index in the [`Compilation`] that corresponds to the GOT.
177    pub index: Option<SectionIndex>,
178}
179
180impl GOT {
181    pub fn empty() -> Self {
182        Self { index: None }
183    }
184}
185/// The result of compiling a WebAssembly module's functions.
186#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
187#[derive(Debug, PartialEq, Eq)]
188pub struct RkyvCompilation {
189    /// Compiled code for the function bodies.
190    pub functions: Functions,
191
192    /// Custom sections for the module.
193    /// It will hold the data, for example, for constants used in a
194    /// function, global variables, rodata_64, hot/cold function partitioning, ...
195    pub custom_sections: CustomSections,
196
197    /// Trampolines to call a function defined locally in the wasm via a
198    /// provided `Vec` of values.
199    ///
200    /// This allows us to call easily Wasm functions, such as:
201    ///
202    /// ```ignore
203    /// let func = instance.exports.get_function("my_func");
204    /// func.call(&[Value::I32(1)]);
205    /// ```
206    pub function_call_trampolines: PrimaryMap<SignatureIndex, FunctionBody>,
207
208    /// Trampolines to call a dynamic function defined in
209    /// a host, from a Wasm module.
210    ///
211    /// This allows us to create dynamic Wasm functions, such as:
212    ///
213    /// ```ignore
214    /// fn my_func(values: &[Val]) -> Result<Vec<Val>, RuntimeError> {
215    ///     // do something
216    /// }
217    ///
218    /// let my_func_type = FunctionType::new(vec![Type::I32], vec![Type::I32]);
219    /// let imports = imports!{
220    ///     "namespace" => {
221    ///         "my_func" => Function::new(&store, my_func_type, my_func),
222    ///     }
223    /// }
224    /// ```
225    ///
226    /// Note: Dynamic function trampolines are only compiled for imported function types.
227    pub dynamic_function_trampolines: PrimaryMap<FunctionIndex, FunctionBody>,
228
229    /// Section ids corresponding to the unwind information.
230    pub unwind_info: UnwindInfo,
231
232    /// A reference to the [`GOT`] instance for the compilation.
233    pub got: GOT,
234}
235
236/// The result of compiling a WebAssembly module's functions can be either an RKYV-based data structure
237/// or relocatable ELF image bytes.
238#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
239#[derive(Debug, PartialEq, Eq)]
240pub enum Compilation {
241    Rkyv {
242        compilation: RkyvCompilation,
243        function_max_stack_usage: PrimaryMap<LocalFunctionIndex, Option<usize>>,
244    },
245    Elf {
246        data: Vec<u8>,
247        function_max_stack_usage: PrimaryMap<LocalFunctionIndex, Option<usize>>,
248    },
249}