use crate::{obj, Tunables};
use crate::{
DefinedFuncIndex, FilePos, FuncIndex, FunctionBodyData, ModuleTranslation, ModuleTypesBuilder,
PrimaryMap, StackMap, WasmError, WasmFuncType,
};
use anyhow::Result;
use object::write::{Object, SymbolId};
use object::{Architecture, BinaryFormat, FileFlags};
use serde_derive::{Deserialize, Serialize};
use std::any::Any;
use std::borrow::Cow;
use std::fmt;
use std::path;
use std::sync::Arc;
use thiserror::Error;
#[derive(Serialize, Deserialize, Default)]
#[allow(missing_docs)]
pub struct WasmFunctionInfo {
pub start_srcloc: FilePos,
pub stack_maps: Box<[StackMapInformation]>,
}
#[derive(Copy, Clone, Serialize, Deserialize)]
pub struct FunctionLoc {
pub start: u32,
pub length: u32,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct StackMapInformation {
pub code_offset: u32,
pub stack_map: StackMap,
}
#[derive(Error, Debug)]
pub enum CompileError {
#[error("WebAssembly translation error")]
Wasm(#[from] WasmError),
#[error("Compilation error: {0}")]
Codegen(String),
#[error("Debug info is not supported with this configuration")]
DebugInfoNotSupported,
}
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<()> {
anyhow::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 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 enum ObjectKind {
Module,
Component,
}
pub trait Compiler: Send + Sync {
fn compile_function(
&self,
translation: &ModuleTranslation<'_>,
index: DefinedFuncIndex,
data: FunctionBodyData<'_>,
types: &ModuleTypesBuilder,
) -> Result<(WasmFunctionInfo, Box<dyn Any + Send>), CompileError>;
fn compile_array_to_wasm_trampoline(
&self,
translation: &ModuleTranslation<'_>,
types: &ModuleTypesBuilder,
index: DefinedFuncIndex,
) -> Result<Box<dyn Any + Send>, CompileError>;
fn compile_native_to_wasm_trampoline(
&self,
translation: &ModuleTranslation<'_>,
types: &ModuleTypesBuilder,
index: DefinedFuncIndex,
) -> Result<Box<dyn Any + Send>, CompileError>;
fn compile_wasm_to_native_trampoline(
&self,
wasm_func_ty: &WasmFuncType,
) -> Result<Box<dyn Any + Send>, CompileError>;
fn append_code(
&self,
obj: &mut Object<'static>,
funcs: &[(String, Box<dyn Any + Send>)],
resolve_reloc: &dyn Fn(usize, FuncIndex) -> usize,
) -> Result<Vec<(SymbolId, FunctionLoc)>>;
fn emit_trampolines_for_array_call_host_func(
&self,
ty: &WasmFuncType,
host_fn: usize,
obj: &mut Object<'static>,
) -> Result<(FunctionLoc, FunctionLoc)>;
fn object(&self, kind: ObjectKind) -> Result<Object<'static>> {
use target_lexicon::Architecture::*;
let triple = self.triple();
let mut obj = Object::new(
BinaryFormat::Elf,
match triple.architecture {
X86_32(_) => Architecture::I386,
X86_64 => Architecture::X86_64,
Arm(_) => Architecture::Arm,
Aarch64(_) => Architecture::Aarch64,
S390x => Architecture::S390x,
Riscv64(_) => Architecture::Riscv64,
architecture => {
anyhow::bail!("target architecture {:?} is unsupported", architecture,);
}
},
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: 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 {
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(
&self,
obj: &mut Object<'_>,
translation: &ModuleTranslation<'_>,
funcs: &PrimaryMap<DefinedFuncIndex, (SymbolId, &(dyn Any + Send))>,
) -> Result<()>;
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
None
}
}
#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
pub enum FlagValue<'a> {
Enum(&'a str),
Num(u8),
Bool(bool),
}
impl fmt::Display for FlagValue<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Enum(v) => v.fmt(f),
Self::Num(v) => v.fmt(f),
Self::Bool(v) => v.fmt(f),
}
}
}