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:
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -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
25
Cargo.lock
generated
@@ -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"
|
||||||
|
|||||||
@@ -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"]
|
||||||
|
|
||||||
|
|||||||
19
crates/cranelift/Cargo.toml
Normal file
19
crates/cranelift/Cargo.toml
Normal 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" }
|
||||||
4
crates/cranelift/README.md
Normal file
4
crates/cranelift/README.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# `wasmtime-cranelfit`
|
||||||
|
|
||||||
|
This crate provides an implementation of the `Compiler` trait which is
|
||||||
|
connected to Cranelift.
|
||||||
@@ -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!(
|
|
||||||
@indices;
|
|
||||||
($index + 1);
|
|
||||||
$( $( #[$rest_attr] )* $rest_name; )*
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_builtin_functions! {
|
wasmtime_environ::foreach_builtin_function!(declare_function_signatures);
|
||||||
/// 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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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"] }
|
||||||
|
|||||||
123
crates/environ/src/builtin.rs
Normal file
123
crates/environ/src/builtin.rs
Normal 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);
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"]
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
18
crates/lightbeam/wasmtime/Cargo.toml
Normal file
18
crates/lightbeam/wasmtime/Cargo.toml
Normal 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" }
|
||||||
4
crates/lightbeam/wasmtime/README.md
Normal file
4
crates/lightbeam/wasmtime/README.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# `wasmtime-lightbeam`
|
||||||
|
|
||||||
|
This crate provides an implementation of the `Compiler` trait which is
|
||||||
|
connected to Lightbeam.
|
||||||
334
crates/lightbeam/wasmtime/src/lib.rs
Normal file
334
crates/lightbeam/wasmtime/src/lib.rs
Normal 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
|
||||||
|
}
|
||||||
@@ -17,6 +17,3 @@ wast = "22.0.0"
|
|||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "actively-developed" }
|
maintenance = { status = "actively-developed" }
|
||||||
|
|
||||||
[features]
|
|
||||||
lightbeam = ["wasmtime/lightbeam"]
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user