use crate::error::Result;
use crate::prelude::*;
use crate::{
DefinedFuncIndex, FlagValue, FuncKey, FunctionLoc, ObjectKind, PrimaryMap, StaticModuleIndex,
TripleExt, Tunables, WasmError, WasmFuncType, obj,
};
use object::write::{Object, SymbolId};
use object::{Architecture, BinaryFormat, FileFlags};
use std::any::Any;
use std::borrow::Cow;
use std::fmt;
use std::path;
use std::sync::Arc;
mod address_map;
mod frame_table;
mod module_artifacts;
mod module_environ;
mod module_types;
mod stack_maps;
mod trap_encoding;
pub use self::address_map::*;
pub use self::frame_table::*;
pub use self::module_artifacts::*;
pub use self::module_environ::*;
pub use self::module_types::*;
pub use self::stack_maps::*;
pub use self::trap_encoding::*;
#[derive(Debug)]
pub enum CompileError {
Wasm(WasmError),
Codegen(String),
DebugInfoNotSupported,
}
impl fmt::Display for CompileError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CompileError::Wasm(_) => write!(f, "WebAssembly translation error"),
CompileError::Codegen(s) => write!(f, "Compilation error: {s}"),
CompileError::DebugInfoNotSupported => {
write!(f, "Debug info is not supported with this configuration")
}
}
}
}
impl From<WasmError> for CompileError {
fn from(err: WasmError) -> CompileError {
CompileError::Wasm(err)
}
}
impl core::error::Error for CompileError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
CompileError::Wasm(e) => Some(e),
_ => None,
}
}
}
pub trait CacheStore: Send + Sync + std::fmt::Debug {
fn get(&self, key: &[u8]) -> Option<Cow<'_, [u8]>>;
fn insert(&self, key: &[u8], value: Vec<u8>) -> bool;
}
pub trait CompilerBuilder: Send + Sync + fmt::Debug {
fn target(&mut self, target: target_lexicon::Triple) -> Result<()>;
fn clif_dir(&mut self, _path: &path::Path) -> Result<()> {
bail!("clif output not supported");
}
fn triple(&self) -> &target_lexicon::Triple;
fn set(&mut self, name: &str, val: &str) -> Result<()>;
fn enable(&mut self, name: &str) -> Result<()>;
fn settings(&self) -> Vec<Setting>;
fn enable_incremental_compilation(&mut self, cache_store: Arc<dyn CacheStore>) -> Result<()>;
fn set_tunables(&mut self, tunables: Tunables) -> Result<()>;
fn tunables(&self) -> Option<&Tunables>;
fn build(&self) -> Result<Box<dyn Compiler>>;
fn wmemcheck(&mut self, _enable: bool) {}
}
#[derive(Clone, Copy, Debug)]
pub struct Setting {
pub name: &'static str,
pub description: &'static str,
pub kind: SettingKind,
pub values: Option<&'static [&'static str]>,
}
#[derive(Clone, Copy, Debug)]
pub enum SettingKind {
Enum,
Num,
Bool,
Preset,
}
pub struct CompiledFunctionBody {
pub code: Box<dyn Any + Send + Sync>,
pub needs_gc_heap: bool,
}
pub trait Compiler: Send + Sync {
fn inlining_compiler(&self) -> Option<&dyn InliningCompiler>;
fn compile_function(
&self,
translation: &ModuleTranslation<'_>,
key: FuncKey,
data: FunctionBodyData<'_>,
types: &ModuleTypesBuilder,
symbol: &str,
) -> Result<CompiledFunctionBody, CompileError>;
fn compile_array_to_wasm_trampoline(
&self,
translation: &ModuleTranslation<'_>,
types: &ModuleTypesBuilder,
key: FuncKey,
symbol: &str,
) -> Result<CompiledFunctionBody, CompileError>;
fn compile_wasm_to_array_trampoline(
&self,
wasm_func_ty: &WasmFuncType,
key: FuncKey,
symbol: &str,
) -> Result<CompiledFunctionBody, CompileError>;
fn compile_wasm_to_builtin(
&self,
key: FuncKey,
symbol: &str,
) -> Result<CompiledFunctionBody, CompileError>;
fn compiled_function_relocation_targets<'a>(
&'a self,
func: &'a dyn Any,
) -> Box<dyn Iterator<Item = FuncKey> + 'a>;
fn append_code(
&self,
obj: &mut Object<'static>,
funcs: &[(String, FuncKey, Box<dyn Any + Send + Sync>)],
resolve_reloc: &dyn Fn(usize, FuncKey) -> usize,
) -> Result<Vec<(SymbolId, FunctionLoc)>>;
fn object(&self, kind: ObjectKind) -> Result<Object<'static>> {
use target_lexicon::Architecture::*;
let triple = self.triple();
let (arch, flags) = match triple.architecture {
X86_32(_) => (Architecture::I386, 0),
X86_64 => (Architecture::X86_64, 0),
Arm(_) => (Architecture::Arm, 0),
Aarch64(_) => (Architecture::Aarch64, 0),
S390x => (Architecture::S390x, 0),
Riscv64(_) => (Architecture::Riscv64, 0),
Pulley32 | Pulley32be => (Architecture::Riscv64, obj::EF_WASMTIME_PULLEY32),
Pulley64 | Pulley64be => (Architecture::Riscv64, obj::EF_WASMTIME_PULLEY64),
architecture => {
bail!("target architecture {architecture:?} is unsupported");
}
};
let mut obj = Object::new(
BinaryFormat::Elf,
arch,
match triple.endianness().unwrap() {
target_lexicon::Endianness::Little => object::Endianness::Little,
target_lexicon::Endianness::Big => object::Endianness::Big,
},
);
obj.flags = FileFlags::Elf {
os_abi: obj::ELFOSABI_WASMTIME,
e_flags: flags
| match kind {
ObjectKind::Module => obj::EF_WASMTIME_MODULE,
ObjectKind::Component => obj::EF_WASMTIME_COMPONENT,
},
abi_version: 0,
};
Ok(obj)
}
fn triple(&self) -> &target_lexicon::Triple;
fn page_size_align(&self) -> u64 {
if self.triple().is_pulley() {
return 0x10000;
}
use target_lexicon::*;
match (self.triple().operating_system, self.triple().architecture) {
(
OperatingSystem::MacOSX { .. }
| OperatingSystem::Darwin(_)
| OperatingSystem::IOS(_)
| OperatingSystem::TvOS(_),
Architecture::Aarch64(..),
) => 0x4000,
(_, Architecture::Aarch64(..)) => 0x10000,
_ => 0x1000,
}
}
fn flags(&self) -> Vec<(&'static str, FlagValue<'static>)>;
fn isa_flags(&self) -> Vec<(&'static str, FlagValue<'static>)>;
fn is_branch_protection_enabled(&self) -> bool;
#[cfg(feature = "component-model")]
fn component_compiler(&self) -> &dyn crate::component::ComponentCompiler;
fn append_dwarf<'a>(
&self,
obj: &mut Object<'_>,
translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
get_func: &'a dyn Fn(
StaticModuleIndex,
DefinedFuncIndex,
) -> (SymbolId, &'a (dyn Any + Send + Sync)),
dwarf_package_bytes: Option<&'a [u8]>,
tunables: &'a Tunables,
) -> Result<()>;
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
None
}
}
pub trait InliningCompiler: Sync + Send {
fn calls(&self, func: &CompiledFunctionBody, calls: &mut IndexSet<FuncKey>) -> Result<()>;
fn size(&self, func: &CompiledFunctionBody) -> u32;
fn inline<'a>(
&self,
func: &mut CompiledFunctionBody,
get_callee: &'a mut dyn FnMut(FuncKey) -> Option<&'a CompiledFunctionBody>,
) -> Result<()>;
fn finish_compiling(
&self,
func: &mut CompiledFunctionBody,
input: Option<wasmparser::FunctionBody<'_>>,
symbol: &str,
) -> Result<()>;
}