4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -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
|
||||
|
||||
@@ -44,3 +44,6 @@ libc = "0.2.50"
|
||||
errno = "0.2.4"
|
||||
|
||||
[workspace]
|
||||
|
||||
[features]
|
||||
lightbeam = ["wasmtime-environ/lightbeam", "wasmtime-jit/lightbeam"]
|
||||
|
||||
1
lightbeam
Submodule
1
lightbeam
Submodule
Submodule lightbeam added at 762cd3fb32
Submodule spec_testsuite updated: 89cc463fa1...b2800641d6
@@ -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 = "
|
||||
@@ -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,
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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.
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -109,9 +109,14 @@ fn get_address_transform(
|
||||
result
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
||||
impl crate::compilation::Compiler for Cranelift {
|
||||
/// Compile the module using Cranelift, producing a compilation result with
|
||||
/// associated relocations.
|
||||
pub fn compile_module<'data, 'module>(
|
||||
fn compile_module<'data, 'module>(
|
||||
module: &'module Module,
|
||||
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
||||
isa: &dyn isa::TargetIsa,
|
||||
@@ -175,3 +180,4 @@ pub fn compile_module<'data, 'module>(
|
||||
// TODO: Reorganize where we create the Vec for the resolved imports.
|
||||
Ok((Compilation::new(functions), relocations, address_transforms))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ use cranelift_codegen::ir::{
|
||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||
use cranelift_entity::EntityRef;
|
||||
use cranelift_wasm::{
|
||||
self, FuncIndex, GlobalIndex, GlobalVariable, MemoryIndex, SignatureIndex, TableIndex,
|
||||
WasmResult,
|
||||
self, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex,
|
||||
GlobalIndex, GlobalVariable, MemoryIndex, SignatureIndex, TableIndex, WasmResult,
|
||||
};
|
||||
use std::vec::Vec;
|
||||
|
||||
@@ -207,6 +207,138 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "lightbeam")]
|
||||
impl lightbeam::ModuleContext for FuncEnvironment<'_> {
|
||||
type Signature = ir::Signature;
|
||||
type GlobalType = ir::Type;
|
||||
|
||||
fn func_index(&self, defined_func_index: u32) -> u32 {
|
||||
self.module
|
||||
.func_index(DefinedFuncIndex::from_u32(defined_func_index))
|
||||
.as_u32()
|
||||
}
|
||||
|
||||
fn defined_func_index(&self, func_index: u32) -> Option<u32> {
|
||||
self.module
|
||||
.defined_func_index(FuncIndex::from_u32(func_index))
|
||||
.map(|i| i.as_u32())
|
||||
}
|
||||
|
||||
fn defined_global_index(&self, global_index: u32) -> Option<u32> {
|
||||
self.module
|
||||
.defined_global_index(GlobalIndex::from_u32(global_index))
|
||||
.map(|i| i.as_u32())
|
||||
}
|
||||
|
||||
fn global_type(&self, global_index: u32) -> &Self::GlobalType {
|
||||
&self.module.globals[GlobalIndex::from_u32(global_index)].ty
|
||||
}
|
||||
|
||||
fn func_type_index(&self, func_idx: u32) -> u32 {
|
||||
self.module.functions[FuncIndex::from_u32(func_idx)].as_u32()
|
||||
}
|
||||
|
||||
fn signature(&self, index: u32) -> &Self::Signature {
|
||||
&self.module.signatures[SignatureIndex::from_u32(index)]
|
||||
}
|
||||
|
||||
fn defined_table_index(&self, table_index: u32) -> Option<u32> {
|
||||
self.module
|
||||
.defined_table_index(TableIndex::from_u32(table_index))
|
||||
.map(|i| i.as_u32())
|
||||
}
|
||||
|
||||
fn defined_memory_index(&self, memory_index: u32) -> Option<u32> {
|
||||
self.module
|
||||
.defined_memory_index(MemoryIndex::from_u32(memory_index))
|
||||
.map(|i| i.as_u32())
|
||||
}
|
||||
|
||||
fn vmctx_vmfunction_import_body(&self, func_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmfunction_import_body(FuncIndex::from_u32(func_index))
|
||||
}
|
||||
fn vmctx_vmfunction_import_vmctx(&self, func_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmfunction_import_vmctx(FuncIndex::from_u32(func_index))
|
||||
}
|
||||
|
||||
fn vmctx_vmglobal_import_from(&self, global_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmglobal_import_from(GlobalIndex::from_u32(global_index))
|
||||
}
|
||||
fn vmctx_vmglobal_definition(&self, defined_global_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmglobal_definition(DefinedGlobalIndex::from_u32(defined_global_index))
|
||||
}
|
||||
fn vmctx_vmmemory_import_from(&self, memory_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmmemory_import_from(MemoryIndex::from_u32(memory_index))
|
||||
}
|
||||
fn vmctx_vmmemory_definition(&self, defined_memory_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmmemory_definition(DefinedMemoryIndex::from_u32(defined_memory_index))
|
||||
}
|
||||
fn vmctx_vmmemory_definition_base(&self, defined_memory_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmmemory_definition_base(DefinedMemoryIndex::from_u32(defined_memory_index))
|
||||
}
|
||||
fn vmctx_vmmemory_definition_current_length(&self, defined_memory_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmmemory_definition_current_length(DefinedMemoryIndex::from_u32(
|
||||
defined_memory_index,
|
||||
))
|
||||
}
|
||||
fn vmmemory_definition_base(&self) -> u8 {
|
||||
self.offsets.vmmemory_definition_base()
|
||||
}
|
||||
fn vmmemory_definition_current_length(&self) -> u8 {
|
||||
self.offsets.vmmemory_definition_current_length()
|
||||
}
|
||||
fn vmctx_vmtable_import_from(&self, table_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmtable_import_from(TableIndex::from_u32(table_index))
|
||||
}
|
||||
fn vmctx_vmtable_definition(&self, defined_table_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmtable_definition(DefinedTableIndex::from_u32(defined_table_index))
|
||||
}
|
||||
fn vmctx_vmtable_definition_base(&self, defined_table_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmtable_definition_base(DefinedTableIndex::from_u32(defined_table_index))
|
||||
}
|
||||
fn vmctx_vmtable_definition_current_elements(&self, defined_table_index: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmtable_definition_current_elements(DefinedTableIndex::from_u32(
|
||||
defined_table_index,
|
||||
))
|
||||
}
|
||||
fn vmtable_definition_base(&self) -> u8 {
|
||||
self.offsets.vmtable_definition_base()
|
||||
}
|
||||
fn vmtable_definition_current_elements(&self) -> u8 {
|
||||
self.offsets.vmtable_definition_current_elements()
|
||||
}
|
||||
fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
|
||||
self.offsets.vmcaller_checked_anyfunc_type_index()
|
||||
}
|
||||
fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
|
||||
self.offsets.vmcaller_checked_anyfunc_func_ptr()
|
||||
}
|
||||
fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
|
||||
self.offsets.vmcaller_checked_anyfunc_vmctx()
|
||||
}
|
||||
fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
|
||||
self.offsets.size_of_vmcaller_checked_anyfunc()
|
||||
}
|
||||
fn vmctx_vmshared_signature_id(&self, signature_idx: u32) -> u32 {
|
||||
self.offsets
|
||||
.vmctx_vmshared_signature_id(SignatureIndex::from_u32(signature_idx))
|
||||
}
|
||||
|
||||
// TODO: type of a global
|
||||
}
|
||||
|
||||
impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'module_environment> {
|
||||
fn target_config(&self) -> TargetFrontendConfig {
|
||||
self.target_config
|
||||
|
||||
@@ -45,11 +45,16 @@ mod tunables;
|
||||
mod vmoffsets;
|
||||
|
||||
pub mod cranelift;
|
||||
#[cfg(feature = "lightbeam")]
|
||||
pub mod lightbeam;
|
||||
|
||||
pub use crate::compilation::{
|
||||
AddressTransforms, Compilation, CompileError, InstructionAddressTransform, Relocation,
|
||||
RelocationTarget, Relocations,
|
||||
AddressTransforms, Compilation, CompileError, Compiler, InstructionAddressTransform,
|
||||
Relocation, RelocationTarget, Relocations,
|
||||
};
|
||||
pub use crate::cranelift::Cranelift;
|
||||
#[cfg(feature = "lightbeam")]
|
||||
pub use crate::lightbeam::Lightbeam;
|
||||
pub use crate::module::{
|
||||
Export, MemoryPlan, MemoryStyle, Module, TableElements, TablePlan, TableStyle,
|
||||
};
|
||||
|
||||
55
wasmtime-environ/src/lightbeam.rs
Normal file
55
wasmtime-environ/src/lightbeam.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
//! Support for compiling with Lightbeam.
|
||||
|
||||
use crate::compilation::{AddressTransforms, Compilation, CompileError, Relocations};
|
||||
use crate::func_environ::FuncEnvironment;
|
||||
use crate::module::Module;
|
||||
use crate::module_environ::FunctionBodyData;
|
||||
// TODO: Put this in `compilation`
|
||||
use crate::cranelift::RelocSink;
|
||||
use cranelift_codegen::isa;
|
||||
use cranelift_entity::PrimaryMap;
|
||||
use cranelift_wasm::DefinedFuncIndex;
|
||||
use lightbeam;
|
||||
|
||||
/// A compiler that compiles a WebAssembly module with Lightbeam, directly translating the Wasm file.
|
||||
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,
|
||||
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
|
||||
isa: &dyn isa::TargetIsa,
|
||||
// TODO
|
||||
_generate_debug_info: bool,
|
||||
) -> Result<(Compilation, Relocations, AddressTransforms), CompileError> {
|
||||
let env = FuncEnvironment::new(isa.frontend_config(), module);
|
||||
let mut relocations = PrimaryMap::new();
|
||||
let mut codegen_session: lightbeam::CodeGenSession<_> =
|
||||
lightbeam::CodeGenSession::new(function_body_inputs.len() as u32, &env);
|
||||
|
||||
for (i, function_body) in &function_body_inputs {
|
||||
let mut reloc_sink = RelocSink::new();
|
||||
|
||||
lightbeam::translate_function(
|
||||
&mut codegen_session,
|
||||
&mut reloc_sink,
|
||||
i.as_u32(),
|
||||
&lightbeam::wasmparser::FunctionBody::new(0, function_body.data),
|
||||
)
|
||||
.expect("Failed to translate function. TODO: Stop this from panicking");
|
||||
relocations.push(reloc_sink.func_relocs);
|
||||
}
|
||||
|
||||
let code_section = codegen_session
|
||||
.into_translated_code_section()
|
||||
.expect("Failed to generate output code. TODO: Stop this from panicking");
|
||||
|
||||
Ok((
|
||||
Compilation::from_buffer(code_section.buffer().to_vec(), code_section.funcs()),
|
||||
relocations,
|
||||
AddressTransforms::new(),
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ wasmparser = "0.29.2"
|
||||
default = ["std"]
|
||||
std = ["cranelift-codegen/std", "cranelift-wasm/std"]
|
||||
core = ["hashbrown/nightly", "cranelift-codegen/core", "cranelift-wasm/core", "wasmtime-environ/core"]
|
||||
lightbeam = ["wasmtime-environ/lightbeam"]
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
|
||||
@@ -17,7 +17,7 @@ use std::vec::Vec;
|
||||
use wasmtime_debug::{emit_debugsections_image, DebugInfoData};
|
||||
use wasmtime_environ::cranelift;
|
||||
use wasmtime_environ::{
|
||||
Compilation, CompileError, FunctionBodyData, Module, Relocations, Tunables,
|
||||
Compilation, CompileError, Compiler as _C, FunctionBodyData, Module, Relocations, Tunables,
|
||||
};
|
||||
use wasmtime_runtime::{InstantiationError, SignatureRegistry, VMFunctionBody};
|
||||
|
||||
@@ -53,6 +53,11 @@ impl Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "lightbeam")]
|
||||
type DefaultCompiler = wasmtime_environ::lightbeam::Lightbeam;
|
||||
#[cfg(not(feature = "lightbeam"))]
|
||||
type DefaultCompiler = wasmtime_environ::cranelift::Cranelift;
|
||||
|
||||
impl Compiler {
|
||||
/// Return the target's frontend configuration settings.
|
||||
pub fn frontend_config(&self) -> TargetFrontendConfig {
|
||||
@@ -78,7 +83,7 @@ impl Compiler {
|
||||
),
|
||||
SetupError,
|
||||
> {
|
||||
let (compilation, relocations, address_transform) = cranelift::compile_module(
|
||||
let (compilation, relocations, address_transform) = DefaultCompiler::compile_module(
|
||||
module,
|
||||
function_body_inputs,
|
||||
&*self.isa,
|
||||
@@ -100,7 +105,7 @@ impl Compiler {
|
||||
let mut funcs = Vec::new();
|
||||
for (i, allocated) in allocated_functions.into_iter() {
|
||||
let ptr = (*allocated) as *const u8;
|
||||
let body_len = compilation.functions[i].len();
|
||||
let body_len = compilation.get(i).len();
|
||||
funcs.push((ptr, body_len));
|
||||
}
|
||||
let bytes = emit_debugsections_image(
|
||||
@@ -255,14 +260,10 @@ fn allocate_functions(
|
||||
// Allocate code for all function in one continuous memory block.
|
||||
// First, collect all function bodies into vector to pass to the
|
||||
// allocate_copy_of_byte_slices.
|
||||
let bodies = compilation
|
||||
.functions
|
||||
.values()
|
||||
.map(|body| body.as_slice())
|
||||
.collect::<Vec<&[u8]>>();
|
||||
let bodies = compilation.into_iter().collect::<Vec<&[u8]>>();
|
||||
let fat_ptrs = code_memory.allocate_copy_of_byte_slices(&bodies)?;
|
||||
// Second, create a PrimaryMap from result vector of pointers.
|
||||
let mut result = PrimaryMap::with_capacity(compilation.functions.len());
|
||||
let mut result = PrimaryMap::with_capacity(compilation.len());
|
||||
for i in 0..fat_ptrs.len() {
|
||||
let fat_ptr: *mut [VMFunctionBody] = fat_ptrs[i];
|
||||
result.push(fat_ptr);
|
||||
|
||||
@@ -62,11 +62,11 @@ pub fn emit_functions(
|
||||
.expect("Missing enable_verifier setting");
|
||||
|
||||
for (i, _function_relocs) in relocations.iter() {
|
||||
let body = &compilation.functions[i];
|
||||
let body = compilation.get(i);
|
||||
let func_index = module.func_index(i);
|
||||
let string_name = format!("_wasm_function_{}", func_index.index());
|
||||
|
||||
obj.define(string_name, body.clone())
|
||||
obj.define(string_name, body.to_vec())
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user