From 693c6ea7715060950702d85f2dcf16627026b0da Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 20 Aug 2020 04:34:31 -0500 Subject: [PATCH] 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. --- .github/workflows/main.yml | 2 + Cargo.lock | 25 +- Cargo.toml | 7 +- crates/cranelift/Cargo.toml | 19 + crates/cranelift/README.md | 4 + .../src/func_environ.rs | 260 +------------- .../src/cranelift.rs => cranelift/src/lib.rs} | 29 +- crates/environ/Cargo.toml | 2 - crates/environ/src/builtin.rs | 123 +++++++ crates/environ/src/lib.rs | 18 +- crates/environ/src/lightbeam.rs | 71 ---- crates/jit/Cargo.toml | 4 +- crates/jit/src/compiler.rs | 4 +- crates/lightbeam/wasmtime/Cargo.toml | 18 + crates/lightbeam/wasmtime/README.md | 4 + crates/lightbeam/wasmtime/src/lib.rs | 334 ++++++++++++++++++ crates/wast/Cargo.toml | 3 - scripts/publish.rs | 4 +- src/obj.rs | 2 - 19 files changed, 564 insertions(+), 369 deletions(-) create mode 100644 crates/cranelift/Cargo.toml create mode 100644 crates/cranelift/README.md rename crates/{environ => cranelift}/src/func_environ.rs (84%) rename crates/{environ/src/cranelift.rs => cranelift/src/lib.rs} (96%) create mode 100644 crates/environ/src/builtin.rs delete mode 100644 crates/environ/src/lightbeam.rs create mode 100644 crates/lightbeam/wasmtime/Cargo.toml create mode 100644 crates/lightbeam/wasmtime/README.md create mode 100644 crates/lightbeam/wasmtime/src/lib.rs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 88674b47d3..6f3a79baeb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -242,6 +242,7 @@ jobs: --features test-programs/test_programs \ --all \ --exclude lightbeam \ + --exclude wasmtime-lightbeam \ --exclude peepmatic \ --exclude peepmatic-automata \ --exclude peepmatic-fuzzing \ @@ -375,6 +376,7 @@ jobs: --release \ --all \ --exclude lightbeam \ + --exclude wasmtime-lightbeam \ --exclude peepmatic \ --exclude peepmatic-automata \ --exclude peepmatic-fuzzing \ diff --git a/Cargo.lock b/Cargo.lock index 77e99deddf..db70f7da2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2414,6 +2414,17 @@ dependencies = [ "wat", ] +[[package]] +name = "wasmtime-cranelift" +version = "0.19.0" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "cranelift-wasm", + "wasmtime-environ", +] + [[package]] name = "wasmtime-debug" version = "0.19.0" @@ -2436,11 +2447,9 @@ dependencies = [ "cfg-if", "cranelift-codegen", "cranelift-entity", - "cranelift-frontend", "cranelift-wasm", "gimli 0.21.0", "indexmap", - "lightbeam", "log", "more-asserts", "serde", @@ -2500,14 +2509,26 @@ dependencies = [ "target-lexicon", "thiserror", "wasmparser 0.59.0", + "wasmtime-cranelift", "wasmtime-debug", "wasmtime-environ", + "wasmtime-lightbeam", "wasmtime-obj", "wasmtime-profiling", "wasmtime-runtime", "winapi", ] +[[package]] +name = "wasmtime-lightbeam" +version = "0.19.0" +dependencies = [ + "cranelift-codegen", + "lightbeam", + "wasmparser 0.59.0", + "wasmtime-environ", +] + [[package]] name = "wasmtime-obj" version = "0.19.0" diff --git a/Cargo.toml b/Cargo.toml index 983811b326..ba36d92e89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,12 +74,7 @@ members = [ [features] default = ["jitdump", "wasmtime/wat", "wasmtime/parallel-compilation"] -lightbeam = [ - "wasmtime-environ/lightbeam", - "wasmtime-jit/lightbeam", - "wasmtime-wast/lightbeam", - "wasmtime/lightbeam", -] +lightbeam = ["wasmtime/lightbeam"] jitdump = ["wasmtime/jitdump"] vtune = ["wasmtime/vtune"] diff --git a/crates/cranelift/Cargo.toml b/crates/cranelift/Cargo.toml new file mode 100644 index 0000000000..f3a586e9dd --- /dev/null +++ b/crates/cranelift/Cargo.toml @@ -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" } diff --git a/crates/cranelift/README.md b/crates/cranelift/README.md new file mode 100644 index 0000000000..c5f7934a8e --- /dev/null +++ b/crates/cranelift/README.md @@ -0,0 +1,4 @@ +# `wasmtime-cranelfit` + +This crate provides an implementation of the `Compiler` trait which is +connected to Cranelift. diff --git a/crates/environ/src/func_environ.rs b/crates/cranelift/src/func_environ.rs similarity index 84% rename from crates/environ/src/func_environ.rs rename to crates/cranelift/src/func_environ.rs index aeaf5f6e79..a7845361eb 100644 --- a/crates/environ/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -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::ir; use cranelift_codegen::ir::condcodes::*; @@ -14,20 +11,18 @@ use cranelift_wasm::{ self, FuncIndex, GlobalIndex, GlobalVariable, MemoryIndex, SignatureIndex, TableIndex, TargetEnvironment, WasmError, WasmResult, WasmType, }; -#[cfg(feature = "lightbeam")] -use cranelift_wasm::{DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex}; 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. pub fn get_func_name(func_index: FuncIndex) -> ir::ExternalName { ir::ExternalName::user(0, func_index.as_u32()) } -/// An index type for builtin functions. -#[derive(Copy, Clone, Debug)] -pub struct BuiltinFunctionIndex(u32); - -macro_rules! declare_builtin_functions { +macro_rules! declare_function_signatures { ( $( $( #[$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! { - /// 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 - } -} +wasmtime_environ::foreach_builtin_function!(declare_function_signatures); /// The `FuncEnvironment` implementation for use by the `ModuleEnvironment`. 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 { - self.module - .defined_func_index(FuncIndex::from_u32(func_index)) - .map(DefinedFuncIndex::as_u32) - } - - fn defined_global_index(&self, global_index: u32) -> Option { - 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 { - self.module - .defined_table_index(TableIndex::from_u32(table_index)) - .map(DefinedTableIndex::as_u32) - } - - fn defined_memory_index(&self, memory_index: u32) -> Option { - 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> { fn target_config(&self) -> TargetFrontendConfig { self.target_config } fn reference_type(&self, ty: WasmType) -> ir::Type { - crate::reference_type(ty, self.pointer_type()) + wasmtime_environ::reference_type(ty, self.pointer_type()) } } diff --git a/crates/environ/src/cranelift.rs b/crates/cranelift/src/lib.rs similarity index 96% rename from crates/environ/src/cranelift.rs rename to crates/cranelift/src/lib.rs index 86b55a253f..c6670659fc 100644 --- a/crates/environ/src/cranelift.rs +++ b/crates/cranelift/src/lib.rs @@ -1,4 +1,7 @@ //! Support for compiling with Cranelift. +//! +//! This crate provides an implementation of [`Compiler`] in the form of +//! [`Cranelift`]. // # How does Wasmtime prevent stack overflow? // @@ -86,13 +89,6 @@ // assume no valid stack pointer will ever be `usize::max_value() - 32k`. 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::machinst::buffer::MachSrcLoc; use cranelift_codegen::print_errors::pretty_error; @@ -100,14 +96,21 @@ use cranelift_codegen::{binemit, isa, Context}; use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator}; use std::convert::TryFrom; 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 -pub struct RelocSink { +struct RelocSink { /// Current function index. func_index: FuncIndex, /// Relocations recorded for the function. - pub func_relocs: Vec, + func_relocs: Vec, } impl binemit::RelocSink for RelocSink { @@ -166,7 +169,7 @@ impl binemit::RelocSink for RelocSink { impl RelocSink { /// Return a new `RelocSink` instance. - pub fn new(func_index: FuncIndex) -> Self { + fn new(func_index: FuncIndex) -> Self { Self { func_index, func_relocs: Vec::new(), @@ -176,14 +179,14 @@ impl RelocSink { /// Implementation of a trap sink that simply stores all trap info in-memory #[derive(Default)] -pub struct TrapSink { +struct TrapSink { /// The in-memory vector of trap info - pub traps: Vec, + traps: Vec, } impl TrapSink { /// Create a new `TrapSink` - pub fn new() -> Self { + fn new() -> Self { Self::default() } } diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml index 0dac39f985..636079815a 100644 --- a/crates/environ/Cargo.toml +++ b/crates/environ/Cargo.toml @@ -15,10 +15,8 @@ edition = "2018" anyhow = "1.0" 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-frontend = { path = "../../cranelift/frontend", version = "0.66.0" } cranelift-wasm = { path = "../../cranelift/wasm", version = "0.66.0", features = ["enable-serde"] } wasmparser = "0.59.0" -lightbeam = { path = "../lightbeam", optional = true, version = "0.19.0" } indexmap = { version = "1.0.2", features = ["serde-1"] } thiserror = "1.0.4" serde = { version = "1.0.94", features = ["derive"] } diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs new file mode 100644 index 0000000000..1060f7caaa --- /dev/null +++ b/crates/environ/src/builtin.rs @@ -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); diff --git a/crates/environ/src/lib.rs b/crates/environ/src/lib.rs index d077926321..f5ab4358c5 100644 --- a/crates/environ/src/lib.rs +++ b/crates/environ/src/lib.rs @@ -25,25 +25,19 @@ )] mod address_map; +mod builtin; mod compilation; mod data_structures; -mod func_environ; mod module; mod module_environ; mod tunables; mod vmoffsets; -pub mod cranelift; -#[cfg(feature = "lightbeam")] -pub mod lightbeam; - pub use crate::address_map::*; +pub use crate::builtin::*; pub use crate::compilation::*; -pub use crate::cranelift::Cranelift; pub use crate::data_structures::*; -pub use crate::func_environ::BuiltinFunctionIndex; -#[cfg(feature = "lightbeam")] -pub use crate::lightbeam::Lightbeam; +// pub use crate::func_environ::BuiltinFunctionIndex; pub use crate::module::{ EntityIndex, MemoryPlan, MemoryStyle, Module, TableElements, TablePlan, TableStyle, }; @@ -60,10 +54,8 @@ pub const WASM_MAX_PAGES: u32 = 0x10000; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); -pub(crate) fn reference_type( - wasm_ty: cranelift_wasm::WasmType, - pointer_type: ir::Type, -) -> ir::Type { +/// Returns the reference type to use for the provided wasm type. +pub fn reference_type(wasm_ty: cranelift_wasm::WasmType, pointer_type: ir::Type) -> ir::Type { match wasm_ty { cranelift_wasm::WasmType::FuncRef => pointer_type, cranelift_wasm::WasmType::ExternRef => match pointer_type { diff --git a/crates/environ/src/lightbeam.rs b/crates/environ/src/lightbeam.rs deleted file mode 100644 index caaba4b024..0000000000 --- a/crates/environ/src/lightbeam.rs +++ /dev/null @@ -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 { - 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(), - }) - } -} diff --git a/crates/jit/Cargo.toml b/crates/jit/Cargo.toml index 1896cbc4e2..71bb031d3b 100644 --- a/crates/jit/Cargo.toml +++ b/crates/jit/Cargo.toml @@ -19,6 +19,8 @@ cranelift-native = { path = "../../cranelift/native", version = "0.66.0" } cranelift-frontend = { path = "../../cranelift/frontend", version = "0.66.0" } wasmtime-environ = { path = "../environ", 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-profiling = { path = "../profiling", 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"] } [features] -lightbeam = ["wasmtime-environ/lightbeam"] +lightbeam = ["wasmtime-lightbeam"] jitdump = ["wasmtime-profiling/jitdump"] vtune = ["wasmtime-profiling/vtune"] parallel-compilation = ["rayon"] diff --git a/crates/jit/src/compiler.rs b/crates/jit/src/compiler.rs index 349135b33e..192b0abcc0 100644 --- a/crates/jit/src/compiler.rs +++ b/crates/jit/src/compiler.rs @@ -50,10 +50,10 @@ impl Compiler { strategy, compiler: match strategy { CompilationStrategy::Auto | CompilationStrategy::Cranelift => { - Box::new(wasmtime_environ::cranelift::Cranelift::default()) + Box::new(wasmtime_cranelift::Cranelift::default()) } #[cfg(feature = "lightbeam")] - CompilationStrategy::Lightbeam => Box::new(wasmtime_environ::lightbeam::Lightbeam), + CompilationStrategy::Lightbeam => Box::new(wasmtime_lightbeam::Lightbeam), }, tunables, } diff --git a/crates/lightbeam/wasmtime/Cargo.toml b/crates/lightbeam/wasmtime/Cargo.toml new file mode 100644 index 0000000000..2a5271eb92 --- /dev/null +++ b/crates/lightbeam/wasmtime/Cargo.toml @@ -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" } diff --git a/crates/lightbeam/wasmtime/README.md b/crates/lightbeam/wasmtime/README.md new file mode 100644 index 0000000000..e86218faa9 --- /dev/null +++ b/crates/lightbeam/wasmtime/README.md @@ -0,0 +1,4 @@ +# `wasmtime-lightbeam` + +This crate provides an implementation of the `Compiler` trait which is +connected to Lightbeam. diff --git a/crates/lightbeam/wasmtime/src/lib.rs b/crates/lightbeam/wasmtime/src/lib.rs new file mode 100644 index 0000000000..d7337b6a76 --- /dev/null +++ b/crates/lightbeam/wasmtime/src/lib.rs @@ -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 { + 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, +} + +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, +} + +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 { + self.module + .defined_func_index(FuncIndex::from_u32(func_index)) + .map(DefinedFuncIndex::as_u32) + } + + fn defined_global_index(&self, global_index: u32) -> Option { + 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 { + self.module + .defined_table_index(TableIndex::from_u32(table_index)) + .map(DefinedTableIndex::as_u32) + } + + fn defined_memory_index(&self, memory_index: u32) -> Option { + 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 +} diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index 5c405d5628..5686413114 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -17,6 +17,3 @@ wast = "22.0.0" [badges] maintenance = { status = "actively-developed" } - -[features] -lightbeam = ["wasmtime/lightbeam"] diff --git a/scripts/publish.rs b/scripts/publish.rs index 152f6b960d..1cc5b9105b 100644 --- a/scripts/publish.rs +++ b/scripts/publish.rs @@ -56,6 +56,8 @@ const CRATES_TO_PUBLISH: &[&str] = &[ "wasmtime-debug", "wasmtime-profiling", "wasmtime-obj", + "wasmtime-cranelift", + "wasmtime-lightbeam", "wasmtime-jit", "wasmtime-cache", "wasmtime", @@ -298,7 +300,7 @@ fn verify(crates: &[Crate]) { .arg("--manifest-path") .arg(&krate.manifest) .env("CARGO_TARGET_DIR", "./target"); - if krate.name == "lightbeam" || krate.name == "witx" { + if krate.name.contains("lightbeam") || krate.name == "witx" { cmd.arg("--no-verify"); } let status = cmd.status().unwrap(); diff --git a/src/obj.rs b/src/obj.rs index a9b43fc7ab..573e0b68c3 100644 --- a/src/obj.rs +++ b/src/obj.rs @@ -2,8 +2,6 @@ use anyhow::{bail, Context as _, Result}; use object::write::Object; use target_lexicon::Triple; use wasmtime::Strategy; -#[cfg(feature = "lightbeam")] -use wasmtime_environ::Lightbeam; use wasmtime_environ::{settings, settings::Configurable, ModuleEnvironment, Tunables}; use wasmtime_jit::{native, Compiler};