Merge branch 'master' into blake3

This commit is contained in:
Syrus Akbary 2020-01-13 13:26:31 +01:00 committed by GitHub
commit 3d00903054
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 242 additions and 218 deletions

View File

@ -4,6 +4,9 @@
- [#1140](https://github.com/wasmerio/wasmer/pull/1140) Use [`blake3`](https://github.com/BLAKE3-team/BLAKE3) as default hashing algorithm for caching. - [#1140](https://github.com/wasmerio/wasmer/pull/1140) Use [`blake3`](https://github.com/BLAKE3-team/BLAKE3) as default hashing algorithm for caching.
- [#1128](https://github.com/wasmerio/wasmer/pull/1128) Fix a crash when a host function is missing and the `allow_missing_functions` flag is enabled - [#1128](https://github.com/wasmerio/wasmer/pull/1128) Fix a crash when a host function is missing and the `allow_missing_functions` flag is enabled
- [#1099](https://github.com/wasmerio/wasmer/pull/1099) Remove `backend::Backend` from `wasmer_runtime_core`
- [#1098](https://github.com/wasmerio/wasmer/pull/1098) Remove `backend::Backend` from `wasmer_runtime_core`
- [#1099](https://github.com/wasmerio/wasmer/pull/1099) Remove `backend::Backend` from `wasmer_runtime_core`
- [#1097](https://github.com/wasmerio/wasmer/pull/1097) Move inline breakpoint outside of runtime backend - [#1097](https://github.com/wasmerio/wasmer/pull/1097) Move inline breakpoint outside of runtime backend
- [#1095](https://github.com/wasmerio/wasmer/pull/1095) Update to cranelift 0.52. - [#1095](https://github.com/wasmerio/wasmer/pull/1095) Update to cranelift 0.52.
- [#1092](https://github.com/wasmerio/wasmer/pull/1092) Add `get_utf8_string_with_nul` to `WasmPtr` to read nul-terminated strings from memory. - [#1092](https://github.com/wasmerio/wasmer/pull/1092) Add `get_utf8_string_with_nul` to `WasmPtr` to read nul-terminated strings from memory.

2
Cargo.lock generated
View File

@ -1765,6 +1765,8 @@ dependencies = [
"criterion", "criterion",
"lazy_static", "lazy_static",
"memmap", "memmap",
"serde",
"serde_derive",
"tempfile", "tempfile",
"wabt", "wabt",
"wasmer-clif-backend", "wasmer-clif-backend",

View File

@ -86,19 +86,16 @@ extra-debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
fast-tests = [] fast-tests = []
backend-cranelift = [ backend-cranelift = [
"wasmer-clif-backend", "wasmer-clif-backend",
"wasmer-runtime-core/backend-cranelift",
"wasmer-runtime/cranelift", "wasmer-runtime/cranelift",
"wasmer-middleware-common-tests/clif", "wasmer-middleware-common-tests/clif",
] ]
backend-llvm = [ backend-llvm = [
"wasmer-llvm-backend", "wasmer-llvm-backend",
"wasmer-runtime-core/backend-llvm",
"wasmer-runtime/llvm", "wasmer-runtime/llvm",
"wasmer-middleware-common-tests/llvm", "wasmer-middleware-common-tests/llvm",
] ]
backend-singlepass = [ backend-singlepass = [
"wasmer-singlepass-backend", "wasmer-singlepass-backend",
"wasmer-runtime-core/backend-singlepass",
"wasmer-runtime/singlepass", "wasmer-runtime/singlepass",
"wasmer-middleware-common-tests/singlepass", "wasmer-middleware-common-tests/singlepass",
] ]

View File

@ -254,6 +254,7 @@ check: check-bench
--features=llvm,default-backend-llvm,debug --features=llvm,default-backend-llvm,debug
$(RUNTIME_CHECK) --release \ $(RUNTIME_CHECK) --release \
--features=llvm,default-backend-llvm --features=llvm,default-backend-llvm
--features=default-backend-singlepass,singlepass,cranelift,llvm,cache,debug,deterministic-execution
# Release # Release
release: release:

View File

@ -18,7 +18,7 @@ use std::mem;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use wasmer_runtime_core::error::CompileError; use wasmer_runtime_core::error::CompileError;
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::{Backend, CacheGen, Token}, backend::{CacheGen, Token},
cache::{Artifact, Error as CacheError}, cache::{Artifact, Error as CacheError},
codegen::*, codegen::*,
memory::MemoryType, memory::MemoryType,
@ -58,8 +58,8 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
unimplemented!("cross compilation is not available for clif backend") unimplemented!("cross compilation is not available for clif backend")
} }
fn backend_id() -> Backend { fn backend_id() -> String {
Backend::Cranelift "cranelift".to_string()
} }
fn check_precondition(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> { fn check_precondition(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> {

View File

@ -32,7 +32,7 @@ use std::{
}; };
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::{Backend, CacheGen, CompilerConfig, Token}, backend::{CacheGen, CompilerConfig, Token},
cache::{Artifact, Error as CacheError}, cache::{Artifact, Error as CacheError},
codegen::*, codegen::*,
memory::MemoryType, memory::MemoryType,
@ -8721,8 +8721,8 @@ impl<'ctx> ModuleCodeGenerator<LLVMFunctionCodeGenerator<'ctx>, LLVMBackend, Cod
} }
} }
fn backend_id() -> Backend { fn backend_id() -> String {
Backend::LLVM "llvm".to_string()
} }
fn check_precondition(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> { fn check_precondition(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> {

View File

@ -10,12 +10,12 @@ publish = false
[dependencies] [dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.12.0" } wasmer-runtime-core = { path = "../runtime-core", version = "0.12.0" }
wasmer-middleware-common = { path = "../middleware-common", version = "0.12.0" } wasmer-middleware-common = { path = "../middleware-common", version = "0.12.0" }
wasmer-clif-backend = { path = "../clif-backend", version = "0.12.0" } wasmer-clif-backend = { path = "../clif-backend", version = "0.12.0", optional = true }
wasmer-llvm-backend = { path = "../llvm-backend", version = "0.12.0", features = ["test"], optional = true } wasmer-llvm-backend = { path = "../llvm-backend", version = "0.12.0", features = ["test"], optional = true }
wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.12.0", optional = true } wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.12.0", optional = true }
[features] [features]
clif = [] clif = ["wasmer-clif-backend"]
llvm = ["wasmer-llvm-backend"] llvm = ["wasmer-llvm-backend"]
singlepass = ["wasmer-singlepass-backend"] singlepass = ["wasmer-singlepass-backend"]

View File

@ -3,47 +3,33 @@ mod tests {
use wabt::wat2wasm; use wabt::wat2wasm;
use wasmer_middleware_common::metering::*; use wasmer_middleware_common::metering::*;
use wasmer_runtime_core::backend::RunnableModule; use wasmer_runtime_core::codegen::ModuleCodeGenerator;
use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler}; use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler};
use wasmer_runtime_core::fault::{pop_code_version, push_code_version}; use wasmer_runtime_core::fault::{pop_code_version, push_code_version};
use wasmer_runtime_core::state::CodeVersion; use wasmer_runtime_core::state::CodeVersion;
use wasmer_runtime_core::{ use wasmer_runtime_core::{backend::Compiler, compile_with, imports, Func};
backend::{Backend, Compiler},
compile_with, imports, Func,
};
#[cfg(feature = "llvm")] #[cfg(feature = "llvm")]
fn get_compiler(limit: u64) -> (impl Compiler, Backend) { use wasmer_llvm_backend::ModuleCodeGenerator as MCG;
use wasmer_llvm_backend::ModuleCodeGenerator as LLVMMCG;
let c: StreamingCompiler<LLVMMCG, _, _, _, _> = StreamingCompiler::new(move || {
let mut chain = MiddlewareChain::new();
chain.push(Metering::new(limit));
chain
});
(c, Backend::LLVM)
}
#[cfg(feature = "singlepass")] #[cfg(feature = "singlepass")]
fn get_compiler(limit: u64) -> (impl Compiler, Backend) { use wasmer_singlepass_backend::ModuleCodeGenerator as MCG;
use wasmer_singlepass_backend::ModuleCodeGenerator as SinglePassMCG;
let c: StreamingCompiler<SinglePassMCG, _, _, _, _> = StreamingCompiler::new(move || { #[cfg(feature = "clif")]
compile_error!("cranelift does not implement metering yet");
fn get_compiler(limit: u64) -> impl Compiler {
let c: StreamingCompiler<MCG, _, _, _, _> = StreamingCompiler::new(move || {
let mut chain = MiddlewareChain::new(); let mut chain = MiddlewareChain::new();
chain.push(Metering::new(limit)); chain.push(Metering::new(limit));
chain chain
}); });
(c, Backend::Singlepass) c
} }
#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))] #[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))]
compile_error!("compiler not specified, activate a compiler via features"); compile_error!("compiler not specified, activate a compiler via features");
#[cfg(feature = "clif")]
fn get_compiler(_limit: u64) -> (impl Compiler, Backend) {
compile_error!("cranelift does not implement metering");
use wasmer_clif_backend::CraneliftCompiler;
(CraneliftCompiler::new(), Backend::Cranelift)
}
// Assemblyscript // Assemblyscript
// export function add_to(x: i32, y: i32): i32 { // export function add_to(x: i32, y: i32): i32 {
// for(var i = 0; i < x; i++){ // for(var i = 0; i < x; i++){
@ -109,7 +95,7 @@ mod tests {
let limit = 100u64; let limit = 100u64;
let (compiler, backend_id) = get_compiler(limit); let compiler = get_compiler(limit);
let module = compile_with(&wasm_binary, &compiler).unwrap(); let module = compile_with(&wasm_binary, &compiler).unwrap();
let import_object = imports! {}; let import_object = imports! {};
@ -124,8 +110,8 @@ mod tests {
baseline: true, baseline: true,
msm: msm, msm: msm,
base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize,
backend: MCG::backend_id(),
runnable_module: instance.module.runnable_module.clone(), runnable_module: instance.module.runnable_module.clone(),
backend: backend_id,
}); });
true true
} else { } else {
@ -151,7 +137,7 @@ mod tests {
let limit = 100u64; let limit = 100u64;
let (compiler, backend_id) = get_compiler(limit); let compiler = get_compiler(limit);
let module = compile_with(&wasm_binary, &compiler).unwrap(); let module = compile_with(&wasm_binary, &compiler).unwrap();
let import_object = imports! {}; let import_object = imports! {};
@ -166,7 +152,7 @@ mod tests {
baseline: true, baseline: true,
msm: msm, msm: msm,
base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize,
backend: backend_id, backend: MCG::backend_id(),
runnable_module: instance.module.runnable_module.clone(), runnable_module: instance.module.runnable_module.clone(),
}); });
true true

View File

@ -52,9 +52,5 @@ cc = "1.0"
[features] [features]
debug = [] debug = []
trace = ["debug"] trace = ["debug"]
# backend flags used in conditional compilation of Backend::variants
"backend-cranelift" = []
"backend-singlepass" = []
"backend-llvm" = []
managed = [] managed = []
deterministic-execution = ["wasmparser/deterministic"] deterministic-execution = ["wasmparser/deterministic"]

View File

@ -22,60 +22,6 @@ pub mod sys {
} }
pub use crate::sig_registry::SigRegistry; pub use crate::sig_registry::SigRegistry;
/// Enum used to select which compiler should be used to generate code.
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
pub enum Backend {
Cranelift,
Singlepass,
LLVM,
Auto,
}
impl Backend {
/// Get a list of the currently enabled (via feature flag) backends.
pub fn variants() -> &'static [&'static str] {
&[
#[cfg(feature = "backend-cranelift")]
"cranelift",
#[cfg(feature = "backend-singlepass")]
"singlepass",
#[cfg(feature = "backend-llvm")]
"llvm",
"auto",
]
}
/// Stable string representation of the backend.
/// It can be used as part of a cache key, for example.
pub fn to_string(&self) -> &'static str {
match self {
Backend::Cranelift => "cranelift",
Backend::Singlepass => "singlepass",
Backend::LLVM => "llvm",
Backend::Auto => "auto",
}
}
}
impl Default for Backend {
fn default() -> Self {
Backend::Cranelift
}
}
impl std::str::FromStr for Backend {
type Err = String;
fn from_str(s: &str) -> Result<Backend, String> {
match s.to_lowercase().as_str() {
"singlepass" => Ok(Backend::Singlepass),
"cranelift" => Ok(Backend::Cranelift),
"llvm" => Ok(Backend::LLVM),
"auto" => Ok(Backend::Auto),
_ => Err(format!("The backend {} doesn't exist", s)),
}
}
}
/// The target architecture for code generation. /// The target architecture for code generation.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum Architecture { pub enum Architecture {
@ -104,22 +50,6 @@ pub struct InlineBreakpoint {
pub ty: InlineBreakpointType, pub ty: InlineBreakpointType,
} }
#[cfg(test)]
mod backend_test {
use super::*;
use std::str::FromStr;
#[test]
fn str_repr_matches() {
// if this test breaks, think hard about why it's breaking
// can we avoid having these be different?
for &backend in &[Backend::Cranelift, Backend::LLVM, Backend::Singlepass] {
assert_eq!(backend, Backend::from_str(backend.to_string()).unwrap());
}
}
}
/// This type cannot be constructed from /// This type cannot be constructed from
/// outside the runtime crate. /// outside the runtime crate.
pub struct Token { pub struct Token {

View File

@ -2,13 +2,9 @@
//! serializing compiled wasm code to a binary format. The binary format can be persisted, //! serializing compiled wasm code to a binary format. The binary format can be persisted,
//! and loaded to allow skipping compilation and fast startup. //! and loaded to allow skipping compilation and fast startup.
use crate::{ use crate::{module::ModuleInfo, sys::Memory};
backend::Backend,
module::{Module, ModuleInfo},
sys::Memory,
};
use blake3; use blake3;
use std::{fmt, io, mem, slice}; use std::{io, mem, slice};
/// Indicates the invalid type of invalid cache file /// Indicates the invalid type of invalid cache file
#[derive(Debug)] #[derive(Debug)]
@ -35,7 +31,7 @@ pub enum Error {
/// The cached binary has been invalidated. /// The cached binary has been invalidated.
InvalidatedCache, InvalidatedCache,
/// The current backend does not support caching. /// The current backend does not support caching.
UnsupportedBackend(Backend), UnsupportedBackend(String),
} }
impl From<io::Error> for Error { impl From<io::Error> for Error {
@ -246,24 +242,6 @@ impl Artifact {
} }
} }
/// A generic cache for storing and loading compiled wasm modules.
///
/// The `wasmer-runtime` supplies a naive `FileSystemCache` api.
pub trait Cache {
/// Error type to return when load error occurs
type LoadError: fmt::Debug;
/// Error type to return when store error occurs
type StoreError: fmt::Debug;
/// loads a module using the default `Backend`
fn load(&self, key: WasmHash) -> Result<Module, Self::LoadError>;
/// loads a cached module using a specific `Backend`
fn load_with_backend(&self, key: WasmHash, backend: Backend)
-> Result<Module, Self::LoadError>;
/// Store a module into the cache with the given key
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::StoreError>;
}
/// A unique ID generated from the version of Wasmer for use with cache versioning /// A unique ID generated from the version of Wasmer for use with cache versioning
pub const WASMER_VERSION_HASH: &'static str = pub const WASMER_VERSION_HASH: &'static str =
include_str!(concat!(env!("OUT_DIR"), "/wasmer_version_hash.txt")); include_str!(concat!(env!("OUT_DIR"), "/wasmer_version_hash.txt"));

View File

@ -4,7 +4,7 @@
use crate::fault::FaultInfo; use crate::fault::FaultInfo;
use crate::{ use crate::{
backend::RunnableModule, backend::RunnableModule,
backend::{Backend, CacheGen, Compiler, CompilerConfig, Features, Token}, backend::{CacheGen, Compiler, CompilerConfig, Features, Token},
cache::{Artifact, Error as CacheError}, cache::{Artifact, Error as CacheError},
error::{CompileError, CompileResult}, error::{CompileError, CompileResult},
module::{ModuleInfo, ModuleInner}, module::{ModuleInfo, ModuleInner},
@ -92,7 +92,12 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule,
) -> Self; ) -> Self;
/// Returns the backend id associated with this MCG. /// Returns the backend id associated with this MCG.
fn backend_id() -> Backend; fn backend_id() -> String;
/// It sets if the current compiler requires validation before compilation
fn requires_pre_validation() -> bool {
true
}
/// Feeds the compiler config. /// Feeds the compiler config.
fn feed_compiler_config(&mut self, _config: &CompilerConfig) -> Result<(), E> { fn feed_compiler_config(&mut self, _config: &CompilerConfig) -> Result<(), E> {
@ -222,12 +227,12 @@ impl<
compiler_config: CompilerConfig, compiler_config: CompilerConfig,
_: Token, _: Token,
) -> CompileResult<ModuleInner> { ) -> CompileResult<ModuleInner> {
if requires_pre_validation(MCG::backend_id()) { if MCG::requires_pre_validation() {
validate_with_features(wasm, &compiler_config.features)?; validate_with_features(wasm, &compiler_config.features)?;
} }
let mut mcg = match MCG::backend_id() { let mut mcg = match MCG::backend_id().as_ref() {
Backend::LLVM => MCG::new_with_target( "llvm" => MCG::new_with_target(
compiler_config.triple.clone(), compiler_config.triple.clone(),
compiler_config.cpu_name.clone(), compiler_config.cpu_name.clone(),
compiler_config.cpu_features.clone(), compiler_config.cpu_features.clone(),
@ -235,13 +240,7 @@ impl<
_ => MCG::new(), _ => MCG::new(),
}; };
let mut chain = (self.middleware_chain_generator)(); let mut chain = (self.middleware_chain_generator)();
let info = crate::parse::read_module( let info = crate::parse::read_module(wasm, &mut mcg, &mut chain, &compiler_config)?;
wasm,
MCG::backend_id(),
&mut mcg,
&mut chain,
&compiler_config,
)?;
let (exec_context, cache_gen) = let (exec_context, cache_gen) =
mcg.finalize(&info.read().unwrap()) mcg.finalize(&info.read().unwrap())
.map_err(|x| CompileError::InternalError { .map_err(|x| CompileError::InternalError {
@ -263,15 +262,6 @@ impl<
} }
} }
fn requires_pre_validation(backend: Backend) -> bool {
match backend {
Backend::Cranelift => true,
Backend::LLVM => true,
Backend::Singlepass => false,
Backend::Auto => false,
}
}
/// A sink for parse events. /// A sink for parse events.
pub struct EventSink<'a, 'b> { pub struct EventSink<'a, 'b> {
buffer: SmallVec<[Event<'a, 'b>; 2]>, buffer: SmallVec<[Event<'a, 'b>; 2]>,

View File

@ -1,7 +1,7 @@
//! The module module contains the implementation data structures and helper functions used to //! The module module contains the implementation data structures and helper functions used to
//! manipulate and access wasm modules. //! manipulate and access wasm modules.
use crate::{ use crate::{
backend::{Backend, RunnableModule}, backend::RunnableModule,
cache::{Artifact, Error as CacheError}, cache::{Artifact, Error as CacheError},
error, error,
import::ImportObject, import::ImportObject,
@ -65,7 +65,7 @@ pub struct ModuleInfo {
/// Map signature index to function signature. /// Map signature index to function signature.
pub signatures: Map<SigIndex, FuncSig>, pub signatures: Map<SigIndex, FuncSig>,
/// Backend. /// Backend.
pub backend: Backend, pub backend: String,
/// Table of namespace indexes. /// Table of namespace indexes.
pub namespace_table: StringTable<NamespaceIndex>, pub namespace_table: StringTable<NamespaceIndex>,

View File

@ -3,7 +3,7 @@
use crate::codegen::*; use crate::codegen::*;
use crate::{ use crate::{
backend::{Backend, CompilerConfig, RunnableModule}, backend::{CompilerConfig, RunnableModule},
error::CompileError, error::CompileError,
module::{ module::{
DataInitializer, ExportIndex, ImportName, ModuleInfo, StringTable, StringTableBuilder, DataInitializer, ExportIndex, ImportName, ModuleInfo, StringTable, StringTableBuilder,
@ -57,7 +57,6 @@ pub fn read_module<
E: Debug, E: Debug,
>( >(
wasm: &[u8], wasm: &[u8],
backend: Backend,
mcg: &mut MCG, mcg: &mut MCG,
middlewares: &mut MiddlewareChain, middlewares: &mut MiddlewareChain,
compiler_config: &CompilerConfig, compiler_config: &CompilerConfig,
@ -83,7 +82,7 @@ pub fn read_module<
func_assoc: Map::new(), func_assoc: Map::new(),
signatures: Map::new(), signatures: Map::new(),
backend: backend, backend: MCG::backend_id(),
namespace_table: StringTable::new(), namespace_table: StringTable::new(),
name_table: StringTable::new(), name_table: StringTable::new(),

View File

@ -2,7 +2,7 @@
//! state could read or updated at runtime. Use cases include generating stack traces, switching //! state could read or updated at runtime. Use cases include generating stack traces, switching
//! generated code from one tier to another, or serializing state of a running instace. //! generated code from one tier to another, or serializing state of a running instace.
use crate::backend::{Backend, RunnableModule}; use crate::backend::RunnableModule;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::ops::Bound::{Included, Unbounded}; use std::ops::Bound::{Included, Unbounded};
use std::sync::Arc; use std::sync::Arc;
@ -186,7 +186,7 @@ pub struct CodeVersion {
pub base: usize, pub base: usize,
/// The backend used to compile this module. /// The backend used to compile this module.
pub backend: Backend, pub backend: String,
/// `RunnableModule` for this code version. /// `RunnableModule` for this code version.
pub runnable_module: Arc<Box<dyn RunnableModule>>, pub runnable_module: Arc<Box<dyn RunnableModule>>,

View File

@ -1,6 +1,6 @@
//! The tiering module supports switching between code compiled with different optimization levels //! The tiering module supports switching between code compiled with different optimization levels
//! as runtime. //! as runtime.
use crate::backend::{Backend, Compiler, CompilerConfig}; use crate::backend::{Compiler, CompilerConfig};
use crate::compile_with_config; use crate::compile_with_config;
use crate::fault::{ use crate::fault::{
catch_unsafe_unwind, ensure_sighandler, pop_code_version, push_code_version, with_ctx, catch_unsafe_unwind, ensure_sighandler, pop_code_version, push_code_version, with_ctx,
@ -43,7 +43,7 @@ struct OptimizationState {
} }
struct OptimizationOutcome { struct OptimizationOutcome {
backend_id: Backend, backend_id: String,
module: Module, module: Module,
} }
@ -54,7 +54,7 @@ unsafe impl Sync for CtxWrapper {}
unsafe fn do_optimize( unsafe fn do_optimize(
binary: &[u8], binary: &[u8],
backend_id: Backend, backend_id: String,
compiler: Box<dyn Compiler>, compiler: Box<dyn Compiler>,
ctx: &Mutex<CtxWrapper>, ctx: &Mutex<CtxWrapper>,
state: &OptimizationState, state: &OptimizationState,
@ -87,8 +87,8 @@ pub unsafe fn run_tiering<F: Fn(InteractiveShellContext) -> ShellExitOperation>(
import_object: &ImportObject, import_object: &ImportObject,
start_raw: extern "C" fn(&mut Ctx), start_raw: extern "C" fn(&mut Ctx),
baseline: &mut Instance, baseline: &mut Instance,
baseline_backend: Backend, baseline_backend: String,
optimized_backends: Vec<(Backend, Box<dyn Fn() -> Box<dyn Compiler> + Send>)>, optimized_backends: Vec<(String, Box<dyn Fn() -> Box<dyn Compiler> + Send>)>,
interactive_shell: F, interactive_shell: F,
) -> Result<(), String> { ) -> Result<(), String> {
ensure_sighandler(); ensure_sighandler();
@ -140,7 +140,7 @@ pub unsafe fn run_tiering<F: Fn(InteractiveShellContext) -> ShellExitOperation>(
})); }));
loop { loop {
let new_optimized: Option<(Backend, &mut Instance)> = { let new_optimized: Option<(String, &mut Instance)> = {
let mut outcome = opt_state.outcome.lock().unwrap(); let mut outcome = opt_state.outcome.lock().unwrap();
if let Some(x) = outcome.take() { if let Some(x) = outcome.take() {
let instance = x let instance = x

View File

@ -1064,7 +1064,7 @@ mod vm_ctx_tests {
fn generate_module() -> ModuleInner { fn generate_module() -> ModuleInner {
use super::Func; use super::Func;
use crate::backend::{sys::Memory, Backend, CacheGen, RunnableModule}; use crate::backend::{sys::Memory, CacheGen, RunnableModule};
use crate::cache::Error as CacheError; use crate::cache::Error as CacheError;
use crate::typed_func::Wasm; use crate::typed_func::Wasm;
use crate::types::{LocalFuncIndex, SigIndex}; use crate::types::{LocalFuncIndex, SigIndex};
@ -1118,7 +1118,7 @@ mod vm_ctx_tests {
func_assoc: Map::new(), func_assoc: Map::new(),
signatures: Map::new(), signatures: Map::new(),
backend: Backend::Cranelift, backend: Default::default(),
namespace_table: StringTable::new(), namespace_table: StringTable::new(),
name_table: StringTable::new(), name_table: StringTable::new(),

View File

@ -24,6 +24,14 @@ path = "../clif-backend"
version = "0.12.0" version = "0.12.0"
optional = true optional = true
# Dependencies for caching.
[dependencies.serde]
version = "1.0"
# This feature is required for serde to support serializing/deserializing reference counted pointers (e.g. Rc and Arc).
features = ["rc"]
[dependencies.serde_derive]
version = "1.0"
[dev-dependencies] [dev-dependencies]
tempfile = "3.1" tempfile = "3.1"
criterion = "0.2" criterion = "0.2"

View File

@ -5,16 +5,33 @@
use crate::Module; use crate::Module;
use memmap::Mmap; use memmap::Mmap;
use std::{ use std::{
fmt,
fs::{create_dir_all, File}, fs::{create_dir_all, File},
io::{self, Write}, io::{self, Write},
path::PathBuf, path::PathBuf,
}; };
pub use super::Backend;
use wasmer_runtime_core::cache::Error as CacheError; use wasmer_runtime_core::cache::Error as CacheError;
pub use wasmer_runtime_core::{ pub use wasmer_runtime_core::cache::{Artifact, WasmHash};
backend::Backend,
cache::{Artifact, Cache, WasmHash}, /// A generic cache for storing and loading compiled wasm modules.
}; ///
/// The `wasmer-runtime` supplies a naive `FileSystemCache` api.
pub trait Cache {
/// Error type to return when load error occurs
type LoadError: fmt::Debug;
/// Error type to return when store error occurs
type StoreError: fmt::Debug;
/// loads a module using the default `Backend`
fn load(&self, key: WasmHash) -> Result<Module, Self::LoadError>;
/// loads a cached module using a specific `Backend`
fn load_with_backend(&self, key: WasmHash, backend: Backend)
-> Result<Module, Self::LoadError>;
/// Store a module into the cache with the given key
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::StoreError>;
}
/// Representation of a directory that contains compiled wasm artifacts. /// Representation of a directory that contains compiled wasm artifacts.
/// ///
@ -105,7 +122,7 @@ impl Cache for FileSystemCache {
wasmer_runtime_core::load_cache_with( wasmer_runtime_core::load_cache_with(
serialized_cache, serialized_cache,
crate::compiler_for_backend(backend) crate::compiler_for_backend(backend)
.ok_or_else(|| CacheError::UnsupportedBackend(backend))? .ok_or_else(|| CacheError::UnsupportedBackend(backend.to_string().to_owned()))?
.as_ref(), .as_ref(),
) )
} }

View File

@ -91,7 +91,10 @@
//! [`wasmer-singlepass-backend`]: https://crates.io/crates/wasmer-singlepass-backend //! [`wasmer-singlepass-backend`]: https://crates.io/crates/wasmer-singlepass-backend
//! [`wasmer-clif-backend`]: https://crates.io/crates/wasmer-clif-backend //! [`wasmer-clif-backend`]: https://crates.io/crates/wasmer-clif-backend
pub use wasmer_runtime_core::backend::{Backend, Features}; #[macro_use]
extern crate serde_derive;
pub use wasmer_runtime_core::backend::Features;
pub use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler}; pub use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler};
pub use wasmer_runtime_core::export::Export; pub use wasmer_runtime_core::export::Export;
pub use wasmer_runtime_core::global::Global; pub use wasmer_runtime_core::global::Global;
@ -144,6 +147,80 @@ pub mod cache;
pub use wasmer_runtime_core::backend::{Compiler, CompilerConfig}; pub use wasmer_runtime_core::backend::{Compiler, CompilerConfig};
/// Enum used to select which compiler should be used to generate code.
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
pub enum Backend {
#[cfg(feature = "singlepass")]
/// Singlepass backend
Singlepass,
#[cfg(feature = "cranelift")]
/// Cranelift backend
Cranelift,
#[cfg(feature = "llvm")]
/// LLVM backend
LLVM,
/// Auto backend
Auto,
}
impl Backend {
/// Get a list of the currently enabled (via feature flag) backends.
pub fn variants() -> &'static [&'static str] {
&[
#[cfg(feature = "singlepass")]
"singlepass",
#[cfg(feature = "cranelift")]
"cranelift",
#[cfg(feature = "llvm")]
"llvm",
"auto",
]
}
/// Stable string representation of the backend.
/// It can be used as part of a cache key, for example.
pub fn to_string(&self) -> &'static str {
match self {
#[cfg(feature = "singlepass")]
Backend::Singlepass => "singlepass",
#[cfg(feature = "cranelift")]
Backend::Cranelift => "cranelift",
#[cfg(feature = "llvm")]
Backend::LLVM => "llvm",
Backend::Auto => "auto",
}
}
}
impl Default for Backend {
fn default() -> Self {
#[cfg(all(feature = "default-backend-singlepass", not(feature = "docs")))]
return Backend::Singlepass;
#[cfg(any(feature = "default-backend-cranelift", feature = "docs"))]
return Backend::Cranelift;
#[cfg(all(feature = "default-backend-llvm", not(feature = "docs")))]
return Backend::LLVM;
}
}
impl std::str::FromStr for Backend {
type Err = String;
fn from_str(s: &str) -> Result<Backend, String> {
match s.to_lowercase().as_str() {
#[cfg(feature = "singlepass")]
"singlepass" => Ok(Backend::Singlepass),
#[cfg(feature = "cranelift")]
"cranelift" => Ok(Backend::Cranelift),
#[cfg(feature = "llvm")]
"llvm" => Ok(Backend::LLVM),
"auto" => Ok(Backend::Auto),
_ => Err(format!("The backend {} doesn't exist", s)),
}
}
}
/// Compile WebAssembly binary code into a [`Module`]. /// Compile WebAssembly binary code into a [`Module`].
/// This function is useful if it is necessary to /// This function is useful if it is necessary to
/// compile a module before it can be instantiated /// compile a module before it can be instantiated
@ -268,11 +345,31 @@ pub fn compiler_for_backend(backend: Backend) -> Option<Box<dyn Compiler>> {
#[cfg(feature = "default-backend-llvm")] #[cfg(feature = "default-backend-llvm")]
return Some(Box::new(wasmer_llvm_backend::LLVMCompiler::new())); return Some(Box::new(wasmer_llvm_backend::LLVMCompiler::new()));
} }
#[cfg(not(all(feature = "llvm", feature = "singlepass", feature = "cranelift")))]
_ => None,
} }
} }
/// The current version of this crate. /// The current version of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = env!("CARGO_PKG_VERSION");
#[cfg(test)]
mod test {
use super::*;
use std::str::FromStr;
#[test]
fn str_repr_matches() {
// if this test breaks, think hard about why it's breaking
// can we avoid having these be different?
for &backend in &[
#[cfg(feature = "cranelift")]
Backend::Cranelift,
#[cfg(feature = "llvm")]
Backend::LLVM,
#[cfg(feature = "singlepass")]
Backend::Singlepass,
] {
assert_eq!(backend, Backend::from_str(backend.to_string()).unwrap());
}
}
}

View File

@ -23,7 +23,7 @@ use std::{
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::{ backend::{
sys::{Memory, Protect}, sys::{Memory, Protect},
Architecture, Backend, CacheGen, CompilerConfig, InlineBreakpoint, InlineBreakpointType, Architecture, CacheGen, CompilerConfig, InlineBreakpoint, InlineBreakpointType,
MemoryBoundCheckMode, RunnableModule, Token, MemoryBoundCheckMode, RunnableModule, Token,
}, },
cache::{Artifact, Error as CacheError}, cache::{Artifact, Error as CacheError},
@ -646,12 +646,17 @@ impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, CodegenError>
} }
} }
fn new_with_target(_: Option<String>, _: Option<String>, _: Option<String>) -> Self { /// Singlepass does validation as it compiles
unimplemented!("cross compilation is not available for singlepass backend") fn requires_pre_validation() -> bool {
false
} }
fn backend_id() -> Backend { fn backend_id() -> String {
Backend::Singlepass "singlepass".to_string()
}
fn new_with_target(_: Option<String>, _: Option<String>, _: Option<String>) -> Self {
unimplemented!("cross compilation is not available for singlepass backend")
} }
fn check_precondition(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> { fn check_precondition(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> {

View File

@ -12,7 +12,7 @@ extern crate structopt;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::fs::{metadata, read_to_string, File}; use std::fs::{read_to_string, File};
use std::io; use std::io;
use std::io::Read; use std::io::Read;
use std::path::PathBuf; use std::path::PathBuf;
@ -30,13 +30,13 @@ use wasmer_llvm_backend::{
}; };
use wasmer_runtime::{ use wasmer_runtime::{
cache::{Cache as BaseCache, FileSystemCache, WasmHash}, cache::{Cache as BaseCache, FileSystemCache, WasmHash},
Value, VERSION, Backend, Value, VERSION,
}; };
#[cfg(feature = "managed")] #[cfg(feature = "managed")]
use wasmer_runtime_core::tiering::{run_tiering, InteractiveShellContext, ShellExitOperation}; use wasmer_runtime_core::tiering::{run_tiering, InteractiveShellContext, ShellExitOperation};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
self, self,
backend::{Backend, Compiler, CompilerConfig, Features, MemoryBoundCheckMode}, backend::{Compiler, CompilerConfig, Features, MemoryBoundCheckMode},
debug, debug,
loader::{Instance as LoadedInstance, LocalLoader}, loader::{Instance as LoadedInstance, LocalLoader},
Module, Module,
@ -143,7 +143,7 @@ struct Run {
#[structopt(parse(from_os_str))] #[structopt(parse(from_os_str))]
path: PathBuf, path: PathBuf,
/// Name of the backend to use. (x86_64) /// Name of the backend to use (x86_64)
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
#[structopt( #[structopt(
long = "backend", long = "backend",
@ -153,7 +153,7 @@ struct Run {
)] )]
backend: Backend, backend: Backend,
/// Name of the backend to use. (aarch64) /// Name of the backend to use (aarch64)
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
#[structopt( #[structopt(
long = "backend", long = "backend",
@ -486,7 +486,7 @@ fn execute_wasi(
baseline: true, baseline: true,
msm: msm, msm: msm,
base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize, base: instance.module.runnable_module.get_code().unwrap().as_ptr() as usize,
backend: options.backend, backend: options.backend.to_string().to_owned(),
runnable_module: instance.module.runnable_module.clone(), runnable_module: instance.module.runnable_module.clone(),
}); });
true true
@ -618,8 +618,15 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
}; };
// Don't error on --enable-all for other backends. // Don't error on --enable-all for other backends.
if options.features.simd && options.backend != Backend::LLVM { if options.features.simd {
return Err("SIMD is only supported in the LLVM backend for now".to_string()); #[cfg(feature = "backend-llvm")]
{
if options.backend != Backend::LLVM {
return Err("SIMD is only supported in the LLVM backend for now".to_string());
}
}
#[cfg(not(feature = "backend-llvm"))]
return Err("SIMD is not supported in this backend".to_string());
} }
if !utils::is_wasm_binary(&wasm_binary) { if !utils::is_wasm_binary(&wasm_binary) {
@ -934,29 +941,43 @@ fn interactive_shell(mut ctx: InteractiveShellContext) -> ShellExitOperation {
} }
} }
fn update_backend(options: &mut Run) { #[allow(unused_variables)]
let binary_size = match metadata(&options.path) { fn get_backend(backend: Backend, path: &PathBuf) -> Backend {
Ok(wasm_binary) => wasm_binary.len(),
Err(_e) => 0,
};
// Update backend when a backend flag is `auto`. // Update backend when a backend flag is `auto`.
// Use the Singlepass backend if it's enabled and the file provided is larger // Use the Singlepass backend if it's enabled and the file provided is larger
// than 10MiB (10485760 bytes), or it's enabled and the target architecture // than 10MiB (10485760 bytes), or it's enabled and the target architecture
// is AArch64. Otherwise, use the Cranelift backend. // is AArch64. Otherwise, use the Cranelift backend.
if options.backend == Backend::Auto { match backend {
if Backend::variants().contains(&Backend::Singlepass.to_string()) Backend::Auto => {
&& (binary_size > 10485760 || cfg!(target_arch = "aarch64")) #[cfg(feature = "backend-singlepass")]
{ {
options.backend = Backend::Singlepass; let binary_size = match &path.metadata() {
} else { Ok(wasm_binary) => wasm_binary.len(),
options.backend = Backend::Cranelift; Err(_e) => 0,
};
if binary_size > 10485760 || cfg!(target_arch = "aarch64") {
return Backend::Singlepass;
}
}
#[cfg(feature = "backend-cranelift")]
{
return Backend::Cranelift;
}
#[cfg(feature = "backend-llvm")]
{
return Backend::LLVM;
}
panic!("Can't find any backend");
} }
backend => backend,
} }
} }
fn run(options: &mut Run) { fn run(options: &mut Run) {
update_backend(options); options.backend = get_backend(options.backend, &options.path);
match execute_wasm(options) { match execute_wasm(options) {
Ok(()) => {} Ok(()) => {}
Err(message) => { Err(message) => {
@ -1031,17 +1052,11 @@ fn get_compiler_by_backend(backend: Backend, _opts: &Run) -> Option<Box<dyn Comp
StreamingCompiler::new(middlewares_gen); StreamingCompiler::new(middlewares_gen);
Box::new(c) Box::new(c)
} }
#[cfg(not(feature = "backend-singlepass"))]
Backend::Singlepass => return None,
#[cfg(feature = "backend-cranelift")] #[cfg(feature = "backend-cranelift")]
Backend::Cranelift => Box::new(CraneliftCompiler::new()), Backend::Cranelift => Box::new(CraneliftCompiler::new()),
#[cfg(not(feature = "backend-cranelift"))]
Backend::Cranelift => return None,
#[cfg(feature = "backend-llvm")] #[cfg(feature = "backend-llvm")]
Backend::LLVM => Box::new(LLVMCompiler::new()), Backend::LLVM => Box::new(LLVMCompiler::new()),
#[cfg(not(feature = "backend-llvm"))] _ => return None,
Backend::LLVM => return None,
Backend::Auto => return None,
}) })
} }