Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[submodule "spec_testsuite"]
path = spec_testsuite
url = https://github.com/WebAssembly/testsuite
[submodule "lightbeam"]
path = lightbeam
url = https://github.com/CraneStation/lightbeam.git
branch = master
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@ file-per-thread-logger = "0.1.1"
wabt = "0.7"

[workspace]

[features]
lightbeam = ["wasmtime-environ/lightbeam", "wasmtime-jit/lightbeam"]
1 change: 1 addition & 0 deletions lightbeam
Submodule lightbeam added at 762cd3
2 changes: 1 addition & 1 deletion spec_testsuite
Submodule spec_testsuite updated 66 files
+84 −84 address.wast
+143 −143 align.wast
+2 −55 binary.wast
+27 −27 block.wast
+17 −63 br.wast
+35 −35 br_if.wast
+44 −44 br_table.wast
+37 −37 call.wast
+86 −86 call_indirect.wast
+292 −292 conversions.wast
+112 −0 custom_section.wast
+10 −10 data.wast
+43 −43 elem.wast
+33 −33 endianness.wast
+26 −26 exports.wast
+11 −11 f32.wast
+3 −3 f32_bitwise.wast
+6 −6 f32_cmp.wast
+11 −11 f64.wast
+3 −3 f64_bitwise.wast
+6 −6 f64_cmp.wast
+23 −23 fac.wast
+420 −420 float_exprs.wast
+62 −62 float_literals.wast
+29 −29 float_misc.wast
+4 −4 forward.wast
+49 −49 func.wast
+11 −11 func_ptrs.wast
+148 −0 get_local.wast
+58 −58 globals.wast
+29 −166 i32.wast
+29 −29 i64.wast
+76 −124 if.wast
+62 −62 imports.wast
+64 −64 int_exprs.wast
+68 −75 labels.wast
+1 −1 left-to-right.wast
+23 −23 linking.wast
+0 −366 load.wast
+0 −223 local_get.wast
+0 −247 local_set.wast
+51 −51 loop.wast
+423 −11 memory.wast
+23 −23 memory_grow.wast
+10 −10 memory_redundancy.wast
+26 −26 memory_trap.wast
+2 −2 names.wast
+87 −87 nop.wast
+73 −73 proposals/threads/atomic.wast
+26 −26 proposals/threads/exports.wast
+62 −70 proposals/threads/imports.wast
+336 −17 proposals/threads/memory.wast
+60 −0 resizing.wast
+15 −61 return.wast
+53 −53 select.wast
+257 −0 set_local.wast
+2,115 −2,115 skip-stack-guard-page.wast
+43 −43 stack.wast
+0 −146 store.wast
+55 −0 store_retval.wast
+16 −16 switch.wast
+117 −117 tee_local.wast
+30 −30 traps.wast
+242 −29 typecheck.wast
+15 −15 unreachable.wast
+4 −4 unreached-invalid.wast
4 changes: 2 additions & 2 deletions src/wasm2obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use std::str;
use std::str::FromStr;
use target_lexicon::Triple;
use wasmtime_debug::{emit_debugsections, read_debuginfo};
use wasmtime_environ::{cranelift, ModuleEnvironment, Tunables};
use wasmtime_environ::{Compiler, Cranelift, ModuleEnvironment, Tunables};
use wasmtime_obj::emit_module;

const USAGE: &str = "
Expand Down Expand Up @@ -159,7 +159,7 @@ fn handle_module(
)
};

let (compilation, relocations, address_transform) = cranelift::compile_module(
let (compilation, relocations, address_transform) = Cranelift::compile_module(
&module,
lazy_function_body_inputs,
&*isa,
Expand Down
1 change: 1 addition & 0 deletions wasmtime-environ/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ edition = "2018"
cranelift-codegen = "0.30.0"
cranelift-entity = "0.30.0"
cranelift-wasm = "0.30.0"
lightbeam = { path = "../lightbeam", optional = true }
cast = { version = "0.2.2", default-features = false }
failure = { version = "0.1.3", default-features = false }
failure_derive = { version = "0.1.3", default-features = false }
Expand Down
69 changes: 63 additions & 6 deletions wasmtime-environ/src/compilation.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,71 @@
//! A `Compilation` contains the compiled function bodies for a WebAssembly
//! module.

use cranelift_codegen::binemit;
use cranelift_codegen::ir;
use cranelift_codegen::CodegenError;
use crate::module;
use crate::module_environ::FunctionBodyData;
use cranelift_codegen::{binemit, ir, isa, CodegenError};
use cranelift_entity::PrimaryMap;
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, WasmError};
use std::ops::Range;
use std::vec::Vec;

type Functions = PrimaryMap<DefinedFuncIndex, Vec<u8>>;

/// The result of compiling a WebAssembly module's functions.
#[derive(Debug)]
pub struct Compilation {
/// Compiled machine code for the function bodies.
pub functions: PrimaryMap<DefinedFuncIndex, Vec<u8>>,
functions: Functions,
}

impl Compilation {
/// Allocates the compilation result with the given function bodies.
pub fn new(functions: PrimaryMap<DefinedFuncIndex, Vec<u8>>) -> Self {
/// 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>>) -> Self {
Self::new(
functions
.into_iter()
.map(|range| buffer[range].to_vec())
.collect(),
)
}

/// Gets the bytes of a single function
pub fn get(&self, func: DefinedFuncIndex) -> &[u8] {
&self.functions[func]
}

/// Gets the number of functions defined.
pub fn len(&self) -> usize {
self.functions.len()
}
}

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 [u8];

fn next(&mut self) -> Option<Self::Item> {
self.iterator.next().map(|(_, b)| &b[..])
}
}

