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, 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    fn base_path(&self, module_hash: &Option<String>) -> PathBuf {
38        let mut path = self.debug_dir.clone();
39        if let Some(hash) = module_hash {
40            path.push(hash);
41        }
42        std::fs::create_dir_all(&path)
43            .unwrap_or_else(|_| panic!("cannot create debug directory: {}", path.display()));
44        path
45    }
46
47    /// Writes the object file memory buffer to a debug file.
48    pub fn obj_memory_buffer(
49        &self,
50        kind: &CompiledKind,
51        module_hash: &Option<String>,
52        mem_buffer: &[u8],
53    ) {
54        let mut path = self.base_path(module_hash);
55        path.push(function_kind_to_filename(kind, ".o"));
56        let mut file =
57            File::create(path).expect("Error while creating debug file from Cranelift object");
58        file.write_all(mem_buffer).unwrap();
59    }
60
61    /// Writes the assembly memory buffer to a debug file.
62    pub fn asm_memory_buffer(
63        &self,
64        kind: &CompiledKind,
65        module_hash: &Option<String>,
66        arch: Architecture,
67        mem_buffer: &[u8],
68        assembly_comments: HashMap<usize, AssemblyComment>,
69    ) -> Result<(), wasmer_types::CompileError> {
70        let mut path = self.base_path(module_hash);
71        path.push(function_kind_to_filename(kind, ".s"));
72        save_assembly_to_file(arch, path, mem_buffer, assembly_comments)
73    }
74}
75
76#[derive(Debug, Clone)]
77pub struct Singlepass {
78    pub(crate) enable_nan_canonicalization: bool,
79
80    /// The middleware chain.
81    pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>,
82
83    pub(crate) callbacks: Option<SinglepassCallbacks>,
84
85    /// The number of threads to use for compilation.
86    pub num_threads: NonZero<usize>,
87}
88
89impl Singlepass {
90    /// Creates a new configuration object with the default configuration
91    /// specified.
92    pub fn new() -> Self {
93        Self {
94            enable_nan_canonicalization: true,
95            middlewares: vec![],
96            callbacks: None,
97            num_threads: std::thread::available_parallelism().unwrap_or(NonZero::new(1).unwrap()),
98        }
99    }
100
101    pub fn canonicalize_nans(&mut self, enable: bool) -> &mut Self {
102        self.enable_nan_canonicalization = enable;
103        self
104    }
105
106    /// Callbacks that will triggered in the different compilation
107    /// phases in Singlepass.
108    pub fn callbacks(&mut self, callbacks: Option<SinglepassCallbacks>) -> &mut Self {
109        self.callbacks = callbacks;
110        self
111    }
112
113    /// Set the number of threads to use for compilation.
114    pub fn num_threads(&mut self, num_threads: NonZero<usize>) -> &mut Self {
115        self.num_threads = num_threads;
116        self
117    }
118}
119
120impl CompilerConfig for Singlepass {
121    fn enable_pic(&mut self) {
122        // Do nothing, since singlepass already emits
123        // PIC code.
124    }
125
126    /// Transform it into the compiler
127    fn compiler(self: Box<Self>) -> Box<dyn Compiler> {
128        Box::new(SinglepassCompiler::new(*self))
129    }
130
131    /// Gets the supported features for this compiler in the given target
132    fn supported_features_for_target(&self, _target: &Target) -> Features {
133        Features::default()
134    }
135
136    /// Pushes a middleware onto the back of the middleware chain.
137    fn push_middleware(&mut self, middleware: Arc<dyn ModuleMiddleware>) {
138        self.middlewares.push(middleware);
139    }
140}
141
142impl Default for Singlepass {
143    fn default() -> Singlepass {
144        Self::new()
145    }
146}
147
148impl From<Singlepass> for Engine {
149    fn from(config: Singlepass) -> Self {
150        EngineBuilder::new(config).engine()
151    }
152}