wasmtime: Pass around more contexts instead of fields (#1486)
* wasmtime: Pass around more contexts instead of fields This commit refactors some wasmtime internals to pass around more context-style structures rather than individual fields of each structure. The intention here is to make the addition of fields to a structure easier to plumb throughout the internals of wasmtime. Currently you need to edit lots of functions to pass lots of parameters, but ideally after this you'll only need to edit one or two struct fields and then relevant locations have access to the information already. Updates in this commit are: * `debug_info` configuration is now folded into `Tunables`. Additionally a `wasmtime::Config` now holds a `Tunables` directly and is passed into an internal `Compiler`. Eventually this should allow for direct configuration of the `Tunables` attributes from the `wasmtime` API, but no new configuration is exposed at this time. * `ModuleTranslation` is now passed around as a whole rather than passing individual components to allow access to all the fields, including `Tunables`. This was motivated by investigating what it would take to optionally allow loops and such to get interrupted, but that sort of codegen setting was currently relatively difficult to plumb all the way through and now it's hoped to be largely just an addition to `Tunables`. * Fix lightbeam compile
This commit is contained in:
@@ -2,12 +2,11 @@
|
||||
//! module.
|
||||
|
||||
use crate::cache::ModuleCacheDataTupleType;
|
||||
use crate::module;
|
||||
use crate::module_environ::FunctionBodyData;
|
||||
use crate::CacheConfig;
|
||||
use crate::ModuleTranslation;
|
||||
use cranelift_codegen::{binemit, ir, isa, Context};
|
||||
use cranelift_entity::PrimaryMap;
|
||||
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, ModuleTranslationState, WasmError};
|
||||
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, WasmError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::Range;
|
||||
use thiserror::Error;
|
||||
@@ -287,12 +286,9 @@ pub enum CompileError {
|
||||
/// 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<'data, 'module>(
|
||||
module: &'module module::Module,
|
||||
module_translation: &ModuleTranslationState,
|
||||
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
||||
fn compile_module(
|
||||
translation: &ModuleTranslation,
|
||||
isa: &dyn isa::TargetIsa,
|
||||
generate_debug_info: bool,
|
||||
cache_config: &CacheConfig,
|
||||
) -> Result<ModuleCacheDataTupleType, CompileError>;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,7 @@ use crate::compilation::{
|
||||
};
|
||||
use crate::frame_layout::FrameLayout;
|
||||
use crate::func_environ::{get_func_name, FuncEnvironment};
|
||||
use crate::module::{Module, ModuleLocal};
|
||||
use crate::module_environ::FunctionBodyData;
|
||||
use crate::CacheConfig;
|
||||
use crate::{CacheConfig, FunctionBodyData, ModuleLocal, ModuleTranslation, Tunables};
|
||||
use cranelift_codegen::ir::{self, ExternalName};
|
||||
use cranelift_codegen::print_errors::pretty_error;
|
||||
use cranelift_codegen::{binemit, isa, Context};
|
||||
@@ -196,72 +194,58 @@ impl crate::compilation::Compiler for Cranelift {
|
||||
/// Compile the module using Cranelift, producing a compilation result with
|
||||
/// associated relocations.
|
||||
fn compile_module(
|
||||
module: &Module,
|
||||
module_translation: &ModuleTranslationState,
|
||||
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'_>>,
|
||||
translation: &ModuleTranslation,
|
||||
isa: &dyn isa::TargetIsa,
|
||||
generate_debug_info: bool,
|
||||
cache_config: &CacheConfig,
|
||||
) -> Result<ModuleCacheDataTupleType, CompileError> {
|
||||
let cache_entry = ModuleCacheEntry::new("cranelift", cache_config);
|
||||
|
||||
let data = cache_entry.get_data(
|
||||
(
|
||||
&module.local,
|
||||
HashedModuleTranslationState(module_translation),
|
||||
function_body_inputs,
|
||||
Isa(isa),
|
||||
generate_debug_info,
|
||||
),
|
||||
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(data.into_tuple())
|
||||
}
|
||||
}
|
||||
|
||||
fn compile(
|
||||
(
|
||||
module,
|
||||
HashedModuleTranslationState(module_translation),
|
||||
function_body_inputs,
|
||||
Isa(isa),
|
||||
generate_debug_info,
|
||||
): (
|
||||
&ModuleLocal,
|
||||
HashedModuleTranslationState<'_>,
|
||||
PrimaryMap<DefinedFuncIndex, FunctionBodyData<'_>>,
|
||||
Isa<'_, '_>,
|
||||
bool,
|
||||
),
|
||||
) -> Result<ModuleCacheDataTupleType, 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 frame_layouts = PrimaryMap::with_capacity(function_body_inputs.len());
|
||||
fn compile(env: CompileEnv<'_>) -> Result<ModuleCacheDataTupleType, 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 frame_layouts = PrimaryMap::with_capacity(env.function_body_inputs.len());
|
||||
|
||||
function_body_inputs
|
||||
env.function_body_inputs
|
||||
.into_iter()
|
||||
.collect::<Vec<(DefinedFuncIndex, &FunctionBodyData<'_>)>>()
|
||||
.par_iter()
|
||||
.map_init(FuncTranslator::new, |func_translator, (i, input)| {
|
||||
let func_index = module.func_index(*i);
|
||||
let func_index = env.local.func_index(*i);
|
||||
let mut context = Context::new();
|
||||
context.func.name = get_func_name(func_index);
|
||||
context.func.signature = module.signatures[module.functions[func_index]].clone();
|
||||
context.func.signature = env.local.signatures[env.local.functions[func_index]].clone();
|
||||
context.func.collect_frame_layout_info();
|
||||
if generate_debug_info {
|
||||
if env.tunables.debug_info {
|
||||
context.func.collect_debug_info();
|
||||
}
|
||||
|
||||
func_translator.translate(
|
||||
module_translation,
|
||||
env.module_translation.0,
|
||||
input.data,
|
||||
input.module_offset,
|
||||
&mut context.func,
|
||||
&mut FuncEnvironment::new(isa.frontend_config(), module),
|
||||
&mut FuncEnvironment::new(isa.frontend_config(), env.local),
|
||||
)?;
|
||||
|
||||
let mut code_buf: Vec<u8> = Vec::new();
|
||||
@@ -282,14 +266,14 @@ fn compile(
|
||||
|
||||
let unwind_info = CompiledFunctionUnwindInfo::new(isa, &context);
|
||||
|
||||
let address_transform = if generate_debug_info {
|
||||
let address_transform = if env.tunables.debug_info {
|
||||
let body_len = code_buf.len();
|
||||
Some(get_function_address_map(&context, input, body_len, isa))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let frame_layout = if generate_debug_info {
|
||||
let frame_layout = if env.tunables.debug_info {
|
||||
let (initial_commands, commands) = get_frame_layout(&context, isa);
|
||||
Some(FrameLayout {
|
||||
call_conv: context.func.signature.call_conv,
|
||||
@@ -300,7 +284,7 @@ fn compile(
|
||||
None
|
||||
};
|
||||
|
||||
let ranges = if generate_debug_info {
|
||||
let ranges = if env.tunables.debug_info {
|
||||
let ranges = context.build_value_labels_ranges(isa).map_err(|error| {
|
||||
CompileError::Codegen(pretty_error(&context.func, Some(isa), error))
|
||||
})?;
|
||||
@@ -366,6 +350,15 @@ fn compile(
|
||||
))
|
||||
}
|
||||
|
||||
#[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.
|
||||
@@ -374,6 +367,7 @@ 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
|
||||
|
||||
@@ -3,15 +3,13 @@
|
||||
use crate::cache::ModuleCacheDataTupleType;
|
||||
use crate::compilation::{Compilation, CompileError, Traps};
|
||||
use crate::func_environ::FuncEnvironment;
|
||||
use crate::module::Module;
|
||||
use crate::module_environ::FunctionBodyData;
|
||||
use crate::ModuleTranslation;
|
||||
// TODO: Put this in `compilation`
|
||||
use crate::address_map::{ModuleAddressMap, ValueLabelsRanges};
|
||||
use crate::cranelift::RelocSink;
|
||||
use crate::CacheConfig;
|
||||
use cranelift_codegen::isa;
|
||||
use cranelift_entity::{PrimaryMap, SecondaryMap};
|
||||
use cranelift_wasm::{DefinedFuncIndex, ModuleTranslationState};
|
||||
|
||||
/// A compiler that compiles a WebAssembly module with Lightbeam, directly translating the Wasm file.
|
||||
pub struct Lightbeam;
|
||||
@@ -19,26 +17,22 @@ pub struct Lightbeam;
|
||||
impl crate::compilation::Compiler for Lightbeam {
|
||||
/// Compile the module using Lightbeam, producing a compilation result with
|
||||
/// associated relocations.
|
||||
fn compile_module<'data, 'module>(
|
||||
module: &'module Module,
|
||||
_module_translation: &ModuleTranslationState,
|
||||
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
||||
fn compile_module(
|
||||
translation: &ModuleTranslation,
|
||||
isa: &dyn isa::TargetIsa,
|
||||
// TODO
|
||||
generate_debug_info: bool,
|
||||
_cache_config: &CacheConfig,
|
||||
) -> Result<ModuleCacheDataTupleType, CompileError> {
|
||||
if generate_debug_info {
|
||||
if translation.tunables.debug_info {
|
||||
return Err(CompileError::DebugInfoNotSupported);
|
||||
}
|
||||
|
||||
let env = FuncEnvironment::new(isa.frontend_config(), &module.local);
|
||||
let env = FuncEnvironment::new(isa.frontend_config(), &translation.module.local);
|
||||
let mut relocations = PrimaryMap::new();
|
||||
let mut codegen_session: lightbeam::CodeGenSession<_> =
|
||||
lightbeam::CodeGenSession::new(function_body_inputs.len() as u32, &env);
|
||||
lightbeam::CodeGenSession::new(translation.function_body_inputs.len() as u32, &env);
|
||||
|
||||
for (i, function_body) in &function_body_inputs {
|
||||
let func_index = module.local.func_index(i);
|
||||
for (i, function_body) in &translation.function_body_inputs {
|
||||
let func_index = translation.module.local.func_index(i);
|
||||
let mut reloc_sink = RelocSink::new(func_index);
|
||||
|
||||
lightbeam::translate_function(
|
||||
|
||||
@@ -62,14 +62,14 @@ pub struct ModuleEnvironment<'data> {
|
||||
|
||||
impl<'data> ModuleEnvironment<'data> {
|
||||
/// Allocates the environment data structures.
|
||||
pub fn new(target_config: TargetFrontendConfig, tunables: Tunables) -> Self {
|
||||
pub fn new(target_config: TargetFrontendConfig, tunables: &Tunables) -> Self {
|
||||
Self {
|
||||
result: ModuleTranslation {
|
||||
target_config,
|
||||
module: Module::new(),
|
||||
function_body_inputs: PrimaryMap::new(),
|
||||
data_initializers: Vec::new(),
|
||||
tunables,
|
||||
tunables: tunables.clone(),
|
||||
module_translation: None,
|
||||
},
|
||||
imports: 0,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/// Tunable parameters for WebAssembly compilation.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Hash)]
|
||||
pub struct Tunables {
|
||||
/// For static heaps, the size in wasm pages of the heap protected by bounds checking.
|
||||
pub static_memory_bound: u32,
|
||||
@@ -9,6 +9,9 @@ pub struct Tunables {
|
||||
|
||||
/// The size in bytes of the offset guard for dynamic heaps.
|
||||
pub dynamic_memory_offset_guard_size: u64,
|
||||
|
||||
/// Whether or not to generate DWARF debug information.
|
||||
pub debug_info: bool,
|
||||
}
|
||||
|
||||
impl Default for Tunables {
|
||||
@@ -39,6 +42,8 @@ impl Default for Tunables {
|
||||
/// Allocate a small guard to optimize common cases but without
|
||||
/// wasting too much memor.
|
||||
dynamic_memory_offset_guard_size: 0x1_0000,
|
||||
|
||||
debug_info: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user