|
|
|
|
@@ -86,14 +86,13 @@
|
|
|
|
|
// assume no valid stack pointer will ever be `usize::max_value() - 32k`.
|
|
|
|
|
|
|
|
|
|
use crate::address_map::{FunctionAddressMap, InstructionAddressMap};
|
|
|
|
|
use crate::cache::ModuleCacheEntry;
|
|
|
|
|
use crate::compilation::{
|
|
|
|
|
Compilation, CompileError, CompiledFunction, Relocation, RelocationTarget, StackMapInformation,
|
|
|
|
|
TrapInformation,
|
|
|
|
|
};
|
|
|
|
|
use crate::compilation::{CompileResult, Compiler};
|
|
|
|
|
use crate::func_environ::{get_func_name, FuncEnvironment};
|
|
|
|
|
use crate::{CacheConfig, FunctionBodyData, ModuleLocal, ModuleTranslation, Tunables};
|
|
|
|
|
use crate::{FunctionBodyData, ModuleLocal, ModuleTranslation, Tunables};
|
|
|
|
|
use cranelift_codegen::ir::{self, ExternalName};
|
|
|
|
|
use cranelift_codegen::machinst::buffer::MachSrcLoc;
|
|
|
|
|
use cranelift_codegen::print_errors::pretty_error;
|
|
|
|
|
@@ -103,7 +102,6 @@ use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator, ModuleTranslat
|
|
|
|
|
#[cfg(feature = "parallel-compilation")]
|
|
|
|
|
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
use std::hash::{Hash, Hasher};
|
|
|
|
|
|
|
|
|
|
/// Implementation of a relocation sink that just saves all the information for later
|
|
|
|
|
pub struct RelocSink {
|
|
|
|
|
@@ -290,49 +288,45 @@ impl Compiler for Cranelift {
|
|
|
|
|
fn compile_module(
|
|
|
|
|
translation: &ModuleTranslation,
|
|
|
|
|
isa: &dyn isa::TargetIsa,
|
|
|
|
|
cache_config: &CacheConfig,
|
|
|
|
|
) -> Result<CompileResult, CompileError> {
|
|
|
|
|
let cache_entry = ModuleCacheEntry::new("cranelift", cache_config);
|
|
|
|
|
|
|
|
|
|
let result = cache_entry.get_data(
|
|
|
|
|
CompileEnv {
|
|
|
|
|
local: &translation.module.local,
|
|
|
|
|
module_translation: HashedModuleTranslationState(
|
|
|
|
|
translation.module_translation.as_ref().unwrap(),
|
|
|
|
|
),
|
|
|
|
|
function_body_inputs: &translation.function_body_inputs,
|
|
|
|
|
isa: Isa(isa),
|
|
|
|
|
tunables: &translation.tunables,
|
|
|
|
|
},
|
|
|
|
|
compile,
|
|
|
|
|
)?;
|
|
|
|
|
Ok(result)
|
|
|
|
|
compile(
|
|
|
|
|
isa,
|
|
|
|
|
&translation.module.local,
|
|
|
|
|
translation.module_translation.as_ref().unwrap(),
|
|
|
|
|
&translation.function_body_inputs,
|
|
|
|
|
&translation.tunables,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn compile(env: CompileEnv<'_>) -> Result<CompileResult, CompileError> {
|
|
|
|
|
let Isa(isa) = env.isa;
|
|
|
|
|
let mut functions = PrimaryMap::with_capacity(env.function_body_inputs.len());
|
|
|
|
|
let mut relocations = PrimaryMap::with_capacity(env.function_body_inputs.len());
|
|
|
|
|
let mut address_transforms = PrimaryMap::with_capacity(env.function_body_inputs.len());
|
|
|
|
|
let mut value_ranges = PrimaryMap::with_capacity(env.function_body_inputs.len());
|
|
|
|
|
let mut stack_slots = PrimaryMap::with_capacity(env.function_body_inputs.len());
|
|
|
|
|
let mut traps = PrimaryMap::with_capacity(env.function_body_inputs.len());
|
|
|
|
|
let mut stack_maps = PrimaryMap::with_capacity(env.function_body_inputs.len());
|
|
|
|
|
fn compile(
|
|
|
|
|
isa: &dyn isa::TargetIsa,
|
|
|
|
|
local: &ModuleLocal,
|
|
|
|
|
module_translation: &ModuleTranslationState,
|
|
|
|
|
function_body_inputs: &PrimaryMap<DefinedFuncIndex, FunctionBodyData<'_>>,
|
|
|
|
|
tunables: &Tunables,
|
|
|
|
|
) -> Result<CompileResult, CompileError> {
|
|
|
|
|
let mut functions = PrimaryMap::with_capacity(function_body_inputs.len());
|
|
|
|
|
let mut relocations = PrimaryMap::with_capacity(function_body_inputs.len());
|
|
|
|
|
let mut address_transforms = PrimaryMap::with_capacity(function_body_inputs.len());
|
|
|
|
|
let mut value_ranges = PrimaryMap::with_capacity(function_body_inputs.len());
|
|
|
|
|
let mut stack_slots = PrimaryMap::with_capacity(function_body_inputs.len());
|
|
|
|
|
let mut traps = PrimaryMap::with_capacity(function_body_inputs.len());
|
|
|
|
|
let mut stack_maps = PrimaryMap::with_capacity(function_body_inputs.len());
|
|
|
|
|
|
|
|
|
|
type FunctionBodyInput<'a> = (DefinedFuncIndex, &'a FunctionBodyData<'a>);
|
|
|
|
|
|
|
|
|
|
let compile_function = |func_translator: &mut FuncTranslator,
|
|
|
|
|
(i, input): &FunctionBodyInput| {
|
|
|
|
|
let func_index = env.local.func_index(*i);
|
|
|
|
|
let func_index = local.func_index(*i);
|
|
|
|
|
let mut context = Context::new();
|
|
|
|
|
context.func.name = get_func_name(func_index);
|
|
|
|
|
context.func.signature = env.local.native_func_signature(func_index).clone();
|
|
|
|
|
if env.tunables.debug_info {
|
|
|
|
|
context.func.signature = local.native_func_signature(func_index).clone();
|
|
|
|
|
if tunables.debug_info {
|
|
|
|
|
context.func.collect_debug_info();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut func_env = FuncEnvironment::new(isa.frontend_config(), env.local, env.tunables);
|
|
|
|
|
let mut func_env = FuncEnvironment::new(isa.frontend_config(), local, tunables);
|
|
|
|
|
|
|
|
|
|
// We use these as constant offsets below in
|
|
|
|
|
// `stack_limit_from_arguments`, so assert their values here. This
|
|
|
|
|
@@ -368,7 +362,7 @@ fn compile(env: CompileEnv<'_>) -> Result<CompileResult, CompileError> {
|
|
|
|
|
});
|
|
|
|
|
context.func.stack_limit = Some(stack_limit);
|
|
|
|
|
func_translator.translate(
|
|
|
|
|
env.module_translation.0,
|
|
|
|
|
module_translation,
|
|
|
|
|
input.data,
|
|
|
|
|
input.module_offset,
|
|
|
|
|
&mut context.func,
|
|
|
|
|
@@ -397,7 +391,7 @@ fn compile(env: CompileEnv<'_>) -> Result<CompileResult, CompileError> {
|
|
|
|
|
|
|
|
|
|
let address_transform = get_function_address_map(&context, input, code_buf.len(), isa);
|
|
|
|
|
|
|
|
|
|
let ranges = if env.tunables.debug_info {
|
|
|
|
|
let ranges = if tunables.debug_info {
|
|
|
|
|
let ranges = context.build_value_labels_ranges(isa).map_err(|error| {
|
|
|
|
|
CompileError::Codegen(pretty_error(&context.func, Some(isa), error))
|
|
|
|
|
})?;
|
|
|
|
|
@@ -419,7 +413,7 @@ fn compile(env: CompileEnv<'_>) -> Result<CompileResult, CompileError> {
|
|
|
|
|
))
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let inputs: Vec<FunctionBodyInput> = env.function_body_inputs.into_iter().collect();
|
|
|
|
|
let inputs: Vec<FunctionBodyInput> = function_body_inputs.into_iter().collect();
|
|
|
|
|
|
|
|
|
|
let results: Result<Vec<_>, CompileError> = {
|
|
|
|
|
cfg_if::cfg_if! {
|
|
|
|
|
@@ -476,49 +470,3 @@ fn compile(env: CompileEnv<'_>) -> Result<CompileResult, CompileError> {
|
|
|
|
|
stack_maps,
|
|
|
|
|
))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Hash)]
|
|
|
|
|
struct CompileEnv<'a> {
|
|
|
|
|
local: &'a ModuleLocal,
|
|
|
|
|
module_translation: HashedModuleTranslationState<'a>,
|
|
|
|
|
function_body_inputs: &'a PrimaryMap<DefinedFuncIndex, FunctionBodyData<'a>>,
|
|
|
|
|
isa: Isa<'a, 'a>,
|
|
|
|
|
tunables: &'a Tunables,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// This is a wrapper struct to hash the specific bits of `TargetIsa` that
|
|
|
|
|
/// affect the output we care about. The trait itself can't implement `Hash`
|
|
|
|
|
/// (it's not object safe) so we have to implement our own hashing.
|
|
|
|
|
struct Isa<'a, 'b>(&'a (dyn isa::TargetIsa + 'b));
|
|
|
|
|
|
|
|
|
|
impl Hash for Isa<'_, '_> {
|
|
|
|
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
|
|
|
|
self.0.triple().hash(hasher);
|
|
|
|
|
self.0.frontend_config().hash(hasher);
|
|
|
|
|
|
|
|
|
|
// TODO: if this `to_string()` is too expensive then we should upstream
|
|
|
|
|
// a native hashing ability of flags into cranelift itself, but
|
|
|
|
|
// compilation and/or cache loading is relatively expensive so seems
|
|
|
|
|
// unlikely.
|
|
|
|
|
self.0.flags().to_string().hash(hasher);
|
|
|
|
|
|
|
|
|
|
// TODO: ... and should we hash anything else? There's a lot of stuff in
|
|
|
|
|
// `TargetIsa`, like registers/encodings/etc. Should we be hashing that
|
|
|
|
|
// too? It seems like wasmtime doesn't configure it too too much, but
|
|
|
|
|
// this may become an issue at some point.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A wrapper struct around cranelift's `ModuleTranslationState` to implement
|
|
|
|
|
/// `Hash` since it's not `Hash` upstream yet.
|
|
|
|
|
///
|
|
|
|
|
/// TODO: we should upstream a `Hash` implementation, it would be very small! At
|
|
|
|
|
/// this moment though based on the definition it should be fine to not hash it
|
|
|
|
|
/// since we'll re-hash the signatures later.
|
|
|
|
|
struct HashedModuleTranslationState<'a>(&'a ModuleTranslationState);
|
|
|
|
|
|
|
|
|
|
impl Hash for HashedModuleTranslationState<'_> {
|
|
|
|
|
fn hash<H: Hasher>(&self, _hasher: &mut H) {
|
|
|
|
|
// nothing to hash right now
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|