/// A record of a relocation to perform.
Expand Down Expand Up @@ -95,3 +141,14 @@ pub struct FunctionAddressTransform {

/// Function AddressTransforms collection.
pub type AddressTransforms = PrimaryMap<DefinedFuncIndex, FunctionAddressTransform>;

/// 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,
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
isa: &dyn isa::TargetIsa,
generate_debug_info: bool,
) -> Result<(Compilation, Relocations, AddressTransforms), CompileError>;
}
128 changes: 67 additions & 61 deletions wasmtime-environ/src/cranelift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use std::vec::Vec;

/// Implementation of a relocation sink that just saves all the information for later
struct RelocSink {
pub struct RelocSink {
/// Relocations recorded for the function.
func_relocs: Vec<Relocation>,
pub func_relocs: Vec<Relocation>,
}

impl binemit::RelocSink for RelocSink {
Expand Down Expand Up @@ -109,69 +109,75 @@ fn get_address_transform(
result
}

/// Compile the module using Cranelift, producing a compilation result with
/// associated relocations.
pub fn compile_module<'data, 'module>(
module: &'module Module,
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
isa: &dyn isa::TargetIsa,
generate_debug_info: bool,
) -> Result<(Compilation, Relocations, AddressTransforms), 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());
/// 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;

function_body_inputs
.into_iter()
.collect::<Vec<(DefinedFuncIndex, &FunctionBodyData<'data>)>>()
.par_iter()
.map(|(i, input)| {
let func_index = module.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();
impl crate::compilation::Compiler for Cranelift {
/// Compile the module using Cranelift, producing a compilation result with
/// associated relocations.
fn compile_module<'data, 'module>(
module: &'module Module,
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
isa: &dyn isa::TargetIsa,
generate_debug_info: bool,
) -> Result<(Compilation, Relocations, AddressTransforms), 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 trans = FuncTranslator::new();
trans
.translate(
input.data,
input.module_offset,
&mut context.func,
&mut FuncEnvironment::new(isa.frontend_config(), module),
)
.map_err(CompileError::Wasm)?;
function_body_inputs
.into_iter()
.collect::<Vec<(DefinedFuncIndex, &FunctionBodyData<'data>)>>()
.par_iter()
.map(|(i, input)| {
let func_index = module.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();

let mut code_buf: Vec<u8> = Vec::new();
let mut reloc_sink = RelocSink::new();
let mut trap_sink = binemit::NullTrapSink {};
context
.compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut trap_sink)
.map_err(CompileError::Codegen)?;
let mut trans = FuncTranslator::new();
trans
.translate(
input.data,
input.module_offset,
&mut context.func,
&mut FuncEnvironment::new(isa.frontend_config(), module),
)
.map_err(CompileError::Wasm)?;

let address_transform = if generate_debug_info {
let body_len = code_buf.len();
let at = get_address_transform(&context, isa);
Some(FunctionAddressTransform {
locations: at,
body_offset: 0,
body_len,
})
} else {
None
};
let mut code_buf: Vec<u8> = Vec::new();
let mut reloc_sink = RelocSink::new();
let mut trap_sink = binemit::NullTrapSink {};
context
.compile_and_emit(isa, &mut code_buf, &mut reloc_sink, &mut trap_sink)
.map_err(CompileError::Codegen)?;

Ok((code_buf, reloc_sink.func_relocs, address_transform))
})
.collect::<Result<Vec<_>, CompileError>>()?
.into_iter()
.for_each(|(function, relocs, address_transform)| {
functions.push(function);
relocations.push(relocs);
if let Some(address_transform) = address_transform {
address_transforms.push(address_transform);
}
});
let address_transform = if generate_debug_info {
let body_len = code_buf.len();
let at = get_address_transform(&context, isa);
Some(FunctionAddressTransform {
locations: at,
body_offset: 0,
body_len,
})
} else {
None
};

Ok((code_buf, reloc_sink.func_relocs, address_transform))
})
.collect::<Result<Vec<_>, CompileError>>()?
.into_iter()
.for_each(|(function, relocs, address_transform)| {
functions.push(function);
relocations.push(relocs);
if let Some(address_transform) = address_transform {
address_transforms.push(address_transform);
}
});

// TODO: Reorganize where we create the Vec for the resolved imports.
Ok((Compilation::new(functions), relocations, address_transforms))
// TODO: Reorganize where we create the Vec for the resolved imports.
Ok((Compilation::new(functions), relocations, address_transforms))
}
}
Loading