unc_vm_compiler/
compiler.rs

1//! This module mainly outputs the `Compiler` trait that custom
2//! compilers will need to implement.
3
4use crate::error::CompileError;
5use crate::function::Compilation;
6use crate::lib::std::boxed::Box;
7use crate::module::CompileModuleInfo;
8use crate::target::Target;
9use crate::FunctionBodyData;
10use crate::ModuleTranslationState;
11use crate::SectionIndex;
12use unc_vm_types::entity::PrimaryMap;
13use unc_vm_types::{Features, FunctionIndex, LocalFunctionIndex, SignatureIndex};
14use wasmparser::{Validator, WasmFeatures};
15
16/// The compiler configuration options.
17pub trait CompilerConfig {
18    /// Enable Position Independent Code (PIC).
19    ///
20    /// This is required for shared object generation (Native Engine),
21    /// but will make the JIT Engine to fail, since PIC is not yet
22    /// supported in the JIT linking phase.
23    fn enable_pic(&mut self) {
24        // By default we do nothing, each backend will need to customize this
25        // in case they do something special for emitting PIC code.
26    }
27
28    /// Enable compiler IR verification.
29    ///
30    /// For compilers capable of doing so, this enables internal consistency
31    /// checking.
32    fn enable_verifier(&mut self) {
33        // By default we do nothing, each backend will need to customize this
34        // in case they create an IR that they can verify.
35    }
36
37    /// Enable NaN canonicalization.
38    ///
39    /// NaN canonicalization is useful when trying to run WebAssembly
40    /// deterministically across different architectures.
41    #[deprecated(note = "Please use the canonicalize_nans instead")]
42    fn enable_nan_canonicalization(&mut self) {
43        // By default we do nothing, each backend will need to customize this
44        // in case they create an IR that they can verify.
45    }
46
47    /// Enable NaN canonicalization.
48    ///
49    /// NaN canonicalization is useful when trying to run WebAssembly
50    /// deterministically across different architectures.
51    fn canonicalize_nans(&mut self, _enable: bool) {
52        // By default we do nothing, each backend will need to customize this
53        // in case they create an IR that they can verify.
54    }
55
56    /// Gets the custom compiler config
57    fn compiler(self: Box<Self>) -> Box<dyn Compiler>;
58
59    /// Gets the default features for this compiler in the given target
60    fn default_features_for_target(&self, _target: &Target) -> Features {
61        Features::default()
62    }
63}
64
65impl<T> From<T> for Box<dyn CompilerConfig + 'static>
66where
67    T: CompilerConfig + 'static,
68{
69    fn from(other: T) -> Self {
70        Box::new(other)
71    }
72}
73
74/// An implementation of a Compiler from parsed WebAssembly module to Compiled native code.
75pub trait Compiler: Send {
76    /// Validates a module.
77    ///
78    /// It returns the a succesful Result in case is valid, `CompileError` in case is not.
79    fn validate_module<'data>(
80        &self,
81        features: &Features,
82        data: &'data [u8],
83    ) -> Result<(), CompileError> {
84        let wasm_features = WasmFeatures {
85            bulk_memory: features.bulk_memory,
86            threads: features.threads,
87            reference_types: features.reference_types,
88            multi_value: features.multi_value,
89            simd: features.simd,
90            tail_call: features.tail_call,
91            multi_memory: features.multi_memory,
92            memory64: features.memory64,
93            exceptions: features.exceptions,
94            floats: true,
95            component_model: false,
96            extended_const: false,
97            mutable_global: features.mutable_global,
98            relaxed_simd: false,
99            saturating_float_to_int: features.saturating_float_to_int,
100            sign_extension: features.sign_extension,
101            memory_control: false,
102        };
103        let mut validator = Validator::new_with_features(wasm_features);
104        validator.validate_all(data).map_err(|e| CompileError::Validate(format!("{}", e)))?;
105        Ok(())
106    }
107
108    /// Compiles a parsed module.
109    ///
110    /// It returns the [`Compilation`] or a [`CompileError`].
111    fn compile_module<'data, 'module>(
112        &self,
113        target: &Target,
114        module: &'module CompileModuleInfo,
115        // The list of function bodies
116        function_body_inputs: PrimaryMap<LocalFunctionIndex, FunctionBodyData<'data>>,
117        tunables: &dyn unc_vm_vm::Tunables,
118        instrumentation: &finite_wasm::AnalysisOutcome,
119    ) -> Result<Compilation, CompileError>;
120
121    /// Compiles a module into a native object file.
122    ///
123    /// It returns the bytes as a `&[u8]` or a [`CompileError`].
124    fn experimental_native_compile_module<'data, 'module>(
125        &self,
126        _target: &Target,
127        _module: &'module CompileModuleInfo,
128        _module_translation: &ModuleTranslationState,
129        // The list of function bodies
130        _function_body_inputs: &PrimaryMap<LocalFunctionIndex, FunctionBodyData<'data>>,
131        _symbol_registry: &dyn SymbolRegistry,
132        // The metadata to inject into the unc_vm_metadata section of the object file.
133        _unc_vm_metadata: &[u8],
134    ) -> Option<Result<Vec<u8>, CompileError>> {
135        None
136    }
137}
138
139/// The kinds of unc_vm_types objects that might be found in a native object file.
140#[derive(Clone, Debug, PartialEq, Eq)]
141pub enum Symbol {
142    /// A function defined in the wasm.
143    LocalFunction(LocalFunctionIndex),
144
145    /// A wasm section.
146    Section(SectionIndex),
147
148    /// The function call trampoline for a given signature.
149    FunctionCallTrampoline(SignatureIndex),
150
151    /// The dynamic function trampoline for a given function.
152    DynamicFunctionTrampoline(FunctionIndex),
153}
154
155/// This trait facilitates symbol name lookups in a native object file.
156pub trait SymbolRegistry: Send + Sync {
157    /// Given a `Symbol` it returns the name for that symbol in the object file
158    fn symbol_to_name(&self, symbol: Symbol) -> String;
159
160    /// Given a name it returns the `Symbol` for that name in the object file
161    ///
162    /// This function is the inverse of [`SymbolRegistry::symbol_to_name`]
163    fn name_to_symbol(&self, name: &str) -> Option<Symbol>;
164}