Refactor where results of compilation are stored (#2086)
* Refactor where results of compilation are stored This commit refactors the internals of compilation in Wasmtime to change where results of individual function compilation are stored. Previously compilation resulted in many maps being returned, and compilation results generally held all these maps together. This commit instead switches this to have all metadata stored in a `CompiledFunction` instead of having a separate map for each item that can be stored. The motivation for this is primarily to help out with future module-linking-related PRs. What exactly "module level" is depends on how we interpret modules and how many modules are in play, so it's a bit easier for operations in wasmtime to work at the function level where possible. This means that we don't have to pass around multiple different maps and a function index, but instead just one map or just one entry representing a compiled function. Additionally this change updates where the parallelism of compilation happens, pushing it into `wasmtime-jit` instead of `wasmtime-environ`. This is another goal where `wasmtime-jit` will have more knowledge about module-level pieces with module linking in play. User-facing-wise this should be the same in terms of parallel compilation, though. The ultimate goal of this refactoring is to make it easier for the results of compilation to actually be a set of wasm modules. This means we won't be able to have a map-per-metadata where the primary key is the function index, because there will be many modules within one "object file". * Don't clear out fields, just don't store them Persist a smaller set of fields in `CompilationArtifacts` instead of trying to clear fields out and dynamically not accessing them.
This commit is contained in:
@@ -2,8 +2,6 @@
|
||||
// addresses of a WebAssembly module into the native code.
|
||||
|
||||
use cranelift_codegen::ir;
|
||||
use cranelift_entity::PrimaryMap;
|
||||
use cranelift_wasm::DefinedFuncIndex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Single source location to generated address mapping.
|
||||
@@ -20,7 +18,7 @@ pub struct InstructionAddressMap {
|
||||
}
|
||||
|
||||
/// Function and its instructions addresses mappings.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct FunctionAddressMap {
|
||||
/// Instructions maps.
|
||||
/// The array is sorted by the InstructionAddressMap::code_offset field.
|
||||
@@ -39,15 +37,6 @@ pub struct FunctionAddressMap {
|
||||
pub body_len: usize,
|
||||
}
|
||||
|
||||
/// Module functions addresses mappings.
|
||||
pub type ModuleAddressMap = PrimaryMap<DefinedFuncIndex, FunctionAddressMap>;
|
||||
|
||||
/// Value ranges for functions.
|
||||
pub type ValueLabelsRanges = PrimaryMap<DefinedFuncIndex, cranelift_codegen::ValueLabelsRanges>;
|
||||
|
||||
/// Stack slots for functions.
|
||||
pub type StackSlots = PrimaryMap<DefinedFuncIndex, ir::StackSlots>;
|
||||
|
||||
/// Memory definition offset in the VMContext structure.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ModuleMemoryOffset {
|
||||
@@ -58,13 +47,3 @@ pub enum ModuleMemoryOffset {
|
||||
/// Offset to the imported memory.
|
||||
Imported(u32),
|
||||
}
|
||||
|
||||
/// Module `vmctx` related info.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ModuleVmctxInfo {
|
||||
/// The memory definition offset in the VMContext structure.
|
||||
pub memory_offset: ModuleMemoryOffset,
|
||||
|
||||
/// The functions stack slots.
|
||||
pub stack_slots: StackSlots,
|
||||
}
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
//! A `Compilation` contains the compiled function bodies for a WebAssembly
|
||||
//! module.
|
||||
|
||||
use crate::address_map::{ModuleAddressMap, ValueLabelsRanges};
|
||||
use crate::ModuleTranslation;
|
||||
use crate::{FunctionAddressMap, FunctionBodyData, 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;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub type CompiledFunctions = PrimaryMap<DefinedFuncIndex, CompiledFunction>;
|
||||
|
||||
/// Compiled function: machine code body, jump table offsets, and unwind information.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct CompiledFunction {
|
||||
/// The function body.
|
||||
/// The machine code for this function.
|
||||
pub body: Vec<u8>,
|
||||
|
||||
/// The jump tables offsets (in the body).
|
||||
@@ -21,93 +23,13 @@ pub struct CompiledFunction {
|
||||
|
||||
/// 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()
|
||||
}
|
||||
|
||||
/// Returns unwind info for all defined functions.
|
||||
pub fn unwind_info(&self) -> PrimaryMap<DefinedFuncIndex, &Option<UnwindInfo>> {
|
||||
self.functions
|
||||
.iter()
|
||||
.map(|(_, func)| &func.unwind_info)
|
||||
.collect::<PrimaryMap<DefinedFuncIndex, _>>()
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
pub relocations: Vec<Relocation>,
|
||||
pub address_map: FunctionAddressMap,
|
||||
pub value_labels_ranges: cranelift_codegen::ValueLabelsRanges,
|
||||
pub stack_slots: ir::StackSlots,
|
||||
pub traps: Vec<TrapInformation>,
|
||||
pub stack_maps: Vec<StackMapInformation>,
|
||||
}
|
||||
|
||||
/// A record of a relocation to perform.
|
||||
@@ -134,9 +56,6 @@ pub enum RelocationTarget {
|
||||
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 {
|
||||
@@ -148,9 +67,6 @@ pub struct TrapInformation {
|
||||
pub trap_code: ir::TrapCode,
|
||||
}
|
||||
|
||||
/// Information about traps associated with the functions where the traps are placed.
|
||||
pub type Traps = PrimaryMap<DefinedFuncIndex, Vec<TrapInformation>>;
|
||||
|
||||
/// The offset within a function of a GC safepoint, and its associated stack
|
||||
/// map.
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||
@@ -163,10 +79,6 @@ pub struct StackMapInformation {
|
||||
pub stack_map: binemit::Stackmap,
|
||||
}
|
||||
|
||||
/// Information about GC safepoints and their associated stack maps within each
|
||||
/// function.
|
||||
pub type StackMaps = PrimaryMap<DefinedFuncIndex, Vec<StackMapInformation>>;
|
||||
|
||||
/// An error while compiling WebAssembly to machine code.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum CompileError {
|
||||
@@ -183,22 +95,15 @@ pub enum CompileError {
|
||||
DebugInfoNotSupported,
|
||||
}
|
||||
|
||||
/// A type alias for the result of `Compiler::compile_module`
|
||||
pub type CompileResult = (
|
||||
Compilation,
|
||||
Relocations,
|
||||
ModuleAddressMap,
|
||||
ValueLabelsRanges,
|
||||
PrimaryMap<DefinedFuncIndex, ir::StackSlots>,
|
||||
Traps,
|
||||
StackMaps,
|
||||
);
|
||||
|
||||
/// 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,
|
||||
/// An implementation of a compiler from parsed WebAssembly module to native
|
||||
/// code.
|
||||
pub trait Compiler: Send + Sync {
|
||||
/// Compile a function with the given `TargetIsa`.
|
||||
fn compile_function(
|
||||
&self,
|
||||
translation: &ModuleTranslation<'_>,
|
||||
index: DefinedFuncIndex,
|
||||
data: &FunctionBodyData<'_>,
|
||||
isa: &dyn isa::TargetIsa,
|
||||
) -> Result<CompileResult, CompileError>;
|
||||
) -> Result<CompiledFunction, CompileError>;
|
||||
}
|
||||
|
||||
@@ -85,23 +85,21 @@
|
||||
// also need to actually catch stack overflow, so for now 32k is chosen and it's
|
||||
// assume no valid stack pointer will ever be `usize::max_value() - 32k`.
|
||||
|
||||
use crate::address_map::{FunctionAddressMap, InstructionAddressMap};
|
||||
use crate::compilation::{
|
||||
Compilation, CompileError, CompiledFunction, Relocation, RelocationTarget, StackMapInformation,
|
||||
use crate::func_environ::{get_func_name, FuncEnvironment};
|
||||
use crate::Compiler;
|
||||
use crate::{
|
||||
CompileError, CompiledFunction, Relocation, RelocationTarget, StackMapInformation,
|
||||
TrapInformation,
|
||||
};
|
||||
use crate::compilation::{CompileResult, Compiler};
|
||||
use crate::func_environ::{get_func_name, FuncEnvironment};
|
||||
use crate::{FunctionBodyData, ModuleLocal, ModuleTranslation, Tunables};
|
||||
use crate::{FunctionAddressMap, InstructionAddressMap};
|
||||
use crate::{FunctionBodyData, ModuleTranslation};
|
||||
use cranelift_codegen::ir::{self, ExternalName};
|
||||
use cranelift_codegen::machinst::buffer::MachSrcLoc;
|
||||
use cranelift_codegen::print_errors::pretty_error;
|
||||
use cranelift_codegen::{binemit, isa, Context};
|
||||
use cranelift_entity::PrimaryMap;
|
||||
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator, ModuleTranslationState};
|
||||
#[cfg(feature = "parallel-compilation")]
|
||||
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
||||
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator};
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// Implementation of a relocation sink that just saves all the information for later
|
||||
pub struct RelocSink {
|
||||
@@ -280,45 +278,33 @@ fn get_function_address_map<'data>(
|
||||
|
||||
/// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR,
|
||||
/// optimizing it and then translating to assembly.
|
||||
pub struct Cranelift;
|
||||
#[derive(Default)]
|
||||
pub struct Cranelift {
|
||||
translators: Mutex<Vec<FuncTranslator>>,
|
||||
}
|
||||
|
||||
impl Compiler for Cranelift {
|
||||
/// Compile the module using Cranelift, producing a compilation result with
|
||||
/// associated relocations.
|
||||
fn compile_module(
|
||||
translation: &ModuleTranslation,
|
||||
isa: &dyn isa::TargetIsa,
|
||||
) -> Result<CompileResult, CompileError> {
|
||||
compile(
|
||||
isa,
|
||||
&translation.module.local,
|
||||
translation.module_translation.as_ref().unwrap(),
|
||||
&translation.function_body_inputs,
|
||||
&translation.tunables,
|
||||
)
|
||||
impl Cranelift {
|
||||
fn take_translator(&self) -> FuncTranslator {
|
||||
let candidate = self.translators.lock().unwrap().pop();
|
||||
candidate.unwrap_or_else(FuncTranslator::new)
|
||||
}
|
||||
|
||||
fn save_translator(&self, translator: FuncTranslator) {
|
||||
self.translators.lock().unwrap().push(translator);
|
||||
}
|
||||
}
|
||||
|
||||
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 = local.func_index(*i);
|
||||
impl Compiler for Cranelift {
|
||||
fn compile_function(
|
||||
&self,
|
||||
translation: &ModuleTranslation<'_>,
|
||||
func_index: DefinedFuncIndex,
|
||||
input: &FunctionBodyData<'_>,
|
||||
isa: &dyn isa::TargetIsa,
|
||||
) -> Result<CompiledFunction, CompileError> {
|
||||
let local = &translation.module.local;
|
||||
let tunables = &translation.tunables;
|
||||
let func_index = local.func_index(func_index);
|
||||
let mut context = Context::new();
|
||||
context.func.name = get_func_name(func_index);
|
||||
context.func.signature = local.native_func_signature(func_index).clone();
|
||||
@@ -361,13 +347,16 @@ fn compile(
|
||||
readonly: false,
|
||||
});
|
||||
context.func.stack_limit = Some(stack_limit);
|
||||
func_translator.translate(
|
||||
module_translation,
|
||||
let mut func_translator = self.take_translator();
|
||||
let result = func_translator.translate(
|
||||
translation.module_translation.as_ref().unwrap(),
|
||||
input.data,
|
||||
input.module_offset,
|
||||
&mut context.func,
|
||||
&mut func_env,
|
||||
)?;
|
||||
);
|
||||
self.save_translator(func_translator);
|
||||
result?;
|
||||
|
||||
let mut code_buf: Vec<u8> = Vec::new();
|
||||
let mut reloc_sink = RelocSink::new(func_index);
|
||||
@@ -400,73 +389,16 @@ fn compile(
|
||||
None
|
||||
};
|
||||
|
||||
Ok((
|
||||
code_buf,
|
||||
context.func.jt_offsets,
|
||||
reloc_sink.func_relocs,
|
||||
address_transform,
|
||||
ranges,
|
||||
context.func.stack_slots,
|
||||
trap_sink.traps,
|
||||
Ok(CompiledFunction {
|
||||
body: code_buf,
|
||||
jt_offsets: context.func.jt_offsets,
|
||||
relocations: reloc_sink.func_relocs,
|
||||
address_map: address_transform,
|
||||
value_labels_ranges: ranges.unwrap_or(Default::default()),
|
||||
stack_slots: context.func.stack_slots,
|
||||
traps: trap_sink.traps,
|
||||
unwind_info,
|
||||
stack_map_sink.finish(),
|
||||
))
|
||||
};
|
||||
|
||||
let inputs: Vec<FunctionBodyInput> = function_body_inputs.into_iter().collect();
|
||||
|
||||
let results: Result<Vec<_>, CompileError> = {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "parallel-compilation")] {
|
||||
inputs
|
||||
.par_iter()
|
||||
.map_init(FuncTranslator::new, compile_function)
|
||||
.collect()
|
||||
} else {
|
||||
let mut func_translator = FuncTranslator::new();
|
||||
inputs
|
||||
.iter()
|
||||
.map(|input| compile_function(&mut func_translator, input))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
results?.into_iter().for_each(
|
||||
|(
|
||||
function,
|
||||
func_jt_offsets,
|
||||
relocs,
|
||||
address_transform,
|
||||
ranges,
|
||||
sss,
|
||||
function_traps,
|
||||
unwind_info,
|
||||
stack_map,
|
||||
)| {
|
||||
functions.push(CompiledFunction {
|
||||
body: function,
|
||||
jt_offsets: func_jt_offsets,
|
||||
unwind_info,
|
||||
});
|
||||
relocations.push(relocs);
|
||||
address_transforms.push(address_transform);
|
||||
value_ranges.push(ranges.unwrap_or_default());
|
||||
stack_slots.push(sss);
|
||||
traps.push(function_traps);
|
||||
stack_maps.push(stack_map);
|
||||
},
|
||||
);
|
||||
|
||||
// TODO: Reorganize where we create the Vec for the resolved imports.
|
||||
|
||||
Ok((
|
||||
Compilation::new(functions),
|
||||
relocations,
|
||||
address_transforms,
|
||||
value_ranges,
|
||||
stack_slots,
|
||||
traps,
|
||||
stack_maps,
|
||||
))
|
||||
stack_maps: stack_map_sink.finish(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,16 +39,10 @@ pub mod cranelift;
|
||||
#[cfg(feature = "lightbeam")]
|
||||
pub mod lightbeam;
|
||||
|
||||
pub use crate::address_map::{
|
||||
FunctionAddressMap, InstructionAddressMap, ModuleAddressMap, ModuleMemoryOffset,
|
||||
ModuleVmctxInfo, ValueLabelsRanges,
|
||||
};
|
||||
pub use crate::address_map::*;
|
||||
pub use crate::cache::create_new_config as cache_create_new_config;
|
||||
pub use crate::cache::{CacheConfig, ModuleCacheEntry};
|
||||
pub use crate::compilation::{
|
||||
Compilation, CompileError, CompiledFunction, Compiler, Relocation, RelocationTarget,
|
||||
Relocations, StackMapInformation, StackMaps, TrapInformation, Traps,
|
||||
};
|
||||
pub use crate::compilation::*;
|
||||
pub use crate::cranelift::Cranelift;
|
||||
pub use crate::data_structures::*;
|
||||
pub use crate::func_environ::BuiltinFunctionIndex;
|
||||
|
||||
@@ -1,86 +1,71 @@
|
||||
//! Support for compiling with Lightbeam.
|
||||
|
||||
use crate::compilation::{Compilation, CompileError, CompileResult, Compiler};
|
||||
use crate::func_environ::FuncEnvironment;
|
||||
use crate::CacheConfig;
|
||||
use crate::ModuleTranslation;
|
||||
// TODO: Put this in `compilation`
|
||||
use crate::address_map::{ModuleAddressMap, ValueLabelsRanges};
|
||||
use crate::compilation::{CompileError, CompiledFunction, Compiler};
|
||||
use crate::cranelift::{RelocSink, TrapSink};
|
||||
use crate::func_environ::FuncEnvironment;
|
||||
use crate::{FunctionBodyData, ModuleTranslation};
|
||||
use cranelift_codegen::isa;
|
||||
use cranelift_entity::{PrimaryMap, SecondaryMap};
|
||||
use cranelift_wasm::DefinedFuncIndex;
|
||||
use lightbeam::{CodeGenSession, NullOffsetSink, Sinks};
|
||||
|
||||
/// A compiler that compiles a WebAssembly module with Lightbeam, directly translating the Wasm file.
|
||||
pub struct Lightbeam;
|
||||
|
||||
impl Compiler for Lightbeam {
|
||||
/// Compile the module using Lightbeam, producing a compilation result with
|
||||
/// associated relocations.
|
||||
fn compile_module(
|
||||
fn compile_function(
|
||||
&self,
|
||||
translation: &ModuleTranslation,
|
||||
i: DefinedFuncIndex,
|
||||
function_body: &FunctionBodyData<'_>,
|
||||
isa: &dyn isa::TargetIsa,
|
||||
) -> Result<CompileResult, CompileError> {
|
||||
) -> Result<CompiledFunction, CompileError> {
|
||||
if translation.tunables.debug_info {
|
||||
return Err(CompileError::DebugInfoNotSupported);
|
||||
}
|
||||
let func_index = translation.module.local.func_index(i);
|
||||
|
||||
let env = FuncEnvironment::new(
|
||||
isa.frontend_config(),
|
||||
&translation.module.local,
|
||||
&translation.tunables,
|
||||
);
|
||||
let mut relocations = PrimaryMap::with_capacity(translation.function_body_inputs.len());
|
||||
let mut traps = PrimaryMap::with_capacity(translation.function_body_inputs.len());
|
||||
let stack_maps = PrimaryMap::with_capacity(translation.function_body_inputs.len());
|
||||
|
||||
let mut codegen_session: CodeGenSession<_> = CodeGenSession::new(
|
||||
translation.function_body_inputs.len() as u32,
|
||||
&env,
|
||||
lightbeam::microwasm::I32,
|
||||
);
|
||||
|
||||
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);
|
||||
let mut trap_sink = TrapSink::new();
|
||||
lightbeam::translate_function(
|
||||
&mut codegen_session,
|
||||
Sinks {
|
||||
relocs: &mut reloc_sink,
|
||||
traps: &mut trap_sink,
|
||||
offsets: &mut NullOffsetSink,
|
||||
},
|
||||
i.as_u32(),
|
||||
wasmparser::FunctionBody::new(0, function_body.data),
|
||||
)
|
||||
.map_err(|e| CompileError::Codegen(format!("Failed to translate function: {}", e)))?;
|
||||
|
||||
relocations.push(reloc_sink.func_relocs);
|
||||
traps.push(trap_sink.traps);
|
||||
}
|
||||
let mut reloc_sink = RelocSink::new(func_index);
|
||||
let mut trap_sink = TrapSink::new();
|
||||
lightbeam::translate_function(
|
||||
&mut codegen_session,
|
||||
Sinks {
|
||||
relocs: &mut reloc_sink,
|
||||
traps: &mut trap_sink,
|
||||
offsets: &mut NullOffsetSink,
|
||||
},
|
||||
i.as_u32(),
|
||||
wasmparser::FunctionBody::new(0, function_body.data),
|
||||
)
|
||||
.map_err(|e| CompileError::Codegen(format!("Failed to translate function: {}", e)))?;
|
||||
|
||||
let code_section = codegen_session
|
||||
.into_translated_code_section()
|
||||
.map_err(|e| CompileError::Codegen(format!("Failed to generate output code: {}", e)))?;
|
||||
|
||||
// TODO pass jump table offsets to Compilation::from_buffer() when they
|
||||
// are implemented in lightbeam -- using empty set of offsets for now.
|
||||
// TODO: pass an empty range for the unwind information until lightbeam emits it
|
||||
let code_section_ranges_and_jt = code_section
|
||||
.funcs()
|
||||
.into_iter()
|
||||
.map(|r| (r, SecondaryMap::new()));
|
||||
Ok(CompiledFunction {
|
||||
// TODO: try to remove copy here (?)
|
||||
body: code_section.buffer().to_vec(),
|
||||
traps: trap_sink.traps,
|
||||
relocations: reloc_sink.func_relocs,
|
||||
|
||||
Ok((
|
||||
Compilation::from_buffer(code_section.buffer().to_vec(), code_section_ranges_and_jt),
|
||||
relocations,
|
||||
ModuleAddressMap::new(),
|
||||
ValueLabelsRanges::new(),
|
||||
PrimaryMap::new(),
|
||||
traps,
|
||||
stack_maps,
|
||||
))
|
||||
// not implemented for lightbeam currently
|
||||
unwind_info: None,
|
||||
stack_maps: Default::default(),
|
||||
stack_slots: Default::default(),
|
||||
value_labels_ranges: Default::default(),
|
||||
address_map: Default::default(),
|
||||
jt_offsets: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user