Skip to main content

wasmer_compiler_singlepass/
config.rs

1// Allow unused imports while developing
2#![allow(unused_imports, dead_code)]
3
4use crate::{compiler::SinglepassCompiler, machine::AssemblyComment};
5use std::{
6    collections::HashMap,
7    fs::File,
8    io::{self, Write},
9    num::NonZero,
10    path::PathBuf,
11    sync::Arc,
12};
13use target_lexicon::Architecture;
14use wasmer_compiler::{
15    Compiler, CompilerConfig, Debugger, Engine, EngineBuilder, ModuleMiddleware,
16    misc::{CompiledKind, function_kind_to_filename, save_assembly_to_file},
17};
18use wasmer_types::{
19    Features,
20    target::{CpuFeature, Target},
21};
22
23/// Callbacks to the different Cranelift compilation phases.
24#[derive(Debug, Clone)]
25pub struct SinglepassCallbacks {
26    debug_dir: PathBuf,
27}
28
29impl SinglepassCallbacks {
30    /// Creates a new instance of `SinglepassCallbacks` with the specified debug directory.
31    pub fn new(debug_dir: PathBuf) -> Result<Self, io::Error> {
32        // Create the debug dir in case it doesn't exist
33        std::fs::create_dir_all(&debug_dir)?;
34        Ok(Self { debug_dir })
35    }
36
37    /// Returns the debug directory used to dump compilation artifacts.
38    pub fn debug_dir(&self) -> &PathBuf {
39        &self.debug_dir
40    }
41
42    fn base_path(&self, module_hash: &Option<String>) -> PathBuf {
43        let mut path = self.debug_dir.clone();
44        if let Some(hash) = module_hash {
45            path.push(hash);
46        }
47        std::fs::create_dir_all(&path)
48            .unwrap_or_else(|_| panic!("cannot create debug directory: {}", path.display()));
49        path
50    }
51
52    /// Writes the object file memory buffer to a debug file.
53    pub fn obj_memory_buffer(
54        &self,
55        kind: &CompiledKind,
56        module_hash: &Option<String>,
57        mem_buffer: &[u8],
58    ) {
59        let mut path = self.base_path(module_hash);
60        path.push(function_kind_to_filename(kind, ".o"));
61        let mut file =
62            File::create(path).expect("Error while creating debug file from Cranelift object");
63        file.write_all(mem_buffer).unwrap();
64    }
65
66    /// Writes the assembly memory buffer to a debug file.
67    pub fn asm_memory_buffer(
68        &self,
69        kind: &CompiledKind,
70        module_hash: &Option<String>,
71        arch: Architecture,
72        mem_buffer: &[u8],
73        assembly_comments: HashMap<usize, AssemblyComment>,
74    ) -> Result<(), wasmer_types::CompileError> {
75        let mut path = self.base_path(module_hash);
76        path.push(function_kind_to_filename(kind, ".s"));
77        save_assembly_to_file(arch, path, mem_buffer, assembly_comments)
78    }
79}
80
81#[derive(Debug, Clone)]
82pub struct Singlepass {
83    pub(crate) enable_nan_canonicalization: bool,
84    pub(crate) allow_experimental_unaligned_memory_accesses: bool,
85    pub(crate) debugger: Option<Debugger>,
86    pub(crate) experimental_artifact: bool,
87
88    /// The middleware chain.
89    pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>,
90
91    pub(crate) callbacks: Option<SinglepassCallbacks>,
92
93    /// The number of threads to use for compilation.
94    pub num_threads: NonZero<usize>,
95}
96
97impl Singlepass {
98    /// Creates a new configuration object with the default configuration
99    /// specified.
100    pub fn new() -> Self {
101        Self {
102            enable_nan_canonicalization: true,
103            allow_experimental_unaligned_memory_accesses: false,
104            debugger: None,
105            experimental_artifact: false,
106            middlewares: vec![],
107            callbacks: None,
108            num_threads: std::thread::available_parallelism().unwrap_or(NonZero::new(1).unwrap()),
109        }
110    }
111
112    /// Enable the experimental artifact format.
113    pub fn experimental_artifact(&mut self, enable: bool) -> &mut Self {
114        self.experimental_artifact = enable;
115        self
116    }
117
118    pub fn canonicalize_nans(&mut self, enable: bool) -> &mut Self {
119        self.enable_nan_canonicalization = enable;
120        self
121    }
122
123    /// Enable run-time handling of potentially unaligned memory accesses.
124    /// Unaligned memory accesses occur when you try to read N bytes of data starting
125    /// from an address that is not evenly divisible by N.
126    ///
127    /// This feature is experimental and currently supports only Cranelift scalar types
128    /// and Singlepass on RISC-V for integral types.
129    pub fn allow_experimental_unaligned_memory_accesses(&mut self, enable: bool) -> &mut Self {
130        self.allow_experimental_unaligned_memory_accesses = enable;
131        self
132    }
133
134    /// Callbacks that will triggered in the different compilation
135    /// phases in Singlepass.
136    pub fn callbacks(&mut self, callbacks: Option<SinglepassCallbacks>) -> &mut Self {
137        self.callbacks = callbacks;
138        self
139    }
140
141    /// Set the number of threads to use for compilation.
142    pub fn num_threads(&mut self, num_threads: NonZero<usize>) -> &mut Self {
143        self.num_threads = num_threads;
144        self
145    }
146}
147
148impl CompilerConfig for Singlepass {
149    fn experimental_artifact(&mut self, enable: bool) {
150        self.experimental_artifact = enable;
151    }
152
153    fn enable_pic(&mut self) {
154        // Do nothing, since singlepass already emits
155        // PIC code.
156    }
157
158    fn enable_debugger(&mut self, debugger: Debugger) {
159        self.debugger = Some(debugger);
160    }
161
162    /// Transform it into the compiler
163    fn compiler(self: Box<Self>) -> Box<dyn Compiler> {
164        Box::new(SinglepassCompiler::new(*self))
165    }
166
167    /// Gets the supported features for this compiler in the given target
168    fn supported_features_for_target(&self, _target: &Target) -> Features {
169        Features::default()
170    }
171
172    /// Pushes a middleware onto the back of the middleware chain.
173    fn push_middleware(&mut self, middleware: Arc<dyn ModuleMiddleware>) {
174        self.middlewares.push(middleware);
175    }
176}
177
178impl Default for Singlepass {
179    fn default() -> Singlepass {
180        Self::new()
181    }
182}
183
184impl From<Singlepass> for Engine {
185    fn from(config: Singlepass) -> Self {
186        EngineBuilder::new(config).engine()
187    }
188}