wasmtime: Extract cranelift/lightbeam compilers to separate crates (#2117)

This commit extracts the two implementations of `Compiler` into two
separate crates, `wasmtime-cranelfit` and `wasmtime-lightbeam`. The
`wasmtime-jit` crate then depends on these two and instantiates them
appropriately. The goal here is to start reducing the weight of the
`wasmtime-environ` crate, which currently serves as a common set of
types between all `wasmtime-*` crates. Long-term I'd like to remove the
dependency on Cranelift from `wasmtime-environ`, but that's going to
take a lot more work.

In the meantime I figure it's a good way to get started by separating
out the lightbeam/cranelift function compilers from the
`wasmtime-environ` crate. We can continue to iterate on moving things
out in the future, too.
This commit is contained in:
Alex Crichton
2020-08-20 04:34:31 -05:00
committed by GitHub
parent b5e24c8c67
commit 693c6ea771
19 changed files with 564 additions and 369 deletions

View File

@@ -242,6 +242,7 @@ jobs:
--features test-programs/test_programs \ --features test-programs/test_programs \
--all \ --all \
--exclude lightbeam \ --exclude lightbeam \
--exclude wasmtime-lightbeam \
--exclude peepmatic \ --exclude peepmatic \
--exclude peepmatic-automata \ --exclude peepmatic-automata \
--exclude peepmatic-fuzzing \ --exclude peepmatic-fuzzing \
@@ -375,6 +376,7 @@ jobs:
--release \ --release \
--all \ --all \
--exclude lightbeam \ --exclude lightbeam \
--exclude wasmtime-lightbeam \
--exclude peepmatic \ --exclude peepmatic \
--exclude peepmatic-automata \ --exclude peepmatic-automata \
--exclude peepmatic-fuzzing \ --exclude peepmatic-fuzzing \

25
Cargo.lock generated
View File

@@ -2414,6 +2414,17 @@ dependencies = [
"wat", "wat",
] ]
[[package]]
name = "wasmtime-cranelift"
version = "0.19.0"
dependencies = [
"cranelift-codegen",
"cranelift-entity",
"cranelift-frontend",
"cranelift-wasm",
"wasmtime-environ",
]
[[package]] [[package]]
name = "wasmtime-debug" name = "wasmtime-debug"
version = "0.19.0" version = "0.19.0"
@@ -2436,11 +2447,9 @@ dependencies = [
"cfg-if", "cfg-if",
"cranelift-codegen", "cranelift-codegen",
"cranelift-entity", "cranelift-entity",
"cranelift-frontend",
"cranelift-wasm", "cranelift-wasm",
"gimli 0.21.0", "gimli 0.21.0",
"indexmap", "indexmap",
"lightbeam",
"log", "log",
"more-asserts", "more-asserts",
"serde", "serde",
@@ -2500,14 +2509,26 @@ dependencies = [
"target-lexicon", "target-lexicon",
"thiserror", "thiserror",
"wasmparser 0.59.0", "wasmparser 0.59.0",
"wasmtime-cranelift",
"wasmtime-debug", "wasmtime-debug",
"wasmtime-environ", "wasmtime-environ",
"wasmtime-lightbeam",
"wasmtime-obj", "wasmtime-obj",
"wasmtime-profiling", "wasmtime-profiling",
"wasmtime-runtime", "wasmtime-runtime",
"winapi", "winapi",
] ]
[[package]]
name = "wasmtime-lightbeam"
version = "0.19.0"
dependencies = [
"cranelift-codegen",
"lightbeam",
"wasmparser 0.59.0",
"wasmtime-environ",
]
[[package]] [[package]]
name = "wasmtime-obj" name = "wasmtime-obj"
version = "0.19.0" version = "0.19.0"

View File

