Skip to main content

wasmtime_internal_cranelift/
builder.rs

1//! Implementation of a "compiler builder" for cranelift
2//!
3//! This module contains the implementation of how Cranelift is configured, as
4//! well as providing a function to return the default configuration to build.
5
6use crate::isa_builder::IsaBuilder;
7use cranelift_codegen::{
8    CodegenResult,
9    isa::{self, OwnedTargetIsa},
10};
11use std::fmt;
12use std::path;
13use std::sync::Arc;
14use target_lexicon::Triple;
15use wasmtime_environ::error::Result;
16use wasmtime_environ::{CacheStore, CompilerBuilder, Setting, Tunables};
17
18struct Builder {
19    tunables: Option<Tunables>,
20    inner: IsaBuilder<CodegenResult<OwnedTargetIsa>>,
21    emit_debug_checks: bool,
22    linkopts: LinkOptions,
23    cache_store: Option<Arc<dyn CacheStore>>,
24    clif_dir: Option<path::PathBuf>,
25    wmemcheck: bool,
26}
27
28#[derive(Clone, Default)]
29pub struct LinkOptions {
30    /// A debug-only setting used to synthetically insert 0-byte padding between
31    /// compiled functions to simulate huge compiled artifacts and exercise
32    /// logic related to jump veneers.
33    pub padding_between_functions: usize,
34
35    /// A debug-only setting used to force inter-function calls in a wasm module
36    /// to always go through "jump veneers" which are typically only generated
37    /// when functions are very far from each other.
38    pub force_jump_veneers: bool,
39}
40
41pub fn builder(triple: Option<Triple>) -> Result<Box<dyn CompilerBuilder>> {
42    let mut builder = Builder {
43        tunables: None,
44        inner: IsaBuilder::new(triple, |triple| isa::lookup(triple).map_err(|e| e.into()))?,
45        linkopts: LinkOptions::default(),
46        cache_store: None,
47        clif_dir: None,
48        wmemcheck: false,
49        emit_debug_checks: false,
50    };
51
52    builder.set("enable_verifier", "false").unwrap();
53    builder.set("opt_level", "speed").unwrap();
54
55    // When running under MIRI try to optimize for compile time of Wasm code
56    // itself as much as possible. Disable optimizations by default and use the
57    // fastest regalloc available to us.
58    if cfg!(miri) {
59        builder.set("opt_level", "none").unwrap();
60        builder.set("regalloc_algorithm", "single_pass").unwrap();
61    }
62
63    Ok(Box::new(builder))
64}
65
66impl CompilerBuilder for Builder {
67    fn triple(&self) -> &target_lexicon::Triple {
68        self.inner.triple()
69    }
70
71    fn clif_dir(&mut self, path: &path::Path) -> Result<()> {
72        self.clif_dir = Some(path.to_path_buf());
73        Ok(())
74    }
75
76    fn target(&mut self, target: target_lexicon::Triple) -> Result<()> {
77        self.inner.target(target)?;
78        Ok(())
79    }
80
81    fn set(&mut self, name: &str, value: &str) -> Result<()> {
82        // Special wasmtime-cranelift-only settings first
83        match name {
84            "wasmtime_linkopt_padding_between_functions" => {
85                self.linkopts.padding_between_functions = value.parse()?;
86            }
87            "wasmtime_linkopt_force_jump_veneer" => {
88                self.linkopts.force_jump_veneers = value.parse()?;
89            }
90            "wasmtime_inlining_intra_module" => {
91                self.tunables.as_mut().unwrap().inlining_intra_module = value.parse()?;
92            }
93            "wasmtime_inlining_small_callee_size" => {
94                self.tunables.as_mut().unwrap().inlining_small_callee_size = value.parse()?;
95            }
96            "wasmtime_inlining_sum_size_threshold" => {
97                self.tunables.as_mut().unwrap().inlining_sum_size_threshold = value.parse()?;
98            }
99            "wasmtime_debug_checks" => {
100                self.emit_debug_checks = true;
101            }
102            _ => {
103                self.inner.set(name, value)?;
104            }
105        }
106        Ok(())
107    }
108
109    fn enable(&mut self, name: &str) -> Result<()> {
110        self.inner.enable(name)
111    }
112
113    fn set_tunables(&mut self, tunables: Tunables) -> Result<()> {
114        self.tunables = Some(tunables);
115        Ok(())
116    }
117
118    fn tunables(&self) -> Option<&Tunables> {
119        self.tunables.as_ref()
120    }
121
122    fn build(&self) -> Result<Box<dyn wasmtime_environ::Compiler>> {
123        let isa = self.inner.build()?;
124        Ok(Box::new(crate::compiler::Compiler::new(
125            self.tunables
126                .as_ref()
127                .expect("set_tunables not called")
128                .clone(),
129            isa,
130            self.cache_store.clone(),
131            self.emit_debug_checks,
132            self.linkopts.clone(),
133            self.clif_dir.clone(),
134            self.wmemcheck,
135        )))
136    }
137
138    fn settings(&self) -> Vec<Setting> {
139        self.inner.settings()
140    }
141
142    fn enable_incremental_compilation(
143        &mut self,
144        cache_store: Arc<dyn wasmtime_environ::CacheStore>,
145    ) -> Result<()> {
146        self.cache_store = Some(cache_store);
147        Ok(())
148    }
149
150    fn wmemcheck(&mut self, enable: bool) {
151        self.wmemcheck = enable;
152    }
153}
154
155impl fmt::Debug for Builder {
156    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157        f.debug_struct("Builder")
158            .field("shared_flags", &self.inner.shared_flags().to_string())
159            .finish()
160    }
161}