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}