diff --git a/Cargo.lock b/Cargo.lock index c56caa5d98e..28625c0f5a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -365,6 +365,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d9d8664cf849d7d0f3114a3a387d2f5e4303176d746d5a951aaddc66dfe9240" +[[package]] +name = "downcast-rs" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba6eb47c2131e784a38b726eb54c1e1484904f013e576a25354d0124161af6" + [[package]] name = "either" version = "1.5.3" @@ -1477,7 +1483,8 @@ dependencies = [ "wasmer-compiler-cranelift", "wasmer-compiler-llvm", "wasmer-compiler-singlepass", - "wasmer-jit", + "wasmer-engine", + "wasmer-engine-jit", "wasmer-runtime", "wat", "winapi", @@ -1502,7 +1509,8 @@ dependencies = [ "wasmer-compiler-cranelift", "wasmer-compiler-llvm", "wasmer-compiler-singlepass", - "wasmer-jit", + "wasmer-engine", + "wasmer-engine-jit", "wasmer-wasi", "wasmer-wasi-experimental-io-devices", "wasmer-wast", @@ -1589,7 +1597,28 @@ dependencies = [ ] [[package]] -name = "wasmer-jit" +name = "wasmer-engine" +version = "0.16.2" +dependencies = [ + "backtrace", + "bincode", + "downcast-rs", + "lazy_static", + "more-asserts", + "region", + "rustc-demangle", + "serde", + "serde_bytes", + "target-lexicon", + "thiserror", + "wasm-common", + "wasmer-compiler", + "wasmer-runtime", + "winapi", +] + +[[package]] +name = "wasmer-engine-jit" version = "0.16.2" dependencies = [ "backtrace", @@ -1604,6 +1633,7 @@ dependencies = [ "thiserror", "wasm-common", "wasmer-compiler", + "wasmer-engine", "wasmer-runtime", "winapi", ] diff --git a/Cargo.toml b/Cargo.toml index 98af92e830e..6ca35580779 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,8 @@ wasmer-compiler = { version = "0.16.2", path = "lib/compiler" } wasmer-compiler-cranelift = { version = "0.16.2", path = "lib/compiler-cranelift", optional = true } wasmer-compiler-singlepass = { version = "0.16.2", path = "lib/compiler-singlepass", optional = true } wasmer-compiler-llvm = { version = "0.16.2", path = "lib/compiler-llvm", optional = true } -wasmer-jit = { version = "0.16.2", path = "lib/jit" } +wasmer-engine = { version = "0.16.2", path = "lib/engine" } +wasmer-engine-jit = { version = "0.16.2", path = "lib/engine-jit", optional = true } wasmer-wasi = { version = "0.16.2", path = "lib/wasi", optional = true } wasmer-wasi-experimental-io-devices = { version = "0.16.2", path = "lib/wasi-experimental-io-devices", optional = true } wasmer-wast = { version = "0.16.2", path = "tests/lib/wast", optional = true } @@ -55,12 +56,17 @@ test-utils = { path = "tests/lib/test-utils" } [features] # Don't add the compiler features in default, please add them on the Makefile # since we might want to autoconfigure them depending on the availability on the host. -default = ["wat", "wast", "wasi", "cranelift", "cache"] +default = ["wat", "wast", "wasi", "cranelift", "cache", "jit"] +engine = [] +jit = [ + "wasmer-engine-jit", + "engine", +] cache = ["wasmer-cache"] wast = ["wasmer-wast"] wasi = ["wasmer-wasi"] wat = ["wasmer/wat"] -compiler = ["wasmer-jit/compiler"] +compiler = ["wasmer-engine-jit/compiler",] experimental-io-devices = [ "wasmer-wasi-experimental-io-devices", "wasi" diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index 67f4a53ca05..f3377ac3319 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -14,7 +14,8 @@ wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "0.16. wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "0.16.2", optional = true } wasmer-compiler-llvm = { path = "../compiler-llvm", version = "0.16.2", optional = true } wasmer-compiler = { path = "../compiler", version = "0.16.2" } -wasmer-jit = { path = "../jit", version = "0.16.2" } +wasmer-engine = { path = "../engine", version = "0.16.2" } +wasmer-engine-jit = { path = "../engine-jit", version = "0.16.2", optional = true } wasm-common = { path = "../wasm-common", version = "0.16.2" } indexmap = { version = "1.3.2", features = ["serde-1"] } cfg-if = "0.1.10" @@ -37,8 +38,10 @@ anyhow = "1.0.28" maintenance = { status = "actively-developed" } [features] -default = ["wat", "cranelift"] -compiler = ["wasmer-jit/compiler"] +default = ["wat", "cranelift", "jit"] +compiler = ["wasmer-engine-jit/compiler"] +engine = [] +jit = ["wasmer-engine-jit"] singlepass = [ "wasmer-compiler-singlepass", "compiler", diff --git a/lib/api/src/externals.rs b/lib/api/src/externals.rs index 3d1b18cf3d7..605288458b2 100644 --- a/lib/api/src/externals.rs +++ b/lib/api/src/externals.rs @@ -8,6 +8,7 @@ use crate::{ExternType, FunctionType, GlobalType, MemoryType, TableType, ValType use std::cmp::max; use std::slice; use wasm_common::{Bytes, HostFunction, Pages, ValueType, WasmTypeList, WithEnv, WithoutEnv}; +use wasmer_engine::Engine as _; use wasmer_runtime::{ wasmer_call_trampoline, Export, ExportFunction, ExportGlobal, ExportMemory, ExportTable, LinearMemory, Table as RuntimeTable, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, diff --git a/lib/api/src/import_object.rs b/lib/api/src/import_object.rs index 5ff1ee24758..4911eab5969 100644 --- a/lib/api/src/import_object.rs +++ b/lib/api/src/import_object.rs @@ -8,7 +8,7 @@ use std::{ ffi::c_void, sync::{Arc, Mutex}, }; -use wasmer_jit::Resolver; +use wasmer_engine::Resolver; use wasmer_runtime::Export; /// The `LikeNamespace` trait represents objects that act as a namespace for imports. diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index 6ee36b7a5ed..2f5ad1e7a66 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -3,7 +3,7 @@ use crate::externals::Extern; use crate::module::Module; use crate::store::Store; use crate::InstantiationError; -use wasmer_jit::Resolver; +use wasmer_engine::Resolver; use wasmer_runtime::InstanceHandle; /// A WebAssembly Instance is a stateful, executable diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index bb0fc6b36eb..93f338d5923 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -19,7 +19,7 @@ pub use crate::instance::Instance; pub use crate::memory_view::MemoryView; pub use crate::module::Module; pub use crate::ptr::{Array, Item, WasmPtr}; -pub use crate::store::{Engine, Store, StoreObject}; +pub use crate::store::{Store, StoreObject}; pub use crate::tunables::Tunables; pub use crate::types::{ AnyRef, ExportType, ExternType, FunctionType, GlobalType, HostInfo, HostRef, ImportType, @@ -30,9 +30,8 @@ pub use wasm_common::{ValueType, WasmExternType, WasmTypeList}; #[cfg(feature = "compiler")] pub use wasmer_compiler::CompilerConfig; pub use wasmer_compiler::{Features, Target}; - -pub use wasmer_jit::{ - DeserializeError, InstantiationError, LinkError, RuntimeError, SerializeError, +pub use wasmer_engine::{ + DeserializeError, Engine, InstantiationError, LinkError, RuntimeError, SerializeError, }; // The compilers are mutually exclusive @@ -62,5 +61,8 @@ pub use wasmer_compiler_cranelift::CraneliftConfig; #[cfg(feature = "llvm")] pub use wasmer_compiler_llvm::LLVMConfig; +#[cfg(feature = "jit")] +pub use wasmer_engine_jit::JITEngine; + /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs index 4d5e9d3904c..d7f53afc9b0 100644 --- a/lib/api/src/module.rs +++ b/lib/api/src/module.rs @@ -1,12 +1,13 @@ use crate::store::Store; use crate::types::{ExportType, ImportType}; use crate::InstantiationError; +use std::borrow::Borrow; use std::io; use std::path::Path; use std::sync::Arc; use thiserror::Error; use wasmer_compiler::{CompileError, WasmError}; -use wasmer_jit::{CompiledModule, DeserializeError, Resolver, SerializeError}; +use wasmer_engine::{CompiledModule, DeserializeError, Engine, Resolver, SerializeError}; use wasmer_runtime::{ExportsIterator, ImportsIterator, InstanceHandle, Module as ModuleInfo}; #[derive(Error, Debug)] @@ -30,7 +31,7 @@ pub enum IoCompileError { #[derive(Clone)] pub struct Module { store: Store, - compiled: Arc, + compiled: Arc, #[cfg(feature = "wat")] #[doc(hidden)] @@ -155,7 +156,7 @@ impl Module { /// let serialized = module.serialize()?; /// ``` pub fn serialize(&self) -> Result, SerializeError> { - self.store.engine().serialize(&self.compiled) + self.store.engine().serialize(self.compiled.borrow()) } /// Deserializes a a serialized Module binary into a `Module`. @@ -183,10 +184,10 @@ impl Module { Ok(Self::from_compiled_module(store, compiled)) } - fn from_compiled_module(store: &Store, compiled: CompiledModule) -> Self { + fn from_compiled_module(store: &Store, compiled: Arc) -> Self { Module { store: store.clone(), - compiled: Arc::new(compiled), + compiled, #[cfg(feature = "wat")] from_wat: false, } @@ -197,7 +198,10 @@ impl Module { resolver: &dyn Resolver, ) -> Result { unsafe { - let instance_handle = self.store.engine().instantiate(&self.compiled, resolver)?; + let instance_handle = self + .store + .engine() + .instantiate(self.compiled.borrow(), resolver)?; // After the instance handle is created, we need to initialize // the data, call the start function and so. However, if any @@ -240,7 +244,7 @@ impl Module { /// ``` pub fn set_name(&mut self, name: &str) { let compiled = Arc::get_mut(&mut self.compiled).unwrap(); - Arc::get_mut(compiled.module_mut()).unwrap().name = Some(name.to_string()); + compiled.module_mut().name = Some(name.to_string()); } /// Returns an iterator over the imported types in the Module. diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index eee6b448a8f..b83635e771e 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -2,35 +2,25 @@ use crate::tunables::Tunables; use std::sync::Arc; #[cfg(feature = "compiler")] use wasmer_compiler::CompilerConfig; -use wasmer_jit::JITEngine; - -pub type Engine = JITEngine; +use wasmer_engine::Engine; #[derive(Clone)] pub struct Store { - engine: Arc, + engine: Arc, } impl Store { - pub fn new(engine: &Engine) -> Store { - Store { - engine: Arc::new(engine.clone()), - } + pub fn new(engine: Arc) -> Store { + Store { engine } } - pub fn engine(&self) -> &Engine { + pub fn engine(&self) -> &Arc { &self.engine } pub fn same(a: &Store, b: &Store) -> bool { Arc::ptr_eq(&a.engine, &b.engine) } - - #[cfg(feature = "compiler")] - fn new_config(config: Box) -> Self { - let tunables = Tunables::for_target(config.target().triple()); - Self::new(&Engine::new(&*config, tunables)) - } } impl PartialEq for Store { @@ -39,8 +29,8 @@ impl PartialEq for Store { } } -// We only implement default if we have assigned a default compiler -#[cfg(feature = "compiler")] +// We only implement default if we have assigned a default compiler and engine +#[cfg(all(feature = "compiler", feature = "engine"))] impl Default for Store { fn default() -> Store { // We store them on a function that returns to make @@ -57,7 +47,18 @@ impl Default for Store { #[cfg(feature = "singlepass")] return Box::new(wasmer_compiler_singlepass::SinglepassConfig::default()); } - Store::new_config(get_config()) + + #[allow(unreachable_code)] + fn get_engine(config: Box) -> Arc { + let tunables = Tunables::for_target(config.target().triple()); + + #[cfg(feature = "jit")] + return Arc::new(wasmer_engine_jit::JITEngine::new(&config, tunables)); + } + + let config = get_config(); + let engine = get_engine(config); + Store::new(config) } } diff --git a/lib/api/src/tunables.rs b/lib/api/src/tunables.rs index d57bd8bf4de..624237cfb03 100644 --- a/lib/api/src/tunables.rs +++ b/lib/api/src/tunables.rs @@ -2,6 +2,7 @@ use more_asserts::assert_ge; use std::cmp::min; use target_lexicon::{OperatingSystem, PointerWidth, Triple, HOST}; use wasm_common::{MemoryType, Pages, TableType}; +use wasmer_engine::Tunables as BaseTunables; use wasmer_runtime::{LinearMemory, Table}; use wasmer_runtime::{MemoryPlan, MemoryStyle, TablePlan, TableStyle}; @@ -57,7 +58,7 @@ impl Tunables { } } -impl wasmer_jit::Tunables for Tunables { +impl BaseTunables for Tunables { /// Get a `MemoryPlan` for the provided `MemoryType` fn memory_plan(&self, memory: MemoryType) -> MemoryPlan { // A heap with a maximum that doesn't exceed the static memory bound specified by the diff --git a/lib/cache/Cargo.toml b/lib/cache/Cargo.toml index 687bc12ff13..782ee4f299b 100644 --- a/lib/cache/Cargo.toml +++ b/lib/cache/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["webassembly", "wasm", "cache"] edition = "2018" [dependencies] -wasmer = { path = "../api", version = "0.16.2" } +wasmer = { path = "../api", version = "0.16.2", default-features = false } memmap = "0.7" hex = "0.4" thiserror = "1" diff --git a/lib/jit/Cargo.toml b/lib/engine-jit/Cargo.toml similarity index 91% rename from lib/jit/Cargo.toml rename to lib/engine-jit/Cargo.toml index 0721981db54..33cf3f6c553 100644 --- a/lib/jit/Cargo.toml +++ b/lib/engine-jit/Cargo.toml @@ -1,8 +1,8 @@ [package] -name = "wasmer-jit" +name = "wasmer-engine-jit" version = "0.16.2" authors = ["Wasmer Engineering Team "] -description = "Wasmer JIT frontend" +description = "Wasmer JIT Engine" license = "(Apache-2.0 WITH LLVM-exception) or MIT" categories = ["wasm"] keywords = ["webassembly", "wasm"] @@ -14,6 +14,7 @@ edition = "2018" wasm-common = { path = "../wasm-common", version = "0.16.2" } wasmer-compiler = { path = "../compiler", version = "0.16.2", default-features = false } wasmer-runtime = { path = "../runtime", version = "0.16.2" } +wasmer-engine = { path = "../engine", version = "0.16.2" } target-lexicon = { version = "0.10.0", default-features = false } # flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" } backtrace = "0.3.46" diff --git a/lib/jit/README.md b/lib/engine-jit/README.md similarity index 100% rename from lib/jit/README.md rename to lib/engine-jit/README.md diff --git a/lib/jit/src/code_memory.rs b/lib/engine-jit/src/code_memory.rs similarity index 100% rename from lib/jit/src/code_memory.rs rename to lib/engine-jit/src/code_memory.rs diff --git a/lib/jit/src/engine.rs b/lib/engine-jit/src/engine.rs similarity index 85% rename from lib/jit/src/engine.rs rename to lib/engine-jit/src/engine.rs index ae6619fbfec..aa5c08303ac 100644 --- a/lib/jit/src/engine.rs +++ b/lib/engine-jit/src/engine.rs @@ -1,10 +1,6 @@ //! JIT compilation. -use crate::error::InstantiationError; -use crate::resolver::Resolver; -use crate::tunables::Tunables; -use crate::CodeMemory; -use crate::{CompiledModule, DeserializeError, SerializeError}; +use crate::{CodeMemory, CompiledModule}; use std::cell::RefCell; use std::collections::HashMap; use std::sync::Arc; @@ -13,6 +9,10 @@ use wasm_common::{FunctionType, LocalFunctionIndex, MemoryIndex, SignatureIndex, use wasmer_compiler::{Compilation, CompileError, FunctionBody, Target}; #[cfg(feature = "compiler")] use wasmer_compiler::{Compiler, CompilerConfig}; +use wasmer_engine::{ + CompiledModule as BaseCompiledModule, DeserializeError, Engine, InstantiationError, Resolver, + SerializeError, Tunables, +}; use wasmer_runtime::{ InstanceHandle, MemoryPlan, Module, SignatureRegistry, TablePlan, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline, @@ -72,11 +72,6 @@ impl JITEngine { } } - /// Get the tunables - pub fn tunables(&self) -> &dyn Tunables { - &**self.tunables - } - pub(crate) fn compiler(&self) -> std::cell::Ref<'_, JITEngineInner> { self.inner.borrow() } @@ -90,45 +85,57 @@ impl JITEngine { pub fn is_deserializable(bytes: &[u8]) -> bool { bytes.starts_with(Self::MAGIC_HEADER) } +} + +impl Engine for JITEngine { + /// Get the tunables + fn tunables(&self) -> &dyn Tunables { + &**self.tunables + } /// Register a signature - pub fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex { + fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex { let compiler = self.compiler(); compiler.signatures().register(func_type) } /// Lookup a signature - pub fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option { + fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option { let compiler = self.compiler(); compiler.signatures().lookup(sig) } /// Retrieves a trampoline given a signature - pub fn trampoline(&self, sig: VMSharedSignatureIndex) -> Option { + fn trampoline(&self, sig: VMSharedSignatureIndex) -> Option { self.compiler().trampoline(sig) } /// Validates a WebAssembly module - pub fn validate(&self, binary: &[u8]) -> Result<(), CompileError> { + fn validate(&self, binary: &[u8]) -> Result<(), CompileError> { self.compiler().validate(binary) } /// Compile a WebAssembly binary - pub fn compile(&self, binary: &[u8]) -> Result { - CompiledModule::new(&self, binary) + fn compile(&self, binary: &[u8]) -> Result, CompileError> { + Ok(Arc::new(CompiledModule::new(&self, binary)?)) } /// Instantiates a WebAssembly module - pub unsafe fn instantiate( + unsafe fn instantiate( &self, - compiled_module: &CompiledModule, + compiled_module: &dyn BaseCompiledModule, resolver: &dyn Resolver, ) -> Result { + let compiled_module = compiled_module.downcast_ref::().unwrap(); unsafe { compiled_module.instantiate(&self, resolver, Box::new(())) } } /// Serializes a WebAssembly module - pub fn serialize(&self, compiled_module: &CompiledModule) -> Result, SerializeError> { + fn serialize( + &self, + compiled_module: &dyn BaseCompiledModule, + ) -> Result, SerializeError> { + let compiled_module = compiled_module.downcast_ref::().unwrap(); // We append the header let mut serialized = Self::MAGIC_HEADER.to_vec(); serialized.extend(compiled_module.serialize()?); @@ -136,16 +143,16 @@ impl JITEngine { } /// Deserializes a WebAssembly module - pub fn deserialize(&self, bytes: &[u8]) -> Result { + fn deserialize(&self, bytes: &[u8]) -> Result, DeserializeError> { if !Self::is_deserializable(bytes) { return Err(DeserializeError::Incompatible( "The provided bytes are not wasmer-jit".to_string(), )); } - Ok(CompiledModule::deserialize( + Ok(Arc::new(CompiledModule::deserialize( &self, &bytes[Self::MAGIC_HEADER.len()..], - )?) + )?)) } } diff --git a/lib/jit/src/function_table.rs b/lib/engine-jit/src/function_table.rs similarity index 100% rename from lib/jit/src/function_table.rs rename to lib/engine-jit/src/function_table.rs diff --git a/lib/jit/src/lib.rs b/lib/engine-jit/src/lib.rs similarity index 80% rename from lib/jit/src/lib.rs rename to lib/engine-jit/src/lib.rs index 2e265fc8afc..0d0a026ec07 100644 --- a/lib/jit/src/lib.rs +++ b/lib/engine-jit/src/lib.rs @@ -27,26 +27,16 @@ mod code_memory; mod engine; -mod error; mod function_table; mod link; mod module; -mod resolver; mod serialize; -mod trap; -mod tunables; pub use crate::code_memory::CodeMemory; pub use crate::engine::JITEngine; -pub use crate::error::{ - DeserializeError, ImportError, InstantiationError, LinkError, SerializeError, -}; pub use crate::function_table::FunctionTable; pub use crate::link::link_module; pub use crate::module::CompiledModule; -pub use crate::resolver::{resolve_imports, NullResolver, Resolver}; -pub use crate::trap::*; -pub use crate::tunables::Tunables; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/lib/jit/src/link.rs b/lib/engine-jit/src/link.rs similarity index 90% rename from lib/jit/src/link.rs rename to lib/engine-jit/src/link.rs index 20d10555f0a..d011886e474 100644 --- a/lib/jit/src/link.rs +++ b/lib/engine-jit/src/link.rs @@ -10,9 +10,8 @@ use wasmer_compiler::{ use wasmer_runtime::Module; use wasmer_runtime::VMFunctionBody; -/// Links a module that has been compiled with `compiled_module` in `wasmer-compiler::Compiler`. -/// -/// Performs all required relocations inside the function code, provided the necessary metadata. +/// Links a module, patching the allocated functions with the +/// required relocations and jump tables. pub fn link_module( module: &Module, allocated_functions: &PrimaryMap, @@ -72,10 +71,8 @@ pub fn link_module( .wrapping_add(reloc_addend as u32); write_unaligned(reloc_address as *mut u32, reloc_delta_u32); } - RelocationKind::X86PCRelRodata4 => { - // ignore - } - _ => panic!("unsupported reloc kind"), + RelocationKind::X86PCRelRodata4 => {} + _ => panic!("Relocation kind unsupported"), } } } diff --git a/lib/jit/src/module.rs b/lib/engine-jit/src/module.rs similarity index 89% rename from lib/jit/src/module.rs rename to lib/engine-jit/src/module.rs index 7760bf2569c..9673bf589d5 100644 --- a/lib/jit/src/module.rs +++ b/lib/engine-jit/src/module.rs @@ -2,17 +2,8 @@ //! done as separate steps. use crate::engine::{JITEngine, JITEngineInner}; -use crate::error::{DeserializeError, SerializeError}; -use crate::error::{InstantiationError, LinkError}; use crate::link::link_module; -use crate::resolver::{resolve_imports, Resolver}; -use crate::serialize::{ - SerializableCompilation, SerializableFunctionFrameInfo, SerializableModule, -}; -use crate::trap::register as register_frame_info; -use crate::trap::GlobalFrameInfoRegistration; -use crate::trap::RuntimeError; -use crate::tunables::Tunables; +use crate::serialize::{SerializableCompilation, SerializableModule}; use serde::{Deserialize, Serialize}; use std::any::Any; use std::sync::{Arc, Mutex}; @@ -24,6 +15,11 @@ use wasm_common::{ use wasmer_compiler::CompileError; #[cfg(feature = "compiler")] use wasmer_compiler::ModuleEnvironment; +use wasmer_engine::{ + register_frame_info, resolve_imports, CompiledModule as BaseCompiledModule, DeserializeError, + Engine, GlobalFrameInfoRegistration, InstantiationError, LinkError, Resolver, RuntimeError, + SerializableFunctionFrameInfo, SerializeError, Tunables, +}; use wasmer_runtime::{ InstanceHandle, LinearMemory, Module, SignatureRegistry, Table, VMFunctionBody, VMGlobalDefinition, VMSharedSignatureIndex, @@ -213,7 +209,7 @@ impl CompiledModule { let tunables = jit.tunables(); let sig_registry: &SignatureRegistry = jit_compiler.signatures(); let imports = resolve_imports( - &self.serializable.module, + &self.module(), &sig_registry, resolver, self.memory_plans(), @@ -222,15 +218,15 @@ impl CompiledModule { .map_err(InstantiationError::Link)?; let finished_memories = tunables - .create_memories(&self.serializable.module, self.memory_plans()) + .create_memories(&self.module(), self.memory_plans()) .map_err(InstantiationError::Link)? .into_boxed_slice(); let finished_tables = tunables - .create_tables(&self.serializable.module, self.table_plans()) + .create_tables(&self.module(), self.table_plans()) .map_err(InstantiationError::Link)? .into_boxed_slice(); let finished_globals = tunables - .create_globals(&self.serializable.module) + .create_globals(&self.module()) .map_err(InstantiationError::Link)? .into_boxed_slice(); @@ -250,21 +246,6 @@ impl CompiledModule { .map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap))) } - /// Finish instantiation of a `InstanceHandle` - /// - /// # Unsafety - /// - /// See `InstanceHandle::finish_instantiation` - pub unsafe fn finish_instantiation( - &self, - handle: &InstanceHandle, - ) -> Result<(), InstantiationError> { - let is_bulk_memory: bool = self.serializable.features.bulk_memory; - handle - .finish_instantiation(is_bulk_memory, &self.data_initializers()) - .map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap))) - } - /// Returns data initializers to pass to `InstanceHandle::initialize` pub fn data_initializers(&self) -> Vec> { self.serializable @@ -276,22 +257,6 @@ impl CompiledModule { }) .collect::>() } - - /// Return a reference-counting pointer to a module. - pub fn module(&self) -> &Arc { - &self.serializable.module - } - - /// Return a reference-counting pointer to a module. - pub fn module_mut(&mut self) -> &mut Arc { - &mut self.serializable.module - } - - /// Return a reference to a module. - pub fn module_ref(&self) -> &Module { - &self.serializable.module - } - /// Register this module's stack frame information into the global scope. /// /// This is required to ensure that any traps can be properly symbolicated. @@ -303,9 +268,29 @@ impl CompiledModule { let frame_infos = &self.serializable.compilation.function_frame_info; let finished_functions = &self.finished_functions; *info = Some(register_frame_info( - &self.module(), + self.serializable.module.clone(), finished_functions, frame_infos.clone(), )); } } + +impl BaseCompiledModule for CompiledModule { + unsafe fn finish_instantiation( + &self, + handle: &InstanceHandle, + ) -> Result<(), InstantiationError> { + let is_bulk_memory: bool = self.serializable.features.bulk_memory; + handle + .finish_instantiation(is_bulk_memory, &self.data_initializers()) + .map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap))) + } + + fn module(&self) -> &Module { + &self.serializable.module + } + + fn module_mut(&mut self) -> &mut Module { + Arc::get_mut(&mut self.serializable.module).unwrap() + } +} diff --git a/lib/engine-jit/src/serialize.rs b/lib/engine-jit/src/serialize.rs new file mode 100644 index 00000000000..12bb9b8bce3 --- /dev/null +++ b/lib/engine-jit/src/serialize.rs @@ -0,0 +1,37 @@ +use serde::{Deserialize, Serialize}; +use std::sync::Arc; +use wasm_common::entity::PrimaryMap; +use wasm_common::{ + Features, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex, +}; +use wasmer_compiler::{FunctionBody, JumpTableOffsets, Relocation, SectionBody, SectionIndex}; +use wasmer_engine::SerializableFunctionFrameInfo; +use wasmer_runtime::Module; +use wasmer_runtime::{MemoryPlan, TablePlan}; + +/// The compilation related data for a serialized modules +#[derive(Serialize, Deserialize)] +pub struct SerializableCompilation { + pub function_bodies: PrimaryMap, + pub function_relocations: PrimaryMap>, + pub function_jt_offsets: PrimaryMap, + // This is `SerializableFunctionFrameInfo` instead of `CompiledFunctionFrameInfo`, + // to allow lazy frame_info deserialization, we convert it to it's lazy binary + // format upon serialization. + pub function_frame_info: PrimaryMap, + pub trampolines: PrimaryMap, + pub custom_sections: PrimaryMap, +} + +/// Serializable struct that is able to serialize from and to +/// a `CompiledModule`. +#[derive(Serialize, Deserialize)] +pub struct SerializableModule { + pub compilation: SerializableCompilation, + pub features: Features, + pub module: Arc, + pub data_initializers: Box<[OwnedDataInitializer]>, + // Plans for that module + pub memory_plans: PrimaryMap, + pub table_plans: PrimaryMap, +} diff --git a/lib/engine/Cargo.toml b/lib/engine/Cargo.toml new file mode 100644 index 00000000000..43d9bc59240 --- /dev/null +++ b/lib/engine/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "wasmer-engine" +version = "0.16.2" +authors = ["Wasmer Engineering Team "] +description = "Wasmer Engine abstraction" +license = "(Apache-2.0 WITH LLVM-exception) or MIT" +categories = ["wasm"] +keywords = ["webassembly", "wasm"] +repository = "https://github.com/wasmerio/wasmer" +readme = "README.md" +edition = "2018" + +[dependencies] +wasm-common = { path = "../wasm-common", version = "0.16.2" } +wasmer-compiler = { path = "../compiler", version = "0.16.2", default-features = false } +wasmer-runtime = { path = "../runtime", version = "0.16.2" } +target-lexicon = { version = "0.10.0", default-features = false } +# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" } +backtrace = "0.3.46" +rustc-demangle = "0.1.16" +more-asserts = "0.2.1" +thiserror = "1.0.16" +region = "2.1.2" +serde = { version = "1.0.106", sfeatures = ["derive", "rc"] } +serde_bytes = { version = "0.11.3" } +bincode = "1.2.1" +lazy_static = "1.4" +downcast-rs = "1.1.1" + +[target.'cfg(target_os = "windows")'.dependencies] +winapi = { version = "0.3.8", features = ["winnt", "impl-default"] } + +[badges] +maintenance = { status = "actively-developed" } diff --git a/lib/engine/README.md b/lib/engine/README.md new file mode 100644 index 00000000000..f45e09291e0 --- /dev/null +++ b/lib/engine/README.md @@ -0,0 +1,12 @@ +# Wasmer Engine + +The Wasmer Engine is the general abstraction for Engines in Wasmer. +It currently has two implementations: +* Wasmer JIT +* Wasmer Native + +### Acknowledgments + +This project borrowed some of the code of the trap implementation from the [wasmtime-api](https://crates.io/crates/wasmtime), the code since then has evolved significantly. + +Please check [Wasmer ATTRIBUTIONS](https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md) to further see licenses and other attributions of the project. diff --git a/lib/engine/src/engine.rs b/lib/engine/src/engine.rs new file mode 100644 index 00000000000..709d5fae4aa --- /dev/null +++ b/lib/engine/src/engine.rs @@ -0,0 +1,46 @@ +//! JIT compilation. + +use crate::error::InstantiationError; +use crate::resolver::Resolver; +use crate::tunables::Tunables; +use crate::{CompiledModule, DeserializeError, SerializeError}; +use std::sync::Arc; +use wasm_common::FunctionType; +use wasmer_compiler::CompileError; +use wasmer_runtime::{InstanceHandle, VMSharedSignatureIndex, VMTrampoline}; + +/// A unimplemented Wasmer `Engine`. +/// This trait is used by implementors to implement custom engines, +/// such as: JIT or Native. +pub trait Engine { + /// Get the tunables + fn tunables(&self) -> &Tunables; + + /// Register a signature + fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex; + + /// Lookup a signature + fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option; + + /// Retrieves a trampoline given a signature + fn trampoline(&self, sig: VMSharedSignatureIndex) -> Option; + + /// Validates a WebAssembly module + fn validate(&self, binary: &[u8]) -> Result<(), CompileError>; + + /// Compile a WebAssembly binary + fn compile(&self, binary: &[u8]) -> Result, CompileError>; + + /// Instantiates a WebAssembly module + unsafe fn instantiate( + &self, + compiled_module: &dyn CompiledModule, + resolver: &dyn Resolver, + ) -> Result; + + /// Serializes a WebAssembly module + fn serialize(&self, compiled_module: &dyn CompiledModule) -> Result, SerializeError>; + + /// Deserializes a WebAssembly module + fn deserialize(&self, bytes: &[u8]) -> Result, DeserializeError>; +} diff --git a/lib/jit/src/error.rs b/lib/engine/src/error.rs similarity index 98% rename from lib/jit/src/error.rs rename to lib/engine/src/error.rs index 1ae5345a5a8..a1dff4cd56b 100644 --- a/lib/jit/src/error.rs +++ b/lib/engine/src/error.rs @@ -1,4 +1,3 @@ -// TODO: Move this errors into a common engine crate. //! The WebAssembly possible errors use crate::trap::RuntimeError; use thiserror::Error; diff --git a/lib/engine/src/lib.rs b/lib/engine/src/lib.rs new file mode 100644 index 00000000000..97d9c322d60 --- /dev/null +++ b/lib/engine/src/lib.rs @@ -0,0 +1,43 @@ +//! Generic Engine abstraction for Wasmer Engines. + +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] +#![warn(unused_import_braces)] +#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))] +#![cfg_attr( + feature = "cargo-clippy", + allow(clippy::new_without_default, clippy::new_without_default) +)] +#![cfg_attr( + feature = "cargo-clippy", + warn( + clippy::float_arithmetic, + clippy::mut_mut, + clippy::nonminimal_bool, + clippy::option_map_unwrap_or, + clippy::option_map_unwrap_or_else, + clippy::print_stdout, + clippy::unicode_not_nfc, + clippy::use_self + ) +)] + +mod engine; +mod error; +mod module; +mod resolver; +mod serialize; +mod trap; +mod tunables; + +pub use crate::engine::Engine; +pub use crate::error::{ + DeserializeError, ImportError, InstantiationError, LinkError, SerializeError, +}; +pub use crate::module::CompiledModule; +pub use crate::resolver::{resolve_imports, NullResolver, Resolver}; +pub use crate::serialize::SerializableFunctionFrameInfo; +pub use crate::trap::*; +pub use crate::tunables::Tunables; + +/// Version number of this crate. +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/lib/engine/src/module.rs b/lib/engine/src/module.rs new file mode 100644 index 00000000000..a1e7510eb52 --- /dev/null +++ b/lib/engine/src/module.rs @@ -0,0 +1,28 @@ +use crate::error::InstantiationError; +use std::sync::Arc; +use wasmer_runtime::InstanceHandle; +use wasmer_runtime::Module; + +use downcast_rs::{impl_downcast, Downcast}; + +/// The `CompiledModule` trait is used by engine implementors, such +/// as a JIT or Native execution. +pub trait CompiledModule: Downcast { + /// Finish instantiation of a `InstanceHandle` + /// + /// # Unsafety + /// + /// See `InstanceHandle::finish_instantiation` + unsafe fn finish_instantiation( + &self, + handle: &InstanceHandle, + ) -> Result<(), InstantiationError>; + + /// Return a reference-counting pointer to a module. + fn module(&self) -> &Module; + + /// Return a reference-counting pointer to a module. + fn module_mut(&mut self) -> &mut Module; +} + +impl_downcast!(CompiledModule); // `sync` => also produce `Arc` downcasts. diff --git a/lib/jit/src/resolver.rs b/lib/engine/src/resolver.rs similarity index 100% rename from lib/jit/src/resolver.rs rename to lib/engine/src/resolver.rs diff --git a/lib/jit/src/serialize.rs b/lib/engine/src/serialize.rs similarity index 69% rename from lib/jit/src/serialize.rs rename to lib/engine/src/serialize.rs index 07af00d4125..42964a24ee2 100644 --- a/lib/jit/src/serialize.rs +++ b/lib/engine/src/serialize.rs @@ -2,45 +2,7 @@ use serde::de::{Deserializer, Visitor}; use serde::ser::Serializer; use serde::{Deserialize, Serialize}; use std::fmt; -use std::sync::Arc; -use wasmer_compiler::{ - CompiledFunctionFrameInfo, FunctionBody, JumpTableOffsets, Relocation, SectionBody, - SectionIndex, -}; -use wasmer_runtime::Module; - -use wasm_common::entity::PrimaryMap; -use wasm_common::{ - Features, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex, -}; -use wasmer_runtime::{MemoryPlan, TablePlan}; - -/// The compilation related data for a serialized modules -#[derive(Serialize, Deserialize)] -pub struct SerializableCompilation { - pub function_bodies: PrimaryMap, - pub function_relocations: PrimaryMap>, - pub function_jt_offsets: PrimaryMap, - // This is `SerializableFunctionFrameInfo` instead of `CompiledFunctionFrameInfo`, - // to allow lazy frame_info deserialization, we convert it to it's lazy binary - // format upon serialization. - pub function_frame_info: PrimaryMap, - pub trampolines: PrimaryMap, - pub custom_sections: PrimaryMap, -} - -/// Serializable struct that is able to serialize from and to -/// a `CompiledModule`. -#[derive(Serialize, Deserialize)] -pub struct SerializableModule { - pub compilation: SerializableCompilation, - pub features: Features, - pub module: Arc, - pub data_initializers: Box<[OwnedDataInitializer]>, - // Plans for that module - pub memory_plans: PrimaryMap, - pub table_plans: PrimaryMap, -} +use wasmer_compiler::CompiledFunctionFrameInfo; /// This is the unserialized verison of `CompiledFunctionFrameInfo`. #[derive(Clone, Serialize, Deserialize)] diff --git a/lib/jit/src/trap/error.rs b/lib/engine/src/trap/error.rs similarity index 98% rename from lib/jit/src/trap/error.rs rename to lib/engine/src/trap/error.rs index 0f9637a6d3e..7f066b6339e 100644 --- a/lib/jit/src/trap/error.rs +++ b/lib/engine/src/trap/error.rs @@ -27,7 +27,7 @@ impl RuntimeError { /// Creates a new `Trap` with `message`. /// # Example /// ``` - /// let trap = wasmer_jit::RuntimeError::new("unexpected error"); + /// let trap = wasmer_engine::RuntimeError::new("unexpected error"); /// assert_eq!("unexpected error", trap.message()); /// ``` pub fn new>(message: I) -> Self { diff --git a/lib/jit/src/trap/frame_info.rs b/lib/engine/src/trap/frame_info.rs similarity index 99% rename from lib/jit/src/trap/frame_info.rs rename to lib/engine/src/trap/frame_info.rs index 1d0d34300ca..5678b9c327e 100644 --- a/lib/jit/src/trap/frame_info.rs +++ b/lib/engine/src/trap/frame_info.rs @@ -225,7 +225,7 @@ impl Drop for GlobalFrameInfoRegistration { /// then `None` will be returned. Otherwise the returned object, when /// dropped, will be used to unregister all name information from this map. pub fn register( - module: &Arc, + module: Arc, finished_functions: &BoxedSlice, frame_infos: PrimaryMap, ) -> Option { diff --git a/lib/engine/src/trap/mod.rs b/lib/engine/src/trap/mod.rs new file mode 100644 index 00000000000..d32440a8866 --- /dev/null +++ b/lib/engine/src/trap/mod.rs @@ -0,0 +1,6 @@ +mod error; +mod frame_info; +pub use error::RuntimeError; +pub use frame_info::{ + register as register_frame_info, FrameInfo, GlobalFrameInfoRegistration, FRAME_INFO, +}; diff --git a/lib/jit/src/tunables.rs b/lib/engine/src/tunables.rs similarity index 100% rename from lib/jit/src/tunables.rs rename to lib/engine/src/tunables.rs diff --git a/lib/jit/src/trap/mod.rs b/lib/jit/src/trap/mod.rs deleted file mode 100644 index 1a37b64afe2..00000000000 --- a/lib/jit/src/trap/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod error; -mod frame_info; -pub use error::RuntimeError; -pub use frame_info::{register, FrameInfo, GlobalFrameInfoRegistration, FRAME_INFO}; diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 934b3c950a8..84fa37b6d9a 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -20,7 +20,7 @@ getrandom = "0.1" time = "0.1" typetag = "0.1" serde = { version = "1", features = ["derive"] } -wasmer = { path = "../api", version = "0.16.2" } +wasmer = { path = "../api", version = "0.16.2", default-features = false } [target.'cfg(windows)'.dependencies] winapi = "0.3" diff --git a/src/commands/run.rs b/src/commands/run.rs index c02858dadc1..3ad64de42ee 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -8,6 +8,8 @@ use std::sync::Arc; use wasmer::*; #[cfg(feature = "cache")] use wasmer_cache::{Cache, FileSystemCache, IoDeserializeError, WasmHash}; +#[cfg(feature = "jit")] +use wasmer_engine_jit::JITEngine; use structopt::StructOpt; @@ -130,13 +132,15 @@ impl Run { fn get_module(&self) -> Result { let contents = std::fs::read(self.path.clone())?; - if Engine::is_deserializable(&contents) { - // We get the tunables for the current host - let tunables = Tunables::default(); - let engine = Engine::headless(tunables); - let store = Store::new(&engine); - let module = unsafe { Module::deserialize(&store, &contents)? }; - return Ok(module); + #[cfg(feature = "jit")] + { + if JITEngine::is_deserializable(&contents) { + let tunables = Tunables::default(); + let engine = JITEngine::headless(tunables); + let store = Store::new(Arc::new(engine)); + let module = unsafe { Module::deserialize(&store, &contents)? }; + return Ok(module); + } } let (store, compiler_name) = self.compiler.get_store()?; // We try to get it from cache, in case caching is enabled diff --git a/src/store.rs b/src/store.rs index 009e749c9a8..a814c3540ae 100644 --- a/src/store.rs +++ b/src/store.rs @@ -5,8 +5,10 @@ use crate::common::WasmFeatures; use anyhow::{bail, Error, Result}; use std::str::FromStr; use std::string::ToString; +use std::sync::Arc; use structopt::StructOpt; use wasmer::*; +use wasmer_compiler::CompilerConfig; #[derive(Debug, Clone, StructOpt)] /// The compiler options @@ -62,7 +64,7 @@ impl FromStr for Compiler { } } -#[cfg(feature = "compiler")] +#[cfg(all(feature = "compiler", feature = "engine"))] impl StoreOptions { fn get_compiler(&self) -> Result { if self.cranelift { @@ -136,13 +138,15 @@ impl StoreOptions { pub fn get_store(&self) -> Result<(Store, String)> { let (compiler_config, compiler_name) = self.get_compiler_config()?; let tunables = self.get_tunables(&*compiler_config); - let engine = Engine::new(&*compiler_config, tunables); - let store = Store::new(&engine); + #[cfg(feature = "jit")] + let engine = wasmer_engine_jit::JITEngine::new(&*compiler_config, tunables); + let store = Store::new(Arc::new(engine)); Ok((store, compiler_name)) } } -#[cfg(not(feature = "compiler"))] +// If we don't have a compiler, but we have an engine +#[cfg(all(not(feature = "compiler"), feature = "engine"))] impl StoreOptions { /// Get the store (headless engine) pub fn get_store(&self) -> Result<(Store, String)> { @@ -153,3 +157,12 @@ impl StoreOptions { Ok((store, "headless".to_string())) } } + +// If we don't have any engine enabled +#[cfg(not(feature = "engine"))] +impl StoreOptions { + /// Get the store (headless engine) + pub fn get_store(&self) -> Result<(Store, String)> { + bail!("No engines are enabled"); + } +} diff --git a/tests/lib/wast/Cargo.toml b/tests/lib/wast/Cargo.toml index b3bfeb375a7..0d85802a987 100644 --- a/tests/lib/wast/Cargo.toml +++ b/tests/lib/wast/Cargo.toml @@ -12,9 +12,13 @@ edition = "2018" [dependencies] anyhow = "1.0.28" -wasmer = { path = "../../../lib/api", version = "0.16.2" } +wasmer = { path = "../../../lib/api", version = "0.16.2", default-features = false } wast = "14.0.0" thiserror = "1.0.15" +[features] +default = ["wat"] +wat = ["wasmer/wat"] + [badges] maintenance = { status = "actively-developed" } diff --git a/tests/wast.rs b/tests/wast.rs index 4a3f6053e99..c024a9fc4ad 100644 --- a/tests/wast.rs +++ b/tests/wast.rs @@ -1,8 +1,11 @@ -#![cfg(feature = "compiler")] +#![cfg(all(feature = "compiler", feature = "engine"))] use std::path::Path; +use std::sync::Arc; use test_utils::get_compiler_config_from_str; -use wasmer::{Engine, Features, Store, Tunables}; +use wasmer::{Features, Store, Tunables}; +#[cfg(feature = "jit")] +use wasmer_engine_jit::JITEngine; use wasmer_wast::Wast; // The generated tests (from build.rs) look like: @@ -30,7 +33,7 @@ fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { let compiler_config = get_compiler_config_from_str(compiler, try_nan_canonicalization, features); let tunables = Tunables::for_target(compiler_config.target().triple()); - let store = Store::new(&Engine::new(&*compiler_config, tunables)); + let store = Store::new(Arc::new(JITEngine::new(&*compiler_config, tunables))); let mut wast = Wast::new_with_spectest(store); // wast.fail_fast = false; let path = Path::new(wast_path);