@@ -74,12 +74,7 @@ members = [
[features] [features]
default = ["jitdump", "wasmtime/wat", "wasmtime/parallel-compilation"] default = ["jitdump", "wasmtime/wat", "wasmtime/parallel-compilation"]
lightbeam = [ lightbeam = ["wasmtime/lightbeam"]
"wasmtime-environ/lightbeam",
"wasmtime-jit/lightbeam",
"wasmtime-wast/lightbeam",
"wasmtime/lightbeam",
]
jitdump = ["wasmtime/jitdump"] jitdump = ["wasmtime/jitdump"]
vtune = ["wasmtime/vtune"] vtune = ["wasmtime/vtune"]

View File

@@ -0,0 +1,19 @@
[package]
name = "wasmtime-cranelift"
version = "0.19.0"
authors = ["The Wasmtime Project Developers"]
description = "Integration between Cranelift and Wasmtime"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/bytecodealliance/wasmtime"
documentation = "https://docs.rs/wasmtime-cranelift/"
categories = ["wasm"]
keywords = ["webassembly", "wasm"]
readme = "README.md"
edition = "2018"
[dependencies]
wasmtime-environ = { path = "../environ", version = "0.19.0" }
cranelift-wasm = { path = "../../cranelift/wasm", version = "0.66.0" }
cranelift-codegen = { path = "../../cranelift/codegen", version = "0.66.0" }
cranelift-frontend = { path = "../../cranelift/frontend", version = "0.66.0" }
cranelift-entity = { path = "../../cranelift/entity", version = "0.66.0" }

View File

@@ -0,0 +1,4 @@
# `wasmtime-cranelfit`
This crate provides an implementation of the `Compiler` trait which is
connected to Cranelift.

View File

@@ -1,6 +1,3 @@
use crate::module::{MemoryPlan, MemoryStyle, TableStyle};
use crate::vmoffsets::VMOffsets;
use crate::{Module, Tunables, INTERRUPTED, WASM_PAGE_SIZE};
use cranelift_codegen::cursor::FuncCursor; use cranelift_codegen::cursor::FuncCursor;
use cranelift_codegen::ir; use cranelift_codegen::ir;
use cranelift_codegen::ir::condcodes::*; use cranelift_codegen::ir::condcodes::*;
@@ -14,20 +11,18 @@ use cranelift_wasm::{
self, FuncIndex, GlobalIndex, GlobalVariable, MemoryIndex, SignatureIndex, TableIndex, self, FuncIndex, GlobalIndex, GlobalVariable, MemoryIndex, SignatureIndex, TableIndex,
TargetEnvironment, WasmError, WasmResult, WasmType, TargetEnvironment, WasmError, WasmResult, WasmType,
}; };
#[cfg(feature = "lightbeam")]
use cranelift_wasm::{DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex};
use std::convert::TryFrom; use std::convert::TryFrom;
use wasmtime_environ::{
BuiltinFunctionIndex, MemoryPlan, MemoryStyle, Module, TableStyle, Tunables, VMOffsets,
INTERRUPTED, WASM_PAGE_SIZE,
};
/// Compute an `ir::ExternalName` for a given wasm function index. /// Compute an `ir::ExternalName` for a given wasm function index.
pub fn get_func_name(func_index: FuncIndex) -> ir::ExternalName { pub fn get_func_name(func_index: FuncIndex) -> ir::ExternalName {
ir::ExternalName::user(0, func_index.as_u32()) ir::ExternalName::user(0, func_index.as_u32())
} }
/// An index type for builtin functions. macro_rules! declare_function_signatures {
#[derive(Copy, Clone, Debug)]
pub struct BuiltinFunctionIndex(u32);
macro_rules! declare_builtin_functions {
( (
$( $(
$( #[$attr:meta] )* $( #[$attr:meta] )*
@@ -91,111 +86,10 @@ macro_rules! declare_builtin_functions {
} }
)* )*
} }
impl BuiltinFunctionIndex {
declare_builtin_functions!(
@indices;
0;
$( $( #[$attr] )* $name; )*
);
}
}; };
// Base case: no more indices to declare, so define the total number of
// function indices.
(
@indices;
$len:expr;
) => {
/// Returns the total number of builtin functions.
pub const fn builtin_functions_total_number() -> u32 {
$len
}
};
// Recursive case: declare the next index, and then keep declaring the rest of
// the indices.
(
@indices;
$index:expr;
$( #[$this_attr:meta] )*
$this_name:ident;
$(
$( #[$rest_attr:meta] )*
$rest_name:ident;
)*
) => {
$( #[$this_attr] )*
pub const fn $this_name() -> Self {
Self($index)
} }
declare_builtin_functions!( wasmtime_environ::foreach_builtin_function!(declare_function_signatures);
@indices;
($index + 1);
$( $( #[$rest_attr] )* $rest_name; )*
);
}
}
declare_builtin_functions! {
/// Returns an index for wasm's `memory.grow` builtin function.
memory32_grow(vmctx, i32, i32) -> (i32);
/// Returns an index for wasm's imported `memory.grow` builtin function.
imported_memory32_grow(vmctx, i32, i32) -> (i32);
/// Returns an index for wasm's `memory.size` builtin function.
memory32_size(vmctx, i32) -> (i32);
/// Returns an index for wasm's imported `memory.size` builtin function.
imported_memory32_size(vmctx, i32) -> (i32);
/// Returns an index for wasm's `table.copy` when both tables are locally
/// defined.
table_copy(vmctx, i32, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `table.init`.
table_init(vmctx, i32, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `elem.drop`.
elem_drop(vmctx, i32) -> ();
/// Returns an index for wasm's `memory.copy` for locally defined memories.
defined_memory_copy(vmctx, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `memory.copy` for imported memories.
imported_memory_copy(vmctx, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `memory.fill` for locally defined memories.
memory_fill(vmctx, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `memory.fill` for imported memories.
imported_memory_fill(vmctx, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `memory.init` instruction.
memory_init(vmctx, i32, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `data.drop` instruction.
data_drop(vmctx, i32) -> ();
/// Returns an index for Wasm's `table.grow` instruction for `funcref`s.
table_grow_funcref(vmctx, i32, i32, pointer) -> (i32);
/// Returns an index for Wasm's `table.grow` instruction for `externref`s.
table_grow_externref(vmctx, i32, i32, reference) -> (i32);
/// Returns an index for Wasm's `table.fill` instruction for `externref`s.
table_fill_externref(vmctx, i32, i32, reference, i32) -> ();
/// Returns an index for Wasm's `table.fill` instruction for `funcref`s.
table_fill_funcref(vmctx, i32, i32, pointer, i32) -> ();
/// Returns an index to drop a `VMExternRef`.
drop_externref(pointer) -> ();
/// Returns an index to do a GC and then insert a `VMExternRef` into the
/// `VMExternRefActivationsTable`.
activations_table_insert_with_gc(vmctx, reference) -> ();
/// Returns an index for Wasm's `global.get` instruction for `externref`s.
externref_global_get(vmctx, i32) -> (reference);
/// Returns an index for Wasm's `global.get` instruction for `externref`s.
externref_global_set(vmctx, i32, reference) -> ();
}
impl BuiltinFunctionIndex {
/// Create a new `BuiltinFunctionIndex` from its index
pub const fn from_u32(i: u32) -> Self {
Self(i)
}
/// Return the index as an u32 number.
pub const fn index(&self) -> u32 {
self.0
}
}
/// The `FuncEnvironment` implementation for use by the `ModuleEnvironment`. /// The `FuncEnvironment` implementation for use by the `ModuleEnvironment`.
pub struct FuncEnvironment<'module_environment> { pub struct FuncEnvironment<'module_environment> {
@@ -464,153 +358,13 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
} }
} }
// TODO: This is necessary as if Lightbeam used `FuncEnvironment` directly it would cause
// a circular dependency graph. We should extract common types out into a separate
// crate that Lightbeam can use but until then we need this trait.
#[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(DefinedFuncIndex::as_u32)
}
fn defined_global_index(&self, global_index: u32) -> Option<u32> {
self.module
.defined_global_index(GlobalIndex::from_u32(global_index))
.map(DefinedGlobalIndex::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)].1
}
fn defined_table_index(&self, table_index: u32) -> Option<u32> {
self.module
.defined_table_index(TableIndex::from_u32(table_index))
.map(DefinedTableIndex::as_u32)
}
fn defined_memory_index(&self, memory_index: u32) -> Option<u32> {
self.module
.defined_memory_index(MemoryIndex::from_u32(memory_index))
.map(DefinedMemoryIndex::as_u32)
}
fn vmctx_builtin_function(&self, func_index: u32) -> u32 {
self.offsets
.vmctx_builtin_function(BuiltinFunctionIndex::from_u32(func_index))
}
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> TargetEnvironment for FuncEnvironment<'module_environment> { impl<'module_environment> TargetEnvironment for FuncEnvironment<'module_environment> {
fn target_config(&self) -> TargetFrontendConfig { fn target_config(&self) -> TargetFrontendConfig {
self.target_config self.target_config
} }
fn reference_type(&self, ty: WasmType) -> ir::Type { fn reference_type(&self, ty: WasmType) -> ir::Type {
crate::reference_type(ty, self.pointer_type()) wasmtime_environ::reference_type(ty, self.pointer_type())
} }
} }

View File

@@ -1,4 +1,7 @@
//! Support for compiling with Cranelift. //! Support for compiling with Cranelift.
//!
//! This crate provides an implementation of [`Compiler`] in the form of
//! [`Cranelift`].
// # How does Wasmtime prevent stack overflow? // # How does Wasmtime prevent stack overflow?
// //
@@ -86,13 +89,6 @@
// assume no valid stack pointer will ever be `usize::max_value() - 32k`. // assume no valid stack pointer will ever be `usize::max_value() - 32k`.
use crate::func_environ::{get_func_name, FuncEnvironment}; use crate::func_environ::{get_func_name, FuncEnvironment};
use crate::Compiler;
use crate::{
CompileError, CompiledFunction, Relocation, RelocationTarget, StackMapInformation,
TrapInformation,
};
use crate::{FunctionAddressMap, InstructionAddressMap};
use crate::{FunctionBodyData, ModuleTranslation};
use cranelift_codegen::ir::{self, ExternalName}; use cranelift_codegen::ir::{self, ExternalName};
use cranelift_codegen::machinst::buffer::MachSrcLoc; use cranelift_codegen::machinst::buffer::MachSrcLoc;
use cranelift_codegen::print_errors::pretty_error; use cranelift_codegen::print_errors::pretty_error;
@@ -100,14 +96,21 @@ use cranelift_codegen::{binemit, isa, Context};
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator}; use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::sync::Mutex; use std::sync::Mutex;
use wasmtime_environ::{
CompileError, CompiledFunction, Compiler, FunctionAddressMap, FunctionBodyData,
InstructionAddressMap, ModuleTranslation, Relocation, RelocationTarget, StackMapInformation,
TrapInformation,
};
mod func_environ;
/// Implementation of a relocation sink that just saves all the information for later /// Implementation of a relocation sink that just saves all the information for later
pub struct RelocSink { struct RelocSink {
/// Current function index. /// Current function index.
func_index: FuncIndex, func_index: FuncIndex,
/// Relocations recorded for the function. /// Relocations recorded for the function.
pub func_relocs: Vec<Relocation>, func_relocs: Vec<Relocation>,
} }
impl binemit::RelocSink for RelocSink { impl binemit::RelocSink for RelocSink {
@@ -166,7 +169,7 @@ impl binemit::RelocSink for RelocSink {
impl RelocSink { impl RelocSink {
/// Return a new `RelocSink` instance. /// Return a new `RelocSink` instance.
pub fn new(func_index: FuncIndex) -> Self { fn new(func_index: FuncIndex) -> Self {
Self { Self {
func_index, func_index,
func_relocs: Vec::new(), func_relocs: Vec::new(),
@@ -176,14 +179,14 @@ impl RelocSink {
/// Implementation of a trap sink that simply stores all trap info in-memory /// Implementation of a trap sink that simply stores all trap info in-memory
#[derive(Default)] #[derive(Default)]
pub struct TrapSink { struct TrapSink {
/// The in-memory vector of trap info /// The in-memory vector of trap info
pub traps: Vec<TrapInformation>, traps: Vec<TrapInformation>,
} }
impl TrapSink { impl TrapSink {
/// Create a new `TrapSink` /// Create a new `TrapSink`
pub fn new() -> Self { fn new() -> Self {
Self::default() Self::default()
} }
} }

View File

@@ -15,10 +15,8 @@ edition = "2018"
anyhow = "1.0" anyhow = "1.0"
cranelift-codegen = { path = "../../cranelift/codegen", version = "0.66.0", features = ["enable-serde"] } cranelift-codegen = { path = "../../cranelift/codegen", version = "0.66.0", features = ["enable-serde"] }
cranelift-entity = { path = "../../cranelift/entity", version = "0.66.0", features = ["enable-serde"] } cranelift-entity = { path = "../../cranelift/entity", version = "0.66.0", features = ["enable-serde"] }
cranelift-frontend = { path = "../../cranelift/frontend", version = "0.66.0" }
cranelift-wasm = { path = "../../cranelift/wasm", version = "0.66.0", features = ["enable-serde"] } cranelift-wasm = { path = "../../cranelift/wasm", version = "0.66.0", features = ["enable-serde"] }
wasmparser = "0.59.0" wasmparser = "0.59.0"
lightbeam = { path = "../lightbeam", optional = true, version = "0.19.0" }
indexmap = { version = "1.0.2", features = ["serde-1"] } indexmap = { version = "1.0.2", features = ["serde-1"] }
thiserror = "1.0.4" thiserror = "1.0.4"
serde = { version = "1.0.94", features = ["derive"] } serde = { version = "1.0.94", features = ["derive"] }

View File

@@ -0,0 +1,123 @@
/// Helper macro to iterate over all builtin functions and their signatures.
#[macro_export]
macro_rules! foreach_builtin_function {
($mac:ident) => {
$mac! {
/// Returns an index for wasm's `memory.grow` builtin function.
memory32_grow(vmctx, i32, i32) -> (i32);
/// Returns an index for wasm's imported `memory.grow` builtin function.
imported_memory32_grow(vmctx, i32, i32) -> (i32);
/// Returns an index for wasm's `memory.size` builtin function.
memory32_size(vmctx, i32) -> (i32);
/// Returns an index for wasm's imported `memory.size` builtin function.
imported_memory32_size(vmctx, i32) -> (i32);
/// Returns an index for wasm's `table.copy` when both tables are locally
/// defined.
table_copy(vmctx, i32, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `table.init`.
table_init(vmctx, i32, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `elem.drop`.
elem_drop(vmctx, i32) -> ();
/// Returns an index for wasm's `memory.copy` for locally defined memories.
defined_memory_copy(vmctx, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `memory.copy` for imported memories.
imported_memory_copy(vmctx, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `memory.fill` for locally defined memories.
memory_fill(vmctx, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `memory.fill` for imported memories.
imported_memory_fill(vmctx, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `memory.init` instruction.
memory_init(vmctx, i32, i32, i32, i32, i32) -> ();
/// Returns an index for wasm's `data.drop` instruction.
data_drop(vmctx, i32) -> ();
/// Returns an index for Wasm's `table.grow` instruction for `funcref`s.
table_grow_funcref(vmctx, i32, i32, pointer) -> (i32);
/// Returns an index for Wasm's `table.grow` instruction for `externref`s.
table_grow_externref(vmctx, i32, i32, reference) -> (i32);
/// Returns an index for Wasm's `table.fill` instruction for `externref`s.
table_fill_externref(vmctx, i32, i32, reference, i32) -> ();
/// Returns an index for Wasm's `table.fill` instruction for `funcref`s.
table_fill_funcref(vmctx, i32, i32, pointer, i32) -> ();
/// Returns an index to drop a `VMExternRef`.
drop_externref(pointer) -> ();
/// Returns an index to do a GC and then insert a `VMExternRef` into the
/// `VMExternRefActivationsTable`.
activations_table_insert_with_gc(vmctx, reference) -> ();
/// Returns an index for Wasm's `global.get` instruction for `externref`s.
externref_global_get(vmctx, i32) -> (reference);
/// Returns an index for Wasm's `global.get` instruction for `externref`s.
externref_global_set(vmctx, i32, reference) -> ();
}
};
}
/// An index type for builtin functions.
#[derive(Copy, Clone, Debug)]
pub struct BuiltinFunctionIndex(u32);
impl BuiltinFunctionIndex {
/// Create a new `BuiltinFunctionIndex` from its index
pub const fn from_u32(i: u32) -> Self {
Self(i)
}
/// Return the index as an u32 number.
pub const fn index(&self) -> u32 {
self.0
}
}
macro_rules! declare_indexes {
(
$(
$( #[$attr:meta] )*
$name:ident( $( $param:ident ),* ) -> ( $( $result:ident ),* );
)*
) => {
impl BuiltinFunctionIndex {
declare_indexes!(
@indices;
0;
$( $( #[$attr] )* $name; )*
);
}
};
// Base case: no more indices to declare, so define the total number of
// function indices.
(
@indices;
$len:expr;
) => {
/// Returns the total number of builtin functions.
pub const fn builtin_functions_total_number() -> u32 {
$len
}
};
// Recursive case: declare the next index, and then keep declaring the rest of
// the indices.
(
@indices;
$index:expr;
$( #[$this_attr:meta] )*
$this_name:ident;
$(
$( #[$rest_attr:meta] )*
$rest_name:ident;
)*
) => {
$( #[$this_attr] )*
pub const fn $this_name() -> Self {
Self($index)
}
declare_indexes!(
@indices;
($index + 1);
$( $( #[$rest_attr] )* $rest_name; )*
);
}
}
foreach_builtin_function!(declare_indexes);

View File

@@ -25,25 +25,19 @@
)] )]
mod address_map; mod address_map;
mod builtin;
mod compilation; mod compilation;
mod data_structures; mod data_structures;
mod func_environ;
mod module; mod module;
mod module_environ; mod module_environ;
mod tunables; mod tunables;
mod vmoffsets; mod vmoffsets;
pub mod cranelift;
#[cfg(feature = "lightbeam")]
pub mod lightbeam;
pub use crate::address_map::*; pub use crate::address_map::*;
pub use crate::builtin::*;
pub use crate::compilation::*; pub use crate::compilation::*;
pub use crate::cranelift::Cranelift;
pub use crate::data_structures::*; pub use crate::data_structures::*;
pub use crate::func_environ::BuiltinFunctionIndex; // pub use crate::func_environ::BuiltinFunctionIndex;
#[cfg(feature = "lightbeam")]
pub use crate::lightbeam::Lightbeam;
pub use crate::module::{ pub use crate::module::{
EntityIndex, MemoryPlan, MemoryStyle, Module, TableElements, TablePlan, TableStyle, EntityIndex, MemoryPlan, MemoryStyle, Module, TableElements, TablePlan, TableStyle,
}; };
@@ -60,10 +54,8 @@ pub const WASM_MAX_PAGES: u32 = 0x10000;
/// Version number of this crate. /// Version number of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub(crate) fn reference_type( /// Returns the reference type to use for the provided wasm type.
wasm_ty: cranelift_wasm::WasmType, pub fn reference_type(wasm_ty: cranelift_wasm::WasmType, pointer_type: ir::Type) -> ir::Type {
pointer_type: ir::Type,
) -> ir::Type {
match wasm_ty { match wasm_ty {
cranelift_wasm::WasmType::FuncRef => pointer_type, cranelift_wasm::WasmType::FuncRef => pointer_type,
cranelift_wasm::WasmType::ExternRef => match pointer_type { cranelift_wasm::WasmType::ExternRef => match pointer_type {

View File

@@ -1,71 +0,0 @@
//! Support for compiling with Lightbeam.
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_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 {
fn compile_function(
&self,
translation: &ModuleTranslation,
i: DefinedFuncIndex,
function_body: &FunctionBodyData<'_>,
isa: &dyn isa::TargetIsa,
) -> Result<CompiledFunction, CompileError> {
if translation.tunables.debug_info {
return Err(CompileError::DebugInfoNotSupported);
}
let func_index = translation.module.func_index(i);
let env = FuncEnvironment::new(
isa.frontend_config(),
&translation.module,
&translation.tunables,
);
let mut codegen_session: CodeGenSession<_> = CodeGenSession::new(
translation.function_body_inputs.len() as u32,
&env,
lightbeam::microwasm::I32,
);
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)))?;
Ok(CompiledFunction {
// TODO: try to remove copy here (?)
body: code_section.buffer().to_vec(),
traps: trap_sink.traps,
relocations: reloc_sink.func_relocs,
// 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(),
})
}
}

View File

@@ -19,6 +19,8 @@ cranelift-native = { path = "../../cranelift/native", version = "0.66.0" }
cranelift-frontend = { path = "../../cranelift/frontend", version = "0.66.0" } cranelift-frontend = { path = "../../cranelift/frontend", version = "0.66.0" }
wasmtime-environ = { path = "../environ", version = "0.19.0" } wasmtime-environ = { path = "../environ", version = "0.19.0" }
wasmtime-runtime = { path = "../runtime", version = "0.19.0" } wasmtime-runtime = { path = "../runtime", version = "0.19.0" }
wasmtime-cranelift = { path = "../cranelift", version = "0.19.0" }
wasmtime-lightbeam = { path = "../lightbeam/wasmtime", version = "0.19.0", optional = true }
wasmtime-debug = { path = "../debug", version = "0.19.0" } wasmtime-debug = { path = "../debug", version = "0.19.0" }
wasmtime-profiling = { path = "../profiling", version = "0.19.0" } wasmtime-profiling = { path = "../profiling", version = "0.19.0" }
wasmtime-obj = { path = "../obj", version = "0.19.0" } wasmtime-obj = { path = "../obj", version = "0.19.0" }
@@ -39,7 +41,7 @@ serde = { version = "1.0.94", features = ["derive"] }
winapi = { version = "0.3.8", features = ["winnt", "impl-default"] } winapi = { version = "0.3.8", features = ["winnt", "impl-default"] }
[features] [features]
lightbeam = ["wasmtime-environ/lightbeam"] lightbeam = ["wasmtime-lightbeam"]
jitdump = ["wasmtime-profiling/jitdump"] jitdump = ["wasmtime-profiling/jitdump"]
vtune = ["wasmtime-profiling/vtune"] vtune = ["wasmtime-profiling/vtune"]
parallel-compilation = ["rayon"] parallel-compilation = ["rayon"]

View File

@@ -50,10 +50,10 @@ impl Compiler {
strategy, strategy,
compiler: match strategy { compiler: match strategy {
CompilationStrategy::Auto | CompilationStrategy::Cranelift => { CompilationStrategy::Auto | CompilationStrategy::Cranelift => {
Box::new(wasmtime_environ::cranelift::Cranelift::default()) Box::new(wasmtime_cranelift::Cranelift::default())
} }
#[cfg(feature = "lightbeam")] #[cfg(feature = "lightbeam")]
CompilationStrategy::Lightbeam => Box::new(wasmtime_environ::lightbeam::Lightbeam), CompilationStrategy::Lightbeam => Box::new(wasmtime_lightbeam::Lightbeam),
}, },
tunables, tunables,
} }

View File

@@ -0,0 +1,18 @@
[package]
name = "wasmtime-lightbeam"
version = "0.19.0"
authors = ["The Wasmtime Project Developers"]
description = "Integration between Lightbeam and Wasmtime"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/bytecodealliance/wasmtime"
documentation = "https://docs.rs/wasmtime-lightbeam/"
categories = ["wasm"]
keywords = ["webassembly", "wasm"]
readme = "README.md"
edition = "2018"
[dependencies]
lightbeam = { path = "..", version = "0.19.0" }
wasmparser = "0.59"
cranelift-codegen = { path = "../../../cranelift/codegen", version = "0.66.0" }
wasmtime-environ = { path = "../../environ", version = "0.19.0" }

View File

@@ -0,0 +1,4 @@
# `wasmtime-lightbeam`
This crate provides an implementation of the `Compiler` trait which is
connected to Lightbeam.

View File

@@ -0,0 +1,334 @@
//! Support for compiling with Lightbeam.
//!
//! This crates provides an implementation of [`Compiler`] in the form of
//! [`Lightbeam`].
use cranelift_codegen::binemit;
use cranelift_codegen::ir::{self, ExternalName};
use cranelift_codegen::isa;
use lightbeam::{CodeGenSession, NullOffsetSink, Sinks};
use wasmtime_environ::wasm::{
DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex,
GlobalIndex, MemoryIndex, SignatureIndex, TableIndex,
};
use wasmtime_environ::{
BuiltinFunctionIndex, CompileError, CompiledFunction, Compiler, FunctionBodyData, Module,
ModuleTranslation, Relocation, RelocationTarget, TrapInformation, VMOffsets,
};
/// A compiler that compiles a WebAssembly module with Lightbeam, directly translating the Wasm file.
pub struct Lightbeam;
impl Compiler for Lightbeam {
fn compile_function(
&self,
translation: &ModuleTranslation,
i: DefinedFuncIndex,
function_body: &FunctionBodyData<'_>,
isa: &dyn isa::TargetIsa,
) -> Result<CompiledFunction, CompileError> {
if translation.tunables.debug_info {
return Err(CompileError::DebugInfoNotSupported);
}
let func_index = translation.module.func_index(i);
let env = FuncEnvironment::new(isa.frontend_config().pointer_bytes(), &translation.module);
let mut codegen_session: CodeGenSession<_> = CodeGenSession::new(
translation.function_body_inputs.len() as u32,
&env,
lightbeam::microwasm::I32,
);
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)))?;
Ok(CompiledFunction {
// TODO: try to remove copy here (?)
body: code_section.buffer().to_vec(),
traps: trap_sink.traps,
relocations: reloc_sink.func_relocs,
// 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(),
})
}
}
/// Implementation of a relocation sink that just saves all the information for later
struct RelocSink {
/// Current function index.
func_index: FuncIndex,
/// Relocations recorded for the function.
func_relocs: Vec<Relocation>,
}
impl binemit::RelocSink for RelocSink {
fn reloc_block(
&mut self,
_offset: binemit::CodeOffset,
_reloc: binemit::Reloc,
_block_offset: binemit::CodeOffset,
) {
// This should use the `offsets` field of `ir::Function`.
panic!("block headers not yet implemented");
}
fn reloc_external(
&mut self,
offset: binemit::CodeOffset,
_srcloc: ir::SourceLoc,
reloc: binemit::Reloc,
name: &ExternalName,
addend: binemit::Addend,
) {
let reloc_target = if let ExternalName::User { namespace, index } = *name {
debug_assert_eq!(namespace, 0);
RelocationTarget::UserFunc(FuncIndex::from_u32(index))
} else if let ExternalName::LibCall(libcall) = *name {
RelocationTarget::LibCall(libcall)
} else {
panic!("unrecognized external name")
};
self.func_relocs.push(Relocation {
reloc,
reloc_target,
offset,
addend,
});
}
fn reloc_constant(
&mut self,
_code_offset: binemit::CodeOffset,
_reloc: binemit::Reloc,
_constant_offset: ir::ConstantOffset,
) {
// Do nothing for now: cranelift emits constant data after the function code and also emits
// function code with correct relative offsets to the constant data.
}
fn reloc_jt(&mut self, offset: binemit::CodeOffset, reloc: binemit::Reloc, jt: ir::JumpTable) {
self.func_relocs.push(Relocation {
reloc,
reloc_target: RelocationTarget::JumpTable(self.func_index, jt),
offset,
addend: 0,
});
}
}
impl RelocSink {
/// Return a new `RelocSink` instance.
fn new(func_index: FuncIndex) -> Self {
Self {
func_index,
func_relocs: Vec::new(),
}
}
}
/// Implementation of a trap sink that simply stores all trap info in-memory
#[derive(Default)]
struct TrapSink {
/// The in-memory vector of trap info
traps: Vec<TrapInformation>,
}
impl TrapSink {
/// Create a new `TrapSink`
fn new() -> Self {
Self::default()
}
}
impl binemit::TrapSink for TrapSink {
fn trap(
&mut self,
code_offset: binemit::CodeOffset,
source_loc: ir::SourceLoc,
trap_code: ir::TrapCode,
) {
self.traps.push(TrapInformation {
code_offset,
source_loc,
trap_code,
});
}
}
/// The `FuncEnvironment` implementation for use by the `ModuleEnvironment`.
struct FuncEnvironment<'module_environment> {
/// The module-level environment which this function-level environment belongs to.
module: &'module_environment Module,
/// Offsets to struct fields accessed by JIT code.
offsets: VMOffsets,
}
impl<'module_environment> FuncEnvironment<'module_environment> {
fn new(pointer_bytes: u8, module: &'module_environment Module) -> Self {
Self {
module,
offsets: VMOffsets::new(pointer_bytes, module),
}
}
}
// TODO: This is necessary as if Lightbeam used `FuncEnvironment` directly it would cause
// a circular dependency graph. We should extract common types out into a separate
// crate that Lightbeam can use but until then we need this trait.
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(DefinedFuncIndex::as_u32)
}
fn defined_global_index(&self, global_index: u32) -> Option<u32> {
self.module
.defined_global_index(GlobalIndex::from_u32(global_index))
.map(DefinedGlobalIndex::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)].1
}
fn defined_table_index(&self, table_index: u32) -> Option<u32> {
self.module
.defined_table_index(TableIndex::from_u32(table_index))
.map(DefinedTableIndex::as_u32)
}
fn defined_memory_index(&self, memory_index: u32) -> Option<u32> {
self.module
.defined_memory_index(MemoryIndex::from_u32(memory_index))
.map(DefinedMemoryIndex::as_u32)
}
fn vmctx_builtin_function(&self, func_index: u32) -> u32 {
self.offsets
.vmctx_builtin_function(BuiltinFunctionIndex::from_u32(func_index))
}
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
}

View File

@@ -17,6 +17,3 @@ wast = "22.0.0"
[badges] [badges]
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }
[features]
lightbeam = ["wasmtime/lightbeam"]

View File

@@ -56,6 +56,8 @@ const CRATES_TO_PUBLISH: &[&str] = &[
"wasmtime-debug", "wasmtime-debug",
"wasmtime-profiling", "wasmtime-profiling",
"wasmtime-obj", "wasmtime-obj",
"wasmtime-cranelift",
"wasmtime-lightbeam",
"wasmtime-jit", "wasmtime-jit",
"wasmtime-cache", "wasmtime-cache",
"wasmtime", "wasmtime",
@@ -298,7 +300,7 @@ fn verify(crates: &[Crate]) {
.arg("--manifest-path") .arg("--manifest-path")
.arg(&krate.manifest) .arg(&krate.manifest)
.env("CARGO_TARGET_DIR", "./target"); .env("CARGO_TARGET_DIR", "./target");
if krate.name == "lightbeam" || krate.name == "witx" { if krate.name.contains("lightbeam") || krate.name == "witx" {
cmd.arg("--no-verify"); cmd.arg("--no-verify");
} }
let status = cmd.status().unwrap(); let status = cmd.status().unwrap();

View File

@@ -2,8 +2,6 @@ use anyhow::{bail, Context as _, Result};
use object::write::Object; use object::write::Object;
use target_lexicon::Triple; use target_lexicon::Triple;
use wasmtime::Strategy; use wasmtime::Strategy;
#[cfg(feature = "lightbeam")]
use wasmtime_environ::Lightbeam;
use wasmtime_environ::{settings, settings::Configurable, ModuleEnvironment, Tunables}; use wasmtime_environ::{settings, settings::Configurable, ModuleEnvironment, Tunables};
use wasmtime_jit::{native, Compiler}; use wasmtime_jit::{native, Compiler};