Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/environ/src/tunables.rs
3068 views
1
use crate::prelude::*;
2
use crate::{IndexType, Limits, Memory, TripleExt};
3
use core::{fmt, str::FromStr};
4
use serde_derive::{Deserialize, Serialize};
5
use target_lexicon::{PointerWidth, Triple};
6
7
macro_rules! define_tunables {
8
(
9
$(#[$outer_attr:meta])*
10
pub struct $tunables:ident {
11
$(
12
$(#[$field_attr:meta])*
13
pub $field:ident : $field_ty:ty,
14
)*
15
}
16
17
pub struct $config_tunables:ident {
18
...
19
}
20
) => {
21
$(#[$outer_attr])*
22
pub struct $tunables {
23
$(
24
$(#[$field_attr])*
25
pub $field: $field_ty,
26
)*
27
}
28
29
/// Optional tunable configuration options used in `wasmtime::Config`
30
#[derive(Default, Clone)]
31
#[expect(missing_docs, reason = "macro-generated fields")]
32
pub struct $config_tunables {
33
$(pub $field: Option<$field_ty>,)*
34
}
35
36
impl $config_tunables {
37
/// Formats configured fields into `f`.
38
pub fn format(&self, f: &mut fmt::DebugStruct<'_,'_>) {
39
$(
40
if let Some(val) = &self.$field {
41
f.field(stringify!($field), val);
42
}
43
)*
44
}
45
46
/// Configure the `Tunables` provided.
47
pub fn configure(&self, tunables: &mut Tunables) {
48
$(
49
if let Some(val) = self.$field {
50
tunables.$field = val;
51
}
52
)*
53
}
54
}
55
};
56
}
57
58
define_tunables! {
59
/// Tunable parameters for WebAssembly compilation.
60
#[derive(Clone, Hash, Serialize, Deserialize, Debug)]
61
pub struct Tunables {
62
/// The garbage collector implementation to use, which implies the layout of
63
/// GC objects and barriers that must be emitted in Wasm code.
64
pub collector: Option<Collector>,
65
66
/// Initial size, in bytes, to be allocated for linear memories.
67
pub memory_reservation: u64,
68
69
/// The size, in bytes, of the guard page region for linear memories.
70
pub memory_guard_size: u64,
71
72
/// The size, in bytes, to allocate at the end of a relocated linear
73
/// memory for growth.
74
pub memory_reservation_for_growth: u64,
75
76
/// Whether or not to generate native DWARF debug information.
77
pub debug_native: bool,
78
79
/// Whether we are enabling precise Wasm-level debugging in
80
/// the guest.
81
pub debug_guest: bool,
82
83
/// Whether or not to retain DWARF sections in compiled modules.
84
pub parse_wasm_debuginfo: bool,
85
86
/// Whether or not fuel is enabled for generated code, meaning that fuel
87
/// will be consumed every time a wasm instruction is executed.
88
pub consume_fuel: bool,
89
90
/// Whether or not we use epoch-based interruption.
91
pub epoch_interruption: bool,
92
93
/// Whether or not linear memories are allowed to be reallocated after
94
/// initial allocation at runtime.
95
pub memory_may_move: bool,
96
97
/// Whether or not linear memory allocations will have a guard region at the
98
/// beginning of the allocation in addition to the end.
99
pub guard_before_linear_memory: bool,
100
101
/// Whether to initialize tables lazily, so that instantiation is fast but
102
/// indirect calls are a little slower. If false, tables are initialized
103
/// eagerly from any active element segments that apply to them during
104
/// instantiation.
105
pub table_lazy_init: bool,
106
107
/// Indicates whether an address map from compiled native code back to wasm
108
/// offsets in the original file is generated.
109
pub generate_address_map: bool,
110
111
/// Flag for the component module whether adapter modules have debug
112
/// assertions baked into them.
113
pub debug_adapter_modules: bool,
114
115
/// Whether or not lowerings for relaxed simd instructions are forced to
116
/// be deterministic.
117
pub relaxed_simd_deterministic: bool,
118
119
/// Whether or not Wasm functions target the winch abi.
120
pub winch_callable: bool,
121
122
/// Whether or not the host will be using native signals (e.g. SIGILL,
123
/// SIGSEGV, etc) to implement traps.
124
pub signals_based_traps: bool,
125
126
/// Whether CoW images might be used to initialize linear memories.
127
pub memory_init_cow: bool,
128
129
/// Whether to enable inlining in Wasmtime's compilation orchestration
130
/// or not.
131
pub inlining: bool,
132
133
/// Whether to inline calls within the same core Wasm module or not.
134
pub inlining_intra_module: IntraModuleInlining,
135
136
/// The size of "small callees" that can be inlined regardless of the
137
/// caller's size.
138
pub inlining_small_callee_size: u32,
139
140
/// The general size threshold for the sum of the caller's and callee's
141
/// sizes, past which we will generally not inline calls anymore.
142
pub inlining_sum_size_threshold: u32,
143
144
/// Whether any component model feature related to concurrency is
145
/// enabled.
146
pub concurrency_support: bool,
147
}
148
149
pub struct ConfigTunables {
150
...
151
}
152
}
153
154
impl Tunables {
155
/// Returns a `Tunables` configuration assumed for running code on the host.
156
pub fn default_host() -> Self {
157
if cfg!(miri) {
158
Tunables::default_miri()
159
} else if cfg!(target_pointer_width = "32") {
160
Tunables::default_u32()
161
} else if cfg!(target_pointer_width = "64") {
162
Tunables::default_u64()
163
} else {
164
panic!("unsupported target_pointer_width");
165
}
166
}
167
168
/// Returns the default set of tunables for the given target triple.
169
pub fn default_for_target(target: &Triple) -> Result<Self> {
170
if cfg!(miri) {
171
return Ok(Tunables::default_miri());
172
}
173
let mut ret = match target
174
.pointer_width()
175
.map_err(|_| format_err!("failed to retrieve target pointer width"))?
176
{
177
PointerWidth::U32 => Tunables::default_u32(),
178
PointerWidth::U64 => Tunables::default_u64(),
179
_ => bail!("unsupported target pointer width"),
180
};
181
182
// Pulley targets never use signals-based-traps and also can't benefit
183
// from guard pages, so disable them.
184
if target.is_pulley() {
185
ret.signals_based_traps = false;
186
ret.memory_guard_size = 0;
187
}
188
Ok(ret)
189
}
190
191
/// Returns the default set of tunables for running under MIRI.
192
pub const fn default_miri() -> Tunables {
193
Tunables {
194
collector: None,
195
196
// No virtual memory tricks are available on miri so make these
197
// limits quite conservative.
198
memory_reservation: 1 << 20,
199
memory_guard_size: 0,
200
memory_reservation_for_growth: 0,
201
202
// General options which have the same defaults regardless of
203
// architecture.
204
debug_native: false,
205
parse_wasm_debuginfo: true,
206
consume_fuel: false,
207
epoch_interruption: false,
208
memory_may_move: true,
209
guard_before_linear_memory: true,
210
table_lazy_init: true,
211
generate_address_map: true,
212
debug_adapter_modules: false,
213
relaxed_simd_deterministic: false,
214
winch_callable: false,
215
signals_based_traps: false,
216
memory_init_cow: true,
217
inlining: false,
218
inlining_intra_module: IntraModuleInlining::WhenUsingGc,
219
inlining_small_callee_size: 50,
220
inlining_sum_size_threshold: 2000,
221
debug_guest: false,
222
concurrency_support: true,
223
}
224
}
225
226
/// Returns the default set of tunables for running under a 32-bit host.
227
pub const fn default_u32() -> Tunables {
228
Tunables {
229
// For 32-bit we scale way down to 10MB of reserved memory. This
230
// impacts performance severely but allows us to have more than a
231
// few instances running around.
232
memory_reservation: 10 * (1 << 20),
233
memory_guard_size: 0x1_0000,
234
memory_reservation_for_growth: 1 << 20, // 1MB
235
signals_based_traps: true,
236
237
..Tunables::default_miri()
238
}
239
}
240
241
/// Returns the default set of tunables for running under a 64-bit host.
242
pub const fn default_u64() -> Tunables {
243
Tunables {
244
// 64-bit has tons of address space to static memories can have 4gb
245
// address space reservations liberally by default, allowing us to
246
// help eliminate bounds checks.
247
//
248
// A 32MiB default guard size is then allocated so we can remove
249
// explicit bounds checks if any static offset is less than this
250
// value. SpiderMonkey found, for example, that in a large corpus of
251
// wasm modules 20MiB was the maximum offset so this is the
252
// power-of-two-rounded up from that and matches SpiderMonkey.
253
memory_reservation: 1 << 32,
254
memory_guard_size: 32 << 20,
255
256
// We've got lots of address space on 64-bit so use a larger
257
// grow-into-this area, but on 32-bit we aren't as lucky. Miri is
258
// not exactly fast so reduce memory consumption instead of trying
259
// to avoid memory movement.
260
memory_reservation_for_growth: 2 << 30, // 2GB
261
262
signals_based_traps: true,
263
..Tunables::default_miri()
264
}
265
}
266
267
/// Get the GC heap's memory type, given our configured tunables.
268
pub fn gc_heap_memory_type(&self) -> Memory {
269
Memory {
270
idx_type: IndexType::I32,
271
limits: Limits { min: 0, max: None },
272
shared: false,
273
// We *could* try to match the target architecture's page size, but that
274
// would require exercising a page size for memories that we don't
275
// otherwise support for Wasm; we conservatively avoid that, and just
276
// use the default Wasm page size, for now.
277
page_size_log2: 16,
278
}
279
}
280
}
281
282
/// The garbage collector implementation to use.
283
#[derive(Clone, Copy, Hash, Serialize, Deserialize, Debug, PartialEq, Eq)]
284
pub enum Collector {
285
/// The deferred reference-counting collector.
286
DeferredReferenceCounting,
287
/// The null collector.
288
Null,
289
}
290
291
impl fmt::Display for Collector {
292
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
293
match self {
294
Collector::DeferredReferenceCounting => write!(f, "deferred reference-counting"),
295
Collector::Null => write!(f, "null"),
296
}
297
}
298
}
299
300
/// Whether to inline function calls within the same module.
301
#[derive(Clone, Copy, Hash, Serialize, Deserialize, Debug, PartialEq, Eq)]
302
#[expect(missing_docs, reason = "self-describing variants")]
303
pub enum IntraModuleInlining {
304
Yes,
305
No,
306
WhenUsingGc,
307
}
308
309
impl FromStr for IntraModuleInlining {
310
type Err = Error;
311
312
fn from_str(s: &str) -> Result<Self, Self::Err> {
313
match s {
314
"y" | "yes" | "true" => Ok(Self::Yes),
315
"n" | "no" | "false" => Ok(Self::No),
316
"gc" => Ok(Self::WhenUsingGc),
317
_ => bail!(
318
"invalid intra-module inlining option string: `{s}`, \
319
only yes,no,gc accepted"
320
),
321
}
322
}
323
}
324
325