Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/environ/src/compile/mod.rs
3089 views
1
//! A `Compilation` contains the compiled function bodies for a WebAssembly
2
//! module.
3
4
use crate::error::Result;
5
use crate::prelude::*;
6
use crate::{
7
DefinedFuncIndex, FlagValue, FuncKey, FunctionLoc, ObjectKind, PrimaryMap, StaticModuleIndex,
8
TripleExt, Tunables, WasmError, WasmFuncType, obj,
9
};
10
use object::write::{Object, SymbolId};
11
use object::{Architecture, BinaryFormat, FileFlags};
12
use std::any::Any;
13
use std::borrow::Cow;
14
use std::fmt;
15
use std::path;
16
use std::sync::Arc;
17
18
mod address_map;
19
mod frame_table;
20
mod module_artifacts;
21
mod module_environ;
22
mod module_types;
23
mod stack_maps;
24
mod trap_encoding;
25
26
pub use self::address_map::*;
27
pub use self::frame_table::*;
28
pub use self::module_artifacts::*;
29
pub use self::module_environ::*;
30
pub use self::module_types::*;
31
pub use self::stack_maps::*;
32
pub use self::trap_encoding::*;
33
34
/// An error while compiling WebAssembly to machine code.
35
#[derive(Debug)]
36
pub enum CompileError {
37
/// A wasm translation error occurred.
38
Wasm(WasmError),
39
40
/// A compilation error occurred.
41
Codegen(String),
42
43
/// A compilation error occurred.
44
DebugInfoNotSupported,
45
}
46
47
impl fmt::Display for CompileError {
48
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49
match self {
50
CompileError::Wasm(_) => write!(f, "WebAssembly translation error"),
51
CompileError::Codegen(s) => write!(f, "Compilation error: {s}"),
52
CompileError::DebugInfoNotSupported => {
53
write!(f, "Debug info is not supported with this configuration")
54
}
55
}
56
}
57
}
58
59
impl From<WasmError> for CompileError {
60
fn from(err: WasmError) -> CompileError {
61
CompileError::Wasm(err)
62
}
63
}
64
65
impl core::error::Error for CompileError {
66
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
67
match self {
68
CompileError::Wasm(e) => Some(e),
69
_ => None,
70
}
71
}
72
}
73
74
/// Implementation of an incremental compilation's key/value cache store.
75
///
76
/// In theory, this could just be Cranelift's `CacheKvStore` trait, but it is not as we want to
77
/// make sure that wasmtime isn't too tied to Cranelift internals (and as a matter of fact, we
78
/// can't depend on the Cranelift trait here).
79
pub trait CacheStore: Send + Sync + std::fmt::Debug {
80
/// Try to retrieve an arbitrary cache key entry, and returns a reference to bytes that were
81
/// inserted via `Self::insert` before.
82
fn get(&self, key: &[u8]) -> Option<Cow<'_, [u8]>>;
83
84
/// Given an arbitrary key and bytes, stores them in the cache.
85
///
86
/// Returns false when insertion in the cache failed.
87
fn insert(&self, key: &[u8], value: Vec<u8>) -> bool;
88
}
89
90
/// Abstract trait representing the ability to create a `Compiler` below.
91
///
92
/// This is used in Wasmtime to separate compiler implementations, currently
93
/// mostly used to separate Cranelift from Wasmtime itself.
94
pub trait CompilerBuilder: Send + Sync + fmt::Debug {
95
/// Sets the target of compilation to the target specified.
96
fn target(&mut self, target: target_lexicon::Triple) -> Result<()>;
97
98
/// Enables clif output in the directory specified.
99
fn clif_dir(&mut self, _path: &path::Path) -> Result<()> {
100
bail!("clif output not supported");
101
}
102
103
/// Returns the currently configured target triple that compilation will
104
/// produce artifacts for.
105
fn triple(&self) -> &target_lexicon::Triple;
106
107
/// Compiler-specific method to configure various settings in the compiler
108
/// itself.
109
///
110
/// This is expected to be defined per-compiler. Compilers should return
111
/// errors for unknown names/values.
112
fn set(&mut self, name: &str, val: &str) -> Result<()>;
113
114
/// Compiler-specific method for configuring settings.
115
///
116
/// Same as [`CompilerBuilder::set`] except for enabling boolean flags.
117
/// Currently cranelift uses this to sometimes enable a family of settings.
118
fn enable(&mut self, name: &str) -> Result<()>;
119
120
/// Returns a list of all possible settings that can be configured with
121
/// [`CompilerBuilder::set`] and [`CompilerBuilder::enable`].
122
fn settings(&self) -> Vec<Setting>;
123
124
/// Enables Cranelift's incremental compilation cache, using the given `CacheStore`
125
/// implementation.
126
///
127
/// This will return an error if the compiler does not support incremental compilation.
128
fn enable_incremental_compilation(&mut self, cache_store: Arc<dyn CacheStore>) -> Result<()>;
129
130
/// Set the tunables for this compiler.
131
fn set_tunables(&mut self, tunables: Tunables) -> Result<()>;
132
133
/// Get the tunables used by this compiler.
134
fn tunables(&self) -> Option<&Tunables>;
135
136
/// Builds a new [`Compiler`] object from this configuration.
137
fn build(&self) -> Result<Box<dyn Compiler>>;
138
139
/// Enables or disables wmemcheck during runtime according to the wmemcheck CLI flag.
140
fn wmemcheck(&mut self, _enable: bool) {}
141
}
142
143
/// Description of compiler settings returned by [`CompilerBuilder::settings`].
144
#[derive(Clone, Copy, Debug)]
145
pub struct Setting {
146
/// The name of the setting.
147
pub name: &'static str,
148
/// The description of the setting.
149
pub description: &'static str,
150
/// The kind of the setting.
151
pub kind: SettingKind,
152
/// The supported values of the setting (for enum values).
153
pub values: Option<&'static [&'static str]>,
154
}
155
156
/// Different kinds of [`Setting`] values that can be configured in a
157
/// [`CompilerBuilder`]
158
#[derive(Clone, Copy, Debug)]
159
pub enum SettingKind {
160
/// The setting is an enumeration, meaning it's one of a set of values.
161
Enum,
162
/// The setting is a number.
163
Num,
164
/// The setting is a boolean.
165
Bool,
166
/// The setting is a preset.
167
Preset,
168
}
169
170
/// The result of compiling a single function body.
171
pub struct CompiledFunctionBody {
172
/// The code. This is whatever type the `Compiler` implementation wants it
173
/// to be, we just shepherd it around.
174
pub code: Box<dyn Any + Send + Sync>,
175
/// Whether the compiled function needs a GC heap to run; that is, whether
176
/// it reads a struct field, allocates, an array, or etc...
177
pub needs_gc_heap: bool,
178
}
179
180
/// An implementation of a compiler which can compile WebAssembly functions to
181
/// machine code and perform other miscellaneous tasks needed by the JIT runtime.
182
///
183
/// The diagram below depicts typical usage of this trait:
184
///
185
/// ```text
186
/// +------+
187
/// | Wasm |
188
/// +------+
189
/// |
190
/// |
191
/// Compiler::compile_function()
192
/// |
193
/// |
194
/// V
195
/// +----------------------+
196
/// | CompiledFunctionBody |
197
/// +----------------------+
198
/// | |
199
/// | |
200
/// | When
201
/// | Compiler::inlining_compiler()
202
/// | is some
203
/// | |
204
/// When |
205
/// Compiler::inlining_compiler() |-----------------.
206
/// is none | |
207
/// | | |
208
/// | Optionally call |
209
/// | InliningCompiler::inline() |
210
/// | | |
211
/// | | |
212
/// | |-----------------'
213
/// | |
214
/// | |
215
/// | V
216
/// | InliningCompiler::finish_compiling()
217
/// | |
218
/// | |
219
/// |------------------'
220
/// |
221
/// |
222
/// Compiler::append_code()
223
/// |
224
/// |
225
/// V
226
/// +--------+
227
/// | Object |
228
/// +--------+
229
/// ```
230
pub trait Compiler: Send + Sync {
231
/// Get this compiler's inliner.
232
///
233
/// Consumers of this trait **must** check for when when this method returns
234
/// `Some(_)`, and **must** call `InliningCompiler::finish_compiling` on all
235
/// `CompiledFunctionBody`s produced by this compiler in that case before
236
/// passing the the compiled functions to `Compiler::append_code`, even if
237
/// the consumer does not actually intend to do any inlining. This allows
238
/// implementations of the trait to only translate to an internal
239
/// representation in `Compiler::compile_*` methods so that they can then
240
/// perform inlining afterwards if the consumer desires, and then finally
241
/// proceed with compilng that internal representation to native code in
242
/// `InliningCompiler::finish_compiling`.
243
fn inlining_compiler(&self) -> Option<&dyn InliningCompiler>;
244
245
/// Compiles the function `index` within `translation`.
246
///
247
/// The body of the function is available in `data` and configuration
248
/// values are also passed in via `tunables`. Type information in
249
/// `translation` is all relative to `types`.
250
fn compile_function(
251
&self,
252
translation: &ModuleTranslation<'_>,
253
key: FuncKey,
254
data: FunctionBodyData<'_>,
255
types: &ModuleTypesBuilder,
256
symbol: &str,
257
) -> Result<CompiledFunctionBody, CompileError>;
258
259
/// Compile a trampoline for an array-call host function caller calling the
260
/// `index`th Wasm function.
261
///
262
/// The trampoline should save the necessary state to record the
263
/// host-to-Wasm transition (e.g. registers used for fast stack walking).
264
fn compile_array_to_wasm_trampoline(
265
&self,
266
translation: &ModuleTranslation<'_>,
267
types: &ModuleTypesBuilder,
268
key: FuncKey,
269
symbol: &str,
270
) -> Result<CompiledFunctionBody, CompileError>;
271
272
/// Compile a trampoline for a Wasm caller calling a array callee with the
273
/// given signature.
274
///
275
/// The trampoline should save the necessary state to record the
276
/// Wasm-to-host transition (e.g. registers used for fast stack walking).
277
fn compile_wasm_to_array_trampoline(
278
&self,
279
wasm_func_ty: &WasmFuncType,
280
key: FuncKey,
281
symbol: &str,
282
) -> Result<CompiledFunctionBody, CompileError>;
283
284
/// Creates a trampoline that can be used to call Wasmtime's implementation
285
/// of the builtin function specified by `index`.
286
///
287
/// The trampoline created can technically have any ABI but currently has
288
/// the native ABI. This will then perform all the necessary duties of an
289
/// exit trampoline from wasm and then perform the actual dispatch to the
290
/// builtin function. Builtin functions in Wasmtime are stored in an array
291
/// in all `VMContext` pointers, so the call to the host is an indirect
292
/// call.
293
fn compile_wasm_to_builtin(
294
&self,
295
key: FuncKey,
296
symbol: &str,
297
) -> Result<CompiledFunctionBody, CompileError>;
298
299
/// Returns the list of relocations required for a function from one of the
300
/// previous `compile_*` functions above.
301
fn compiled_function_relocation_targets<'a>(
302
&'a self,
303
func: &'a dyn Any,
304
) -> Box<dyn Iterator<Item = FuncKey> + 'a>;
305
306
/// Appends a list of compiled functions to an in-memory object.
307
///
308
/// This function will receive the same `Box<dyn Any>` produced as part of
309
/// compilation from functions like `compile_function`,
310
/// `compile_host_to_wasm_trampoline`, and other component-related shims.
311
/// Internally this will take all of these functions and add information to
312
/// the object such as:
313
///
314
/// * Compiled code in a `.text` section
315
/// * Unwind information in Wasmtime-specific sections
316
/// * Relocations, if necessary, for the text section
317
///
318
/// Each function is accompanied with its desired symbol name and the return
319
/// value of this function is the symbol for each function as well as where
320
/// each function was placed within the object.
321
///
322
/// The `resolve_reloc` argument is intended to resolving relocations
323
/// between function, chiefly resolving intra-module calls within one core
324
/// wasm module. The closure here takes two arguments:
325
///
326
/// 1. First, the index within `funcs` that is being resolved,
327
///
328
/// 2. and next the `RelocationTarget` which is the relocation target to
329
/// resolve.
330
///
331
/// The return value is an index within `funcs` that the relocation points
332
/// to.
333
fn append_code(
334
&self,
335
obj: &mut Object<'static>,
336
funcs: &[(String, FuncKey, Box<dyn Any + Send + Sync>)],
337
resolve_reloc: &dyn Fn(usize, FuncKey) -> usize,
338
) -> Result<Vec<(SymbolId, FunctionLoc)>>;
339
340
/// Creates a new `Object` file which is used to build the results of a
341
/// compilation into.
342
///
343
/// The returned object file will have an appropriate
344
/// architecture/endianness for `self.triple()`, but at this time it is
345
/// always an ELF file, regardless of target platform.
346
fn object(&self, kind: ObjectKind) -> Result<Object<'static>> {
347
use target_lexicon::Architecture::*;
348
349
let triple = self.triple();
350
let (arch, flags) = match triple.architecture {
351
X86_32(_) => (Architecture::I386, 0),
352
X86_64 => (Architecture::X86_64, 0),
353
Arm(_) => (Architecture::Arm, 0),
354
Aarch64(_) => (Architecture::Aarch64, 0),
355
S390x => (Architecture::S390x, 0),
356
Riscv64(_) => (Architecture::Riscv64, 0),
357
// XXX: the `object` crate won't successfully build an object
358
// with relocations and such if it doesn't know the
359
// architecture, so just pretend we are riscv64. Yolo!
360
//
361
// Also note that we add some flags to `e_flags` in the object file
362
// to indicate that it's pulley, not actually riscv64. This is used
363
// by `wasmtime objdump` for example.
364
Pulley32 | Pulley32be => (Architecture::Riscv64, obj::EF_WASMTIME_PULLEY32),
365
Pulley64 | Pulley64be => (Architecture::Riscv64, obj::EF_WASMTIME_PULLEY64),
366
architecture => {
367
bail!("target architecture {architecture:?} is unsupported");
368
}
369
};
370
let mut obj = Object::new(
371
BinaryFormat::Elf,
372
arch,
373
match triple.endianness().unwrap() {
374
target_lexicon::Endianness::Little => object::Endianness::Little,
375
target_lexicon::Endianness::Big => object::Endianness::Big,
376
},
377
);
378
obj.flags = FileFlags::Elf {
379
os_abi: obj::ELFOSABI_WASMTIME,
380
e_flags: flags
381
| match kind {
382
ObjectKind::Module => obj::EF_WASMTIME_MODULE,
383
ObjectKind::Component => obj::EF_WASMTIME_COMPONENT,
384
},
385
abi_version: 0,
386
};
387
Ok(obj)
388
}
389
390
/// Returns the target triple that this compiler is compiling for.
391
fn triple(&self) -> &target_lexicon::Triple;
392
393
/// Returns the alignment necessary to align values to the page size of the
394
/// compilation target. Note that this may be an upper-bound where the
395
/// alignment is larger than necessary for some platforms since it may
396
/// depend on the platform's runtime configuration.
397
fn page_size_align(&self) -> u64 {
398
// Conservatively assume the max-of-all-supported-hosts for pulley
399
// and round up to 64k.
400
if self.triple().is_pulley() {
401
return 0x10000;
402
}
403
404
use target_lexicon::*;
405
match (self.triple().operating_system, self.triple().architecture) {
406
(
407
OperatingSystem::MacOSX { .. }
408
| OperatingSystem::Darwin(_)
409
| OperatingSystem::IOS(_)
410
| OperatingSystem::TvOS(_),
411
Architecture::Aarch64(..),
412
) => 0x4000,
413
// 64 KB is the maximal page size (i.e. memory translation granule size)
414
// supported by the architecture and is used on some platforms.
415
(_, Architecture::Aarch64(..)) => 0x10000,
416
_ => 0x1000,
417
}
418
}
419
420
/// Returns a list of configured settings for this compiler.
421
fn flags(&self) -> Vec<(&'static str, FlagValue<'static>)>;
422
423
/// Same as [`Compiler::flags`], but ISA-specific (a cranelift-ism)
424
fn isa_flags(&self) -> Vec<(&'static str, FlagValue<'static>)>;
425
426
/// Get a flag indicating whether branch protection is enabled.
427
fn is_branch_protection_enabled(&self) -> bool;
428
429
/// Returns a suitable compiler usable for component-related compilations.
430
///
431
/// Note that the `ComponentCompiler` trait can also be implemented for
432
/// `Self` in which case this function would simply return `self`.
433
#[cfg(feature = "component-model")]
434
fn component_compiler(&self) -> &dyn crate::component::ComponentCompiler;
435
436
/// Appends generated DWARF sections to the `obj` specified.
437
///
438
/// The `translations` track all compiled functions and `get_func` can be
439
/// used to acquire the metadata for a particular function within a module.
440
fn append_dwarf<'a>(
441
&self,
442
obj: &mut Object<'_>,
443
translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
444
get_func: &'a dyn Fn(
445
StaticModuleIndex,
446
DefinedFuncIndex,
447
) -> (SymbolId, &'a (dyn Any + Send + Sync)),
448
dwarf_package_bytes: Option<&'a [u8]>,
449
tunables: &'a Tunables,
450
) -> Result<()>;
451
452
/// Creates a new System V Common Information Entry for the ISA.
453
///
454
/// Returns `None` if the ISA does not support System V unwind information.
455
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
456
// By default, an ISA cannot create a System V CIE.
457
None
458
}
459
}
460
461
/// An inlining compiler.
462
pub trait InliningCompiler: Sync + Send {
463
/// Enumerate the function calls that the given `func` makes.
464
fn calls(&self, func: &CompiledFunctionBody, calls: &mut IndexSet<FuncKey>) -> Result<()>;
465
466
/// Get the abstract size of the given function, for the purposes of
467
/// inlining heuristics.
468
fn size(&self, func: &CompiledFunctionBody) -> u32;
469
470
/// Process this function for inlining.
471
///
472
/// Implementations should call `get_callee` for each of their direct
473
/// function call sites and if `get_callee` returns `Some(_)`, they should
474
/// inline the given function body into that call site.
475
fn inline<'a>(
476
&self,
477
func: &mut CompiledFunctionBody,
478
get_callee: &'a mut dyn FnMut(FuncKey) -> Option<&'a CompiledFunctionBody>,
479
) -> Result<()>;
480
481
/// Finish compiling the given function.
482
///
483
/// This method **must** be called before passing the
484
/// `CompiledFunctionBody`'s contents to `Compiler::append_code`, even if no
485
/// inlining was performed.
486
fn finish_compiling(
487
&self,
488
func: &mut CompiledFunctionBody,
489
input: Option<wasmparser::FunctionBody<'_>>,
490
symbol: &str,
491
) -> Result<()>;
492
}
493
494