This commit makes the following changes to unwind information generation in Cranelift: * Remove frame layout change implementation in favor of processing the prologue and epilogue instructions when unwind information is requested. This also means this work is no longer performed for Windows, which didn't utilize it. It also helps simplify the prologue and epilogue generation code. * Remove the unwind sink implementation that required each unwind information to be represented in final form. For FDEs, this meant writing a complete frame table per function, which wastes 20 bytes or so for each function with duplicate CIEs. This also enables Cranelift users to collect the unwind information and write it as a single frame table. * For System V calling convention, the unwind information is no longer stored in code memory (it's only a requirement for Windows ABI to do so). This allows for more compact code memory for modules with a lot of functions. * Deletes some duplicate code relating to frame table generation. Users can now simply use gimli to create a frame table from each function's unwind information. Fixes #1181.
172 lines
5.3 KiB
Rust
172 lines
5.3 KiB
Rust
//! A `Compilation` contains the compiled function bodies for a WebAssembly
|
|
//! module.
|
|
|
|
use crate::cache::ModuleCacheDataTupleType;
|
|
use crate::CacheConfig;
|
|
use crate::ModuleTranslation;
|
|
use cranelift_codegen::{binemit, ir, isa, isa::unwind::UnwindInfo};
|
|
use cranelift_entity::PrimaryMap;
|
|
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, WasmError};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::ops::Range;
|
|
use thiserror::Error;
|
|
|
|
/// Compiled function: machine code body, jump table offsets, and unwind information.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
|
pub struct CompiledFunction {
|
|
/// The function body.
|
|
pub body: Vec<u8>,
|
|
|
|
/// The jump tables offsets (in the body).
|
|
pub jt_offsets: ir::JumpTableOffsets,
|
|
|
|
/// The unwind information.
|
|
pub unwind_info: Option<UnwindInfo>,
|
|
}
|
|
|
|
type Functions = PrimaryMap<DefinedFuncIndex, CompiledFunction>;
|
|
|
|
/// The result of compiling a WebAssembly module's functions.
|
|
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
|
|
pub struct Compilation {
|
|
/// Compiled machine code for the function bodies.
|
|
functions: Functions,
|
|
}
|
|
|
|
impl Compilation {
|
|
/// Creates a compilation artifact from a contiguous function buffer and a set of ranges
|
|
pub fn new(functions: Functions) -> Self {
|
|
Self { functions }
|
|
}
|
|
|
|
/// Allocates the compilation result with the given function bodies.
|
|
pub fn from_buffer(
|
|
buffer: Vec<u8>,
|
|
functions: impl IntoIterator<Item = (Range<usize>, ir::JumpTableOffsets)>,
|
|
) -> Self {
|
|
Self::new(
|
|
functions
|
|
.into_iter()
|
|
.map(|(body_range, jt_offsets)| CompiledFunction {
|
|
body: buffer[body_range].to_vec(),
|
|
jt_offsets,
|
|
unwind_info: None, // not implemented for lightbeam currently
|
|
})
|
|
.collect(),
|
|
)
|
|
}
|
|
|
|
/// Gets the bytes of a single function
|
|
pub fn get(&self, func: DefinedFuncIndex) -> &CompiledFunction {
|
|
&self.functions[func]
|
|
}
|
|
|
|
/// Gets the number of functions defined.
|
|
pub fn len(&self) -> usize {
|
|
self.functions.len()
|
|
}
|
|
|
|
/// Returns whether there are no functions defined.
|
|
pub fn is_empty(&self) -> bool {
|
|
self.functions.is_empty()
|
|
}
|
|
|
|
/// Gets functions jump table offsets.
|
|
pub fn get_jt_offsets(&self) -> PrimaryMap<DefinedFuncIndex, ir::JumpTableOffsets> {
|
|
self.functions
|
|
.iter()
|
|
.map(|(_, func)| func.jt_offsets.clone())
|
|
.collect::<PrimaryMap<DefinedFuncIndex, _>>()
|
|
}
|
|
}
|
|
|
|
impl<'a> IntoIterator for &'a Compilation {
|
|
type IntoIter = Iter<'a>;
|
|
type Item = <Self::IntoIter as Iterator>::Item;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
Iter {
|
|
iterator: self.functions.iter(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Iter<'a> {
|
|
iterator: <&'a Functions as IntoIterator>::IntoIter,
|
|
}
|
|
|
|
impl<'a> Iterator for Iter<'a> {
|
|
type Item = &'a CompiledFunction;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
self.iterator.next().map(|(_, b)| b)
|
|
}
|
|
}
|
|
|
|
/// A record of a relocation to perform.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
|
pub struct Relocation {
|
|
/// The relocation code.
|
|
pub reloc: binemit::Reloc,
|
|
/// Relocation target.
|
|
pub reloc_target: RelocationTarget,
|
|
/// The offset where to apply the relocation.
|
|
pub offset: binemit::CodeOffset,
|
|
/// The addend to add to the relocation value.
|
|
pub addend: binemit::Addend,
|
|
}
|
|
|
|
/// Destination function. Can be either user function or some special one, like `memory.grow`.
|
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
|
|
pub enum RelocationTarget {
|
|
/// The user function index.
|
|
UserFunc(FuncIndex),
|
|
/// A compiler-generated libcall.
|
|
LibCall(ir::LibCall),
|
|
/// Jump table index.
|
|
JumpTable(FuncIndex, ir::JumpTable),
|
|
}
|
|
|
|
/// Relocations to apply to function bodies.
|
|
pub type Relocations = PrimaryMap<DefinedFuncIndex, Vec<Relocation>>;
|
|
|
|
/// Information about trap.
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
|
pub struct TrapInformation {
|
|
/// The offset of the trapping instruction in native code. It is relative to the beginning of the function.
|
|
pub code_offset: binemit::CodeOffset,
|
|
/// Location of trapping instruction in WebAssembly binary module.
|
|
pub source_loc: ir::SourceLoc,
|
|
/// Code of the trap.
|
|
pub trap_code: ir::TrapCode,
|
|
}
|
|
|
|
/// Information about traps associated with the functions where the traps are placed.
|
|
pub type Traps = PrimaryMap<DefinedFuncIndex, Vec<TrapInformation>>;
|
|
|
|
/// An error while compiling WebAssembly to machine code.
|
|
#[derive(Error, Debug)]
|
|
pub enum CompileError {
|
|
/// A wasm translation error occured.
|
|
#[error("WebAssembly translation error")]
|
|
Wasm(#[from] WasmError),
|
|
|
|
/// A compilation error occured.
|
|
#[error("Compilation error: {0}")]
|
|
Codegen(String),
|
|
|
|
/// A compilation error occured.
|
|
#[error("Debug info is not supported with this configuration")]
|
|
DebugInfoNotSupported,
|
|
}
|
|
|
|
/// An implementation of a compiler from parsed WebAssembly module to native code.
|
|
pub trait Compiler {
|
|
/// Compile a parsed module with the given `TargetIsa`.
|
|
fn compile_module(
|
|
translation: &ModuleTranslation,
|
|
isa: &dyn isa::TargetIsa,
|
|
cache_config: &CacheConfig,
|
|
) -> Result<ModuleCacheDataTupleType, CompileError>;
|
|
}
|