From d150be816bd1af05817339b94eebc5bdcc33b130 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 17 Jun 2020 13:57:06 -0700 Subject: [PATCH 01/59] Implement shared, delayed WASI memory initialization --- lib/wasi/src/lib.rs | 76 ++++++++++++++++++++++++++++++++++++---- src/commands/run/wasi.rs | 3 +- 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 4277a7edb..cd88af524 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -28,6 +28,9 @@ pub use crate::utils::{get_wasi_version, is_wasi_module, WasiVersion}; use thiserror::Error; use wasmer::{imports, Function, ImportObject, Memory, Module, Store}; +use std::mem::MaybeUninit; +use std::ptr::NonNull; +use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex, MutexGuard}; /// This is returned in `RuntimeError`. @@ -45,14 +48,75 @@ pub enum WasiError { #[derive(Clone)] pub struct WasiEnv { state: Arc>, - memory: Option>, + memory: Arc, +} + +struct WasiMemory { + initialized: AtomicBool, + memory: NonNull>, + mutate_lock: Mutex<()>, +} + +impl WasiMemory { + fn new() -> Self { + let boxed_memory = Box::new(MaybeUninit::zeroed()); + let memory = unsafe { NonNull::new_unchecked(Box::into_raw(boxed_memory)) }; + Self { + initialized: AtomicBool::new(false), + memory, + mutate_lock: Mutex::new(()), + } + } + + fn set_memory(&self, memory: Memory) -> bool { + // synchronize it + let _guard = self.mutate_lock.lock(); + if self.initialized.load(Ordering::Acquire) { + return false; + } + + unsafe { + let ptr = self.memory.as_ptr(); + // maybe some UB here with getting &mut indirectly from a `&self`? + let mem_inner: &mut MaybeUninit = &mut *ptr; + mem_inner.as_mut_ptr().write(memory); + } + self.initialized.store(true, Ordering::Release); + + true + } + + fn get_memory(&self) -> Option<&Memory> { + // Based on normal usage, `Relaxed` is fine... + // TODO: investigate if it's possible to use the API in a way where `Relaxed` + // is not fine + if self.initialized.load(Ordering::Relaxed) { + unsafe { + let maybe_mem = self.memory.as_ref(); + Some(&*maybe_mem.as_ptr()) + } + } else { + None + } + } +} + +impl Drop for WasiMemory { + fn drop(&mut self) { + if self.initialized.load(Ordering::Acquire) { + unsafe { + let maybe_uninit = Box::from_raw(self.memory.as_ptr()); + (*maybe_uninit).assume_init(); + } + } + } } impl WasiEnv { pub fn new(state: WasiState) -> Self { Self { state: Arc::new(Mutex::new(state)), - memory: None, + memory: Arc::new(WasiMemory::new()), } } @@ -66,8 +130,8 @@ impl WasiEnv { } /// Set the memory - pub fn set_memory(&mut self, memory: Arc) { - self.memory = Some(memory); + pub fn set_memory(&mut self, memory: Memory) -> bool { + self.memory.set_memory(memory) } /// Get the WASI state @@ -82,14 +146,14 @@ impl WasiEnv { /// Get a reference to the memory pub fn memory(&self) -> &Memory { - self.memory.as_ref().expect("The expected Memory is not attached to the `WasiEnv`. Did you forgot to call wasi_env.set_memory(...)?") + self.memory.get_memory().expect("The expected Memory is not attached to the `WasiEnv`. Did you forgot to call wasi_env.set_memory(...)?") } pub(crate) fn get_memory_and_wasi_state( &mut self, _mem_index: u32, ) -> (&Memory, MutexGuard) { - let memory = self.memory.as_ref().unwrap(); + let memory = self.memory.get_memory().unwrap(); let state = self.state.lock().unwrap(); (memory, state) } diff --git a/src/commands/run/wasi.rs b/src/commands/run/wasi.rs index 6fb60d7d3..98840a66f 100644 --- a/src/commands/run/wasi.rs +++ b/src/commands/run/wasi.rs @@ -1,7 +1,6 @@ use crate::utils::{parse_envvar, parse_mapdir}; use anyhow::{Context, Result}; use std::path::PathBuf; -use std::sync::Arc; use wasmer::{Instance, Module}; use wasmer_wasi::{get_wasi_version, WasiState, WasiVersion}; @@ -59,7 +58,7 @@ impl Wasi { let import_object = wasi_env.import_object(&module)?; let instance = Instance::new(&module, &import_object)?; - wasi_env.set_memory(Arc::new(instance.exports.get_memory("memory")?.clone())); + wasi_env.set_memory(instance.exports.get_memory("memory")?.clone()); let start = instance.exports.get_function("_start")?; start From 084a1550fa5932485180bcd2417b8ffd8303172f Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 17 Jun 2020 15:45:40 -0700 Subject: [PATCH 02/59] Clean up and comment WASI delayed initialization code --- lib/c-api/src/import/wasi.rs | 3 +-- lib/wasi/src/lib.rs | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/lib/c-api/src/import/wasi.rs b/lib/c-api/src/import/wasi.rs index 12e33880d..d1d131894 100644 --- a/lib/c-api/src/import/wasi.rs +++ b/lib/c-api/src/import/wasi.rs @@ -4,7 +4,6 @@ use libc::c_uchar; use std::path::PathBuf; use std::ptr; use std::str; -use std::sync::Arc; use wasmer::{Memory, MemoryType, NamedResolver}; use wasmer_wasi as wasi; @@ -217,7 +216,7 @@ pub unsafe extern "C" fn wasmer_wasi_generate_default_import_object() -> *mut wa // this API will now leak a `Memory` let memory_type = MemoryType::new(0, None, false); let memory = Memory::new(store, memory_type).expect("create memory"); - wasi_env.set_memory(Arc::new(memory)); + wasi_env.set_memory(memory); // TODO(mark): review lifetime of `Memory` here let import_object_inner: Box = Box::new( wasi::generate_import_object_from_env(store, wasi_env, wasi::WasiVersion::Latest), diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index cd88af524..0dfde83d8 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -28,8 +28,8 @@ pub use crate::utils::{get_wasi_version, is_wasi_module, WasiVersion}; use thiserror::Error; use wasmer::{imports, Function, ImportObject, Memory, Module, Store}; +use std::cell::UnsafeCell; use std::mem::MaybeUninit; -use std::ptr::NonNull; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex, MutexGuard}; @@ -51,23 +51,30 @@ pub struct WasiEnv { memory: Arc, } +/// Wrapper type around `Memory` used to delay initialization of the memory. +/// +/// The `initialized` field is used to indicate if it's safe to read `memory` as `Memory`. +/// +/// The `mutate_lock` is used to prevent access from multiple threads during initialization. struct WasiMemory { initialized: AtomicBool, - memory: NonNull>, + memory: UnsafeCell>, mutate_lock: Mutex<()>, } impl WasiMemory { fn new() -> Self { - let boxed_memory = Box::new(MaybeUninit::zeroed()); - let memory = unsafe { NonNull::new_unchecked(Box::into_raw(boxed_memory)) }; Self { initialized: AtomicBool::new(false), - memory, + memory: UnsafeCell::new(MaybeUninit::zeroed()), mutate_lock: Mutex::new(()), } } + /// Initialize the memory, making it safe to read from. + /// + /// Returns whether or not the set was successful. If the set failed then + /// the memory has already been initialized. fn set_memory(&self, memory: Memory) -> bool { // synchronize it let _guard = self.mutate_lock.lock(); @@ -76,8 +83,7 @@ impl WasiMemory { } unsafe { - let ptr = self.memory.as_ptr(); - // maybe some UB here with getting &mut indirectly from a `&self`? + let ptr = self.memory.get(); let mem_inner: &mut MaybeUninit = &mut *ptr; mem_inner.as_mut_ptr().write(memory); } @@ -86,14 +92,16 @@ impl WasiMemory { true } + /// Returns `None` if the memory has not been initialized yet. + /// Otherwise returns the memory that was used to initialize it. fn get_memory(&self) -> Option<&Memory> { // Based on normal usage, `Relaxed` is fine... // TODO: investigate if it's possible to use the API in a way where `Relaxed` // is not fine if self.initialized.load(Ordering::Relaxed) { unsafe { - let maybe_mem = self.memory.as_ref(); - Some(&*maybe_mem.as_ptr()) + let maybe_mem = self.memory.get(); + Some(&*(*maybe_mem).as_ptr()) } } else { None @@ -105,8 +113,9 @@ impl Drop for WasiMemory { fn drop(&mut self) { if self.initialized.load(Ordering::Acquire) { unsafe { - let maybe_uninit = Box::from_raw(self.memory.as_ptr()); - (*maybe_uninit).assume_init(); + let mut maybe_uninit = UnsafeCell::new(MaybeUninit::zeroed()); + std::mem::swap(&mut self.memory, &mut maybe_uninit); + maybe_uninit.into_inner().assume_init(); } } } From d5fd82bed4d86ed08abb925f77627841cc394ac5 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 17 Jun 2020 16:08:23 -0700 Subject: [PATCH 03/59] Add comment explaining WasiMemory Drop logic --- lib/wasi/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 0dfde83d8..efac78f9f 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -113,6 +113,10 @@ impl Drop for WasiMemory { fn drop(&mut self) { if self.initialized.load(Ordering::Acquire) { unsafe { + // We want to get the internal value in memory, so we need to consume + // the `UnsafeCell` and assume the `MapbeInit` is initialized, but because + // we only have a `&mut self` we can't do this directly, so we swap the data + // out so we can drop it (via `assume_init`). let mut maybe_uninit = UnsafeCell::new(MaybeUninit::zeroed()); std::mem::swap(&mut self.memory, &mut maybe_uninit); maybe_uninit.into_inner().assume_init(); From e062e87d8b3ceb1b207239cd058f3c0e5209e7f7 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 17 Jun 2020 19:02:54 -0700 Subject: [PATCH 04/59] Refactored Compilers --- lib/api/src/store.rs | 12 +++++-- lib/compiler-cranelift/src/compiler.rs | 17 ++++------ lib/compiler-cranelift/src/config.rs | 19 +++++------ lib/compiler-llvm/src/compiler.rs | 24 ++++++-------- lib/compiler-llvm/src/config.rs | 16 +++------- lib/compiler-singlepass/src/compiler.rs | 22 ++++++------- lib/compiler-singlepass/src/config.rs | 14 ++------- lib/compiler/src/compiler.rs | 20 +++++------- lib/compiler/src/error.rs | 4 +++ lib/compiler/src/lib.rs | 2 ++ lib/compiler/src/module.rs | 27 ++++++++++++++++ lib/engine-jit/src/artifact.rs | 40 ++++++++++++----------- lib/engine-jit/src/engine.rs | 13 +++++++- lib/engine-jit/src/serialize.rs | 9 ++---- lib/engine-native/src/artifact.rs | 40 ++++++++++++----------- lib/engine-native/src/engine.rs | 13 ++++++-- lib/engine-native/src/serialize.rs | 8 ++--- src/store.rs | 17 +++++----- tests/compilers/utils.rs | 16 +++++++--- tests/lib/test-utils/src/lib.rs | 42 ++++++++++++++++--------- tests/wast.rs | 9 ++++-- 21 files changed, 217 insertions(+), 167 deletions(-) create mode 100644 lib/compiler/src/module.rs diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index 42ddb4b0c..15b96711d 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -57,10 +57,18 @@ impl Default for Store { let tunables = Tunables::for_target(config.target().triple()); #[cfg(feature = "jit")] - return Arc::new(wasmer_engine_jit::JITEngine::new(config, tunables)); + return Arc::new(wasmer_engine_jit::JITEngine::new( + config, + tunables, + Default::default(), + )); #[cfg(feature = "native")] - return Arc::new(wasmer_engine_native::NativeEngine::new(config, tunables)); + return Arc::new(wasmer_engine_native::NativeEngine::new( + config, + tunables, + Default::default(), + )); } let config = get_config(); diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index 675081d6d..0a8fd89eb 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -26,10 +26,9 @@ use wasm_common::{ use wasmer_compiler::CompileError; use wasmer_compiler::{CallingConvention, CompilerConfig, ModuleTranslationState, Target}; use wasmer_compiler::{ - Compilation, CompiledFunction, CompiledFunctionFrameInfo, CompiledFunctionUnwindInfo, Compiler, - Dwarf, FunctionBody, FunctionBodyData, SectionIndex, + Compilation, CompileModuleInfo, CompiledFunction, CompiledFunctionFrameInfo, + CompiledFunctionUnwindInfo, Compiler, Dwarf, FunctionBody, FunctionBodyData, SectionIndex, }; -use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan}; /// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR, /// optimizing it and then translating to assembly. @@ -60,11 +59,6 @@ impl CraneliftCompiler { } impl Compiler for CraneliftCompiler { - /// Gets the WebAssembly features for this Compiler - fn features(&self) -> &Features { - self.config.features() - } - /// Gets the target associated to the Cranelift ISA. fn target(&self) -> &Target { self.config.target() @@ -74,14 +68,15 @@ impl Compiler for CraneliftCompiler { /// associated relocations. fn compile_module( &self, - module: &ModuleInfo, + compile_info: &CompileModuleInfo, module_translation: &ModuleTranslationState, function_body_inputs: PrimaryMap>, - memory_plans: PrimaryMap, - table_plans: PrimaryMap, ) -> Result { let isa = self.isa(); let frontend_config = isa.frontend_config(); + let memory_plans = &compile_info.memory_plans; + let table_plans = &compile_info.table_plans; + let module = &compile_info.module; let signatures = module .signatures .iter() diff --git a/lib/compiler-cranelift/src/config.rs b/lib/compiler-cranelift/src/config.rs index b9b0b5385..c57339729 100644 --- a/lib/compiler-cranelift/src/config.rs +++ b/lib/compiler-cranelift/src/config.rs @@ -41,12 +41,14 @@ pub struct CraneliftConfig { /// The verifier assures that the generated Cranelift IR is valid. pub enable_verifier: bool, + /// Should we enable simd support? + pub enable_simd: bool, + enable_pic: bool, /// The optimization levels when optimizing the IR. pub opt_level: OptLevel, - features: Features, target: Target, /// The middleware chain. @@ -56,13 +58,13 @@ pub struct CraneliftConfig { impl CraneliftConfig { /// Creates a new configuration object with the default configuration /// specified. - pub fn new(features: Features, target: Target) -> Self { + pub fn new(target: Target) -> Self { Self { enable_nan_canonicalization: false, enable_verifier: false, opt_level: OptLevel::Speed, enable_pic: false, - features, + enable_simd: false, target, middlewares: vec![], } @@ -148,7 +150,7 @@ impl CraneliftConfig { .set("enable_verifier", enable_verifier) .expect("should be valid flag"); - let opt_level = if self.features.simd { + let opt_level = if self.enable_simd { "none" } else { match self.opt_level { @@ -162,7 +164,7 @@ impl CraneliftConfig { .set("opt_level", opt_level) .expect("should be valid flag"); - let enable_simd = if self.features.simd { "true" } else { "false" }; + let enable_simd = if self.enable_simd { "true" } else { "false" }; flags .set("enable_simd", enable_simd) .expect("should be valid flag"); @@ -181,11 +183,6 @@ impl CraneliftConfig { } impl CompilerConfig for CraneliftConfig { - /// Gets the WebAssembly features - fn features(&self) -> &Features { - &self.features - } - fn enable_pic(&mut self) { self.enable_pic = true; } @@ -209,6 +206,6 @@ impl CompilerConfig for CraneliftConfig { impl Default for CraneliftConfig { fn default() -> Self { - Self::new(Default::default(), Default::default()) + Self::new(Default::default()) } } diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index 8b51f0a9d..bcc27d034 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -3,13 +3,11 @@ use crate::trampoline::FuncTrampoline; use crate::translator::FuncTranslator; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use wasm_common::entity::{EntityRef, PrimaryMap, SecondaryMap}; -use wasm_common::Features; -use wasm_common::{LocalFunctionIndex, MemoryIndex, TableIndex}; +use wasm_common::LocalFunctionIndex; use wasmer_compiler::{ - Compilation, CompileError, Compiler, CompilerConfig, FunctionBodyData, ModuleTranslationState, - RelocationTarget, SectionIndex, Target, + Compilation, CompileError, CompileModuleInfo, Compiler, CompilerConfig, FunctionBodyData, + ModuleTranslationState, RelocationTarget, SectionIndex, Target, }; -use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan}; //use std::sync::{Arc, Mutex}; @@ -27,18 +25,13 @@ impl LLVMCompiler { } } - /// Gets the WebAssembly features for this Compiler + /// Gets the config for this Compiler fn config(&self) -> &LLVMConfig { &self.config } } impl Compiler for LLVMCompiler { - /// Gets the WebAssembly features for this Compiler - fn features(&self) -> &Features { - self.config.features() - } - /// Gets the target associated to this Compiler. fn target(&self) -> &Target { self.config.target() @@ -48,14 +41,15 @@ impl Compiler for LLVMCompiler { /// associated relocations. fn compile_module<'data, 'module>( &self, - module: &'module ModuleInfo, + compile_info: &'module CompileModuleInfo, module_translation: &ModuleTranslationState, function_body_inputs: PrimaryMap>, - memory_plans: PrimaryMap, - table_plans: PrimaryMap, ) -> Result { //let data = Arc::new(Mutex::new(0)); let mut func_names = SecondaryMap::new(); + let memory_plans = &compile_info.memory_plans; + let table_plans = &compile_info.table_plans; + let module = &compile_info.module; // TODO: merge constants in sections. @@ -75,7 +69,7 @@ impl Compiler for LLVMCompiler { // TODO: remove (to serialize) //let mut data = data.lock().unwrap(); func_translator.translate( - module, + &module, module_translation, i, input, diff --git a/lib/compiler-llvm/src/config.rs b/lib/compiler-llvm/src/config.rs index 642e4a9fd..fff8fe6f1 100644 --- a/lib/compiler-llvm/src/config.rs +++ b/lib/compiler-llvm/src/config.rs @@ -8,9 +8,7 @@ use itertools::Itertools; use std::sync::Arc; use target_lexicon::Architecture; use wasm_common::{FunctionType, LocalFunctionIndex}; -use wasmer_compiler::{ - Compiler, CompilerConfig, Features, FunctionMiddlewareGenerator, Target, Triple, -}; +use wasmer_compiler::{Compiler, CompilerConfig, FunctionMiddlewareGenerator, Target, Triple}; /// The InkWell ModuleInfo type pub type InkwellModule<'ctx> = inkwell::module::Module<'ctx>; @@ -66,25 +64,24 @@ pub struct LLVMConfig { /// The middleware chain. pub(crate) middlewares: Vec>, - features: Features, target: Target, } impl LLVMConfig { /// Creates a new configuration object with the default configuration /// specified. - pub fn new(features: Features, target: Target) -> Self { + pub fn new(target: Target) -> Self { Self { enable_nan_canonicalization: true, enable_verifier: false, opt_level: OptimizationLevel::Aggressive, is_pic: false, - features, target, callbacks: None, middlewares: vec![], } } + fn reloc_mode(&self) -> RelocMode { if self.is_pic { RelocMode::PIC @@ -171,11 +168,6 @@ impl LLVMConfig { } impl CompilerConfig for LLVMConfig { - /// Gets the WebAssembly features. - fn features(&self) -> &Features { - &self.features - } - /// Emit code suitable for dlopen. fn enable_pic(&mut self) { // TODO: although we can emit PIC, the object file parser does not yet @@ -202,6 +194,6 @@ impl CompilerConfig for LLVMConfig { impl Default for LLVMConfig { fn default() -> LLVMConfig { - Self::new(Default::default(), Default::default()) + Self::new(Default::default()) } } diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index c06f42584..e8abb73b3 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -10,18 +10,17 @@ use crate::config::SinglepassConfig; use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; use std::sync::Arc; use wasm_common::entity::{EntityRef, PrimaryMap}; -use wasm_common::Features; use wasm_common::{FunctionIndex, FunctionType, LocalFunctionIndex, MemoryIndex, TableIndex}; use wasmer_compiler::wasmparser::BinaryReaderError; use wasmer_compiler::TrapInformation; use wasmer_compiler::{Compilation, CompileError, CompiledFunction, Compiler, SectionIndex}; use wasmer_compiler::{ - CompilerConfig, GenerateMiddlewareChain, MiddlewareBinaryReader, ModuleTranslationState, Target, + CompileModuleInfo, CompilerConfig, GenerateMiddlewareChain, MiddlewareBinaryReader, + ModuleTranslationState, Target, }; use wasmer_compiler::{FunctionBody, FunctionBodyData}; use wasmer_runtime::ModuleInfo; use wasmer_runtime::TrapCode; -use wasmer_runtime::{MemoryPlan, TablePlan, VMOffsets}; /// A compiler that compiles a WebAssembly module with Singlepass. /// It does the compilation in one pass @@ -37,18 +36,13 @@ impl SinglepassCompiler { } } - /// Gets the WebAssembly features for this Compiler + /// Gets the config for this Compiler fn config(&self) -> &SinglepassConfig { &self.config } } impl Compiler for SinglepassCompiler { - /// Gets the WebAssembly features for this Compiler - fn features(&self) -> &Features { - self.config.features() - } - /// Gets the target associated to this Compiler. fn target(&self) -> &Target { self.config.target() @@ -58,13 +52,17 @@ impl Compiler for SinglepassCompiler { /// associated relocations. fn compile_module( &self, - module: &ModuleInfo, + compile_info: &CompileModuleInfo, _module_translation: &ModuleTranslationState, function_body_inputs: PrimaryMap>, - memory_plans: PrimaryMap, - table_plans: PrimaryMap, ) -> Result { + if compile_info.features.multi_value { + return Err(CompileError::UnsupportedFeature("multivalue")); + } let vmoffsets = VMOffsets::new(8, module); + let memory_plans = compile_info.memory_plans; + let table_plans = compile_info.table_plans; + let module = compile_info.module; let import_trampolines: PrimaryMap = (0..module.num_imported_funcs) .map(FunctionIndex::new) .collect::>() diff --git a/lib/compiler-singlepass/src/config.rs b/lib/compiler-singlepass/src/config.rs index 9905eb607..c2432f8ed 100644 --- a/lib/compiler-singlepass/src/config.rs +++ b/lib/compiler-singlepass/src/config.rs @@ -4,7 +4,7 @@ use crate::compiler::SinglepassCompiler; use std::sync::Arc; use wasmer_compiler::{ - Compiler, CompilerConfig, CpuFeature, Features, FunctionMiddlewareGenerator, Target, + Compiler, CompilerConfig, CpuFeature, FunctionMiddlewareGenerator, Target, }; #[derive(Clone)] @@ -24,7 +24,6 @@ pub struct SinglepassConfig { /// different platforms. pub enable_stack_check: bool, - features: Features, target: Target, /// The middleware chain. @@ -34,14 +33,10 @@ pub struct SinglepassConfig { impl SinglepassConfig { /// Creates a new configuration object with the default configuration /// specified. - pub fn new(mut features: Features, target: Target) -> Self { - // Override the default multi-value switch - features.multi_value = false; - + pub fn new(target: Target) -> Self { Self { enable_nan_canonicalization: true, enable_stack_check: false, - features, target, middlewares: vec![], } @@ -49,11 +44,6 @@ impl SinglepassConfig { } impl CompilerConfig for SinglepassConfig { - /// Gets the WebAssembly features - fn features(&self) -> &Features { - &self.features - } - fn enable_pic(&mut self) { // Do nothing, since singlepass already emits // PIC code. diff --git a/lib/compiler/src/compiler.rs b/lib/compiler/src/compiler.rs index 6ea56a509..eb5deb862 100644 --- a/lib/compiler/src/compiler.rs +++ b/lib/compiler/src/compiler.rs @@ -5,6 +5,7 @@ use crate::error::CompileError; use crate::function::Compilation; use crate::lib::std::boxed::Box; use crate::lib::std::sync::Arc; +use crate::module::CompileModuleInfo; use crate::target::Target; use crate::translator::FunctionMiddlewareGenerator; use crate::FunctionBodyData; @@ -20,9 +21,6 @@ use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig}; /// This options must have WebAssembly `Features` and a specific /// `Target` to compile to. pub trait CompilerConfig { - /// Gets the WebAssembly features - fn features(&self) -> &Features; - /// Should Position Independent Code (PIC) be enabled. /// /// This is required for shared object generation (Native Engine), @@ -46,14 +44,14 @@ pub trait Compiler { /// Gets the target associated with this compiler fn target(&self) -> &Target; - /// Gets the WebAssembly features for this Compiler - fn features(&self) -> &Features; - /// Validates a module. /// /// It returns the a succesful Result in case is valid, `CompileError` in case is not. - fn validate_module<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> { - let features = self.features(); + fn validate_module<'data>( + &self, + features: &Features, + data: &'data [u8], + ) -> Result<(), CompileError> { let config = ValidatingParserConfig { operator_config: OperatorValidatorConfig { enable_threads: features.threads, @@ -72,13 +70,9 @@ pub trait Compiler { /// It returns the [`Compilation`] or a [`CompileError`]. fn compile_module<'data, 'module>( &self, - module: &'module ModuleInfo, + module: &'module CompileModuleInfo, module_translation: &ModuleTranslationState, // The list of function bodies function_body_inputs: PrimaryMap>, - // The plans for the module memories (imported and local) - memory_plans: PrimaryMap, - // The plans for the module tables (imported and local) - table_plans: PrimaryMap, ) -> Result; } diff --git a/lib/compiler/src/error.rs b/lib/compiler/src/error.rs index 236c40530..f95676464 100644 --- a/lib/compiler/src/error.rs +++ b/lib/compiler/src/error.rs @@ -23,6 +23,10 @@ pub enum CompileError { #[error("Validation error: {0}")] Validate(String), + /// The compiler doesn't support a Wasm feature + #[error("Feature {0} is not yet supported")] + UnsupportedFeature(String), + /// Insufficient resources available for execution. #[error("Insufficient resources: {0}")] Resource(String), diff --git a/lib/compiler/src/lib.rs b/lib/compiler/src/lib.rs index c5ce3580e..2cbbfc3a4 100644 --- a/lib/compiler/src/lib.rs +++ b/lib/compiler/src/lib.rs @@ -57,6 +57,7 @@ mod compiler; mod error; mod function; mod jump_table; +mod module; mod relocation; mod target; mod trap; @@ -76,6 +77,7 @@ pub use crate::function::{ Functions, }; pub use crate::jump_table::{JumpTable, JumpTableOffsets}; +pub use crate::module::CompileModuleInfo; pub use crate::relocation::{Relocation, RelocationKind, RelocationTarget, Relocations}; pub use crate::section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex}; pub use crate::sourceloc::SourceLoc; diff --git a/lib/compiler/src/module.rs b/lib/compiler/src/module.rs new file mode 100644 index 000000000..688a6fae6 --- /dev/null +++ b/lib/compiler/src/module.rs @@ -0,0 +1,27 @@ +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; +use std::sync::Arc; +use wasm_common::entity::PrimaryMap; +use wasm_common::{Features, MemoryIndex, TableIndex}; +use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan}; + +/// The required info for compiling a module. +/// +/// This differs from [`ModuleInfo`] because it have extra info only +/// possible after translation (such as the features used for compiling, +/// or the `MemoryPlan` and `TablePlan`). +#[derive(Debug)] +#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))] +pub struct CompileModuleInfo { + /// The features used for compiling the module + pub features: Features, + /// The module information + pub module: Arc, + /// The memory plans used for compiling. + /// + /// The compiler will emit the most optimal code based + /// on the memory style (static or dynamic) chosen. + pub memory_plans: PrimaryMap, + /// The table plans used for compiling. + pub table_plans: PrimaryMap, +} diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index f2d4bfdc8..2aa346830 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -13,9 +13,9 @@ use wasm_common::{ FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex, }; -#[cfg(feature = "compiler")] -use wasmer_compiler::ModuleEnvironment; use wasmer_compiler::{CompileError, Features, Triple}; +#[cfg(feature = "compiler")] +use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment}; use wasmer_engine::{ register_frame_info, Artifact, DeserializeError, GlobalFrameInfoRegistration, SerializeError, }; @@ -47,6 +47,7 @@ impl JITArtifact { let environ = ModuleEnvironment::new(); let mut inner_jit = jit.inner_mut(); let tunables = jit.tunables(); + let features = inner_jit.features(); let translation = environ.translate(data).map_err(CompileError::Wasm)?; @@ -63,15 +64,20 @@ impl JITArtifact { .map(|table_type| tunables.table_plan(*table_type)) .collect(); + let compile_info = CompileModuleInfo { + module: Arc::new(translation.module), + features: features.clone(), + memory_plans, + table_plans, + }; + let compiler = inner_jit.compiler()?; // Compile the Module let compilation = compiler.compile_module( - &translation.module, + &compile_info, translation.module_translation.as_ref().unwrap(), translation.function_body_inputs, - memory_plans.clone(), - table_plans.clone(), )?; let function_call_trampolines = compilation.get_function_call_trampolines(); let dynamic_function_trampolines = compilation.get_dynamic_function_trampolines(); @@ -102,11 +108,8 @@ impl JITArtifact { }; let serializable = SerializableModule { compilation: serializable_compilation, - module: Arc::new(translation.module), - features: inner_jit.compiler()?.features().clone(), + compile_info, data_initializers, - memory_plans, - table_plans, }; Self::from_parts(&mut inner_jit, serializable) } @@ -150,7 +153,7 @@ impl JITArtifact { finished_dynamic_function_trampolines, ) = inner_jit.allocate( &mut unwind_registry, - &serializable.module, + &serializable.compile_info.module, &serializable.compilation.function_bodies, &serializable.compilation.function_call_trampolines, &serializable.compilation.dynamic_function_trampolines, @@ -159,7 +162,7 @@ impl JITArtifact { inner_jit.allocate_custom_sections(&serializable.compilation.custom_sections)?; link_module( - &serializable.module, + &serializable.compile_info.module, &finished_functions, &serializable.compilation.function_jt_offsets, serializable.compilation.function_relocations.clone(), @@ -171,6 +174,7 @@ impl JITArtifact { let signatures = { let signature_registry = inner_jit.signatures(); serializable + .compile_info .module .signatures .values() @@ -227,15 +231,15 @@ impl JITArtifact { impl Artifact for JITArtifact { fn module(&self) -> Arc { - self.serializable.module.clone() + self.serializable.compile_info.module.clone() } fn module_ref(&self) -> &ModuleInfo { - &self.serializable.module + &self.serializable.compile_info.module } fn module_mut(&mut self) -> Option<&mut ModuleInfo> { - Arc::get_mut(&mut self.serializable.module) + Arc::get_mut(&mut self.serializable.compile_info.module) } fn register_frame_info(&self) { @@ -248,14 +252,14 @@ impl Artifact for JITArtifact { let frame_infos = &self.serializable.compilation.function_frame_info; let finished_functions = &self.finished_functions; *info = register_frame_info( - self.serializable.module.clone(), + self.serializable.compile_info.module.clone(), finished_functions, frame_infos.clone(), ); } fn features(&self) -> &Features { - &self.serializable.features + &self.serializable.compile_info.features } fn data_initializers(&self) -> &[OwnedDataInitializer] { @@ -263,11 +267,11 @@ impl Artifact for JITArtifact { } fn memory_plans(&self) -> &PrimaryMap { - &self.serializable.memory_plans + &self.serializable.compile_info.memory_plans } fn table_plans(&self) -> &PrimaryMap { - &self.serializable.table_plans + &self.serializable.compile_info.table_plans } fn finished_functions(&self) -> &BoxedSlice { diff --git a/lib/engine-jit/src/engine.rs b/lib/engine-jit/src/engine.rs index db2094960..afe577f38 100644 --- a/lib/engine-jit/src/engine.rs +++ b/lib/engine-jit/src/engine.rs @@ -5,6 +5,7 @@ use crate::{CodeMemory, JITArtifact}; use std::collections::HashMap; use std::sync::{Arc, Mutex}; use wasm_common::entity::PrimaryMap; +use wasm_common::Features; use wasm_common::{FunctionIndex, FunctionType, LocalFunctionIndex, SignatureIndex}; use wasmer_compiler::{ CompileError, CustomSection, CustomSectionProtection, FunctionBody, SectionIndex, @@ -30,6 +31,7 @@ impl JITEngine { pub fn new( config: Box, tunables: impl Tunables + 'static + Send + Sync, + features: Features, ) -> Self { let compiler = config.compiler(); Self { @@ -38,6 +40,7 @@ impl JITEngine { function_call_trampolines: HashMap::new(), code_memory: CodeMemory::new(), signatures: SignatureRegistry::new(), + features, })), tunables: Arc::new(tunables), engine_id: EngineId::default(), @@ -65,6 +68,7 @@ impl JITEngine { function_call_trampolines: HashMap::new(), code_memory: CodeMemory::new(), signatures: SignatureRegistry::new(), + features: Features::default(), })), tunables: Arc::new(tunables), engine_id: EngineId::default(), @@ -130,6 +134,8 @@ pub struct JITEngineInner { compiler: Option>, /// Pointers to trampoline functions used to enter particular signatures function_call_trampolines: HashMap, + /// The features to compile the Wasm module with + features: Features, /// The code memory is responsible of publishing the compiled /// functions to memory. code_memory: CodeMemory, @@ -151,7 +157,7 @@ impl JITEngineInner { /// Validate the module #[cfg(feature = "compiler")] pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> { - self.compiler()?.validate_module(data) + self.compiler()?.validate_module(self.features(), data) } /// Validate the module @@ -163,6 +169,11 @@ impl JITEngineInner { )) } + /// The Wasm featuress + pub fn features(&self) -> &Features { + &self.features + } + /// Allocate custom sections into memory pub(crate) fn allocate_custom_sections( &mut self, diff --git a/lib/engine-jit/src/serialize.rs b/lib/engine-jit/src/serialize.rs index c6d527d88..1aca0a01d 100644 --- a/lib/engine-jit/src/serialize.rs +++ b/lib/engine-jit/src/serialize.rs @@ -6,7 +6,8 @@ use wasm_common::{ TableIndex, }; use wasmer_compiler::{ - CustomSection, Dwarf, FunctionBody, JumpTableOffsets, Relocation, SectionIndex, + CompileModuleInfo, CustomSection, Dwarf, FunctionBody, JumpTableOffsets, Relocation, + SectionIndex, }; use wasmer_engine::SerializableFunctionFrameInfo; use wasmer_runtime::ModuleInfo; @@ -45,10 +46,6 @@ pub struct SerializableCompilation { #[derive(Serialize, Deserialize)] pub struct SerializableModule { pub compilation: SerializableCompilation, - pub features: Features, - pub module: Arc, + pub compile_info: CompileModuleInfo, pub data_initializers: Box<[OwnedDataInitializer]>, - // Plans for that module - pub memory_plans: PrimaryMap, - pub table_plans: PrimaryMap, } diff --git a/lib/engine-native/src/artifact.rs b/lib/engine-native/src/artifact.rs index 0b6f3238a..6e831ca4f 100644 --- a/lib/engine-native/src/artifact.rs +++ b/lib/engine-native/src/artifact.rs @@ -28,7 +28,7 @@ use wasmer_compiler::{ Architecture, BinaryFormat, CustomSectionProtection, Endianness, ModuleEnvironment, OperatingSystem, RelocationTarget, Triple, }; -use wasmer_compiler::{CompileError, Features}; +use wasmer_compiler::{CompileError, CompileModuleInfo, Features}; #[cfg(feature = "compiler")] use wasmer_engine::Engine; use wasmer_engine::{ @@ -101,7 +101,7 @@ impl NativeArtifact { let tunables = engine.tunables(); let translation = environ.translate(data).map_err(CompileError::Wasm)?; - + let features = engine_inner.features(); let memory_plans: PrimaryMap = translation .module .memories @@ -115,14 +115,19 @@ impl NativeArtifact { .map(|table_type| tunables.table_plan(*table_type)) .collect(); + let compile_info = CompileModuleInfo { + module: Arc::new(translation.module), + features: features.clone(), + memory_plans, + table_plans, + }; + let compiler = engine_inner.compiler()?; // Compile the Module let compilation = compiler.compile_module( - &translation.module, + &compile_info, translation.module_translation.as_ref().unwrap(), translation.function_body_inputs, - memory_plans.clone(), - table_plans.clone(), )?; let function_call_trampolines = compilation.get_function_call_trampolines(); let dynamic_function_trampolines = compilation.get_dynamic_function_trampolines(); @@ -180,13 +185,10 @@ impl NativeArtifact { .collect::>(); let metadata = ModuleMetadata { - features: compiler.features().clone(), - module: Arc::new(translation.module), + compile_info, prefix: engine_inner.get_prefix(&data), data_initializers, function_body_lengths, - memory_plans, - table_plans, }; let serialized_data = bincode::serialize(&metadata).map_err(to_compile_error)?; @@ -530,7 +532,7 @@ impl NativeArtifact { } // Retrieve function call trampolines (for all signatures in the module) - for (sig_index, func_type) in metadata.module.signatures.iter() { + for (sig_index, func_type) in metadata.compile_info.module.signatures.iter() { let function_name = metadata.get_function_call_trampoline_name(sig_index); unsafe { let trampoline: LibrarySymbol = lib @@ -544,12 +546,13 @@ impl NativeArtifact { let mut finished_dynamic_function_trampolines: PrimaryMap< FunctionIndex, *mut [VMFunctionBody], - > = PrimaryMap::with_capacity(metadata.module.num_imported_funcs); + > = PrimaryMap::with_capacity(metadata.compile_info.module.num_imported_funcs); for func_index in metadata + .compile_info .module .functions .keys() - .take(metadata.module.num_imported_funcs) + .take(metadata.compile_info.module.num_imported_funcs) { let function_name = metadata.get_dynamic_function_trampoline_name(func_index); unsafe { @@ -582,6 +585,7 @@ impl NativeArtifact { let signatures = { let signature_registry = engine_inner.signatures(); metadata + .compile_info .module .signatures .values() @@ -697,15 +701,15 @@ impl NativeArtifact { impl Artifact for NativeArtifact { fn module(&self) -> Arc { - self.metadata.module.clone() + self.metadata.compile_info.module.clone() } fn module_ref(&self) -> &ModuleInfo { - &self.metadata.module + &self.metadata.compile_info.module } fn module_mut(&mut self) -> Option<&mut ModuleInfo> { - Arc::get_mut(&mut self.metadata.module) + Arc::get_mut(&mut self.metadata.compile_info.module) } fn register_frame_info(&self) { @@ -713,7 +717,7 @@ impl Artifact for NativeArtifact { } fn features(&self) -> &Features { - &self.metadata.features + &self.metadata.compile_info.features } fn data_initializers(&self) -> &[OwnedDataInitializer] { @@ -721,11 +725,11 @@ impl Artifact for NativeArtifact { } fn memory_plans(&self) -> &PrimaryMap { - &self.metadata.memory_plans + &self.metadata.compile_info.memory_plans } fn table_plans(&self) -> &PrimaryMap { - &self.metadata.table_plans + &self.metadata.compile_info.table_plans } fn finished_functions(&self) -> &BoxedSlice { diff --git a/lib/engine-native/src/engine.rs b/lib/engine-native/src/engine.rs index b1052aa0d..3d470dadf 100644 --- a/lib/engine-native/src/engine.rs +++ b/lib/engine-native/src/engine.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use std::path::Path; use std::sync::Arc; use std::sync::Mutex; -use wasm_common::FunctionType; +use wasm_common::{Features, FunctionType}; use wasmer_compiler::CompileError; #[cfg(feature = "compiler")] use wasmer_compiler::{Compiler, CompilerConfig}; @@ -26,6 +26,7 @@ impl NativeEngine { pub fn new( mut config: Box, tunables: impl Tunables + 'static + Send + Sync, + features: Features, ) -> Self { config.enable_pic(); let compiler = config.compiler(); @@ -35,6 +36,7 @@ impl NativeEngine { trampolines: HashMap::new(), signatures: SignatureRegistry::new(), prefixer: None, + features, })), tunables: Arc::new(tunables), engine_id: EngineId::default(), @@ -62,6 +64,7 @@ impl NativeEngine { trampolines: HashMap::new(), signatures: SignatureRegistry::new(), prefixer: None, + features: Features::default(), })), tunables: Arc::new(tunables), engine_id: EngineId::default(), @@ -154,6 +157,8 @@ pub struct NativeEngineInner { /// The compiler #[cfg(feature = "compiler")] compiler: Option>, + /// The WebAssembly features to use + features: Features, /// Pointers to trampoline functions used to enter particular signatures trampolines: HashMap, /// The signature registry is used mainly to operate with trampolines @@ -186,10 +191,14 @@ impl NativeEngineInner { } } + pub(crate) fn features(&self) -> &Features { + &self.features + } + /// Validate the module #[cfg(feature = "compiler")] pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> { - self.compiler()?.validate_module(data) + self.compiler()?.validate_module(self.features(), data) } /// Validate the module diff --git a/lib/engine-native/src/serialize.rs b/lib/engine-native/src/serialize.rs index a0dd3561f..c9dffa2ab 100644 --- a/lib/engine-native/src/serialize.rs +++ b/lib/engine-native/src/serialize.rs @@ -5,22 +5,18 @@ use wasm_common::{ Features, FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex, }; -use wasmer_compiler::SectionIndex; +use wasmer_compiler::{CompileModuleInfo, SectionIndex}; use wasmer_runtime::ModuleInfo; use wasmer_runtime::{MemoryPlan, TablePlan}; /// Serializable struct that represents the compiled metadata. #[derive(Serialize, Deserialize, Debug)] pub struct ModuleMetadata { - pub features: Features, - pub module: Arc, + pub compile_info: CompileModuleInfo, pub prefix: String, pub data_initializers: Box<[OwnedDataInitializer]>, // The function body lengths (used for reverse-locate traps in the function) pub function_body_lengths: PrimaryMap, - // Plans for that module - pub memory_plans: PrimaryMap, - pub table_plans: PrimaryMap, } impl ModuleMetadata { diff --git a/src/store.rs b/src/store.rs index b70747156..aa26722f8 100644 --- a/src/store.rs +++ b/src/store.rs @@ -179,17 +179,16 @@ impl StoreOptions { target: Target, ) -> Result<(Box, CompilerType)> { let compiler = self.get_compiler()?; - let features = self.get_features()?; let compiler_config: Box = match compiler { CompilerType::Headless => bail!("The headless engine can't be chosen"), #[cfg(feature = "singlepass")] CompilerType::Singlepass => { - let config = wasmer_compiler_singlepass::SinglepassConfig::new(features, target); + let config = wasmer_compiler_singlepass::SinglepassConfig::new(target); Box::new(config) } #[cfg(feature = "cranelift")] CompilerType::Cranelift => { - let config = wasmer_compiler_cranelift::CraneliftConfig::new(features, target); + let config = wasmer_compiler_cranelift::CraneliftConfig::new(target); Box::new(config) } #[cfg(feature = "llvm")] @@ -201,7 +200,7 @@ impl StoreOptions { CompiledFunctionKind, InkwellMemoryBuffer, InkwellModule, LLVMCallbacks, LLVMConfig, }; - let mut config = LLVMConfig::new(features, target); + let mut config = LLVMConfig::new(target); struct Callbacks { debug_dir: PathBuf, } @@ -320,15 +319,19 @@ impl StoreOptions { compiler_config: Box, ) -> Result<(Arc, EngineType)> { let engine_type = self.get_engine()?; + let features = self.get_features()?; let engine: Arc = match engine_type { #[cfg(feature = "jit")] - EngineType::JIT => { - Arc::new(wasmer_engine_jit::JITEngine::new(compiler_config, tunables)) - } + EngineType::JIT => Arc::new(wasmer_engine_jit::JITEngine::new( + compiler_config, + tunables, + features, + )), #[cfg(feature = "native")] EngineType::Native => Arc::new(wasmer_engine_native::NativeEngine::new( compiler_config, tunables, + features, )), #[cfg(not(all(feature = "jit", feature = "native",)))] engine => bail!( diff --git a/tests/compilers/utils.rs b/tests/compilers/utils.rs index c187158ce..6ffa5bf87 100644 --- a/tests/compilers/utils.rs +++ b/tests/compilers/utils.rs @@ -26,9 +26,13 @@ pub fn get_store() -> Store { let features = Features::default(); let try_nan_canonicalization = false; let compiler_config = - get_compiler_config_from_str(get_compiler_str(), try_nan_canonicalization, features); + get_compiler_config_from_str(get_compiler_str(), try_nan_canonicalization); let tunables = Tunables::for_target(compiler_config.target().triple()); - let store = Store::new(Arc::new(JITEngine::new(compiler_config, tunables))); + let store = Store::new(Arc::new(JITEngine::new( + compiler_config, + tunables, + features, + ))); store } @@ -38,12 +42,16 @@ pub fn get_store_with_middlewares Box { // We use the current host target for testing locally let target = Target::default(); @@ -16,21 +15,20 @@ pub fn get_compiler_config_from_str( match compiler_name { #[cfg(feature = "singlepass")] "singlepass" => { - let mut singlepass_config = - wasmer_compiler_singlepass::SinglepassConfig::new(features, target); + // Singlepass.canonicalize_nans(true).compiler() + let mut singlepass_config = wasmer_compiler_singlepass::SinglepassConfig::new(target); singlepass_config.enable_nan_canonicalization = try_nan_canonicalization; Box::new(singlepass_config) } #[cfg(feature = "cranelift")] "cranelift" => { - let mut cranelift_config = - wasmer_compiler_cranelift::CraneliftConfig::new(features, target); + let mut cranelift_config = wasmer_compiler_cranelift::CraneliftConfig::new(target); cranelift_config.enable_nan_canonicalization = try_nan_canonicalization; Box::new(cranelift_config) } #[cfg(feature = "llvm")] "llvm" => { - let mut llvm_config = wasmer_compiler_llvm::LLVMConfig::new(features, target); + let mut llvm_config = wasmer_compiler_llvm::LLVMConfig::new(target); llvm_config.enable_nan_canonicalization = try_nan_canonicalization; Box::new(llvm_config) } @@ -40,28 +38,44 @@ pub fn get_compiler_config_from_str( /// for when you need a store but you don't care about the details pub fn get_default_store() -> Store { - let compiler_config = get_compiler_config_from_str("cranelift", false, Features::default()); + let compiler_config = get_compiler_config_from_str("cranelift", false); let tunables = Tunables::for_target(compiler_config.target().triple()); - Store::new(Arc::new(JITEngine::new(compiler_config, tunables))) + Store::new(Arc::new(JITEngine::new( + compiler_config, + tunables, + Features::default(), + ))) } #[cfg(feature = "llvm")] pub fn get_default_llvm_store() -> Store { - let compiler_config = get_compiler_config_from_str("llvm", false, Features::default()); + let compiler_config = get_compiler_config_from_str("llvm", false); let tunables = Tunables::for_target(compiler_config.target().triple()); - Store::new(Arc::new(JITEngine::new(compiler_config, tunables))) + Store::new(Arc::new(JITEngine::new( + compiler_config, + tunables, + Features::default(), + ))) } #[cfg(feature = "cranelift")] pub fn get_default_cranelift_store() -> Store { - let compiler_config = get_compiler_config_from_str("cranelift", false, Features::default()); + let compiler_config = get_compiler_config_from_str("cranelift", false); let tunables = Tunables::for_target(compiler_config.target().triple()); - Store::new(Arc::new(JITEngine::new(compiler_config, tunables))) + Store::new(Arc::new(JITEngine::new( + compiler_config, + tunables, + Features::default(), + ))) } #[cfg(feature = "singlepass")] pub fn get_default_singlepass_store() -> Store { - let compiler_config = get_compiler_config_from_str("singlepass", false, Features::default()); + let compiler_config = get_compiler_config_from_str("singlepass", false); let tunables = Tunables::for_target(compiler_config.target().triple()); - Store::new(Arc::new(JITEngine::new(compiler_config, tunables))) + Store::new(Arc::new(JITEngine::new( + compiler_config, + tunables, + Features::default(), + ))) } diff --git a/tests/wast.rs b/tests/wast.rs index 33eb7c585..ff893a3ba 100644 --- a/tests/wast.rs +++ b/tests/wast.rs @@ -39,10 +39,13 @@ fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { if wast_path.contains("bulk-memory") { features.bulk_memory(true); } - let compiler_config = - get_compiler_config_from_str(compiler, try_nan_canonicalization, features); + let compiler_config = get_compiler_config_from_str(compiler, try_nan_canonicalization); let tunables = Tunables::for_target(compiler_config.target().triple()); - let store = Store::new(Arc::new(JITEngine::new(compiler_config, tunables))); + let store = Store::new(Arc::new(JITEngine::new( + compiler_config, + tunables, + features, + ))); // let mut native = NativeEngine::new(compiler_config, tunables); // native.set_deterministic_prefixer(native_prefixer); // let store = Store::new(Arc::new(native)); From 8649f2eb7978bcc4f758f1b9ab58e5591e24dd4a Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 17 Jun 2020 20:26:50 -0700 Subject: [PATCH 05/59] Remove target from CompilerConfig --- lib/api/src/store.rs | 2 +- lib/api/src/tunables.rs | 14 +++++- lib/compiler-cranelift/src/compiler.rs | 34 ++++--------- lib/compiler-cranelift/src/config.rs | 20 ++------ lib/compiler-llvm/src/compiler.rs | 64 ++++++++++++++---------- lib/compiler-llvm/src/config.rs | 21 ++------ lib/compiler-llvm/src/trampoline/wasm.rs | 14 +++--- lib/compiler-llvm/src/translator/code.rs | 10 ++-- lib/compiler-singlepass/src/config.rs | 4 +- lib/compiler/src/compiler.rs | 11 +--- lib/engine-jit/src/artifact.rs | 1 + lib/engine-native/src/artifact.rs | 4 +- lib/engine/src/tunables.rs | 8 ++- src/store.rs | 20 +++----- tests/compilers/utils.rs | 6 +-- tests/lib/test-utils/src/lib.rs | 21 ++++---- tests/wast.rs | 2 +- 17 files changed, 118 insertions(+), 138 deletions(-) diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index 15b96711d..cbdc2747c 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -54,7 +54,7 @@ impl Default for Store { fn get_engine( config: Box, ) -> Arc { - let tunables = Tunables::for_target(config.target().triple()); + let tunables = Tunables::default(); #[cfg(feature = "jit")] return Arc::new(wasmer_engine_jit::JITEngine::new( diff --git a/lib/api/src/tunables.rs b/lib/api/src/tunables.rs index bb5f79e47..d91457fc7 100644 --- a/lib/api/src/tunables.rs +++ b/lib/api/src/tunables.rs @@ -5,6 +5,7 @@ use more_asserts::assert_ge; use std::cmp::min; use std::sync::Arc; use target_lexicon::{OperatingSystem, PointerWidth, Triple, HOST}; +use wasmer_compiler::Target; use wasmer_engine::Tunables as BaseTunables; use wasmer_runtime::MemoryError; use wasmer_runtime::{Memory, MemoryPlan, MemoryStyle, Table, TablePlan, TableStyle}; @@ -12,6 +13,8 @@ use wasmer_runtime::{Memory, MemoryPlan, MemoryStyle, Table, TablePlan, TableSty /// Tunable parameters for WebAssembly compilation. #[derive(Clone)] pub struct Tunables { + pub target: Target, + /// For static heaps, the size in wasm pages of the heap protected by bounds checking. pub static_memory_bound: Pages, @@ -24,7 +27,8 @@ pub struct Tunables { impl Tunables { /// Get the `Tunables` for a specific Target - pub fn for_target(triple: &Triple) -> Self { + pub fn for_target(target: Target) -> Self { + let triple = target.triple(); let pointer_width: PointerWidth = triple.pointer_width().unwrap(); let (mut static_memory_bound, mut static_memory_offset_guard_size): (Pages, u64) = match pointer_width { @@ -54,11 +58,17 @@ impl Tunables { static_memory_bound, static_memory_offset_guard_size, dynamic_memory_offset_guard_size, + target, } } } impl BaseTunables for Tunables { + /// Get the target for this Tunables + fn target(&self) -> &Target { + &self.target + } + /// 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 @@ -105,6 +115,6 @@ impl BaseTunables for Tunables { impl Default for Tunables { fn default() -> Self { - Self::for_target(&HOST) + Self::for_target(Target::default()) } } diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index 0a8fd89eb..ad6b0abd8 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -33,25 +33,17 @@ use wasmer_compiler::{ /// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR, /// optimizing it and then translating to assembly. pub struct CraneliftCompiler { - isa: Box, config: CraneliftConfig, } impl CraneliftCompiler { /// Creates a new Cranelift compiler pub fn new(config: &CraneliftConfig) -> Self { - let isa = config.isa(); Self { - isa, config: config.clone(), } } - /// Retrieves the starget ISA - fn isa(&self) -> &dyn isa::TargetIsa { - &*self.isa - } - /// Gets the WebAssembly features for this Compiler pub fn config(&self) -> &CraneliftConfig { &self.config @@ -59,20 +51,16 @@ impl CraneliftCompiler { } impl Compiler for CraneliftCompiler { - /// Gets the target associated to the Cranelift ISA. - fn target(&self) -> &Target { - self.config.target() - } - /// Compile the module using Cranelift, producing a compilation result with /// associated relocations. fn compile_module( &self, + target: &Target, compile_info: &CompileModuleInfo, module_translation: &ModuleTranslationState, function_body_inputs: PrimaryMap>, ) -> Result { - let isa = self.isa(); + let isa = self.config().isa(target); let frontend_config = isa.frontend_config(); let memory_plans = &compile_info.memory_plans; let table_plans = &compile_info.table_plans; @@ -87,7 +75,7 @@ impl Compiler for CraneliftCompiler { #[cfg(feature = "unwind")] let dwarf_frametable = { use std::sync::{Arc, Mutex}; - match self.target().triple().default_calling_convention() { + match target.triple().default_calling_convention() { Ok(CallingConvention::SystemV) => { match isa.create_systemv_cie() { Some(cie) => { @@ -139,17 +127,17 @@ impl Compiler for CraneliftCompiler { let mut stackmap_sink = binemit::NullStackmapSink {}; context .compile_and_emit( - isa, + &*isa, &mut code_buf, &mut reloc_sink, &mut trap_sink, &mut stackmap_sink, ) .map_err(|error| { - CompileError::Codegen(pretty_error(&context.func, Some(isa), error)) + CompileError::Codegen(pretty_error(&context.func, Some(&*isa), error)) })?; - let unwind_info = match compiled_function_unwind_info(isa, &context)? { + let unwind_info = match compiled_function_unwind_info(&*isa, &context)? { #[cfg(feature = "unwind")] CraneliftUnwindInfo::FDE(fde) => { if let Some((dwarf_frametable, cie_id)) = &dwarf_frametable { @@ -176,7 +164,7 @@ impl Compiler for CraneliftCompiler { other => other.maybe_into_to_windows_unwind(), }; - let address_map = get_function_address_map(&context, input, code_buf.len(), isa); + let address_map = get_function_address_map(&context, input, code_buf.len(), &*isa); // We transform the Cranelift JumpTable's into compiler JumpTables let func_jt_offsets = transform_jump_table(context.func.jt_offsets); @@ -202,9 +190,7 @@ impl Compiler for CraneliftCompiler { let (custom_sections, dwarf) = { let mut custom_sections = PrimaryMap::new(); let dwarf = if let Some((dwarf_frametable, _cie_id)) = dwarf_frametable { - let mut eh_frame = EhFrame(WriterRelocate::new( - self.target().triple().endianness().ok(), - )); + let mut eh_frame = EhFrame(WriterRelocate::new(target.triple().endianness().ok())); dwarf_frametable .lock() .unwrap() @@ -229,7 +215,7 @@ impl Compiler for CraneliftCompiler { .collect::>() .par_iter() .map_init(FunctionBuilderContext::new, |mut cx, sig| { - make_trampoline_function_call(&*self.isa, &mut cx, sig) + make_trampoline_function_call(&*isa, &mut cx, sig) }) .collect::, CompileError>>()? .into_iter() @@ -243,7 +229,7 @@ impl Compiler for CraneliftCompiler { .collect::>() .par_iter() .map_init(FunctionBuilderContext::new, |mut cx, func_type| { - make_trampoline_dynamic_function(&*self.isa, &offsets, &mut cx, &func_type) + make_trampoline_dynamic_function(&*isa, &offsets, &mut cx, &func_type) }) .collect::, CompileError>>()? .into_iter() diff --git a/lib/compiler-cranelift/src/config.rs b/lib/compiler-cranelift/src/config.rs index c57339729..5dd189450 100644 --- a/lib/compiler-cranelift/src/config.rs +++ b/lib/compiler-cranelift/src/config.rs @@ -49,8 +49,6 @@ pub struct CraneliftConfig { /// The optimization levels when optimizing the IR. pub opt_level: OptLevel, - target: Target, - /// The middleware chain. pub(crate) middlewares: Vec>, } @@ -58,21 +56,19 @@ pub struct CraneliftConfig { impl CraneliftConfig { /// Creates a new configuration object with the default configuration /// specified. - pub fn new(target: Target) -> Self { + pub fn new() -> Self { Self { enable_nan_canonicalization: false, enable_verifier: false, opt_level: OptLevel::Speed, enable_pic: false, enable_simd: false, - target, middlewares: vec![], } } - /// Generates the ISA for the current target - pub fn isa(&self) -> Box { - let target = self.target(); + /// Generates the ISA for the provided target + pub fn isa(&self, target: &Target) -> Box { let mut builder = lookup(target.triple().clone()).expect("construct Cranelift ISA for triple"); // Cpu Features @@ -126,7 +122,7 @@ impl CraneliftConfig { builder.finish(self.flags()) } - /// Generates the flags for the current target + /// Generates the flags for the compiler pub fn flags(&self) -> settings::Flags { let mut flags = settings::builder(); @@ -187,12 +183,6 @@ impl CompilerConfig for CraneliftConfig { self.enable_pic = true; } - /// Gets the target that we will use for compiling - /// the WebAssembly module - fn target(&self) -> &Target { - &self.target - } - /// Transform it into the compiler fn compiler(&self) -> Box { Box::new(CraneliftCompiler::new(&self)) @@ -206,6 +196,6 @@ impl CompilerConfig for CraneliftConfig { impl Default for CraneliftConfig { fn default() -> Self { - Self::new(Default::default()) + Self::new() } } diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index bcc27d034..508a38165 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -5,7 +5,7 @@ use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use wasm_common::entity::{EntityRef, PrimaryMap, SecondaryMap}; use wasm_common::LocalFunctionIndex; use wasmer_compiler::{ - Compilation, CompileError, CompileModuleInfo, Compiler, CompilerConfig, FunctionBodyData, + Compilation, CompileError, CompileModuleInfo, Compiler, FunctionBodyData, ModuleTranslationState, RelocationTarget, SectionIndex, Target, }; @@ -32,15 +32,11 @@ impl LLVMCompiler { } impl Compiler for LLVMCompiler { - /// Gets the target associated to this Compiler. - fn target(&self) -> &Target { - self.config.target() - } - /// Compile the module using LLVM, producing a compilation result with /// associated relocations. fn compile_module<'data, 'module>( &self, + target: &Target, compile_info: &'module CompileModuleInfo, module_translation: &ModuleTranslationState, function_body_inputs: PrimaryMap>, @@ -65,20 +61,26 @@ impl Compiler for LLVMCompiler { .into_iter() .collect::)>>() .par_iter() - .map_init(FuncTranslator::new, |func_translator, (i, input)| { - // TODO: remove (to serialize) - //let mut data = data.lock().unwrap(); - func_translator.translate( - &module, - module_translation, - i, - input, - self.config(), - &memory_plans, - &table_plans, - &func_names, - ) - }) + .map_init( + || { + let target_machine = self.config().target_machine(target); + FuncTranslator::new(target_machine) + }, + |func_translator, (i, input)| { + // TODO: remove (to serialize) + //let mut data = data.lock().unwrap(); + func_translator.translate( + &module, + module_translation, + i, + input, + self.config(), + &memory_plans, + &table_plans, + &func_names, + ) + }, + ) .collect::, CompileError>>()? .into_iter() .map(|(mut compiled_function, function_custom_sections)| { @@ -111,9 +113,13 @@ impl Compiler for LLVMCompiler { .values() .collect::>() .par_iter() - .map_init(FuncTrampoline::new, |func_trampoline, sig| { - func_trampoline.trampoline(sig, self.config()) - }) + .map_init( + || { + let target_machine = self.config().target_machine(target); + FuncTrampoline::new(target_machine) + }, + |func_trampoline, sig| func_trampoline.trampoline(sig, self.config()), + ) .collect::>() .into_iter() .collect::, CompileError>>()?; @@ -122,9 +128,15 @@ impl Compiler for LLVMCompiler { .imported_function_types() .collect::>() .par_iter() - .map_init(FuncTrampoline::new, |func_trampoline, func_type| { - func_trampoline.dynamic_trampoline(&func_type, self.config()) - }) + .map_init( + || { + let target_machine = self.config().target_machine(target); + FuncTrampoline::new(target_machine) + }, + |func_trampoline, func_type| { + func_trampoline.dynamic_trampoline(&func_type, self.config()) + }, + ) .collect::, CompileError>>()? .into_iter() .collect::>(); diff --git a/lib/compiler-llvm/src/config.rs b/lib/compiler-llvm/src/config.rs index fff8fe6f1..705859664 100644 --- a/lib/compiler-llvm/src/config.rs +++ b/lib/compiler-llvm/src/config.rs @@ -63,20 +63,17 @@ pub struct LLVMConfig { /// The middleware chain. pub(crate) middlewares: Vec>, - - target: Target, } impl LLVMConfig { /// Creates a new configuration object with the default configuration /// specified. - pub fn new(target: Target) -> Self { + pub fn new() -> Self { Self { enable_nan_canonicalization: true, enable_verifier: false, opt_level: OptimizationLevel::Aggressive, is_pic: false, - target, callbacks: None, middlewares: vec![], } @@ -94,8 +91,7 @@ impl LLVMConfig { CodeModel::Large } - pub fn target_triple(&self) -> TargetTriple { - let target = self.target(); + fn target_triple(&self, target: &Target) -> TargetTriple { let operating_system = if target.triple().operating_system == wasmer_compiler::OperatingSystem::Darwin { // LLVM detects static relocation + darwin + 64-bit and @@ -119,8 +115,7 @@ impl LLVMConfig { } /// Generates the target machine for the current target - pub fn target_machine(&self) -> TargetMachine { - let target = self.target(); + pub fn target_machine(&self, target: &Target) -> TargetMachine { let triple = target.triple(); let cpu_features = &target.cpu_features(); @@ -152,7 +147,7 @@ impl LLVMConfig { .map(|feature| format!("+{}", feature.to_string())) .join(","); - let target_triple = self.target_triple(); + let target_triple = self.target_triple(&target); let llvm_target = InkwellTarget::from_triple(&target_triple).unwrap(); llvm_target .create_target_machine( @@ -175,12 +170,6 @@ impl CompilerConfig for LLVMConfig { self.is_pic = true; } - /// Gets the target that we will use for compiling. - /// the WebAssembly module - fn target(&self) -> &Target { - &self.target - } - /// Transform it into the compiler. fn compiler(&self) -> Box { Box::new(LLVMCompiler::new(&self)) @@ -194,6 +183,6 @@ impl CompilerConfig for LLVMConfig { impl Default for LLVMConfig { fn default() -> LLVMConfig { - Self::new(Default::default()) + Self::new() } } diff --git a/lib/compiler-llvm/src/trampoline/wasm.rs b/lib/compiler-llvm/src/trampoline/wasm.rs index 2de47e18e..53643aa63 100644 --- a/lib/compiler-llvm/src/trampoline/wasm.rs +++ b/lib/compiler-llvm/src/trampoline/wasm.rs @@ -10,7 +10,7 @@ use inkwell::{ context::Context, module::Linkage, passes::PassManager, - targets::FileType, + targets::{FileType, TargetMachine}, types::BasicType, values::{BasicValue, FunctionValue}, AddressSpace, @@ -22,14 +22,16 @@ use wasmer_compiler::{CompileError, FunctionBody}; pub struct FuncTrampoline { ctx: Context, + target_machine: TargetMachine, } const FUNCTION_SECTION: &str = ".wasmer_trampoline"; impl FuncTrampoline { - pub fn new() -> Self { + pub fn new(target_machine: TargetMachine) -> Self { Self { ctx: Context::create(), + target_machine, } } @@ -41,8 +43,8 @@ impl FuncTrampoline { // The function type, used for the callbacks. let function = CompiledFunctionKind::FunctionCallTrampoline(ty.clone()); let module = self.ctx.create_module(""); - let target_triple = config.target_triple(); - let target_machine = config.target_machine(); + let target_machine = &self.target_machine; + let target_triple = target_machine.get_triple(); module.set_triple(&target_triple); module.set_data_layout(&target_machine.get_target_data().get_data_layout()); let intrinsics = Intrinsics::declare(&module, &self.ctx); @@ -130,8 +132,8 @@ impl FuncTrampoline { // The function type, used for the callbacks let function = CompiledFunctionKind::DynamicFunctionTrampoline(ty.clone()); let module = self.ctx.create_module(""); - let target_triple = config.target_triple(); - let target_machine = config.target_machine(); + let target_machine = &self.target_machine; + let target_triple = target_machine.get_triple(); module.set_triple(&target_triple); module.set_data_layout(&target_machine.get_target_data().get_data_layout()); let intrinsics = Intrinsics::declare(&module, &self.ctx); diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index c401a2d92..e2a0b8058 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -12,7 +12,7 @@ use inkwell::{ context::Context, module::{Linkage, Module}, passes::PassManager, - targets::FileType, + targets::{FileType, TargetMachine}, types::{BasicType, BasicTypeEnum, FloatMathType, IntType, PointerType, VectorType}, values::{ BasicValue, BasicValueEnum, FloatValue, FunctionValue, InstructionOpcode, InstructionValue, @@ -55,12 +55,14 @@ fn const_zero(ty: BasicTypeEnum) -> BasicValueEnum { pub struct FuncTranslator { ctx: Context, + target_machine: TargetMachine, } impl FuncTranslator { - pub fn new() -> Self { + pub fn new(target_machine: TargetMachine) -> Self { Self { ctx: Context::create(), + target_machine, } } @@ -85,8 +87,8 @@ impl FuncTranslator { }; let module = self.ctx.create_module(module_name.as_str()); - let target_triple = config.target_triple(); - let target_machine = config.target_machine(); + let target_machine = &self.target_machine; + let target_triple = target_machine.get_triple(); module.set_triple(&target_triple); module.set_data_layout(&target_machine.get_target_data().get_data_layout()); let wasm_fn_type = wasm_module diff --git a/lib/compiler-singlepass/src/config.rs b/lib/compiler-singlepass/src/config.rs index c2432f8ed..dc8660148 100644 --- a/lib/compiler-singlepass/src/config.rs +++ b/lib/compiler-singlepass/src/config.rs @@ -3,9 +3,7 @@ use crate::compiler::SinglepassCompiler; use std::sync::Arc; -use wasmer_compiler::{ - Compiler, CompilerConfig, CpuFeature, FunctionMiddlewareGenerator, Target, -}; +use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, FunctionMiddlewareGenerator, Target}; #[derive(Clone)] pub struct SinglepassConfig { diff --git a/lib/compiler/src/compiler.rs b/lib/compiler/src/compiler.rs index eb5deb862..13df596a9 100644 --- a/lib/compiler/src/compiler.rs +++ b/lib/compiler/src/compiler.rs @@ -17,9 +17,6 @@ use wasmer_runtime::{MemoryPlan, TablePlan}; use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig}; /// The compiler configuration options. -/// -/// This options must have WebAssembly `Features` and a specific -/// `Target` to compile to. pub trait CompilerConfig { /// Should Position Independent Code (PIC) be enabled. /// @@ -28,10 +25,6 @@ pub trait CompilerConfig { /// supported in the JIT linking phase. fn enable_pic(&mut self); - /// Gets the target that we will use for compiling - /// the WebAssembly module - fn target(&self) -> &Target; - /// Gets the custom compiler config fn compiler(&self) -> Box; @@ -41,9 +34,6 @@ pub trait CompilerConfig { /// An implementation of a Compiler from parsed WebAssembly module to Compiled native code. pub trait Compiler { - /// Gets the target associated with this compiler - fn target(&self) -> &Target; - /// Validates a module. /// /// It returns the a succesful Result in case is valid, `CompileError` in case is not. @@ -70,6 +60,7 @@ pub trait Compiler { /// It returns the [`Compilation`] or a [`CompileError`]. fn compile_module<'data, 'module>( &self, + target: &Target, module: &'module CompileModuleInfo, module_translation: &ModuleTranslationState, // The list of function bodies diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index 2aa346830..a212dc525 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -75,6 +75,7 @@ impl JITArtifact { // Compile the Module let compilation = compiler.compile_module( + &tunables.target(), &compile_info, translation.module_translation.as_ref().unwrap(), translation.function_body_inputs, diff --git a/lib/engine-native/src/artifact.rs b/lib/engine-native/src/artifact.rs index 6e831ca4f..493d8945b 100644 --- a/lib/engine-native/src/artifact.rs +++ b/lib/engine-native/src/artifact.rs @@ -123,8 +123,11 @@ impl NativeArtifact { }; let compiler = engine_inner.compiler()?; + let target = tunables.target(); + // Compile the Module let compilation = compiler.compile_module( + &target, &compile_info, translation.module_translation.as_ref().unwrap(), translation.function_body_inputs, @@ -139,7 +142,6 @@ impl NativeArtifact { .collect::>() .into_boxed_slice(); - let target = compiler.target(); let target_triple = target.triple().clone(); let obj_binary_format = match target_triple.binary_format { diff --git a/lib/engine/src/tunables.rs b/lib/engine/src/tunables.rs index 0f7a25f51..0f3c57670 100644 --- a/lib/engine/src/tunables.rs +++ b/lib/engine/src/tunables.rs @@ -5,16 +5,20 @@ use wasm_common::{ LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, TableIndex, TableType, }; +use wasmer_compiler::Target; use wasmer_runtime::MemoryError; use wasmer_runtime::{Memory, ModuleInfo, Table, VMGlobalDefinition}; use wasmer_runtime::{MemoryPlan, TablePlan}; /// Tunables for an engine pub trait Tunables { - /// Get a `MemoryPlan` for the provided `MemoryType` + /// Get the target for this Tunables + fn target(&self) -> &Target; + + /// Construct a `MemoryPlan` for the provided `MemoryType` fn memory_plan(&self, memory: MemoryType) -> MemoryPlan; - /// Get a `TablePlan` for the provided `TableType` + /// Construct a `TablePlan` for the provided `TableType` fn table_plan(&self, table: TableType) -> TablePlan; /// Create a memory given a memory type diff --git a/src/store.rs b/src/store.rs index aa26722f8..a5e69e6da 100644 --- a/src/store.rs +++ b/src/store.rs @@ -174,21 +174,18 @@ impl StoreOptions { /// Get the Compiler Config for the current options #[allow(unused_variables)] - fn get_compiler_config( - &self, - target: Target, - ) -> Result<(Box, CompilerType)> { + fn get_compiler_config(&self) -> Result<(Box, CompilerType)> { let compiler = self.get_compiler()?; let compiler_config: Box = match compiler { CompilerType::Headless => bail!("The headless engine can't be chosen"), #[cfg(feature = "singlepass")] CompilerType::Singlepass => { - let config = wasmer_compiler_singlepass::SinglepassConfig::new(target); + let config = wasmer_compiler_singlepass::SinglepassConfig::new(); Box::new(config) } #[cfg(feature = "cranelift")] CompilerType::Cranelift => { - let config = wasmer_compiler_cranelift::CraneliftConfig::new(target); + let config = wasmer_compiler_cranelift::CraneliftConfig::new(); Box::new(config) } #[cfg(feature = "llvm")] @@ -200,7 +197,7 @@ impl StoreOptions { CompiledFunctionKind, InkwellMemoryBuffer, InkwellModule, LLVMCallbacks, LLVMConfig, }; - let mut config = LLVMConfig::new(target); + let mut config = LLVMConfig::new(); struct Callbacks { debug_dir: PathBuf, } @@ -290,11 +287,6 @@ impl StoreOptions { Ok((compiler_config, compiler)) } - /// Gets the tunables for the compiler target - pub fn get_tunables(&self, compiler_config: &dyn CompilerConfig) -> Tunables { - Tunables::for_target(compiler_config.target().triple()) - } - /// Gets the store for the host target, with the engine name and compiler name selected pub fn get_store(&self) -> Result<(Store, EngineType, CompilerType)> { let target = Target::default(); @@ -306,8 +298,8 @@ impl StoreOptions { &self, target: Target, ) -> Result<(Store, EngineType, CompilerType)> { - let (compiler_config, compiler_type) = self.get_compiler_config(target)?; - let tunables = self.get_tunables(&*compiler_config); + let (compiler_config, compiler_type) = self.get_compiler_config()?; + let tunables = Tunables::for_target(target); let (engine, engine_type) = self.get_engine_with_compiler(tunables, compiler_config)?; let store = Store::new(engine); Ok((store, engine_type, compiler_type)) diff --git a/tests/compilers/utils.rs b/tests/compilers/utils.rs index 6ffa5bf87..e526b7650 100644 --- a/tests/compilers/utils.rs +++ b/tests/compilers/utils.rs @@ -27,7 +27,7 @@ pub fn get_store() -> Store { let try_nan_canonicalization = false; let compiler_config = get_compiler_config_from_str(get_compiler_str(), try_nan_canonicalization); - let tunables = Tunables::for_target(compiler_config.target().triple()); + let tunables = Tunables::default(); let store = Store::new(Arc::new(JITEngine::new( compiler_config, tunables, @@ -46,7 +46,7 @@ pub fn get_store_with_middlewares Store { - let tunables = Tunables::for_target(&Triple::host()); + let tunables = Tunables::default(); let store = Store::new(Arc::new(JITEngine::headless(tunables))); store } diff --git a/tests/lib/test-utils/src/lib.rs b/tests/lib/test-utils/src/lib.rs index 597dd4389..267e178bb 100644 --- a/tests/lib/test-utils/src/lib.rs +++ b/tests/lib/test-utils/src/lib.rs @@ -9,26 +9,23 @@ pub fn get_compiler_config_from_str( compiler_name: &str, try_nan_canonicalization: bool, ) -> Box { - // We use the current host target for testing locally - let target = Target::default(); - match compiler_name { #[cfg(feature = "singlepass")] "singlepass" => { // Singlepass.canonicalize_nans(true).compiler() - let mut singlepass_config = wasmer_compiler_singlepass::SinglepassConfig::new(target); + let mut singlepass_config = wasmer_compiler_singlepass::SinglepassConfig::new(); singlepass_config.enable_nan_canonicalization = try_nan_canonicalization; Box::new(singlepass_config) } #[cfg(feature = "cranelift")] "cranelift" => { - let mut cranelift_config = wasmer_compiler_cranelift::CraneliftConfig::new(target); + let mut cranelift_config = wasmer_compiler_cranelift::CraneliftConfig::new(); cranelift_config.enable_nan_canonicalization = try_nan_canonicalization; Box::new(cranelift_config) } #[cfg(feature = "llvm")] "llvm" => { - let mut llvm_config = wasmer_compiler_llvm::LLVMConfig::new(target); + let mut llvm_config = wasmer_compiler_llvm::LLVMConfig::new(); llvm_config.enable_nan_canonicalization = try_nan_canonicalization; Box::new(llvm_config) } @@ -38,8 +35,9 @@ pub fn get_compiler_config_from_str( /// for when you need a store but you don't care about the details pub fn get_default_store() -> Store { + let target = Target::default(); let compiler_config = get_compiler_config_from_str("cranelift", false); - let tunables = Tunables::for_target(compiler_config.target().triple()); + let tunables = Tunables::for_target(target); Store::new(Arc::new(JITEngine::new( compiler_config, tunables, @@ -49,8 +47,9 @@ pub fn get_default_store() -> Store { #[cfg(feature = "llvm")] pub fn get_default_llvm_store() -> Store { + let target = Target::default(); let compiler_config = get_compiler_config_from_str("llvm", false); - let tunables = Tunables::for_target(compiler_config.target().triple()); + let tunables = Tunables::for_target(target); Store::new(Arc::new(JITEngine::new( compiler_config, tunables, @@ -60,8 +59,9 @@ pub fn get_default_llvm_store() -> Store { #[cfg(feature = "cranelift")] pub fn get_default_cranelift_store() -> Store { + let target = Target::default(); let compiler_config = get_compiler_config_from_str("cranelift", false); - let tunables = Tunables::for_target(compiler_config.target().triple()); + let tunables = Tunables::for_target(target); Store::new(Arc::new(JITEngine::new( compiler_config, tunables, @@ -71,8 +71,9 @@ pub fn get_default_cranelift_store() -> Store { #[cfg(feature = "singlepass")] pub fn get_default_singlepass_store() -> Store { + let target = Target::default(); let compiler_config = get_compiler_config_from_str("singlepass", false); - let tunables = Tunables::for_target(compiler_config.target().triple()); + let tunables = Tunables::for_target(target); Store::new(Arc::new(JITEngine::new( compiler_config, tunables, diff --git a/tests/wast.rs b/tests/wast.rs index ff893a3ba..c7176c944 100644 --- a/tests/wast.rs +++ b/tests/wast.rs @@ -40,7 +40,7 @@ fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { features.bulk_memory(true); } let compiler_config = get_compiler_config_from_str(compiler, try_nan_canonicalization); - let tunables = Tunables::for_target(compiler_config.target().triple()); + let tunables = Tunables::default(); let store = Store::new(Arc::new(JITEngine::new( compiler_config, tunables, From 99bd98458af26bfccfb37dc2d1884645b6a3e1a4 Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 17 Jun 2020 22:47:32 -0700 Subject: [PATCH 06/59] Improved compiler configurations --- lib/api/src/store.rs | 11 +++-- lib/c-api/src/lib.rs | 2 +- lib/c-api/src/wasm_c_api.rs | 2 +- lib/compiler-cranelift/src/config.rs | 51 ++++++++++++++-------- lib/compiler-llvm/src/config.rs | 58 +++++++++++++++---------- lib/compiler-singlepass/src/compiler.rs | 19 +++----- lib/compiler-singlepass/src/config.rs | 57 ++++++++++++------------ lib/engine-jit/src/engine.rs | 4 ++ lib/engine-native/src/engine.rs | 4 ++ lib/engine/src/engine.rs | 3 ++ src/commands/run.rs | 4 +- src/store.rs | 14 +++--- tests/compilers/utils.rs | 22 ++++------ tests/lib/engine-dummy/src/engine.rs | 4 ++ tests/lib/test-utils/src/lib.rs | 29 ++++++------- tests/wast.rs | 10 ++--- 16 files changed, 164 insertions(+), 130 deletions(-) diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index cbdc2747c..1c008cf58 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -12,8 +12,13 @@ pub struct Store { } impl Store { - pub fn new(engine: Arc) -> Store { - Store { engine } + pub fn new(engine: &E) -> Store + where + E: Engine + ?Sized, + { + Store { + engine: engine.cloned(), + } } pub fn engine(&self) -> &Arc { @@ -73,7 +78,7 @@ impl Default for Store { let config = get_config(); let engine = get_engine(config); - Store::new(engine) + Store { engine } } } diff --git a/lib/c-api/src/lib.rs b/lib/c-api/src/lib.rs index aaef3e8cb..2bbaa9a34 100644 --- a/lib/c-api/src/lib.rs +++ b/lib/c-api/src/lib.rs @@ -195,7 +195,7 @@ pub(crate) unsafe fn get_slice_checked<'a, T>(ptr: *const T, len: usize) -> &'a lazy_static! { pub(crate) static ref GLOBAL_STORE: wasmer::Store = - wasmer::Store::new(crate::wasm_c_api::wasm_engine_new().inner); + wasmer::Store::new(&crate::wasm_c_api::wasm_engine_new().inner); } pub(crate) fn get_global_store() -> &'static wasmer::Store { diff --git a/lib/c-api/src/wasm_c_api.rs b/lib/c-api/src/wasm_c_api.rs index 1aeb47915..0b7ef63ba 100644 --- a/lib/c-api/src/wasm_c_api.rs +++ b/lib/c-api/src/wasm_c_api.rs @@ -299,7 +299,7 @@ pub unsafe extern "C" fn wasm_store_new( ) -> Option> { let wasm_engine_ptr = wasm_engine_ptr?; let wasm_engine = wasm_engine_ptr.as_ref(); - let store = Store::new(wasm_engine.inner.clone()); + let store = Store::new(&wasm_engine.inner); Some(NonNull::new_unchecked( Box::into_raw(Box::new(store)) as *mut wasm_store_t )) diff --git a/lib/compiler-cranelift/src/config.rs b/lib/compiler-cranelift/src/config.rs index 5dd189450..1b886f8b8 100644 --- a/lib/compiler-cranelift/src/config.rs +++ b/lib/compiler-cranelift/src/config.rs @@ -30,25 +30,11 @@ pub enum OptLevel { /// [`Engine::new()`] #[derive(Clone)] pub struct CraneliftConfig { - /// Enable NaN canonicalization. - /// - /// NaN canonicalization is useful when trying to run WebAssembly - /// deterministically across different architectures. - pub enable_nan_canonicalization: bool, - - /// Should the Cranelift verifier be enabled. - /// - /// The verifier assures that the generated Cranelift IR is valid. - pub enable_verifier: bool, - - /// Should we enable simd support? - pub enable_simd: bool, - + enable_nan_canonicalization: bool, + enable_verifier: bool, + enable_simd: bool, enable_pic: bool, - - /// The optimization levels when optimizing the IR. - pub opt_level: OptLevel, - + opt_level: OptLevel, /// The middleware chain. pub(crate) middlewares: Vec>, } @@ -67,6 +53,35 @@ impl CraneliftConfig { } } + /// Should the Cranelift verifier be enabled. + /// + /// The verifier assures that the generated Cranelift IR is valid. + pub fn verify_ir(&mut self, enable: bool) -> &mut Self { + self.enable_verifier = enable; + self + } + + /// Enable NaN canonicalization. + /// + /// NaN canonicalization is useful when trying to run WebAssembly + /// deterministically across different architectures. + pub fn canonicalize_nans(&mut self, enable: bool) -> &mut Self { + self.enable_nan_canonicalization = enable; + self + } + + /// Enable SIMD support. + pub fn enable_simd(&mut self, enable: bool) -> &mut Self { + self.enable_simd = enable; + self + } + + /// The optimization levels when optimizing the IR. + pub fn opt_level(&mut self, opt_level: OptLevel) -> &mut Self { + self.opt_level = opt_level; + self + } + /// Generates the ISA for the provided target pub fn isa(&self, target: &Target) -> Box { let mut builder = diff --git a/lib/compiler-llvm/src/config.rs b/lib/compiler-llvm/src/config.rs index 705859664..1b3a3c8d3 100644 --- a/lib/compiler-llvm/src/config.rs +++ b/lib/compiler-llvm/src/config.rs @@ -40,27 +40,11 @@ pub trait LLVMCallbacks: Send + Sync { #[derive(Clone)] pub struct LLVMConfig { - /// Enable NaN canonicalization. - /// - /// NaN canonicalization is useful when trying to run WebAssembly - /// deterministically across different architectures. - pub enable_nan_canonicalization: bool, - - /// Should the LLVM IR verifier be enabled. - /// - /// The verifier assures that the generated LLVM IR is valid. - pub enable_verifier: bool, - - /// The optimization levels when optimizing the IR. - pub opt_level: OptimizationLevel, - - /// Whether to emit PIC. - pub is_pic: bool, - - /// Callbacks that will triggered in the different compilation - /// phases in LLVM. - pub callbacks: Option>, - + pub(crate) enable_nan_canonicalization: bool, + pub(crate) enable_verifier: bool, + pub(crate) opt_level: OptimizationLevel, + is_pic: bool, + pub(crate) callbacks: Option>, /// The middleware chain. pub(crate) middlewares: Vec>, } @@ -70,7 +54,7 @@ impl LLVMConfig { /// specified. pub fn new() -> Self { Self { - enable_nan_canonicalization: true, + enable_nan_canonicalization: false, enable_verifier: false, opt_level: OptimizationLevel::Aggressive, is_pic: false, @@ -79,6 +63,36 @@ impl LLVMConfig { } } + /// Should the LLVM verifier be enabled. + /// + /// The verifier assures that the generated LLVM IR is valid. + pub fn verify_ir(&mut self, enable: bool) -> &mut Self { + self.enable_verifier = enable; + self + } + + /// Enable NaN canonicalization. + /// + /// NaN canonicalization is useful when trying to run WebAssembly + /// deterministically across different architectures. + pub fn canonicalize_nans(&mut self, enable: bool) -> &mut Self { + self.enable_nan_canonicalization = enable; + self + } + + /// The optimization levels when optimizing the IR. + pub fn opt_level(&mut self, opt_level: OptimizationLevel) -> &mut Self { + self.opt_level = opt_level; + self + } + + /// Callbacks that will triggered in the different compilation + /// phases in LLVM. + pub fn callbacks(&mut self, callbacks: Option>) -> &mut Self { + self.callbacks = callbacks; + self + } + fn reloc_mode(&self) -> RelocMode { if self.is_pic { RelocMode::PIC diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index e8abb73b3..b5ef983d5 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -19,8 +19,7 @@ use wasmer_compiler::{ ModuleTranslationState, Target, }; use wasmer_compiler::{FunctionBody, FunctionBodyData}; -use wasmer_runtime::ModuleInfo; -use wasmer_runtime::TrapCode; +use wasmer_runtime::{ModuleInfo, TrapCode, VMOffsets}; /// A compiler that compiles a WebAssembly module with Singlepass. /// It does the compilation in one pass @@ -43,26 +42,22 @@ impl SinglepassCompiler { } impl Compiler for SinglepassCompiler { - /// Gets the target associated to this Compiler. - fn target(&self) -> &Target { - self.config.target() - } - /// Compile the module using Singlepass, producing a compilation result with /// associated relocations. fn compile_module( &self, + target: &Target, compile_info: &CompileModuleInfo, _module_translation: &ModuleTranslationState, function_body_inputs: PrimaryMap>, ) -> Result { if compile_info.features.multi_value { - return Err(CompileError::UnsupportedFeature("multivalue")); + return Err(CompileError::UnsupportedFeature("multivalue".to_string())); } - let vmoffsets = VMOffsets::new(8, module); - let memory_plans = compile_info.memory_plans; - let table_plans = compile_info.table_plans; - let module = compile_info.module; + let vmoffsets = VMOffsets::new(8, &compile_info.module); + let memory_plans = &compile_info.memory_plans; + let table_plans = &compile_info.table_plans; + let module = &compile_info.module; let import_trampolines: PrimaryMap = (0..module.num_imported_funcs) .map(FunctionIndex::new) .collect::>() diff --git a/lib/compiler-singlepass/src/config.rs b/lib/compiler-singlepass/src/config.rs index dc8660148..59c4b7b80 100644 --- a/lib/compiler-singlepass/src/config.rs +++ b/lib/compiler-singlepass/src/config.rs @@ -7,11 +7,22 @@ use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, FunctionMiddlewareGe #[derive(Clone)] pub struct SinglepassConfig { - /// Enable NaN canonicalization. - /// - /// NaN canonicalization is useful when trying to run WebAssembly - /// deterministically across different architectures. - pub enable_nan_canonicalization: bool, + pub(crate) enable_nan_canonicalization: bool, + pub(crate) enable_stack_check: bool, + /// The middleware chain. + pub(crate) middlewares: Vec>, +} + +impl SinglepassConfig { + /// Creates a new configuration object with the default configuration + /// specified. + pub fn new() -> Self { + Self { + enable_nan_canonicalization: true, + enable_stack_check: false, + middlewares: vec![], + } + } /// Enable stack check. /// @@ -20,24 +31,18 @@ pub struct SinglepassConfig { /// /// Note that this doesn't guarantee deterministic execution across /// different platforms. - pub enable_stack_check: bool, + pub fn enable_stack_check(&mut self, enable: bool) -> &mut Self { + self.enable_stack_check = enable; + self + } - target: Target, - - /// The middleware chain. - pub(crate) middlewares: Vec>, -} - -impl SinglepassConfig { - /// Creates a new configuration object with the default configuration - /// specified. - pub fn new(target: Target) -> Self { - Self { - enable_nan_canonicalization: true, - enable_stack_check: false, - target, - middlewares: vec![], - } + /// Enable NaN canonicalization. + /// + /// NaN canonicalization is useful when trying to run WebAssembly + /// deterministically across different architectures. + pub fn canonicalize_nans(&mut self, enable: bool) -> &mut Self { + self.enable_nan_canonicalization = enable; + self } } @@ -47,12 +52,6 @@ impl CompilerConfig for SinglepassConfig { // PIC code. } - /// Gets the target that we will use for compiling - /// the WebAssembly module - fn target(&self) -> &Target { - &self.target - } - /// Transform it into the compiler fn compiler(&self) -> Box { Box::new(SinglepassCompiler::new(&self)) @@ -66,6 +65,6 @@ impl CompilerConfig for SinglepassConfig { impl Default for SinglepassConfig { fn default() -> SinglepassConfig { - Self::new(Default::default(), Default::default()) + Self::new() } } diff --git a/lib/engine-jit/src/engine.rs b/lib/engine-jit/src/engine.rs index afe577f38..35bb4f299 100644 --- a/lib/engine-jit/src/engine.rs +++ b/lib/engine-jit/src/engine.rs @@ -125,6 +125,10 @@ impl Engine for JITEngine { fn id(&self) -> &EngineId { &self.engine_id } + + fn cloned(&self) -> Arc { + Arc::new(self.clone()) + } } /// The inner contents of `JITEngine` diff --git a/lib/engine-native/src/engine.rs b/lib/engine-native/src/engine.rs index 3d470dadf..d05258ad2 100644 --- a/lib/engine-native/src/engine.rs +++ b/lib/engine-native/src/engine.rs @@ -150,6 +150,10 @@ impl Engine for NativeEngine { fn id(&self) -> &EngineId { &self.engine_id } + + fn cloned(&self) -> Arc { + Arc::new(self.clone()) + } } /// The inner contents of `NativeEngine` diff --git a/lib/engine/src/engine.rs b/lib/engine/src/engine.rs index 046627a65..0b5eb9dd8 100644 --- a/lib/engine/src/engine.rs +++ b/lib/engine/src/engine.rs @@ -60,6 +60,9 @@ pub trait Engine { /// comparing two trait objects unsafely relies on implementation details /// of trait representation. fn id(&self) -> &EngineId; + + /// Clone the engine + fn cloned(&self) -> Arc; } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] diff --git a/src/commands/run.rs b/src/commands/run.rs index 4ca4a2434..a146c0cb1 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -175,7 +175,7 @@ impl Run { if wasmer_engine_native::NativeArtifact::is_deserializable(&contents) { let tunables = Tunables::default(); let engine = wasmer_engine_native::NativeEngine::headless(tunables); - let store = Store::new(Arc::new(engine)); + let store = Store::new(&engine); let module = unsafe { Module::deserialize_from_file(&store, &self.path)? }; return Ok(module); } @@ -185,7 +185,7 @@ impl Run { if wasmer_engine_jit::JITArtifact::is_deserializable(&contents) { let tunables = Tunables::default(); let engine = wasmer_engine_jit::JITEngine::headless(tunables); - let store = Store::new(Arc::new(engine)); + let store = Store::new(&engine); let module = unsafe { Module::deserialize_from_file(&store, &self.path)? }; return Ok(module); } diff --git a/src/store.rs b/src/store.rs index a5e69e6da..99a810326 100644 --- a/src/store.rs +++ b/src/store.rs @@ -274,7 +274,7 @@ impl StoreOptions { } } if let Some(ref llvm_debug_dir) = self.llvm_debug_dir { - config.callbacks = Some(Arc::new(Callbacks::new(llvm_debug_dir.clone())?)); + config.callbacks(Some(Arc::new(Callbacks::new(llvm_debug_dir.clone())?))); } Box::new(config) } @@ -301,7 +301,7 @@ impl StoreOptions { let (compiler_config, compiler_type) = self.get_compiler_config()?; let tunables = Tunables::for_target(target); let (engine, engine_type) = self.get_engine_with_compiler(tunables, compiler_config)?; - let store = Store::new(engine); + let store = Store::new(&*engine); Ok((store, engine_type, compiler_type)) } @@ -309,18 +309,18 @@ impl StoreOptions { &self, tunables: Tunables, compiler_config: Box, - ) -> Result<(Arc, EngineType)> { + ) -> Result<(Box, EngineType)> { let engine_type = self.get_engine()?; let features = self.get_features()?; - let engine: Arc = match engine_type { + let engine: Box = match engine_type { #[cfg(feature = "jit")] - EngineType::JIT => Arc::new(wasmer_engine_jit::JITEngine::new( + EngineType::JIT => Box::new(wasmer_engine_jit::JITEngine::new( compiler_config, tunables, features, )), #[cfg(feature = "native")] - EngineType::Native => Arc::new(wasmer_engine_native::NativeEngine::new( + EngineType::Native => Box::new(wasmer_engine_native::NativeEngine::new( compiler_config, tunables, features, @@ -382,7 +382,7 @@ impl StoreOptions { // Get the tunables for the current host let tunables = Tunables::default(); let (engine, engine_type) = self.get_engine_headless(tunables)?; - let store = Store::new(engine); + let store = Store::new(&engine); Ok((store, engine_type, CompilerType::Headless)) } diff --git a/tests/compilers/utils.rs b/tests/compilers/utils.rs index e526b7650..409fddc9d 100644 --- a/tests/compilers/utils.rs +++ b/tests/compilers/utils.rs @@ -23,23 +23,23 @@ fn get_compiler_str() -> &'static str { } pub fn get_store() -> Store { - let features = Features::default(); + let mut features = Features::default(); + #[cfg(feature = "test-singlepass")] + features.multi_value(false); let try_nan_canonicalization = false; let compiler_config = get_compiler_config_from_str(get_compiler_str(), try_nan_canonicalization); let tunables = Tunables::default(); - let store = Store::new(Arc::new(JITEngine::new( - compiler_config, - tunables, - features, - ))); + let store = Store::new(&JITEngine::new(compiler_config, tunables, features)); store } pub fn get_store_with_middlewares>>( middlewares: I, ) -> Store { - let features = Features::default(); + let mut features = Features::default(); + #[cfg(feature = "test-singlepass")] + features.multi_value(false); let try_nan_canonicalization = false; let mut compiler_config = get_compiler_config_from_str(get_compiler_str(), try_nan_canonicalization); @@ -47,16 +47,12 @@ pub fn get_store_with_middlewares Store { let tunables = Tunables::default(); - let store = Store::new(Arc::new(JITEngine::headless(tunables))); + let store = Store::new(&JITEngine::headless(tunables)); store } diff --git a/tests/lib/engine-dummy/src/engine.rs b/tests/lib/engine-dummy/src/engine.rs index bfb116b51..52c16c371 100644 --- a/tests/lib/engine-dummy/src/engine.rs +++ b/tests/lib/engine-dummy/src/engine.rs @@ -104,4 +104,8 @@ impl Engine for DummyEngine { fn id(&self) -> &EngineId { &self.engine_id } + + fn cloned(&self) -> Arc { + Arc::new(self.clone()) + } } diff --git a/tests/lib/test-utils/src/lib.rs b/tests/lib/test-utils/src/lib.rs index 267e178bb..be9def14e 100644 --- a/tests/lib/test-utils/src/lib.rs +++ b/tests/lib/test-utils/src/lib.rs @@ -7,26 +7,25 @@ use wasmer_engine_jit::JITEngine; pub fn get_compiler_config_from_str( compiler_name: &str, - try_nan_canonicalization: bool, + do_nan_canonicalization: bool, ) -> Box { match compiler_name { #[cfg(feature = "singlepass")] "singlepass" => { - // Singlepass.canonicalize_nans(true).compiler() let mut singlepass_config = wasmer_compiler_singlepass::SinglepassConfig::new(); - singlepass_config.enable_nan_canonicalization = try_nan_canonicalization; + singlepass_config.canonicalize_nans(do_nan_canonicalization); Box::new(singlepass_config) } #[cfg(feature = "cranelift")] "cranelift" => { let mut cranelift_config = wasmer_compiler_cranelift::CraneliftConfig::new(); - cranelift_config.enable_nan_canonicalization = try_nan_canonicalization; + cranelift_config.canonicalize_nans(do_nan_canonicalization); Box::new(cranelift_config) } #[cfg(feature = "llvm")] "llvm" => { let mut llvm_config = wasmer_compiler_llvm::LLVMConfig::new(); - llvm_config.enable_nan_canonicalization = try_nan_canonicalization; + llvm_config.canonicalize_nans(do_nan_canonicalization); Box::new(llvm_config) } _ => panic!("Compiler {} not supported", compiler_name), @@ -38,11 +37,11 @@ pub fn get_default_store() -> Store { let target = Target::default(); let compiler_config = get_compiler_config_from_str("cranelift", false); let tunables = Tunables::for_target(target); - Store::new(Arc::new(JITEngine::new( + Store::new(&JITEngine::new( compiler_config, tunables, Features::default(), - ))) + )) } #[cfg(feature = "llvm")] @@ -50,11 +49,11 @@ pub fn get_default_llvm_store() -> Store { let target = Target::default(); let compiler_config = get_compiler_config_from_str("llvm", false); let tunables = Tunables::for_target(target); - Store::new(Arc::new(JITEngine::new( + Store::new(&JITEngine::new( compiler_config, tunables, Features::default(), - ))) + )) } #[cfg(feature = "cranelift")] @@ -62,21 +61,19 @@ pub fn get_default_cranelift_store() -> Store { let target = Target::default(); let compiler_config = get_compiler_config_from_str("cranelift", false); let tunables = Tunables::for_target(target); - Store::new(Arc::new(JITEngine::new( + Store::new(&JITEngine::new( compiler_config, tunables, Features::default(), - ))) + )) } #[cfg(feature = "singlepass")] pub fn get_default_singlepass_store() -> Store { let target = Target::default(); + let mut features = Features::default(); + features.multi_value(false); let compiler_config = get_compiler_config_from_str("singlepass", false); let tunables = Tunables::for_target(target); - Store::new(Arc::new(JITEngine::new( - compiler_config, - tunables, - Features::default(), - ))) + Store::new(&JITEngine::new(compiler_config, tunables, features)) } diff --git a/tests/wast.rs b/tests/wast.rs index c7176c944..10729e24c 100644 --- a/tests/wast.rs +++ b/tests/wast.rs @@ -39,16 +39,14 @@ fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { if wast_path.contains("bulk-memory") { features.bulk_memory(true); } + #[cfg(feature = "test-singlepass")] + features.multi_value(false); let compiler_config = get_compiler_config_from_str(compiler, try_nan_canonicalization); let tunables = Tunables::default(); - let store = Store::new(Arc::new(JITEngine::new( - compiler_config, - tunables, - features, - ))); + let store = Store::new(&JITEngine::new(compiler_config, tunables, features)); // let mut native = NativeEngine::new(compiler_config, tunables); // native.set_deterministic_prefixer(native_prefixer); - // let store = Store::new(Arc::new(native)); + // let store = Store::new(&native); let mut wast = Wast::new_with_spectest(store); if compiler == "singlepass" { // We don't support multivalue yet in singlepass From 5f6c931710e9c6a2bb7962cac006f4dbdb9db79c Mon Sep 17 00:00:00 2001 From: Syrus Date: Wed, 17 Jun 2020 23:17:13 -0700 Subject: [PATCH 07/59] Fixed c-api compilation --- lib/c-api/src/lib.rs | 2 +- lib/c-api/src/wasm_c_api.rs | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/c-api/src/lib.rs b/lib/c-api/src/lib.rs index 2bbaa9a34..46a94adbc 100644 --- a/lib/c-api/src/lib.rs +++ b/lib/c-api/src/lib.rs @@ -195,7 +195,7 @@ pub(crate) unsafe fn get_slice_checked<'a, T>(ptr: *const T, len: usize) -> &'a lazy_static! { pub(crate) static ref GLOBAL_STORE: wasmer::Store = - wasmer::Store::new(&crate::wasm_c_api::wasm_engine_new().inner); + wasmer::Store::new(&*crate::wasm_c_api::wasm_engine_new().inner); } pub(crate) fn get_global_store() -> &'static wasmer::Store { diff --git a/lib/c-api/src/wasm_c_api.rs b/lib/c-api/src/wasm_c_api.rs index 0b7ef63ba..ab2bab854 100644 --- a/lib/c-api/src/wasm_c_api.rs +++ b/lib/c-api/src/wasm_c_api.rs @@ -10,9 +10,9 @@ use std::sync::Arc; #[cfg(feature = "engine")] use wasmer::Tunables; use wasmer::{ - Engine, ExportType, Extern, ExternType, Function, FunctionType, Global, GlobalType, Instance, - Memory, MemoryType, Module, Mutability, OrderedResolver, Pages, RuntimeError, Store, Table, - TableType, Val, ValType, + Engine, ExportType, Extern, ExternType, Features, Function, FunctionType, Global, GlobalType, + Instance, Memory, MemoryType, Module, Mutability, OrderedResolver, Pages, RuntimeError, Store, + Table, TableType, Val, ValType, }; #[cfg(feature = "jit")] use wasmer_engine_jit::JITEngine; @@ -48,7 +48,7 @@ pub extern "C" fn wasm_config_new() -> *mut wasm_config_t { #[repr(C)] pub struct wasm_engine_t { - pub(crate) inner: Arc, + pub(crate) inner: Box, } cfg_if! { @@ -73,7 +73,8 @@ cfg_if! { pub extern "C" fn wasm_engine_new() -> Box { let compiler_config: Box = get_default_compiler_config(); let tunables = Tunables::default(); - let engine: Arc = Arc::new(JITEngine::new(compiler_config, tunables)); + let features = Features::default(); + let engine: Box = Box::new(JITEngine::new(compiler_config, tunables, features)); Box::new(wasm_engine_t { inner: engine }) } } @@ -82,7 +83,7 @@ cfg_if! { #[no_mangle] pub extern "C" fn wasm_engine_new() -> Box { let tunables = Tunables::default(); - let engine: Arc = Arc::new(JITEngine::headless(tunables)); + let engine: Box = Arc::new(JITEngine::headless(tunables)); Box::new(wasm_engine_t { inner: engine }) } } @@ -299,7 +300,7 @@ pub unsafe extern "C" fn wasm_store_new( ) -> Option> { let wasm_engine_ptr = wasm_engine_ptr?; let wasm_engine = wasm_engine_ptr.as_ref(); - let store = Store::new(&wasm_engine.inner); + let store = Store::new(&*wasm_engine.inner); Some(NonNull::new_unchecked( Box::into_raw(Box::new(store)) as *mut wasm_store_t )) From f2fa2a9100953e9851bdfa9aa94d702b781d0955 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 18 Jun 2020 00:57:32 -0700 Subject: [PATCH 08/59] Created builders for JIT and Native engines --- lib/api/src/store.rs | 30 ++++++------- lib/api/src/tunables.rs | 24 ++++------ lib/engine-jit/src/artifact.rs | 2 +- lib/engine-jit/src/builder.rs | 72 ++++++++++++++++++++++++++++++ lib/engine-jit/src/engine.rs | 25 +++++++---- lib/engine-jit/src/lib.rs | 2 + lib/engine-native/src/artifact.rs | 2 +- lib/engine-native/src/builder.rs | 73 +++++++++++++++++++++++++++++++ lib/engine-native/src/engine.rs | 24 ++++++---- lib/engine-native/src/lib.rs | 2 + lib/engine/src/tunables.rs | 3 -- src/commands/run.rs | 10 +++-- src/store.rs | 52 ++++++++++++---------- tests/compilers/utils.rs | 21 ++++++--- tests/lib/test-utils/src/lib.rs | 47 ++++++++++---------- tests/wast.rs | 10 +++-- 16 files changed, 285 insertions(+), 114 deletions(-) create mode 100644 lib/engine-jit/src/builder.rs create mode 100644 lib/engine-native/src/builder.rs diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index 1c008cf58..a0d3da814 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -58,27 +58,27 @@ impl Default for Store { #[allow(unreachable_code)] fn get_engine( config: Box, - ) -> Arc { - let tunables = Tunables::default(); - + ) -> Box { #[cfg(feature = "jit")] - return Arc::new(wasmer_engine_jit::JITEngine::new( - config, - tunables, - Default::default(), - )); + return Box::new( + wasmer_engine_jit::JIT::new(&*config) + .tunables(Tunables::for_target) + .engine(), + ); - #[cfg(feature = "native")] - return Arc::new(wasmer_engine_native::NativeEngine::new( - config, - tunables, - Default::default(), - )); + // #[cfg(feature = "native")] + // return Arc::new(wasmer_engine_native::NativeEngine::new( + // config, + // tunables, + // Default::default(), + // )); } let config = get_config(); let engine = get_engine(config); - Store { engine } + Store { + engine: engine.into(), + } } } diff --git a/lib/api/src/tunables.rs b/lib/api/src/tunables.rs index d91457fc7..a581d8b84 100644 --- a/lib/api/src/tunables.rs +++ b/lib/api/src/tunables.rs @@ -13,8 +13,6 @@ use wasmer_runtime::{Memory, MemoryPlan, MemoryStyle, Table, TablePlan, TableSty /// Tunable parameters for WebAssembly compilation. #[derive(Clone)] pub struct Tunables { - pub target: Target, - /// For static heaps, the size in wasm pages of the heap protected by bounds checking. pub static_memory_bound: Pages, @@ -27,7 +25,7 @@ pub struct Tunables { impl Tunables { /// Get the `Tunables` for a specific Target - pub fn for_target(target: Target) -> Self { + pub fn for_target(target: &Target) -> Box { let triple = target.triple(); let pointer_width: PointerWidth = triple.pointer_width().unwrap(); let (mut static_memory_bound, mut static_memory_offset_guard_size): (Pages, u64) = @@ -54,21 +52,15 @@ impl Tunables { static_memory_offset_guard_size = min(static_memory_offset_guard_size, 0x10000); } - Self { + Box::new(Self { static_memory_bound, static_memory_offset_guard_size, dynamic_memory_offset_guard_size, - target, - } + }) } } impl BaseTunables for Tunables { - /// Get the target for this Tunables - fn target(&self) -> &Target { - &self.target - } - /// 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 @@ -113,8 +105,8 @@ impl BaseTunables for Tunables { } } -impl Default for Tunables { - fn default() -> Self { - Self::for_target(Target::default()) - } -} +// impl Default for Tunables { +// fn default() -> Self { +// Self::for_target(&Target::default()) +// } +// } diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index a212dc525..7f9778152 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -75,7 +75,7 @@ impl JITArtifact { // Compile the Module let compilation = compiler.compile_module( - &tunables.target(), + &inner_jit.target(), &compile_info, translation.module_translation.as_ref().unwrap(), translation.function_body_inputs, diff --git a/lib/engine-jit/src/builder.rs b/lib/engine-jit/src/builder.rs new file mode 100644 index 000000000..b6cd9abed --- /dev/null +++ b/lib/engine-jit/src/builder.rs @@ -0,0 +1,72 @@ +use crate::JITEngine; +use std::sync::Arc; +use wasmer_compiler::{Compiler, CompilerConfig, Features, Target}; +use wasmer_engine::Tunables; + +/// The JIT builder +pub struct JIT { + compiler: Option>, + tunables_fn: Option Box>>, + target: Option, + features: Option, +} + +impl JIT { + /// Create a new JIT + pub fn new(compiler_config: &dyn CompilerConfig) -> Self { + Self { + compiler: Some(compiler_config.compiler()), + target: None, + tunables_fn: None, + features: None, + } + } + + /// Create a new headless JIT + pub fn headless() -> Self { + Self { + compiler: None, + target: None, + tunables_fn: None, + features: None, + } + } + + /// Set the target + pub fn target(mut self, target: Target) -> Self { + self.target = Some(target); + self + } + + /// Set the tunables constructor function. + /// + /// It should receive a [`Target`] and return a + pub fn tunables(mut self, tunables_fn: F) -> Self + where + F: Fn(&Target) -> Box + 'static, + { + self.tunables_fn = Some(Box::new(tunables_fn)); + self + } + + /// Set the features + pub fn features(mut self, features: Features) -> Self { + self.features = Some(features); + self + } + + /// Build the `JITEngine` for this configuration + pub fn engine(self) -> JITEngine { + let target = self.target.unwrap_or_default(); + let tunables_fn = self + .tunables_fn + .expect("You need to specify tunables for the JIT"); + let tunables: Arc = tunables_fn(&target).into(); + if let Some(compiler) = self.compiler { + let features = self.features.unwrap_or_default(); + JITEngine::new(compiler, target, tunables, features) + } else { + JITEngine::headless(tunables) + } + } +} diff --git a/lib/engine-jit/src/engine.rs b/lib/engine-jit/src/engine.rs index 35bb4f299..ea2d6e77a 100644 --- a/lib/engine-jit/src/engine.rs +++ b/lib/engine-jit/src/engine.rs @@ -8,7 +8,7 @@ use wasm_common::entity::PrimaryMap; use wasm_common::Features; use wasm_common::{FunctionIndex, FunctionType, LocalFunctionIndex, SignatureIndex}; use wasmer_compiler::{ - CompileError, CustomSection, CustomSectionProtection, FunctionBody, SectionIndex, + CompileError, CustomSection, CustomSectionProtection, FunctionBody, SectionIndex, Target, }; #[cfg(feature = "compiler")] use wasmer_compiler::{Compiler, CompilerConfig}; @@ -29,11 +29,11 @@ impl JITEngine { /// Create a new `JITEngine` with the given config #[cfg(feature = "compiler")] pub fn new( - config: Box, - tunables: impl Tunables + 'static + Send + Sync, + compiler: Box, + target: Target, + tunables: Arc, features: Features, ) -> Self { - let compiler = config.compiler(); Self { inner: Arc::new(Mutex::new(JITEngineInner { compiler: Some(compiler), @@ -41,8 +41,9 @@ impl JITEngine { code_memory: CodeMemory::new(), signatures: SignatureRegistry::new(), features, + target: Some(target), })), - tunables: Arc::new(tunables), + tunables: tunables, engine_id: EngineId::default(), } } @@ -60,7 +61,7 @@ impl JITEngine { /// /// Headless engines can't compile or validate any modules, /// they just take already processed Modules (via `Module::serialize`). - pub fn headless(tunables: impl Tunables + 'static + Send + Sync) -> Self { + pub fn headless(tunables: Arc) -> Self { Self { inner: Arc::new(Mutex::new(JITEngineInner { #[cfg(feature = "compiler")] @@ -69,8 +70,9 @@ impl JITEngine { code_memory: CodeMemory::new(), signatures: SignatureRegistry::new(), features: Features::default(), + target: None, })), - tunables: Arc::new(tunables), + tunables, engine_id: EngineId::default(), } } @@ -140,6 +142,8 @@ pub struct JITEngineInner { function_call_trampolines: HashMap, /// The features to compile the Wasm module with features: Features, + /// The target for the compiler + target: Option, /// The code memory is responsible of publishing the compiled /// functions to memory. code_memory: CodeMemory, @@ -173,7 +177,12 @@ impl JITEngineInner { )) } - /// The Wasm featuress + /// The target + pub fn target(&self) -> &Target { + &self.target.as_ref().unwrap() + } + + /// The Wasm features pub fn features(&self) -> &Features { &self.features } diff --git a/lib/engine-jit/src/lib.rs b/lib/engine-jit/src/lib.rs index ae5799ffb..698d7c323 100644 --- a/lib/engine-jit/src/lib.rs +++ b/lib/engine-jit/src/lib.rs @@ -26,6 +26,7 @@ )] mod artifact; +mod builder; mod code_memory; mod engine; mod link; @@ -33,6 +34,7 @@ mod serialize; mod unwind; pub use crate::artifact::JITArtifact; +pub use crate::builder::JIT; pub use crate::code_memory::CodeMemory; pub use crate::engine::JITEngine; pub use crate::link::link_module; diff --git a/lib/engine-native/src/artifact.rs b/lib/engine-native/src/artifact.rs index 493d8945b..464f4fc63 100644 --- a/lib/engine-native/src/artifact.rs +++ b/lib/engine-native/src/artifact.rs @@ -123,7 +123,7 @@ impl NativeArtifact { }; let compiler = engine_inner.compiler()?; - let target = tunables.target(); + let target = engine_inner.target(); // Compile the Module let compilation = compiler.compile_module( diff --git a/lib/engine-native/src/builder.rs b/lib/engine-native/src/builder.rs new file mode 100644 index 000000000..8ef046ce2 --- /dev/null +++ b/lib/engine-native/src/builder.rs @@ -0,0 +1,73 @@ +use crate::NativeEngine; +use std::sync::Arc; +use wasmer_compiler::{Compiler, CompilerConfig, Features, Target}; +use wasmer_engine::Tunables; + +/// The Native builder +pub struct Native { + compiler: Option>, + tunables_fn: Option Box>>, + target: Option, + features: Option, +} + +impl Native { + /// Create a new Native + pub fn new(compiler_config: &mut dyn CompilerConfig) -> Self { + compiler_config.enable_pic(); + Self { + compiler: Some(compiler_config.compiler()), + target: None, + tunables_fn: None, + features: None, + } + } + + /// Create a new headless Native + pub fn headless() -> Self { + Self { + compiler: None, + target: None, + tunables_fn: None, + features: None, + } + } + + /// Set the target + pub fn target(mut self, target: Target) -> Self { + self.target = Some(target); + self + } + + /// Set the tunables constructor function. + /// + /// It should receive a [`Target`] and return a + pub fn tunables(mut self, tunables_fn: F) -> Self + where + F: Fn(&Target) -> Box + 'static, + { + self.tunables_fn = Some(Box::new(tunables_fn)); + self + } + + /// Set the features + pub fn features(mut self, features: Features) -> Self { + self.features = Some(features); + self + } + + /// Build the `NativeEngine` for this configuration + pub fn engine(self) -> NativeEngine { + let target = self.target.unwrap_or_default(); + let tunables_fn = self + .tunables_fn + .expect("You need to specify tunables for the JIT"); + let tunables: Arc = tunables_fn(&target).into(); + if let Some(compiler) = self.compiler { + let features = self.features.unwrap_or_default(); + NativeEngine::new(compiler, target, tunables, features) + } else { + NativeEngine::headless(tunables) + } + } +} diff --git a/lib/engine-native/src/engine.rs b/lib/engine-native/src/engine.rs index d05258ad2..c778c5a2e 100644 --- a/lib/engine-native/src/engine.rs +++ b/lib/engine-native/src/engine.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::sync::Arc; use std::sync::Mutex; use wasm_common::{Features, FunctionType}; -use wasmer_compiler::CompileError; +use wasmer_compiler::{CompileError, Target}; #[cfg(feature = "compiler")] use wasmer_compiler::{Compiler, CompilerConfig}; use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables}; @@ -24,21 +24,21 @@ impl NativeEngine { /// Create a new `NativeEngine` with the given config #[cfg(feature = "compiler")] pub fn new( - mut config: Box, - tunables: impl Tunables + 'static + Send + Sync, + compiler: Box, + target: Target, + tunables: Arc, features: Features, ) -> Self { - config.enable_pic(); - let compiler = config.compiler(); Self { inner: Arc::new(Mutex::new(NativeEngineInner { compiler: Some(compiler), trampolines: HashMap::new(), signatures: SignatureRegistry::new(), prefixer: None, + target: Some(target), features, })), - tunables: Arc::new(tunables), + tunables, engine_id: EngineId::default(), } } @@ -56,7 +56,7 @@ impl NativeEngine { /// /// Headless engines can't compile or validate any modules, /// they just take already processed Modules (via `Module::serialize`). - pub fn headless(tunables: impl Tunables + 'static + Send + Sync) -> Self { + pub fn headless(tunables: Arc) -> Self { Self { inner: Arc::new(Mutex::new(NativeEngineInner { #[cfg(feature = "compiler")] @@ -64,9 +64,10 @@ impl NativeEngine { trampolines: HashMap::new(), signatures: SignatureRegistry::new(), prefixer: None, + target: None, features: Features::default(), })), - tunables: Arc::new(tunables), + tunables, engine_id: EngineId::default(), } } @@ -172,6 +173,8 @@ pub struct NativeEngineInner { /// the functions in the shared object generated by the `NativeEngine`, /// so we can assure no collisions. prefixer: Option String + Send>>, + /// The target for the compiler + target: Option, } impl NativeEngineInner { @@ -199,6 +202,11 @@ impl NativeEngineInner { &self.features } + /// The target + pub fn target(&self) -> &Target { + &self.target.as_ref().unwrap() + } + /// Validate the module #[cfg(feature = "compiler")] pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> { diff --git a/lib/engine-native/src/lib.rs b/lib/engine-native/src/lib.rs index 3568d2060..73ce79444 100644 --- a/lib/engine-native/src/lib.rs +++ b/lib/engine-native/src/lib.rs @@ -26,10 +26,12 @@ )] mod artifact; +mod builder; mod engine; mod serialize; pub use crate::artifact::NativeArtifact; +pub use crate::builder::Native; pub use crate::engine::NativeEngine; /// Version number of this crate. diff --git a/lib/engine/src/tunables.rs b/lib/engine/src/tunables.rs index 0f3c57670..17b625d45 100644 --- a/lib/engine/src/tunables.rs +++ b/lib/engine/src/tunables.rs @@ -12,9 +12,6 @@ use wasmer_runtime::{MemoryPlan, TablePlan}; /// Tunables for an engine pub trait Tunables { - /// Get the target for this Tunables - fn target(&self) -> &Target; - /// Construct a `MemoryPlan` for the provided `MemoryType` fn memory_plan(&self, memory: MemoryType) -> MemoryPlan; diff --git a/src/commands/run.rs b/src/commands/run.rs index a146c0cb1..ecc76d669 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -173,8 +173,9 @@ impl Run { #[cfg(feature = "native")] { if wasmer_engine_native::NativeArtifact::is_deserializable(&contents) { - let tunables = Tunables::default(); - let engine = wasmer_engine_native::NativeEngine::headless(tunables); + let engine = wasmer_engine_native::Native::headless() + .tunables(Tunables::for_target) + .engine(); let store = Store::new(&engine); let module = unsafe { Module::deserialize_from_file(&store, &self.path)? }; return Ok(module); @@ -183,8 +184,9 @@ impl Run { #[cfg(feature = "jit")] { if wasmer_engine_jit::JITArtifact::is_deserializable(&contents) { - let tunables = Tunables::default(); - let engine = wasmer_engine_jit::JITEngine::headless(tunables); + let engine = wasmer_engine_jit::JIT::headless() + .tunables(Tunables::for_target) + .engine(); let store = Store::new(&engine); let module = unsafe { Module::deserialize_from_file(&store, &self.path)? }; return Ok(module); diff --git a/src/store.rs b/src/store.rs index 99a810326..b49b6bdaf 100644 --- a/src/store.rs +++ b/src/store.rs @@ -299,32 +299,35 @@ impl StoreOptions { target: Target, ) -> Result<(Store, EngineType, CompilerType)> { let (compiler_config, compiler_type) = self.get_compiler_config()?; - let tunables = Tunables::for_target(target); - let (engine, engine_type) = self.get_engine_with_compiler(tunables, compiler_config)?; + let (engine, engine_type) = self.get_engine_with_compiler(target, compiler_config)?; let store = Store::new(&*engine); Ok((store, engine_type, compiler_type)) } fn get_engine_with_compiler( &self, - tunables: Tunables, - compiler_config: Box, + target: Target, + mut compiler_config: Box, ) -> Result<(Box, EngineType)> { let engine_type = self.get_engine()?; let features = self.get_features()?; let engine: Box = match engine_type { #[cfg(feature = "jit")] - EngineType::JIT => Box::new(wasmer_engine_jit::JITEngine::new( - compiler_config, - tunables, - features, - )), + EngineType::JIT => Box::new( + wasmer_engine_jit::JIT::new(&*compiler_config) + .tunables(Tunables::for_target) + .features(features) + .target(target) + .engine(), + ), #[cfg(feature = "native")] - EngineType::Native => Box::new(wasmer_engine_native::NativeEngine::new( - compiler_config, - tunables, - features, - )), + EngineType::Native => Box::new( + wasmer_engine_native::Native::new(&mut *compiler_config) + .tunables(Tunables::for_target) + .target(target) + .features(features) + .engine(), + ), #[cfg(not(all(feature = "jit", feature = "native",)))] engine => bail!( "The `{}` engine is not included in this binary.", @@ -358,16 +361,21 @@ impl StoreOptions { // If we don't have a compiler, but we have an engine #[cfg(all(not(feature = "compiler"), feature = "engine"))] impl StoreOptions { - fn get_engine_headless( - &self, - tunables: Tunables, - ) -> Result<(Arc, EngineType)> { + fn get_engine_headless(&self) -> Result<(Arc, EngineType)> { let engine_type = self.get_engine()?; let engine: Arc = match engine_type { #[cfg(feature = "jit")] - EngineType::JIT => Arc::new(wasmer_engine_jit::JITEngine::headless(tunables)), + EngineType::JIT => Arc::new( + wasmer_engine_jit::JIT::headless() + .tunables(Tunables::for_target) + .engine(), + ), #[cfg(feature = "native")] - EngineType::Native => Arc::new(wasmer_engine_native::NativeEngine::headless(tunables)), + EngineType::Native => Arc::new( + wasmer_engine_native::Native::headless() + .tunables(Tunables::for_target) + .engine(), + ), #[cfg(not(all(feature = "jit", feature = "native",)))] engine => bail!( "The `{}` engine is not included in this binary.", @@ -379,9 +387,7 @@ impl StoreOptions { /// Get the store (headless engine) pub fn get_store(&self) -> Result<(Store, EngineType, CompilerType)> { - // Get the tunables for the current host - let tunables = Tunables::default(); - let (engine, engine_type) = self.get_engine_headless(tunables)?; + let (engine, engine_type) = self.get_engine_headless()?; let store = Store::new(&engine); Ok((store, engine_type, CompilerType::Headless)) } diff --git a/tests/compilers/utils.rs b/tests/compilers/utils.rs index 409fddc9d..378e8b088 100644 --- a/tests/compilers/utils.rs +++ b/tests/compilers/utils.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use test_utils::get_compiler_config_from_str; use wasmer::{Features, FunctionMiddlewareGenerator, Store, Triple, Tunables}; -use wasmer_engine_jit::JITEngine; +use wasmer_engine_jit::JIT; fn get_compiler_str() -> &'static str { cfg_if::cfg_if! { @@ -29,8 +29,12 @@ pub fn get_store() -> Store { let try_nan_canonicalization = false; let compiler_config = get_compiler_config_from_str(get_compiler_str(), try_nan_canonicalization); - let tunables = Tunables::default(); - let store = Store::new(&JITEngine::new(compiler_config, tunables, features)); + let store = Store::new( + &JIT::new(&*compiler_config) + .tunables(Tunables::for_target) + .features(features) + .engine(), + ); store } @@ -46,13 +50,16 @@ pub fn get_store_with_middlewares Store { - let tunables = Tunables::default(); - let store = Store::new(&JITEngine::headless(tunables)); + let store = Store::new(&JIT::headless().tunables(Tunables::for_target).engine()); store } diff --git a/tests/lib/test-utils/src/lib.rs b/tests/lib/test-utils/src/lib.rs index be9def14e..0dc7a1fe1 100644 --- a/tests/lib/test-utils/src/lib.rs +++ b/tests/lib/test-utils/src/lib.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use wasmer::{Store, Tunables}; use wasmer_compiler::{CompilerConfig, Features, Target}; -use wasmer_engine_jit::JITEngine; +use wasmer_engine_jit::JIT; pub fn get_compiler_config_from_str( compiler_name: &str, @@ -34,46 +34,43 @@ pub fn get_compiler_config_from_str( /// for when you need a store but you don't care about the details pub fn get_default_store() -> Store { - let target = Target::default(); let compiler_config = get_compiler_config_from_str("cranelift", false); - let tunables = Tunables::for_target(target); - Store::new(&JITEngine::new( - compiler_config, - tunables, - Features::default(), - )) + Store::new( + &JIT::new(&*compiler_config) + .tunables(Tunables::for_target) + .engine(), + ) } #[cfg(feature = "llvm")] pub fn get_default_llvm_store() -> Store { - let target = Target::default(); let compiler_config = get_compiler_config_from_str("llvm", false); - let tunables = Tunables::for_target(target); - Store::new(&JITEngine::new( - compiler_config, - tunables, - Features::default(), - )) + Store::new( + &JIT::new(&*compiler_config) + .tunables(Tunables::for_target) + .engine(), + ) } #[cfg(feature = "cranelift")] pub fn get_default_cranelift_store() -> Store { - let target = Target::default(); let compiler_config = get_compiler_config_from_str("cranelift", false); - let tunables = Tunables::for_target(target); - Store::new(&JITEngine::new( - compiler_config, - tunables, - Features::default(), - )) + Store::new( + &JIT::new(&*compiler_config) + .tunables(Tunables::for_target) + .engine(), + ) } #[cfg(feature = "singlepass")] pub fn get_default_singlepass_store() -> Store { - let target = Target::default(); let mut features = Features::default(); features.multi_value(false); let compiler_config = get_compiler_config_from_str("singlepass", false); - let tunables = Tunables::for_target(target); - Store::new(&JITEngine::new(compiler_config, tunables, features)) + Store::new( + &JIT::new(&*compiler_config) + .tunables(Tunables::for_target) + .features(features) + .engine(), + ) } diff --git a/tests/wast.rs b/tests/wast.rs index 10729e24c..ef6fde3b9 100644 --- a/tests/wast.rs +++ b/tests/wast.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use test_utils::get_compiler_config_from_str; use wasmer::{Features, Store, Tunables}; #[cfg(feature = "jit")] -use wasmer_engine_jit::JITEngine; +use wasmer_engine_jit::JIT; #[cfg(feature = "native")] use wasmer_engine_native::NativeEngine; use wasmer_wast::Wast; @@ -42,8 +42,12 @@ fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { #[cfg(feature = "test-singlepass")] features.multi_value(false); let compiler_config = get_compiler_config_from_str(compiler, try_nan_canonicalization); - let tunables = Tunables::default(); - let store = Store::new(&JITEngine::new(compiler_config, tunables, features)); + let store = Store::new( + &JIT::new(&*compiler_config) + .tunables(Tunables::for_target) + .features(features) + .engine(), + ); // let mut native = NativeEngine::new(compiler_config, tunables); // native.set_deterministic_prefixer(native_prefixer); // let store = Store::new(&native); From 74e4ab0e530bf35621da380d209b712eb8672aa3 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 18 Jun 2020 01:20:26 -0700 Subject: [PATCH 09/59] Simplify testing logic --- Cargo.lock | 13 ------ Cargo.toml | 4 -- tests/compilers/main.rs | 4 ++ tests/compilers/utils.rs | 60 +++++++++++++------------- tests/{ => compilers}/wast.rs | 8 ++-- tests/lib/test-utils/Cargo.toml | 32 -------------- tests/lib/test-utils/src/lib.rs | 76 --------------------------------- 7 files changed, 39 insertions(+), 158 deletions(-) rename tests/{ => compilers}/wast.rs (90%) delete mode 100644 tests/lib/test-utils/Cargo.toml delete mode 100644 tests/lib/test-utils/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index e8723f60f..f00266d64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1794,18 +1794,6 @@ dependencies = [ "target-lexicon", ] -[[package]] -name = "test-utils" -version = "1.0.0-alpha.1" -dependencies = [ - "wasmer", - "wasmer-compiler", - "wasmer-compiler-cranelift", - "wasmer-compiler-llvm", - "wasmer-compiler-singlepass", - "wasmer-engine-jit", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -2098,7 +2086,6 @@ dependencies = [ "rustc_version", "structopt", "test-generator", - "test-utils", "wasm-common", "wasmer", "wasmer-cache", diff --git a/Cargo.toml b/Cargo.toml index 9b3a91baa..f01b0e011 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,6 @@ anyhow = "1.0" blake3 = "0.3" criterion = "0.3" lazy_static = "1.4" -test-utils = { path = "tests/lib/test-utils" } wasmer-engine-dummy = { path = "tests/lib/engine-dummy" } [features] @@ -104,17 +103,14 @@ experimental-io-devices = [ ] singlepass = [ "wasmer-compiler-singlepass", - "test-utils/singlepass", "compiler", ] cranelift = [ "wasmer-compiler-cranelift", - "test-utils/cranelift", "compiler", ] llvm = [ "wasmer-compiler-llvm", - "test-utils/llvm", "compiler", ] diff --git a/tests/compilers/main.rs b/tests/compilers/main.rs index e9cff7570..521357f90 100644 --- a/tests/compilers/main.rs +++ b/tests/compilers/main.rs @@ -11,3 +11,7 @@ mod multi_value_imports; mod serialize; mod traps; mod utils; +mod wast; + +pub use crate::utils::get_compiler; +pub use crate::wast::run_wast; diff --git a/tests/compilers/utils.rs b/tests/compilers/utils.rs index 378e8b088..16404d8ea 100644 --- a/tests/compilers/utils.rs +++ b/tests/compilers/utils.rs @@ -1,9 +1,9 @@ use std::sync::Arc; -use test_utils::get_compiler_config_from_str; -use wasmer::{Features, FunctionMiddlewareGenerator, Store, Triple, Tunables}; +use wasmer::{CompilerConfig, Features, FunctionMiddlewareGenerator, Store, Triple, Tunables}; +use wasmer_engine::Engine; use wasmer_engine_jit::JIT; -fn get_compiler_str() -> &'static str { +pub fn get_compiler(canonicalize_nans: bool) -> impl CompilerConfig { cfg_if::cfg_if! { if #[cfg(any( all(feature = "test-llvm", any(feature = "test-cranelift", feature = "test-singlepass")), @@ -11,31 +11,37 @@ fn get_compiler_str() -> &'static str { ))] { compile_error!("Only one compiler can be selected") } else if #[cfg(feature = "test-cranelift")] { - "cranelift" + let mut compiler = wasmer_compiler_cranelift::CraneliftConfig::new(); + compiler.canonicalize_nans(canonicalize_nans); + compiler } else if #[cfg(feature = "test-llvm")] { - "llvm" + let mut compiler = wasmer_compiler_llvm::LLVMConfig::new(); + compiler.canonicalize_nans(canonicalize_nans); + compiler } else if #[cfg(feature = "test-singlepass")] { - "singlepass" + let mut compiler = wasmer_compiler_singlepass::SinglepassConfig::new(); + compiler.canonicalize_nans(canonicalize_nans); + compiler } else { compile_error!("No compiler chosen for the tests") } } } -pub fn get_store() -> Store { +pub fn get_engine() -> impl Engine { let mut features = Features::default(); #[cfg(feature = "test-singlepass")] features.multi_value(false); - let try_nan_canonicalization = false; - let compiler_config = - get_compiler_config_from_str(get_compiler_str(), try_nan_canonicalization); - let store = Store::new( - &JIT::new(&*compiler_config) - .tunables(Tunables::for_target) - .features(features) - .engine(), - ); - store + + let compiler_config = get_compiler(false); + JIT::new(&compiler_config) + .tunables(Tunables::for_target) + .features(features) + .engine() +} + +pub fn get_store() -> Store { + Store::new(&get_engine()) } pub fn get_store_with_middlewares>>( @@ -44,22 +50,18 @@ pub fn get_store_with_middlewares Store { - let store = Store::new(&JIT::headless().tunables(Tunables::for_target).engine()); - store + Store::new(&JIT::headless().tunables(Tunables::for_target).engine()) } diff --git a/tests/wast.rs b/tests/compilers/wast.rs similarity index 90% rename from tests/wast.rs rename to tests/compilers/wast.rs index ef6fde3b9..4f8ed92fa 100644 --- a/tests/wast.rs +++ b/tests/compilers/wast.rs @@ -1,8 +1,8 @@ #![cfg(all(feature = "compiler", feature = "engine"))] +use crate::utils::get_compiler; use std::path::Path; use std::sync::Arc; -use test_utils::get_compiler_config_from_str; use wasmer::{Features, Store, Tunables}; #[cfg(feature = "jit")] use wasmer_engine_jit::JIT; @@ -29,7 +29,7 @@ fn native_prefixer(bytes: &[u8]) -> String { format!("{}", hash.to_hex()) } -fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { +pub fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { println!( "Running wast `{}` with the {} compiler", wast_path, compiler @@ -41,9 +41,9 @@ fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { } #[cfg(feature = "test-singlepass")] features.multi_value(false); - let compiler_config = get_compiler_config_from_str(compiler, try_nan_canonicalization); + let compiler_config = get_compiler(true); let store = Store::new( - &JIT::new(&*compiler_config) + &JIT::new(&compiler_config) .tunables(Tunables::for_target) .features(features) .engine(), diff --git a/tests/lib/test-utils/Cargo.toml b/tests/lib/test-utils/Cargo.toml deleted file mode 100644 index 7377b1330..000000000 --- a/tests/lib/test-utils/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "test-utils" -version = "1.0.0-alpha.1" -authors = ["Wasmer Engineering Team "] -description = "wasmer testing utils" -edition = "2018" -publish = false - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -wasmer-compiler = { path = "../../../lib/compiler", version = "1.0.0-alpha.1" } -wasmer-compiler-singlepass = { path = "../../../lib/compiler-singlepass", version = "1.0.0-alpha.1", optional = true } -wasmer-compiler-cranelift = { path = "../../../lib/compiler-cranelift", version = "1.0.0-alpha.1", optional = true } -wasmer-compiler-llvm = { path = "../../../lib/compiler-llvm", version = "1.0.0-alpha.1", optional = true } -wasmer-engine-jit = { path = "../../../lib/engine-jit", version = "1.0.0-alpha.1" } -wasmer = { path = "../../../lib/api", version = "1.0.0-alpha.1", default-features = false } - -[features] -compiler = [] -singlepass = [ - "wasmer-compiler-singlepass", - "compiler", -] -cranelift = [ - "wasmer-compiler-cranelift", - "compiler", -] -llvm = [ - "wasmer-compiler-llvm", - "compiler", -] diff --git a/tests/lib/test-utils/src/lib.rs b/tests/lib/test-utils/src/lib.rs deleted file mode 100644 index 0dc7a1fe1..000000000 --- a/tests/lib/test-utils/src/lib.rs +++ /dev/null @@ -1,76 +0,0 @@ -#![cfg(feature = "compiler")] - -use std::sync::Arc; -use wasmer::{Store, Tunables}; -use wasmer_compiler::{CompilerConfig, Features, Target}; -use wasmer_engine_jit::JIT; - -pub fn get_compiler_config_from_str( - compiler_name: &str, - do_nan_canonicalization: bool, -) -> Box { - match compiler_name { - #[cfg(feature = "singlepass")] - "singlepass" => { - let mut singlepass_config = wasmer_compiler_singlepass::SinglepassConfig::new(); - singlepass_config.canonicalize_nans(do_nan_canonicalization); - Box::new(singlepass_config) - } - #[cfg(feature = "cranelift")] - "cranelift" => { - let mut cranelift_config = wasmer_compiler_cranelift::CraneliftConfig::new(); - cranelift_config.canonicalize_nans(do_nan_canonicalization); - Box::new(cranelift_config) - } - #[cfg(feature = "llvm")] - "llvm" => { - let mut llvm_config = wasmer_compiler_llvm::LLVMConfig::new(); - llvm_config.canonicalize_nans(do_nan_canonicalization); - Box::new(llvm_config) - } - _ => panic!("Compiler {} not supported", compiler_name), - } -} - -/// for when you need a store but you don't care about the details -pub fn get_default_store() -> Store { - let compiler_config = get_compiler_config_from_str("cranelift", false); - Store::new( - &JIT::new(&*compiler_config) - .tunables(Tunables::for_target) - .engine(), - ) -} - -#[cfg(feature = "llvm")] -pub fn get_default_llvm_store() -> Store { - let compiler_config = get_compiler_config_from_str("llvm", false); - Store::new( - &JIT::new(&*compiler_config) - .tunables(Tunables::for_target) - .engine(), - ) -} - -#[cfg(feature = "cranelift")] -pub fn get_default_cranelift_store() -> Store { - let compiler_config = get_compiler_config_from_str("cranelift", false); - Store::new( - &JIT::new(&*compiler_config) - .tunables(Tunables::for_target) - .engine(), - ) -} - -#[cfg(feature = "singlepass")] -pub fn get_default_singlepass_store() -> Store { - let mut features = Features::default(); - features.multi_value(false); - let compiler_config = get_compiler_config_from_str("singlepass", false); - Store::new( - &JIT::new(&*compiler_config) - .tunables(Tunables::for_target) - .features(features) - .engine(), - ) -} From 1002a2765c248b283bfa5cc199ec5de5977fb29b Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 18 Jun 2020 01:34:11 -0700 Subject: [PATCH 10/59] Improved default store --- lib/api/Cargo.toml | 25 ++++++++++++++++- lib/api/src/lib.rs | 23 ++++++++-------- lib/api/src/store.rs | 64 +++++++++++++++++++++++++------------------- 3 files changed, 73 insertions(+), 39 deletions(-) diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index d724faae0..edfec7d0c 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -40,7 +40,7 @@ anyhow = "1.0" maintenance = { status = "actively-developed" } [features] -default = ["wat", "cranelift", "jit"] +default = ["wat", "default-cranelift", "default-jit"] compiler = [ "wasmer-engine-jit/compiler", "wasmer-engine-native/compiler", @@ -66,3 +66,26 @@ llvm = [ "wasmer-compiler-llvm", "compiler", ] +default-compiler = [] +default-engine = [] + +default-singlepass = [ + "singlepass", + "default-compiler" +] +default-cranelift = [ + "cranelift", + "default-compiler" +] +default-llvm = [ + "llvm", + "default-compiler" +] +default-jit = [ + "jit", + "default-engine" +] +default-native = [ + "native", + "default-engine" +] diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 03c7d5b33..98ce3de8d 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -56,20 +56,21 @@ pub use wat::parse_bytes as wat2wasm; // The compilers are mutually exclusive #[cfg(any( - all(feature = "llvm", any(feature = "cranelift", feature = "singlepass")), - all(feature = "cranelift", feature = "singlepass") + all( + feature = "default-llvm", + any(feature = "default-cranelift", feature = "default-singlepass") + ), + all(feature = "default-cranelift", feature = "default-singlepass") ))] compile_error!( - r#"The `singlepass`, `cranelift` and `llvm` features are mutually exclusive. -If you wish to use more than one compiler, you can simply import it from it's own crate. Eg.: + r#"The `default-singlepass`, `default-cranelift` and `default-llvm` features are mutually exclusive. +If you wish to use more than one compiler, you can simply create the own store. Eg.: ``` -use wasmer::{Store, Engine}; -use wasmer_compiler_singlepass::SinglepassConfig; +use wasmer::{Store, JIT, Singlepass}; -// TODO: update this, this is now out of date: -let engine = Engine::new(SinglepassConfig::default()); -let store = Store::new_config(&engine); +let engine = JIT::new(&SinglepassConfig::default()).engine(); +let store = Store::new(&engine); ```"# ); @@ -83,10 +84,10 @@ pub use wasmer_compiler_cranelift::CraneliftConfig; pub use wasmer_compiler_llvm::LLVMConfig; #[cfg(feature = "jit")] -pub use wasmer_engine_jit::JITEngine; +pub use wasmer_engine_jit::{JITArtifact, JITEngine, JIT}; #[cfg(feature = "native")] -pub use wasmer_engine_native::NativeEngine; +pub use wasmer_engine_native::{Native, NativeArtifact, NativeEngine}; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index a0d3da814..6802411f3 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -37,47 +37,57 @@ impl PartialEq for Store { } // We only implement default if we have assigned a default compiler and engine -#[cfg(all(feature = "compiler", feature = "engine"))] +#[cfg(all(feature = "default-compiler", feature = "default-engine"))] impl Default for Store { fn default() -> Store { // We store them on a function that returns to make // sure this function doesn't emit a compile error even if // more than one compiler is enabled. #[allow(unreachable_code)] - fn get_config() -> Box { - #[cfg(feature = "cranelift")] - return Box::new(wasmer_compiler_cranelift::CraneliftConfig::default()); - - #[cfg(feature = "llvm")] - return Box::new(wasmer_compiler_llvm::LLVMConfig::default()); - - #[cfg(feature = "singlepass")] - return Box::new(wasmer_compiler_singlepass::SinglepassConfig::default()); + fn get_config() -> impl CompilerConfig + Send + Sync { + cfg_if::cfg_if! { + if #[cfg(any( + all(feature = "default-llvm", any(feature = "default-cranelift", feature = "default-singlepass")), + all(feature = "default-cranelift", feature = "default-singlepass") + ))] { + compile_error!("Only one compiler can be the default") + } else if #[cfg(feature = "default-cranelift")] { + wasmer_compiler_cranelift::CraneliftConfig::default() + } else if #[cfg(feature = "default-llvm")] { + wasmer_compiler_llvm::LLVMConfig::default() + } else if #[cfg(feature = "default-singlepass")] { + wasmer_compiler_singlepass::SinglepassConfig::default() + } else { + compile_error!("No compiler chosen") + } + } } #[allow(unreachable_code)] - fn get_engine( - config: Box, - ) -> Box { - #[cfg(feature = "jit")] - return Box::new( - wasmer_engine_jit::JIT::new(&*config) - .tunables(Tunables::for_target) - .engine(), - ); - - // #[cfg(feature = "native")] - // return Arc::new(wasmer_engine_native::NativeEngine::new( - // config, - // tunables, - // Default::default(), - // )); + fn get_engine(config: impl CompilerConfig + Send + Sync) -> impl Engine + Send + Sync { + cfg_if::cfg_if! { + if #[cfg(all( + feature = "default-jit", feature = "default-native" + ))] { + compile_error!("Only one engine can be the default") + } else if #[cfg(feature = "default-jit")] { + wasmer_engine_jit::JIT::new(&config) + .tunables(Tunables::for_target) + .engine() + } else if #[cfg(feature = "default-llvm")] { + wasmer_engine_native::Native::new(&config) + .tunables(Tunables::for_target) + .engine() + } else { + compile_error!("No default engine chosen") + } + } } let config = get_config(); let engine = get_engine(config); Store { - engine: engine.into(), + engine: Arc::new(engine), } } } From 422051ebe52419bb4634aecbf786b3a9452e465d Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 18 Jun 2020 01:36:25 -0700 Subject: [PATCH 11/59] Simplified compiler config names --- lib/api/src/lib.rs | 8 ++++---- lib/api/src/store.rs | 6 +++--- lib/c-api/src/wasm_c_api.rs | 6 +++--- lib/compiler-cranelift/src/compiler.rs | 8 ++++---- lib/compiler-cranelift/src/config.rs | 8 ++++---- lib/compiler-cranelift/src/lib.rs | 2 +- .../src/translator/func_translator.rs | 4 ++-- lib/compiler-llvm/src/compiler.rs | 8 ++++---- lib/compiler-llvm/src/config.rs | 10 +++++----- lib/compiler-llvm/src/lib.rs | 2 +- lib/compiler-llvm/src/trampoline/wasm.rs | 6 +++--- lib/compiler-llvm/src/translator/code.rs | 4 ++-- lib/compiler-singlepass/src/codegen_x64.rs | 8 +++----- lib/compiler-singlepass/src/compiler.rs | 8 ++++---- lib/compiler-singlepass/src/config.rs | 10 +++++----- lib/compiler-singlepass/src/lib.rs | 2 +- src/store.rs | 9 ++++----- tests/compilers/utils.rs | 6 +++--- 18 files changed, 56 insertions(+), 59 deletions(-) diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 98ce3de8d..fb37ebfca 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -69,19 +69,19 @@ If you wish to use more than one compiler, you can simply create the own store. ``` use wasmer::{Store, JIT, Singlepass}; -let engine = JIT::new(&SinglepassConfig::default()).engine(); +let engine = JIT::new(&Singlepass::default()).engine(); let store = Store::new(&engine); ```"# ); #[cfg(feature = "singlepass")] -pub use wasmer_compiler_singlepass::SinglepassConfig; +pub use wasmer_compiler_singlepass::Singlepass; #[cfg(feature = "cranelift")] -pub use wasmer_compiler_cranelift::CraneliftConfig; +pub use wasmer_compiler_cranelift::Cranelift; #[cfg(feature = "llvm")] -pub use wasmer_compiler_llvm::LLVMConfig; +pub use wasmer_compiler_llvm::LLVM; #[cfg(feature = "jit")] pub use wasmer_engine_jit::{JITArtifact, JITEngine, JIT}; diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index 6802411f3..ec5916cf6 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -52,11 +52,11 @@ impl Default for Store { ))] { compile_error!("Only one compiler can be the default") } else if #[cfg(feature = "default-cranelift")] { - wasmer_compiler_cranelift::CraneliftConfig::default() + wasmer_compiler_cranelift::Cranelift::default() } else if #[cfg(feature = "default-llvm")] { - wasmer_compiler_llvm::LLVMConfig::default() + wasmer_compiler_llvm::LLVM::default() } else if #[cfg(feature = "default-singlepass")] { - wasmer_compiler_singlepass::SinglepassConfig::default() + wasmer_compiler_singlepass::Singlepass::default() } else { compile_error!("No compiler chosen") } diff --git a/lib/c-api/src/wasm_c_api.rs b/lib/c-api/src/wasm_c_api.rs index ab2bab854..f49d6dcc6 100644 --- a/lib/c-api/src/wasm_c_api.rs +++ b/lib/c-api/src/wasm_c_api.rs @@ -58,11 +58,11 @@ cfg_if! { fn get_default_compiler_config() -> Box { cfg_if! { if #[cfg(feature = "cranelift")] { - Box::new(wasmer_compiler_cranelift::CraneliftConfig::default()) + Box::new(wasmer_compiler_cranelift::Cranelift::default()) } else if #[cfg(feature = "llvm")] { - Box::new(wasmer_compiler_llvm::LLVMConfig::default()) + Box::new(wasmer_compiler_llvm::LLVM::default()) } else if #[cfg(feature = "singlepass")] { - Box::new(wasmer_compiler_singlepass::SinglepassConfig::default()) + Box::new(wasmer_compiler_singlepass::Singlepass::default()) } else { compile_error!("Please enable one of the compiler backends") } diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index ad6b0abd8..0bcf13b1a 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -1,7 +1,7 @@ //! Support for compiling with Cranelift. use crate::address_map::get_function_address_map; -use crate::config::CraneliftConfig; +use crate::config::Cranelift; #[cfg(feature = "unwind")] use crate::dwarf::WriterRelocate; use crate::func_environ::{get_func_name, FuncEnvironment}; @@ -33,19 +33,19 @@ use wasmer_compiler::{ /// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR, /// optimizing it and then translating to assembly. pub struct CraneliftCompiler { - config: CraneliftConfig, + config: Cranelift, } impl CraneliftCompiler { /// Creates a new Cranelift compiler - pub fn new(config: &CraneliftConfig) -> Self { + pub fn new(config: &Cranelift) -> Self { Self { config: config.clone(), } } /// Gets the WebAssembly features for this Compiler - pub fn config(&self) -> &CraneliftConfig { + pub fn config(&self) -> &Cranelift { &self.config } } diff --git a/lib/compiler-cranelift/src/config.rs b/lib/compiler-cranelift/src/config.rs index 1b886f8b8..7588ee6f1 100644 --- a/lib/compiler-cranelift/src/config.rs +++ b/lib/compiler-cranelift/src/config.rs @@ -29,7 +29,7 @@ pub enum OptLevel { /// This structure exposed a builder-like interface and is primarily consumed by /// [`Engine::new()`] #[derive(Clone)] -pub struct CraneliftConfig { +pub struct Cranelift { enable_nan_canonicalization: bool, enable_verifier: bool, enable_simd: bool, @@ -39,7 +39,7 @@ pub struct CraneliftConfig { pub(crate) middlewares: Vec>, } -impl CraneliftConfig { +impl Cranelift { /// Creates a new configuration object with the default configuration /// specified. pub fn new() -> Self { @@ -193,7 +193,7 @@ impl CraneliftConfig { } } -impl CompilerConfig for CraneliftConfig { +impl CompilerConfig for Cranelift { fn enable_pic(&mut self) { self.enable_pic = true; } @@ -209,7 +209,7 @@ impl CompilerConfig for CraneliftConfig { } } -impl Default for CraneliftConfig { +impl Default for Cranelift { fn default() -> Self { Self::new() } diff --git a/lib/compiler-cranelift/src/lib.rs b/lib/compiler-cranelift/src/lib.rs index 702fafbdf..6c9911fe3 100644 --- a/lib/compiler-cranelift/src/lib.rs +++ b/lib/compiler-cranelift/src/lib.rs @@ -57,7 +57,7 @@ mod trampoline; mod translator; pub use crate::compiler::CraneliftCompiler; -pub use crate::config::CraneliftConfig; +pub use crate::config::Cranelift; pub use crate::debug::{ModuleInfoMemoryOffset, ModuleInfoVmctxInfo, ValueLabelsRanges}; pub use crate::trampoline::make_trampoline_function_call; diff --git a/lib/compiler-cranelift/src/translator/func_translator.rs b/lib/compiler-cranelift/src/translator/func_translator.rs index 3f68c6ca4..1550a47ed 100644 --- a/lib/compiler-cranelift/src/translator/func_translator.rs +++ b/lib/compiler-cranelift/src/translator/func_translator.rs @@ -11,7 +11,7 @@ use super::code_translator::{bitcast_arguments, translate_operator, wasm_param_t use super::func_environ::{FuncEnvironment, ReturnMode}; use super::func_state::FuncTranslationState; use super::translation_utils::get_vmctx_value_label; -use crate::config::CraneliftConfig; +use crate::config::Cranelift; use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::{self, Block, InstBuilder, ValueLabel}; use cranelift_codegen::timing; @@ -69,7 +69,7 @@ impl FuncTranslator { func: &mut ir::Function, environ: &mut FE, local_function_index: LocalFunctionIndex, - config: &CraneliftConfig, + config: &Cranelift, ) -> WasmResult<()> { let mut reader = MiddlewareBinaryReader::new_with_offset(code, code_offset); reader.set_middleware_chain( diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index 508a38165..9e9e81366 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -1,4 +1,4 @@ -use crate::config::LLVMConfig; +use crate::config::LLVM; use crate::trampoline::FuncTrampoline; use crate::translator::FuncTranslator; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; @@ -14,19 +14,19 @@ use wasmer_compiler::{ /// A compiler that compiles a WebAssembly module with LLVM, translating the Wasm to LLVM IR, /// optimizing it and then translating to assembly. pub struct LLVMCompiler { - config: LLVMConfig, + config: LLVM, } impl LLVMCompiler { /// Creates a new LLVM compiler - pub fn new(config: &LLVMConfig) -> LLVMCompiler { + pub fn new(config: &LLVM) -> LLVMCompiler { LLVMCompiler { config: config.clone(), } } /// Gets the config for this Compiler - fn config(&self) -> &LLVMConfig { + fn config(&self) -> &LLVM { &self.config } } diff --git a/lib/compiler-llvm/src/config.rs b/lib/compiler-llvm/src/config.rs index 1b3a3c8d3..6b0106fa8 100644 --- a/lib/compiler-llvm/src/config.rs +++ b/lib/compiler-llvm/src/config.rs @@ -39,7 +39,7 @@ pub trait LLVMCallbacks: Send + Sync { } #[derive(Clone)] -pub struct LLVMConfig { +pub struct LLVM { pub(crate) enable_nan_canonicalization: bool, pub(crate) enable_verifier: bool, pub(crate) opt_level: OptimizationLevel, @@ -49,7 +49,7 @@ pub struct LLVMConfig { pub(crate) middlewares: Vec>, } -impl LLVMConfig { +impl LLVM { /// Creates a new configuration object with the default configuration /// specified. pub fn new() -> Self { @@ -176,7 +176,7 @@ impl LLVMConfig { } } -impl CompilerConfig for LLVMConfig { +impl CompilerConfig for LLVM { /// Emit code suitable for dlopen. fn enable_pic(&mut self) { // TODO: although we can emit PIC, the object file parser does not yet @@ -195,8 +195,8 @@ impl CompilerConfig for LLVMConfig { } } -impl Default for LLVMConfig { - fn default() -> LLVMConfig { +impl Default for LLVM { + fn default() -> LLVM { Self::new() } } diff --git a/lib/compiler-llvm/src/lib.rs b/lib/compiler-llvm/src/lib.rs index 76427b427..09160eea5 100644 --- a/lib/compiler-llvm/src/lib.rs +++ b/lib/compiler-llvm/src/lib.rs @@ -22,5 +22,5 @@ mod translator; pub use crate::compiler::LLVMCompiler; pub use crate::config::{ - CompiledFunctionKind, InkwellMemoryBuffer, InkwellModule, LLVMCallbacks, LLVMConfig, + CompiledFunctionKind, InkwellMemoryBuffer, InkwellModule, LLVMCallbacks, LLVM, }; diff --git a/lib/compiler-llvm/src/trampoline/wasm.rs b/lib/compiler-llvm/src/trampoline/wasm.rs index 53643aa63..afa1ba5df 100644 --- a/lib/compiler-llvm/src/trampoline/wasm.rs +++ b/lib/compiler-llvm/src/trampoline/wasm.rs @@ -1,4 +1,4 @@ -use crate::config::{CompiledFunctionKind, LLVMConfig}; +use crate::config::{CompiledFunctionKind, LLVM}; use crate::object_file::load_object_file; use crate::translator::abi::{ func_type_to_llvm, get_vmctx_ptr_param, is_sret, pack_values_for_register_return, @@ -38,7 +38,7 @@ impl FuncTrampoline { pub fn trampoline( &mut self, ty: &FunctionType, - config: &LLVMConfig, + config: &LLVM, ) -> Result { // The function type, used for the callbacks. let function = CompiledFunctionKind::FunctionCallTrampoline(ty.clone()); @@ -127,7 +127,7 @@ impl FuncTrampoline { pub fn dynamic_trampoline( &mut self, ty: &FunctionType, - config: &LLVMConfig, + config: &LLVM, ) -> Result { // The function type, used for the callbacks let function = CompiledFunctionKind::DynamicFunctionTrampoline(ty.clone()); diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index e2a0b8058..2a1c1951d 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -22,7 +22,7 @@ use inkwell::{ }; use smallvec::SmallVec; -use crate::config::{CompiledFunctionKind, LLVMConfig}; +use crate::config::{CompiledFunctionKind, LLVM}; use crate::object_file::load_object_file; use wasm_common::entity::{PrimaryMap, SecondaryMap}; use wasm_common::{ @@ -72,7 +72,7 @@ impl FuncTranslator { module_translation: &ModuleTranslationState, local_func_index: &LocalFunctionIndex, function_body: &FunctionBodyData, - config: &LLVMConfig, + config: &LLVM, memory_plans: &PrimaryMap, _table_plans: &PrimaryMap, func_names: &SecondaryMap, diff --git a/lib/compiler-singlepass/src/codegen_x64.rs b/lib/compiler-singlepass/src/codegen_x64.rs index 8fb10dec0..47279ff71 100644 --- a/lib/compiler-singlepass/src/codegen_x64.rs +++ b/lib/compiler-singlepass/src/codegen_x64.rs @@ -1,6 +1,4 @@ -use crate::{ - common_decl::*, config::SinglepassConfig, emitter_x64::*, machine::Machine, x64_decl::*, -}; +use crate::{common_decl::*, config::Singlepass, emitter_x64::*, machine::Machine, x64_decl::*}; use dynasmrt::{x64::Assembler, DynamicLabel}; use smallvec::{smallvec, SmallVec}; use std::collections::BTreeMap; @@ -32,7 +30,7 @@ pub struct FuncGen<'a> { module: &'a ModuleInfo, /// ModuleInfo compilation config. - config: &'a SinglepassConfig, + config: &'a Singlepass, /// Offsets of vmctx fields. vmoffsets: &'a VMOffsets, @@ -1781,7 +1779,7 @@ impl<'a> FuncGen<'a> { pub fn new( module: &'a ModuleInfo, - config: &'a SinglepassConfig, + config: &'a Singlepass, vmoffsets: &'a VMOffsets, memory_plans: &'a PrimaryMap, _table_plans: &'a PrimaryMap, diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index b5ef983d5..235b8d7ab 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -6,7 +6,7 @@ use crate::codegen_x64::{ gen_import_call_trampoline, gen_std_dynamic_import_trampoline, gen_std_trampoline, CodegenError, FuncGen, }; -use crate::config::SinglepassConfig; +use crate::config::Singlepass; use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; use std::sync::Arc; use wasm_common::entity::{EntityRef, PrimaryMap}; @@ -24,19 +24,19 @@ use wasmer_runtime::{ModuleInfo, TrapCode, VMOffsets}; /// A compiler that compiles a WebAssembly module with Singlepass. /// It does the compilation in one pass pub struct SinglepassCompiler { - config: SinglepassConfig, + config: Singlepass, } impl SinglepassCompiler { /// Creates a new Singlepass compiler - pub fn new(config: &SinglepassConfig) -> Self { + pub fn new(config: &Singlepass) -> Self { Self { config: config.clone(), } } /// Gets the config for this Compiler - fn config(&self) -> &SinglepassConfig { + fn config(&self) -> &Singlepass { &self.config } } diff --git a/lib/compiler-singlepass/src/config.rs b/lib/compiler-singlepass/src/config.rs index 59c4b7b80..53fdac747 100644 --- a/lib/compiler-singlepass/src/config.rs +++ b/lib/compiler-singlepass/src/config.rs @@ -6,14 +6,14 @@ use std::sync::Arc; use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, FunctionMiddlewareGenerator, Target}; #[derive(Clone)] -pub struct SinglepassConfig { +pub struct Singlepass { pub(crate) enable_nan_canonicalization: bool, pub(crate) enable_stack_check: bool, /// The middleware chain. pub(crate) middlewares: Vec>, } -impl SinglepassConfig { +impl Singlepass { /// Creates a new configuration object with the default configuration /// specified. pub fn new() -> Self { @@ -46,7 +46,7 @@ impl SinglepassConfig { } } -impl CompilerConfig for SinglepassConfig { +impl CompilerConfig for Singlepass { fn enable_pic(&mut self) { // Do nothing, since singlepass already emits // PIC code. @@ -63,8 +63,8 @@ impl CompilerConfig for SinglepassConfig { } } -impl Default for SinglepassConfig { - fn default() -> SinglepassConfig { +impl Default for Singlepass { + fn default() -> Singlepass { Self::new() } } diff --git a/lib/compiler-singlepass/src/lib.rs b/lib/compiler-singlepass/src/lib.rs index 15613fe1c..3a890c74a 100644 --- a/lib/compiler-singlepass/src/lib.rs +++ b/lib/compiler-singlepass/src/lib.rs @@ -21,4 +21,4 @@ mod machine; mod x64_decl; pub use crate::compiler::SinglepassCompiler; -pub use crate::config::SinglepassConfig; +pub use crate::config::Singlepass; diff --git a/src/store.rs b/src/store.rs index b49b6bdaf..9c6b25c0a 100644 --- a/src/store.rs +++ b/src/store.rs @@ -180,12 +180,12 @@ impl StoreOptions { CompilerType::Headless => bail!("The headless engine can't be chosen"), #[cfg(feature = "singlepass")] CompilerType::Singlepass => { - let config = wasmer_compiler_singlepass::SinglepassConfig::new(); + let config = wasmer_compiler_singlepass::Singlepass::new(); Box::new(config) } #[cfg(feature = "cranelift")] CompilerType::Cranelift => { - let config = wasmer_compiler_cranelift::CraneliftConfig::new(); + let config = wasmer_compiler_cranelift::Cranelift::new(); Box::new(config) } #[cfg(feature = "llvm")] @@ -194,10 +194,9 @@ impl StoreOptions { use std::io::Write; use wasm_common::entity::EntityRef; use wasmer_compiler_llvm::{ - CompiledFunctionKind, InkwellMemoryBuffer, InkwellModule, LLVMCallbacks, - LLVMConfig, + CompiledFunctionKind, InkwellMemoryBuffer, InkwellModule, LLVMCallbacks, LLVM, }; - let mut config = LLVMConfig::new(); + let mut config = LLVM::new(); struct Callbacks { debug_dir: PathBuf, } diff --git a/tests/compilers/utils.rs b/tests/compilers/utils.rs index 16404d8ea..124e07964 100644 --- a/tests/compilers/utils.rs +++ b/tests/compilers/utils.rs @@ -11,15 +11,15 @@ pub fn get_compiler(canonicalize_nans: bool) -> impl CompilerConfig { ))] { compile_error!("Only one compiler can be selected") } else if #[cfg(feature = "test-cranelift")] { - let mut compiler = wasmer_compiler_cranelift::CraneliftConfig::new(); + let mut compiler = wasmer_compiler_cranelift::Cranelift::new(); compiler.canonicalize_nans(canonicalize_nans); compiler } else if #[cfg(feature = "test-llvm")] { - let mut compiler = wasmer_compiler_llvm::LLVMConfig::new(); + let mut compiler = wasmer_compiler_llvm::LLVM::new(); compiler.canonicalize_nans(canonicalize_nans); compiler } else if #[cfg(feature = "test-singlepass")] { - let mut compiler = wasmer_compiler_singlepass::SinglepassConfig::new(); + let mut compiler = wasmer_compiler_singlepass::Singlepass::new(); compiler.canonicalize_nans(canonicalize_nans); compiler } else { From 769ffebb613c9bf43a807af78cf35c2b4eb1b154 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 18 Jun 2020 02:11:54 -0700 Subject: [PATCH 12/59] Improved feature-generation to be compiler-based --- lib/compiler-cranelift/src/config.rs | 5 +++++ lib/compiler-llvm/src/config.rs | 6 ++++++ lib/compiler-singlepass/src/config.rs | 8 ++++++++ lib/compiler/src/compiler.rs | 3 +++ lib/engine-jit/src/builder.rs | 19 +++++++++++-------- lib/engine-native/src/builder.rs | 19 +++++++++++-------- tests/compilers/utils.rs | 10 ---------- 7 files changed, 44 insertions(+), 26 deletions(-) diff --git a/lib/compiler-cranelift/src/config.rs b/lib/compiler-cranelift/src/config.rs index 7588ee6f1..d5222f0f1 100644 --- a/lib/compiler-cranelift/src/config.rs +++ b/lib/compiler-cranelift/src/config.rs @@ -207,6 +207,11 @@ impl CompilerConfig for Cranelift { fn push_middleware(&mut self, middleware: Arc) { self.middlewares.push(middleware); } + + /// Gets the default features for this compiler in the given target + fn default_features_for_target(&self, _target: &Target) -> Features { + Features::default() + } } impl Default for Cranelift { diff --git a/lib/compiler-llvm/src/config.rs b/lib/compiler-llvm/src/config.rs index 6b0106fa8..35e1b08c4 100644 --- a/lib/compiler-llvm/src/config.rs +++ b/lib/compiler-llvm/src/config.rs @@ -7,6 +7,7 @@ use inkwell::OptimizationLevel; use itertools::Itertools; use std::sync::Arc; use target_lexicon::Architecture; +use wasm_common::Features; use wasm_common::{FunctionType, LocalFunctionIndex}; use wasmer_compiler::{Compiler, CompilerConfig, FunctionMiddlewareGenerator, Target, Triple}; @@ -189,6 +190,11 @@ impl CompilerConfig for LLVM { Box::new(LLVMCompiler::new(&self)) } + /// Gets the default features for this compiler in the given target + fn default_features_for_target(&self, _target: &Target) -> Features { + Features::default() + } + /// Pushes a middleware onto the back of the middleware chain. fn push_middleware(&mut self, middleware: Arc) { self.middlewares.push(middleware); diff --git a/lib/compiler-singlepass/src/config.rs b/lib/compiler-singlepass/src/config.rs index 53fdac747..4398b3c6c 100644 --- a/lib/compiler-singlepass/src/config.rs +++ b/lib/compiler-singlepass/src/config.rs @@ -3,6 +3,7 @@ use crate::compiler::SinglepassCompiler; use std::sync::Arc; +use wasm_common::Features; use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, FunctionMiddlewareGenerator, Target}; #[derive(Clone)] @@ -57,6 +58,13 @@ impl CompilerConfig for Singlepass { Box::new(SinglepassCompiler::new(&self)) } + /// Gets the default features for this compiler in the given target + fn default_features_for_target(&self, target: &Target) -> Features { + let mut features = Features::default(); + features.multi_value(false); + features + } + /// Pushes a middleware onto the back of the middleware chain. fn push_middleware(&mut self, middleware: Arc) { self.middlewares.push(middleware); diff --git a/lib/compiler/src/compiler.rs b/lib/compiler/src/compiler.rs index 13df596a9..2b49d4267 100644 --- a/lib/compiler/src/compiler.rs +++ b/lib/compiler/src/compiler.rs @@ -28,6 +28,9 @@ pub trait CompilerConfig { /// Gets the custom compiler config fn compiler(&self) -> Box; + /// Gets the default features for this compiler in the given target + fn default_features_for_target(&self, target: &Target) -> Features; + /// Pushes a middleware onto the back of the middleware chain. fn push_middleware(&mut self, middleware: Arc); } diff --git a/lib/engine-jit/src/builder.rs b/lib/engine-jit/src/builder.rs index b6cd9abed..eb86b43b9 100644 --- a/lib/engine-jit/src/builder.rs +++ b/lib/engine-jit/src/builder.rs @@ -4,18 +4,18 @@ use wasmer_compiler::{Compiler, CompilerConfig, Features, Target}; use wasmer_engine::Tunables; /// The JIT builder -pub struct JIT { - compiler: Option>, +pub struct JIT<'a> { + compiler_config: Option<&'a dyn CompilerConfig>, tunables_fn: Option Box>>, target: Option, features: Option, } -impl JIT { +impl<'a> JIT<'a> { /// Create a new JIT - pub fn new(compiler_config: &dyn CompilerConfig) -> Self { + pub fn new(compiler_config: &'a dyn CompilerConfig) -> Self { Self { - compiler: Some(compiler_config.compiler()), + compiler_config: Some(compiler_config), target: None, tunables_fn: None, features: None, @@ -25,7 +25,7 @@ impl JIT { /// Create a new headless JIT pub fn headless() -> Self { Self { - compiler: None, + compiler_config: None, target: None, tunables_fn: None, features: None, @@ -62,8 +62,11 @@ impl JIT { .tunables_fn .expect("You need to specify tunables for the JIT"); let tunables: Arc = tunables_fn(&target).into(); - if let Some(compiler) = self.compiler { - let features = self.features.unwrap_or_default(); + if let Some(compiler_config) = self.compiler_config { + let features = self + .features + .unwrap_or_else(|| compiler_config.default_features_for_target(&target)); + let compiler = compiler_config.compiler(); JITEngine::new(compiler, target, tunables, features) } else { JITEngine::headless(tunables) diff --git a/lib/engine-native/src/builder.rs b/lib/engine-native/src/builder.rs index 8ef046ce2..9d925ff0b 100644 --- a/lib/engine-native/src/builder.rs +++ b/lib/engine-native/src/builder.rs @@ -4,19 +4,19 @@ use wasmer_compiler::{Compiler, CompilerConfig, Features, Target}; use wasmer_engine::Tunables; /// The Native builder -pub struct Native { - compiler: Option>, +pub struct Native<'a> { + compiler_config: Option<&'a CompilerConfig>, tunables_fn: Option Box>>, target: Option, features: Option, } -impl Native { +impl<'a> Native<'a> { /// Create a new Native - pub fn new(compiler_config: &mut dyn CompilerConfig) -> Self { + pub fn new(compiler_config: &'a mut dyn CompilerConfig) -> Self { compiler_config.enable_pic(); Self { - compiler: Some(compiler_config.compiler()), + compiler_config: Some(compiler_config), target: None, tunables_fn: None, features: None, @@ -26,7 +26,7 @@ impl Native { /// Create a new headless Native pub fn headless() -> Self { Self { - compiler: None, + compiler_config: None, target: None, tunables_fn: None, features: None, @@ -63,8 +63,11 @@ impl Native { .tunables_fn .expect("You need to specify tunables for the JIT"); let tunables: Arc = tunables_fn(&target).into(); - if let Some(compiler) = self.compiler { - let features = self.features.unwrap_or_default(); + if let Some(compiler_config) = self.compiler_config { + let features = self + .features + .unwrap_or_else(|| compiler_config.default_features_for_target(&target)); + let compiler = compiler_config.compiler(); NativeEngine::new(compiler, target, tunables, features) } else { NativeEngine::headless(tunables) diff --git a/tests/compilers/utils.rs b/tests/compilers/utils.rs index 124e07964..92665e1fa 100644 --- a/tests/compilers/utils.rs +++ b/tests/compilers/utils.rs @@ -29,14 +29,9 @@ pub fn get_compiler(canonicalize_nans: bool) -> impl CompilerConfig { } pub fn get_engine() -> impl Engine { - let mut features = Features::default(); - #[cfg(feature = "test-singlepass")] - features.multi_value(false); - let compiler_config = get_compiler(false); JIT::new(&compiler_config) .tunables(Tunables::for_target) - .features(features) .engine() } @@ -47,17 +42,12 @@ pub fn get_store() -> Store { pub fn get_store_with_middlewares>>( middlewares: I, ) -> Store { - let mut features = Features::default(); - #[cfg(feature = "test-singlepass")] - features.multi_value(false); - let mut compiler_config = get_compiler(false); for x in middlewares { compiler_config.push_middleware(x); } let engine = JIT::new(&compiler_config) .tunables(Tunables::for_target) - .features(features) .engine(); Store::new(&engine) } From b71d929f66ab03bc8747e1e1b4f5c0f6345b04eb Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Jun 2020 17:16:42 +0200 Subject: [PATCH 13/59] doc(runtime) Fix a typo. --- lib/runtime/src/vmcontext.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime/src/vmcontext.rs b/lib/runtime/src/vmcontext.rs index 0c1198bb2..fb544ec9b 100644 --- a/lib/runtime/src/vmcontext.rs +++ b/lib/runtime/src/vmcontext.rs @@ -126,7 +126,7 @@ pub enum VMFunctionKind { /// 2. In the WebAssembly file Static, - /// A function is dynamic when it's address matches the signature: + /// A function is dynamic when its address matches the signature: /// (ctx, &[Type]) -> Vec /// /// This is the default for functions that are defined: From 4da16e0c4826146b8655845d62fe5797b9c2652d Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Jun 2020 17:17:40 +0200 Subject: [PATCH 14/59] chore(wasm-common) Clean up the code. --- lib/wasm-common/src/native.rs | 66 ----------------------------------- 1 file changed, 66 deletions(-) diff --git a/lib/wasm-common/src/native.rs b/lib/wasm-common/src/native.rs index 7c09ad548..ee8b1ed33 100644 --- a/lib/wasm-common/src/native.rs +++ b/lib/wasm-common/src/native.rs @@ -411,16 +411,6 @@ impl WasmTypeList for Infallible { fn wasm_types() -> &'static [Type] { &[] } - - // #[allow(non_snake_case)] - // unsafe fn call( - // self, - // ) -> Result - // where - // Rets: WasmTypeList, - // { - // unreachable!() - // } } macro_rules! impl_traits { @@ -492,66 +482,10 @@ macro_rules! impl_traits { $($x: WasmExternType,)* FN: Fn( $( $x ),* ) -> Rets + 'static { - // println!("WRAP"); - // println!("Struct {:?}", (($( $x ),*) as WasmTypeList).into_c_struct()); - // $( println!("X: {:?}", $x); )* let f: &FN = unsafe { &*(&() as *const () as *const FN) }; f( $( WasmExternType::from_native($x) ),* ).into_c_struct() } wrap::<$( $x, )* Rets, Self> as *const FunctionBody - - // extern fn wrap<$( $x: WasmExternType, )* Rets>(a: &dyn Any, b: &dyn Any, $($x: $x, )* ) -> Rets::CStruct - // where - // Rets: WasmTypeList - // { - // println!("WRAP"); - // let f: &fn( &dyn Any, &dyn Any, $( $x ),* ) -> Rets = unsafe { std::mem::transmute(&()) }; - // f( a, b, $( $x ),* ).into_c_struct() - // } - // wrap::<$( $x, )* Rets> as *const FunctionBody - - // extern fn wrap<$( $x, )* Rets, FN>( - // $($x: <$x as WasmExternType>::Native , )* - // ) -> Rets::CStruct - // where - // $( $x: WasmExternType, )* - // Rets: WasmTypeList, - // FN: Fn($( $x, )*) -> Rets::CStruct, - // { - // // let self_pointer = wrap::<$( $x, )* Rets, FN> as *const FunctionBody; - // let f: &FN = unsafe { - // std::mem::transmute(&()) - // }; - // f($( $x, )*) - // } - // unimplemented!(""); - // extern fn wrap( - // env: &FuncEnv, - // args: Args::Array, - // returns: Rets::Array - // ) - // where - // Args: WasmTypeList, - // Rets: WasmTypeList, - // { - // let self_pointer = wrap:: as *const FunctionBody; - // self_pointer($( $x , )*); - // } - // unimplemented!(""); - // $( $x: WasmExternType, )* - // Rets: WasmTypeList, - // Trap: TrapEarly, - // FN: Fn($( $x, )*) -> Trap, - // { - // let x = |args: <(i32, i32) as WasmTypeList>::Array, rets: &mut <(i32, i32) as WasmTypeList>::Array| { - // let result = func_i32_i32__i32_i32(args[0] as _, args[1] as _); - // rets[0] = result.0 as _; - // rets[1] = result.1 as _; - // }; - - // &self as *const _ as *const FunctionBody - // let x: *const FunctionBody = unsafe { std::mem::transmute(self) }; - // unimplemented!(""); } } From e82a78c383432964e446a73283cf247b5da9fc70 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Jun 2020 17:17:58 +0200 Subject: [PATCH 15/59] feat(wasm-common) Support `Result` as returned type for host functions. We re-use the `TrapEarly` trait to represent a host function that return a Wasm value, or a `Result` of a Wasm value. In this patch, the returned value of the `wrap` functions is `Result`. Note that it will require a large amount of modification on the compilers side. --- lib/wasm-common/src/native.rs | 41 ++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/lib/wasm-common/src/native.rs b/lib/wasm-common/src/native.rs index ee8b1ed33..941c98fd4 100644 --- a/lib/wasm-common/src/native.rs +++ b/lib/wasm-common/src/native.rs @@ -467,49 +467,60 @@ macro_rules! impl_traits { } #[allow(unused_parens)] - impl< $( $x, )* Rets, FN > HostFunction<( $( $x ),* ), Rets, WithoutEnv, ()> for FN + impl< $( $x, )* Rets, Trap, FN > HostFunction<( $( $x ),* ), Rets, WithoutEnv, ()> for FN where $( $x: WasmExternType, )* Rets: WasmTypeList, - FN: Fn($( $x , )*) -> Rets + 'static + Send + Trap: TrapEarly, + FN: Fn($( $x , )*) -> Trap + 'static + Send, { #[allow(non_snake_case)] fn to_raw(self) -> *const FunctionBody { - // unimplemented!(""); - extern fn wrap<$( $x, )* Rets, FN>( _: usize, $($x: $x::Native, )* ) -> Rets::CStruct + extern fn wrap<$( $x, )* Rets, Trap, FN>( _: usize, $($x: $x::Native, )* ) -> Result where Rets: WasmTypeList, - $($x: WasmExternType,)* - FN: Fn( $( $x ),* ) -> Rets + 'static + Trap: TrapEarly, + $( $x: WasmExternType, )* + FN: Fn( $( $x ),* ) -> Trap + 'static { let f: &FN = unsafe { &*(&() as *const () as *const FN) }; - f( $( WasmExternType::from_native($x) ),* ).into_c_struct() + + f( $( WasmExternType::from_native($x) ),* ) + .report() + .map(|results| results.into_c_struct()) } - wrap::<$( $x, )* Rets, Self> as *const FunctionBody + + wrap::<$( $x, )* Rets, Trap, Self> as *const FunctionBody } } #[allow(unused_parens)] - impl< $( $x, )* Rets, FN, T > HostFunction<( $( $x ),* ), Rets, WithEnv, T> for FN + impl< $( $x, )* Rets, Trap, T, FN > HostFunction<( $( $x ),* ), Rets, WithEnv, T> for FN where $( $x: WasmExternType, )* Rets: WasmTypeList, + Trap: TrapEarly, T: Sized, - FN: Fn(&mut T, $( $x , )*) -> Rets + 'static + Send + FN: Fn(&mut T, $( $x , )*) -> Trap + 'static + Send { #[allow(non_snake_case)] fn to_raw(self) -> *const FunctionBody { - extern fn wrap<$( $x, )* Rets, FN, T>( ctx: &mut T, $($x: $x::Native, )* ) -> Rets::CStruct + extern fn wrap<$( $x, )* Rets, Trap, T, FN>( ctx: &mut T, $($x: $x::Native, )* ) -> Result where Rets: WasmTypeList, - $($x: WasmExternType,)* + Trap: TrapEarly, + $( $x: WasmExternType, )* T: Sized, - FN: Fn(&mut T, $( $x ),* ) -> Rets + 'static + FN: Fn(&mut T, $( $x ),* ) -> Trap + 'static { let f: &FN = unsafe { &*(&() as *const () as *const FN) }; - f(ctx, $( WasmExternType::from_native($x) ),* ).into_c_struct() + + f(ctx, $( WasmExternType::from_native($x) ),* ) + .report() + .map(|results| results.into_c_struct()) } - wrap::<$( $x, )* Rets, Self, T> as *const FunctionBody + + wrap::<$( $x, )* Rets, Trap, T, Self> as *const FunctionBody } } }; From a312d9b67de67880b85d74ce68f7c717961ec234 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Jun 2020 17:21:31 +0200 Subject: [PATCH 16/59] feat(wasm-common) Variant of the previous patch: `panic!` in `wrap`. --- lib/wasm-common/src/native.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/wasm-common/src/native.rs b/lib/wasm-common/src/native.rs index 941c98fd4..159818126 100644 --- a/lib/wasm-common/src/native.rs +++ b/lib/wasm-common/src/native.rs @@ -476,7 +476,7 @@ macro_rules! impl_traits { { #[allow(non_snake_case)] fn to_raw(self) -> *const FunctionBody { - extern fn wrap<$( $x, )* Rets, Trap, FN>( _: usize, $($x: $x::Native, )* ) -> Result + extern fn wrap<$( $x, )* Rets, Trap, FN>( _: usize, $($x: $x::Native, )* ) -> Rets::CStruct where Rets: WasmTypeList, Trap: TrapEarly, @@ -484,10 +484,12 @@ macro_rules! impl_traits { FN: Fn( $( $x ),* ) -> Trap + 'static { let f: &FN = unsafe { &*(&() as *const () as *const FN) }; + let results = f( $( WasmExternType::from_native($x) ),* ).report(); - f( $( WasmExternType::from_native($x) ),* ) - .report() - .map(|results| results.into_c_struct()) + match results { + Ok(results) => return results.into_c_struct(), + Err(error) => panic!(error), + } } wrap::<$( $x, )* Rets, Trap, Self> as *const FunctionBody @@ -505,7 +507,7 @@ macro_rules! impl_traits { { #[allow(non_snake_case)] fn to_raw(self) -> *const FunctionBody { - extern fn wrap<$( $x, )* Rets, Trap, T, FN>( ctx: &mut T, $($x: $x::Native, )* ) -> Result + extern fn wrap<$( $x, )* Rets, Trap, T, FN>( ctx: &mut T, $($x: $x::Native, )* ) -> Rets::CStruct where Rets: WasmTypeList, Trap: TrapEarly, @@ -514,10 +516,12 @@ macro_rules! impl_traits { FN: Fn(&mut T, $( $x ),* ) -> Trap + 'static { let f: &FN = unsafe { &*(&() as *const () as *const FN) }; + let results = f(ctx, $( WasmExternType::from_native($x) ),* ).report(); - f(ctx, $( WasmExternType::from_native($x) ),* ) - .report() - .map(|results| results.into_c_struct()) + match results { + Ok(results) => return results.into_c_struct(), + Err(error) => panic!(error), + } } wrap::<$( $x, )* Rets, Trap, T, Self> as *const FunctionBody From 83203a849b8a66294e74361cb3a6aebced7246ef Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 18 Jun 2020 12:08:55 -0700 Subject: [PATCH 17/59] Improved tunables story --- lib/api/src/store.rs | 17 ++++------------- lib/api/src/tunables.rs | 12 +++--------- lib/compiler/src/compiler.rs | 2 +- lib/engine-jit/src/builder.rs | 9 ++++++--- lib/engine-native/src/builder.rs | 9 ++++++--- 5 files changed, 20 insertions(+), 29 deletions(-) diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index ec5916cf6..5ed740a28 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -46,19 +46,14 @@ impl Default for Store { #[allow(unreachable_code)] fn get_config() -> impl CompilerConfig + Send + Sync { cfg_if::cfg_if! { - if #[cfg(any( - all(feature = "default-llvm", any(feature = "default-cranelift", feature = "default-singlepass")), - all(feature = "default-cranelift", feature = "default-singlepass") - ))] { - compile_error!("Only one compiler can be the default") - } else if #[cfg(feature = "default-cranelift")] { + if #[cfg(feature = "default-cranelift")] { wasmer_compiler_cranelift::Cranelift::default() } else if #[cfg(feature = "default-llvm")] { wasmer_compiler_llvm::LLVM::default() } else if #[cfg(feature = "default-singlepass")] { wasmer_compiler_singlepass::Singlepass::default() } else { - compile_error!("No compiler chosen") + compile_error!("No default compiler chosen") } } } @@ -66,15 +61,11 @@ impl Default for Store { #[allow(unreachable_code)] fn get_engine(config: impl CompilerConfig + Send + Sync) -> impl Engine + Send + Sync { cfg_if::cfg_if! { - if #[cfg(all( - feature = "default-jit", feature = "default-native" - ))] { - compile_error!("Only one engine can be the default") - } else if #[cfg(feature = "default-jit")] { + if #[cfg(feature = "default-jit")] { wasmer_engine_jit::JIT::new(&config) .tunables(Tunables::for_target) .engine() - } else if #[cfg(feature = "default-llvm")] { + } else if #[cfg(feature = "default-native")] { wasmer_engine_native::Native::new(&config) .tunables(Tunables::for_target) .engine() diff --git a/lib/api/src/tunables.rs b/lib/api/src/tunables.rs index a581d8b84..dbcdb893b 100644 --- a/lib/api/src/tunables.rs +++ b/lib/api/src/tunables.rs @@ -25,7 +25,7 @@ pub struct Tunables { impl Tunables { /// Get the `Tunables` for a specific Target - pub fn for_target(target: &Target) -> Box { + pub fn for_target(target: &Target) -> Self { let triple = target.triple(); let pointer_width: PointerWidth = triple.pointer_width().unwrap(); let (mut static_memory_bound, mut static_memory_offset_guard_size): (Pages, u64) = @@ -52,11 +52,11 @@ impl Tunables { static_memory_offset_guard_size = min(static_memory_offset_guard_size, 0x10000); } - Box::new(Self { + Self { static_memory_bound, static_memory_offset_guard_size, dynamic_memory_offset_guard_size, - }) + } } } @@ -104,9 +104,3 @@ impl BaseTunables for Tunables { Ok(Arc::new(LinearTable::new(&plan)?)) } } - -// impl Default for Tunables { -// fn default() -> Self { -// Self::for_target(&Target::default()) -// } -// } diff --git a/lib/compiler/src/compiler.rs b/lib/compiler/src/compiler.rs index 2b49d4267..f7e271475 100644 --- a/lib/compiler/src/compiler.rs +++ b/lib/compiler/src/compiler.rs @@ -18,7 +18,7 @@ use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig}; /// The compiler configuration options. pub trait CompilerConfig { - /// Should Position Independent Code (PIC) be enabled. + /// Enable Position Independent Code (PIC). /// /// This is required for shared object generation (Native Engine), /// but will make the JIT Engine to fail, since PIC is not yet diff --git a/lib/engine-jit/src/builder.rs b/lib/engine-jit/src/builder.rs index eb86b43b9..17bbf6619 100644 --- a/lib/engine-jit/src/builder.rs +++ b/lib/engine-jit/src/builder.rs @@ -41,11 +41,14 @@ impl<'a> JIT<'a> { /// Set the tunables constructor function. /// /// It should receive a [`Target`] and return a - pub fn tunables(mut self, tunables_fn: F) -> Self + pub fn tunables(mut self, tunables_fn: F) -> Self where - F: Fn(&Target) -> Box + 'static, + F: Fn(&Target) -> T + 'static, + T: Tunables + Send + Sync + 'static { - self.tunables_fn = Some(Box::new(tunables_fn)); + self.tunables_fn = Some(Box::new(move |target: &Target| { + Box::new(tunables_fn(target)) + })); self } diff --git a/lib/engine-native/src/builder.rs b/lib/engine-native/src/builder.rs index 9d925ff0b..8b629d165 100644 --- a/lib/engine-native/src/builder.rs +++ b/lib/engine-native/src/builder.rs @@ -42,11 +42,14 @@ impl<'a> Native<'a> { /// Set the tunables constructor function. /// /// It should receive a [`Target`] and return a - pub fn tunables(mut self, tunables_fn: F) -> Self + pub fn tunables(mut self, tunables_fn: F) -> Self where - F: Fn(&Target) -> Box + 'static, + F: Fn(&Target) -> T + 'static, + T: Tunables + Send + Sync + 'static { - self.tunables_fn = Some(Box::new(tunables_fn)); + self.tunables_fn = Some(Box::new(move |target: &Target| { + Box::new(tunables_fn(target)) + })); self } From 5273fa0cae4dd75cc0f72143914b8f795435ddfa Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 18 Jun 2020 12:56:38 -0700 Subject: [PATCH 18/59] Moved tunables into Store --- benches/static_and_dynamic_functions.rs | 15 +++++----- lib/api/src/externals/memory.rs | 2 +- lib/api/src/externals/table.rs | 2 +- lib/api/src/module.rs | 12 ++++---- lib/api/src/store.rs | 25 ++++++++++++++-- lib/engine-jit/src/artifact.rs | 10 +++++-- lib/engine-jit/src/builder.rs | 26 ++--------------- lib/engine-jit/src/engine.rs | 39 ++++++++++--------------- lib/engine-native/src/artifact.rs | 10 +++++-- lib/engine-native/src/builder.rs | 25 ++-------------- lib/engine-native/src/engine.rs | 39 ++++++++++--------------- lib/engine/src/engine.rs | 12 +++++--- src/commands/run.rs | 8 ++--- src/store.rs | 14 ++------- tests/compilers/utils.rs | 10 ++----- tests/compilers/wast.rs | 7 +---- tests/lib/engine-dummy/src/artifact.rs | 9 ++++-- tests/lib/engine-dummy/src/engine.rs | 20 ++++++++----- 18 files changed, 118 insertions(+), 167 deletions(-) diff --git a/benches/static_and_dynamic_functions.rs b/benches/static_and_dynamic_functions.rs index 4ce0aa9c2..35ae4926f 100644 --- a/benches/static_and_dynamic_functions.rs +++ b/benches/static_and_dynamic_functions.rs @@ -1,8 +1,7 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use test_utils::get_compiler_config_from_str; use wasmer::*; -use wasmer_engine_jit::JITEngine; +use wasmer_engine_jit::JIT; static BASIC_WAT: &str = r#"(module (func $multiply (import "env" "multiply") (param i32 i32) (result i32)) @@ -151,19 +150,19 @@ pub fn run_basic_dynamic_function(store: &Store, compiler_name: &str, c: &mut Cr fn run_static_benchmarks(c: &mut Criterion) { #[cfg(feature = "llvm")] { - let store = test_utils::get_default_llvm_store(); + let store = Store::new(&JIT::new(&wasmer_compiler_llvm::LLVM::new()).engine()); run_basic_static_function(&store, "llvm", c); } #[cfg(feature = "cranelift")] { - let store = test_utils::get_default_cranelift_store(); + let store = Store::new(&JIT::new(&wasmer_compiler_cranelift::Cranelift::new()).engine()); run_basic_static_function(&store, "cranelift", c); } #[cfg(feature = "singlepass")] { - let store = test_utils::get_default_singlepass_store(); + let store = Store::new(&JIT::new(&wasmer_compiler_singlepass::Singlepass::new()).engine()); run_basic_static_function(&store, "singlepass", c); } } @@ -171,19 +170,19 @@ fn run_static_benchmarks(c: &mut Criterion) { fn run_dynamic_benchmarks(c: &mut Criterion) { #[cfg(feature = "llvm")] { - let store = test_utils::get_default_llvm_store(); + let store = Store::new(&JIT::new(&wasmer_compiler_llvm::LLVM::new()).engine()); run_basic_dynamic_function(&store, "llvm", c); } #[cfg(feature = "cranelift")] { - let store = test_utils::get_default_cranelift_store(); + let store = Store::new(&JIT::new(&wasmer_compiler_cranelift::Cranelift::new()).engine()); run_basic_dynamic_function(&store, "cranelift", c); } #[cfg(feature = "singlepass")] { - let store = test_utils::get_default_singlepass_store(); + let store = Store::new(&JIT::new(&wasmer_compiler_singlepass::Singlepass::new()).engine()); run_basic_dynamic_function(&store, "singlepass", c); } } diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index b387e06a5..c9466abf9 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -19,7 +19,7 @@ pub struct Memory { impl Memory { pub fn new(store: &Store, ty: MemoryType) -> Result { - let tunables = store.engine().tunables(); + let tunables = store.tunables(); let memory_plan = tunables.memory_plan(ty); let memory = tunables.create_memory(memory_plan)?; diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs index ba4c22d28..a327f88f7 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/externals/table.rs @@ -33,7 +33,7 @@ impl Table { /// All the elements in the table will be set to the `init` value. pub fn new(store: &Store, ty: TableType, init: Val) -> Result { let item = init.into_checked_anyfunc(store)?; - let tunables = store.engine().tunables(); + let tunables = store.tunables(); let table_plan = tunables.table_plan(ty); let table = tunables .create_table(table_plan) diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs index a8b633c62..9e66f9be1 100644 --- a/lib/api/src/module.rs +++ b/lib/api/src/module.rs @@ -8,7 +8,7 @@ use thiserror::Error; use wasmer_compiler::CompileError; #[cfg(feature = "wat")] use wasmer_compiler::WasmError; -use wasmer_engine::{Artifact, DeserializeError, Resolver, SerializeError}; +use wasmer_engine::{Artifact, DeserializeError, Resolver, SerializeError, Tunables as _}; use wasmer_runtime::{ExportsIterator, ImportsIterator, InstanceHandle, ModuleInfo}; #[derive(Error, Debug)] @@ -156,7 +156,7 @@ impl Module { } fn compile(store: &Store, binary: &[u8]) -> Result { - let artifact = store.engine().compile(binary)?; + let artifact = store.engine().compile(binary, store.tunables())?; Ok(Self::from_artifact(store, artifact)) } @@ -261,11 +261,9 @@ impl Module { resolver: &dyn Resolver, ) -> Result { unsafe { - let instance_handle = self.artifact.instantiate( - self.store.engine().tunables(), - resolver, - Box::new(()), - )?; + let instance_handle = + self.artifact + .instantiate(self.store.tunables(), resolver, Box::new(()))?; // After the instance handle is created, we need to initialize // the data, call the start function and so. However, if any diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index 5ed740a28..e3db97c6e 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -1,7 +1,7 @@ -#[cfg(all(feature = "compiler", feature = "engine"))] use crate::tunables::Tunables; #[cfg(all(feature = "compiler", feature = "engine"))] use wasmer_compiler::CompilerConfig; +use wasmer_engine::Tunables as BaseTunables; use std::sync::Arc; use wasmer_engine::Engine; @@ -9,6 +9,7 @@ use wasmer_engine::Engine; #[derive(Clone)] pub struct Store { engine: Arc, + tunables: Arc, } impl Store { @@ -18,9 +19,27 @@ impl Store { { Store { engine: engine.cloned(), + tunables: Arc::new(Tunables::for_target(engine.target())), } } + pub fn new_with_tunables( + engine: &E, + tunables: impl BaseTunables + Send + Sync + 'static, + ) -> Store + where + E: Engine + ?Sized, + { + Store { + engine: engine.cloned(), + tunables: Arc::new(tunables), + } + } + + pub fn tunables(&self) -> &dyn BaseTunables { + self.tunables.as_ref() + } + pub fn engine(&self) -> &Arc { &self.engine } @@ -63,11 +82,9 @@ impl Default for Store { cfg_if::cfg_if! { if #[cfg(feature = "default-jit")] { wasmer_engine_jit::JIT::new(&config) - .tunables(Tunables::for_target) .engine() } else if #[cfg(feature = "default-native")] { wasmer_engine_native::Native::new(&config) - .tunables(Tunables::for_target) .engine() } else { compile_error!("No default engine chosen") @@ -77,8 +94,10 @@ impl Default for Store { let config = get_config(); let engine = get_engine(config); + let tunables = Tunables::for_target(engine.target()); Store { engine: Arc::new(engine), + tunables: Arc::new(tunables), } } } diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index 7f9778152..33deae5fd 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -18,6 +18,7 @@ use wasmer_compiler::{CompileError, Features, Triple}; use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment}; use wasmer_engine::{ register_frame_info, Artifact, DeserializeError, GlobalFrameInfoRegistration, SerializeError, + Tunables, }; #[cfg(feature = "compiler")] use wasmer_engine::{Engine, SerializableFunctionFrameInfo}; @@ -43,10 +44,13 @@ impl JITArtifact { /// Compile a data buffer into a `JITArtifact`, which may then be instantiated. #[cfg(feature = "compiler")] - pub fn new(jit: &JITEngine, data: &[u8]) -> Result { + pub fn new( + jit: &JITEngine, + data: &[u8], + tunables: &dyn Tunables, + ) -> Result { let environ = ModuleEnvironment::new(); let mut inner_jit = jit.inner_mut(); - let tunables = jit.tunables(); let features = inner_jit.features(); let translation = environ.translate(data).map_err(CompileError::Wasm)?; @@ -75,7 +79,7 @@ impl JITArtifact { // Compile the Module let compilation = compiler.compile_module( - &inner_jit.target(), + &jit.target(), &compile_info, translation.module_translation.as_ref().unwrap(), translation.function_body_inputs, diff --git a/lib/engine-jit/src/builder.rs b/lib/engine-jit/src/builder.rs index 17bbf6619..c8001122b 100644 --- a/lib/engine-jit/src/builder.rs +++ b/lib/engine-jit/src/builder.rs @@ -1,12 +1,10 @@ use crate::JITEngine; use std::sync::Arc; use wasmer_compiler::{Compiler, CompilerConfig, Features, Target}; -use wasmer_engine::Tunables; /// The JIT builder pub struct JIT<'a> { compiler_config: Option<&'a dyn CompilerConfig>, - tunables_fn: Option Box>>, target: Option, features: Option, } @@ -17,7 +15,6 @@ impl<'a> JIT<'a> { Self { compiler_config: Some(compiler_config), target: None, - tunables_fn: None, features: None, } } @@ -27,7 +24,6 @@ impl<'a> JIT<'a> { Self { compiler_config: None, target: None, - tunables_fn: None, features: None, } } @@ -38,20 +34,6 @@ impl<'a> JIT<'a> { self } - /// Set the tunables constructor function. - /// - /// It should receive a [`Target`] and return a - pub fn tunables(mut self, tunables_fn: F) -> Self - where - F: Fn(&Target) -> T + 'static, - T: Tunables + Send + Sync + 'static - { - self.tunables_fn = Some(Box::new(move |target: &Target| { - Box::new(tunables_fn(target)) - })); - self - } - /// Set the features pub fn features(mut self, features: Features) -> Self { self.features = Some(features); @@ -61,18 +43,14 @@ impl<'a> JIT<'a> { /// Build the `JITEngine` for this configuration pub fn engine(self) -> JITEngine { let target = self.target.unwrap_or_default(); - let tunables_fn = self - .tunables_fn - .expect("You need to specify tunables for the JIT"); - let tunables: Arc = tunables_fn(&target).into(); if let Some(compiler_config) = self.compiler_config { let features = self .features .unwrap_or_else(|| compiler_config.default_features_for_target(&target)); let compiler = compiler_config.compiler(); - JITEngine::new(compiler, target, tunables, features) + JITEngine::new(compiler, target, features) } else { - JITEngine::headless(tunables) + JITEngine::headless() } } } diff --git a/lib/engine-jit/src/engine.rs b/lib/engine-jit/src/engine.rs index ea2d6e77a..880cdadad 100644 --- a/lib/engine-jit/src/engine.rs +++ b/lib/engine-jit/src/engine.rs @@ -21,19 +21,15 @@ use wasmer_runtime::{ #[derive(Clone)] pub struct JITEngine { inner: Arc>, - tunables: Arc, + /// The target for the compiler + target: Arc, engine_id: EngineId, } impl JITEngine { /// Create a new `JITEngine` with the given config #[cfg(feature = "compiler")] - pub fn new( - compiler: Box, - target: Target, - tunables: Arc, - features: Features, - ) -> Self { + pub fn new(compiler: Box, target: Target, features: Features) -> Self { Self { inner: Arc::new(Mutex::new(JITEngineInner { compiler: Some(compiler), @@ -41,9 +37,8 @@ impl JITEngine { code_memory: CodeMemory::new(), signatures: SignatureRegistry::new(), features, - target: Some(target), })), - tunables: tunables, + target: Arc::new(target), engine_id: EngineId::default(), } } @@ -61,7 +56,7 @@ impl JITEngine { /// /// Headless engines can't compile or validate any modules, /// they just take already processed Modules (via `Module::serialize`). - pub fn headless(tunables: Arc) -> Self { + pub fn headless() -> Self { Self { inner: Arc::new(Mutex::new(JITEngineInner { #[cfg(feature = "compiler")] @@ -70,9 +65,8 @@ impl JITEngine { code_memory: CodeMemory::new(), signatures: SignatureRegistry::new(), features: Features::default(), - target: None, })), - tunables, + target: Arc::new(Target::default()), engine_id: EngineId::default(), } } @@ -87,9 +81,9 @@ impl JITEngine { } impl Engine for JITEngine { - /// Get the tunables - fn tunables(&self) -> &dyn Tunables { - &*self.tunables + /// The target + fn target(&self) -> &Target { + &self.target } /// Register a signature @@ -115,8 +109,12 @@ impl Engine for JITEngine { } /// Compile a WebAssembly binary - fn compile(&self, binary: &[u8]) -> Result, CompileError> { - Ok(Arc::new(JITArtifact::new(&self, binary)?)) + fn compile( + &self, + binary: &[u8], + tunables: &dyn Tunables, + ) -> Result, CompileError> { + Ok(Arc::new(JITArtifact::new(&self, binary, tunables)?)) } /// Deserializes a WebAssembly module @@ -142,8 +140,6 @@ pub struct JITEngineInner { function_call_trampolines: HashMap, /// The features to compile the Wasm module with features: Features, - /// The target for the compiler - target: Option, /// The code memory is responsible of publishing the compiled /// functions to memory. code_memory: CodeMemory, @@ -177,11 +173,6 @@ impl JITEngineInner { )) } - /// The target - pub fn target(&self) -> &Target { - &self.target.as_ref().unwrap() - } - /// The Wasm features pub fn features(&self) -> &Features { &self.features diff --git a/lib/engine-native/src/artifact.rs b/lib/engine-native/src/artifact.rs index 464f4fc63..a198f997f 100644 --- a/lib/engine-native/src/artifact.rs +++ b/lib/engine-native/src/artifact.rs @@ -33,6 +33,7 @@ use wasmer_compiler::{CompileError, CompileModuleInfo, Features}; use wasmer_engine::Engine; use wasmer_engine::{ Artifact, DeserializeError, InstantiationError, LinkError, RuntimeError, SerializeError, + Tunables, }; use wasmer_runtime::{MemoryPlan, TablePlan}; use wasmer_runtime::{ModuleInfo, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline}; @@ -95,10 +96,13 @@ impl NativeArtifact { /// Compile a data buffer into a `NativeArtifact`, which may then be instantiated. #[cfg(feature = "compiler")] - pub fn new(engine: &NativeEngine, data: &[u8]) -> Result { + pub fn new( + engine: &NativeEngine, + data: &[u8], + tunables: &dyn Tunables, + ) -> Result { let environ = ModuleEnvironment::new(); let mut engine_inner = engine.inner_mut(); - let tunables = engine.tunables(); let translation = environ.translate(data).map_err(CompileError::Wasm)?; let features = engine_inner.features(); @@ -123,7 +127,7 @@ impl NativeArtifact { }; let compiler = engine_inner.compiler()?; - let target = engine_inner.target(); + let target = engine.target(); // Compile the Module let compilation = compiler.compile_module( diff --git a/lib/engine-native/src/builder.rs b/lib/engine-native/src/builder.rs index 8b629d165..c2f7a1aa2 100644 --- a/lib/engine-native/src/builder.rs +++ b/lib/engine-native/src/builder.rs @@ -6,7 +6,6 @@ use wasmer_engine::Tunables; /// The Native builder pub struct Native<'a> { compiler_config: Option<&'a CompilerConfig>, - tunables_fn: Option Box>>, target: Option, features: Option, } @@ -18,7 +17,6 @@ impl<'a> Native<'a> { Self { compiler_config: Some(compiler_config), target: None, - tunables_fn: None, features: None, } } @@ -28,7 +26,6 @@ impl<'a> Native<'a> { Self { compiler_config: None, target: None, - tunables_fn: None, features: None, } } @@ -39,20 +36,6 @@ impl<'a> Native<'a> { self } - /// Set the tunables constructor function. - /// - /// It should receive a [`Target`] and return a - pub fn tunables(mut self, tunables_fn: F) -> Self - where - F: Fn(&Target) -> T + 'static, - T: Tunables + Send + Sync + 'static - { - self.tunables_fn = Some(Box::new(move |target: &Target| { - Box::new(tunables_fn(target)) - })); - self - } - /// Set the features pub fn features(mut self, features: Features) -> Self { self.features = Some(features); @@ -62,18 +45,14 @@ impl<'a> Native<'a> { /// Build the `NativeEngine` for this configuration pub fn engine(self) -> NativeEngine { let target = self.target.unwrap_or_default(); - let tunables_fn = self - .tunables_fn - .expect("You need to specify tunables for the JIT"); - let tunables: Arc = tunables_fn(&target).into(); if let Some(compiler_config) = self.compiler_config { let features = self .features .unwrap_or_else(|| compiler_config.default_features_for_target(&target)); let compiler = compiler_config.compiler(); - NativeEngine::new(compiler, target, tunables, features) + NativeEngine::new(compiler, target, features) } else { - NativeEngine::headless(tunables) + NativeEngine::headless() } } } diff --git a/lib/engine-native/src/engine.rs b/lib/engine-native/src/engine.rs index c778c5a2e..57acdce08 100644 --- a/lib/engine-native/src/engine.rs +++ b/lib/engine-native/src/engine.rs @@ -16,29 +16,24 @@ use wasmer_runtime::{SignatureRegistry, VMSharedSignatureIndex, VMTrampoline}; #[derive(Clone)] pub struct NativeEngine { inner: Arc>, - tunables: Arc, + /// The target for the compiler + target: Arc, engine_id: EngineId, } impl NativeEngine { /// Create a new `NativeEngine` with the given config #[cfg(feature = "compiler")] - pub fn new( - compiler: Box, - target: Target, - tunables: Arc, - features: Features, - ) -> Self { + pub fn new(compiler: Box, target: Target, features: Features) -> Self { Self { inner: Arc::new(Mutex::new(NativeEngineInner { compiler: Some(compiler), trampolines: HashMap::new(), signatures: SignatureRegistry::new(), prefixer: None, - target: Some(target), features, })), - tunables, + target: Arc::new(target), engine_id: EngineId::default(), } } @@ -56,7 +51,7 @@ impl NativeEngine { /// /// Headless engines can't compile or validate any modules, /// they just take already processed Modules (via `Module::serialize`). - pub fn headless(tunables: Arc) -> Self { + pub fn headless() -> Self { Self { inner: Arc::new(Mutex::new(NativeEngineInner { #[cfg(feature = "compiler")] @@ -64,10 +59,9 @@ impl NativeEngine { trampolines: HashMap::new(), signatures: SignatureRegistry::new(), prefixer: None, - target: None, features: Features::default(), })), - tunables, + target: Arc::new(Target::default()), engine_id: EngineId::default(), } } @@ -100,9 +94,9 @@ impl NativeEngine { } impl Engine for NativeEngine { - /// Get the tunables - fn tunables(&self) -> &dyn Tunables { - &*self.tunables + /// The target + fn target(&self) -> &Target { + &self.target } /// Register a signature @@ -128,8 +122,12 @@ impl Engine for NativeEngine { } /// Compile a WebAssembly binary - fn compile(&self, binary: &[u8]) -> Result, CompileError> { - Ok(Arc::new(NativeArtifact::new(&self, binary)?)) + fn compile( + &self, + binary: &[u8], + tunables: &dyn Tunables, + ) -> Result, CompileError> { + Ok(Arc::new(NativeArtifact::new(&self, binary, tunables)?)) } /// Deserializes a WebAssembly module (binary content of a Shared Object file) @@ -173,8 +171,6 @@ pub struct NativeEngineInner { /// the functions in the shared object generated by the `NativeEngine`, /// so we can assure no collisions. prefixer: Option String + Send>>, - /// The target for the compiler - target: Option, } impl NativeEngineInner { @@ -202,11 +198,6 @@ impl NativeEngineInner { &self.features } - /// The target - pub fn target(&self) -> &Target { - &self.target.as_ref().unwrap() - } - /// Validate the module #[cfg(feature = "compiler")] pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> { diff --git a/lib/engine/src/engine.rs b/lib/engine/src/engine.rs index 0b5eb9dd8..327e7ca4d 100644 --- a/lib/engine/src/engine.rs +++ b/lib/engine/src/engine.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use std::sync::Arc; use wasm_common::FunctionType; -use wasmer_compiler::CompileError; +use wasmer_compiler::{CompileError, Target}; use wasmer_runtime::{VMSharedSignatureIndex, VMTrampoline}; /// A unimplemented Wasmer `Engine`. @@ -16,8 +16,8 @@ use wasmer_runtime::{VMSharedSignatureIndex, VMTrampoline}; /// /// The product that an `Engine` produces and consumes is the [`Artifact`]. pub trait Engine { - /// Get the tunables - fn tunables(&self) -> &dyn Tunables; + /// Gets the target + fn target(&self) -> &Target; /// Register a signature fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex; @@ -32,7 +32,11 @@ pub trait Engine { fn validate(&self, binary: &[u8]) -> Result<(), CompileError>; /// Compile a WebAssembly binary - fn compile(&self, binary: &[u8]) -> Result, CompileError>; + fn compile( + &self, + binary: &[u8], + tunables: &dyn Tunables, + ) -> Result, CompileError>; /// Deserializes a WebAssembly module /// diff --git a/src/commands/run.rs b/src/commands/run.rs index ecc76d669..21231bd1a 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -173,9 +173,7 @@ impl Run { #[cfg(feature = "native")] { if wasmer_engine_native::NativeArtifact::is_deserializable(&contents) { - let engine = wasmer_engine_native::Native::headless() - .tunables(Tunables::for_target) - .engine(); + let engine = wasmer_engine_native::Native::headless().engine(); let store = Store::new(&engine); let module = unsafe { Module::deserialize_from_file(&store, &self.path)? }; return Ok(module); @@ -184,9 +182,7 @@ impl Run { #[cfg(feature = "jit")] { if wasmer_engine_jit::JITArtifact::is_deserializable(&contents) { - let engine = wasmer_engine_jit::JIT::headless() - .tunables(Tunables::for_target) - .engine(); + let engine = wasmer_engine_jit::JIT::headless().engine(); let store = Store::new(&engine); let module = unsafe { Module::deserialize_from_file(&store, &self.path)? }; return Ok(module); diff --git a/src/store.rs b/src/store.rs index 9c6b25c0a..25a0f1cf1 100644 --- a/src/store.rs +++ b/src/store.rs @@ -314,7 +314,6 @@ impl StoreOptions { #[cfg(feature = "jit")] EngineType::JIT => Box::new( wasmer_engine_jit::JIT::new(&*compiler_config) - .tunables(Tunables::for_target) .features(features) .target(target) .engine(), @@ -322,7 +321,6 @@ impl StoreOptions { #[cfg(feature = "native")] EngineType::Native => Box::new( wasmer_engine_native::Native::new(&mut *compiler_config) - .tunables(Tunables::for_target) .target(target) .features(features) .engine(), @@ -364,17 +362,9 @@ impl StoreOptions { let engine_type = self.get_engine()?; let engine: Arc = match engine_type { #[cfg(feature = "jit")] - EngineType::JIT => Arc::new( - wasmer_engine_jit::JIT::headless() - .tunables(Tunables::for_target) - .engine(), - ), + EngineType::JIT => Arc::new(wasmer_engine_jit::JIT::headless().engine()), #[cfg(feature = "native")] - EngineType::Native => Arc::new( - wasmer_engine_native::Native::headless() - .tunables(Tunables::for_target) - .engine(), - ), + EngineType::Native => Arc::new(wasmer_engine_native::Native::headless().engine()), #[cfg(not(all(feature = "jit", feature = "native",)))] engine => bail!( "The `{}` engine is not included in this binary.", diff --git a/tests/compilers/utils.rs b/tests/compilers/utils.rs index 92665e1fa..485873b88 100644 --- a/tests/compilers/utils.rs +++ b/tests/compilers/utils.rs @@ -30,9 +30,7 @@ pub fn get_compiler(canonicalize_nans: bool) -> impl CompilerConfig { pub fn get_engine() -> impl Engine { let compiler_config = get_compiler(false); - JIT::new(&compiler_config) - .tunables(Tunables::for_target) - .engine() + JIT::new(&compiler_config).engine() } pub fn get_store() -> Store { @@ -46,12 +44,10 @@ pub fn get_store_with_middlewares Store { - Store::new(&JIT::headless().tunables(Tunables::for_target).engine()) + Store::new(&JIT::headless().engine()) } diff --git a/tests/compilers/wast.rs b/tests/compilers/wast.rs index 4f8ed92fa..c0a2cf589 100644 --- a/tests/compilers/wast.rs +++ b/tests/compilers/wast.rs @@ -42,12 +42,7 @@ pub fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { #[cfg(feature = "test-singlepass")] features.multi_value(false); let compiler_config = get_compiler(true); - let store = Store::new( - &JIT::new(&compiler_config) - .tunables(Tunables::for_target) - .features(features) - .engine(), - ); + let store = Store::new(&JIT::new(&compiler_config).features(features).engine()); // let mut native = NativeEngine::new(compiler_config, tunables); // native.set_deterministic_prefixer(native_prefixer); // let store = Store::new(&native); diff --git a/tests/lib/engine-dummy/src/artifact.rs b/tests/lib/engine-dummy/src/artifact.rs index bbe6b9b46..dbc1738b4 100644 --- a/tests/lib/engine-dummy/src/artifact.rs +++ b/tests/lib/engine-dummy/src/artifact.rs @@ -13,7 +13,7 @@ use wasm_common::{ use wasmer_compiler::CompileError; #[cfg(feature = "compiler")] use wasmer_compiler::ModuleEnvironment; -use wasmer_engine::{Artifact, DeserializeError, Engine as _, SerializeError}; +use wasmer_engine::{Artifact, DeserializeError, Engine as _, SerializeError, Tunables}; use wasmer_runtime::{ MemoryPlan, ModuleInfo, TablePlan, VMContext, VMFunctionBody, VMSharedSignatureIndex, }; @@ -55,9 +55,12 @@ impl DummyArtifact { #[cfg(feature = "compiler")] /// Compile a data buffer into a `DummyArtifact`, which may then be instantiated. - pub fn new(engine: &DummyEngine, data: &[u8]) -> Result { + pub fn new( + engine: &DummyEngine, + data: &[u8], + tunables: &dyn Tunables, + ) -> Result { let environ = ModuleEnvironment::new(); - let tunables = engine.tunables(); let translation = environ.translate(data).map_err(CompileError::Wasm)?; diff --git a/tests/lib/engine-dummy/src/engine.rs b/tests/lib/engine-dummy/src/engine.rs index 52c16c371..f72a2d520 100644 --- a/tests/lib/engine-dummy/src/engine.rs +++ b/tests/lib/engine-dummy/src/engine.rs @@ -3,7 +3,7 @@ use crate::DummyArtifact; use std::sync::Arc; use wasm_common::FunctionType; -use wasmer_compiler::{CompileError, Features}; +use wasmer_compiler::{CompileError, Features, Target}; use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables}; use wasmer_runtime::{ SignatureRegistry, VMContext, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline, @@ -22,17 +22,17 @@ extern "C" fn dummy_trampoline( pub struct DummyEngine { signatures: Arc, features: Arc, - tunables: Arc, + target: Arc, engine_id: EngineId, } impl DummyEngine { #[cfg(feature = "compiler")] - pub fn new(tunables: impl Tunables + 'static + Send + Sync) -> Self { + pub fn new() -> Self { Self { signatures: Arc::new(SignatureRegistry::new()), - tunables: Arc::new(tunables), features: Arc::new(Default::default()), + target: Arc::new(Default::default()), engine_id: EngineId::default(), } } @@ -44,8 +44,8 @@ impl DummyEngine { impl Engine for DummyEngine { /// Get the tunables - fn tunables(&self) -> &dyn Tunables { - &*self.tunables + fn target(&self) -> &Target { + &self.target } /// Register a signature @@ -92,8 +92,12 @@ impl Engine for DummyEngine { } /// Compile a WebAssembly binary - fn compile(&self, binary: &[u8]) -> Result, CompileError> { - Ok(Arc::new(DummyArtifact::new(&self, &binary)?)) + fn compile( + &self, + binary: &[u8], + tunables: &dyn Tunables, + ) -> Result, CompileError> { + Ok(Arc::new(DummyArtifact::new(&self, binary, tunables)?)) } /// Deserializes a WebAssembly module (binary content of a Shared Object file) From e604d6db49d4985c9d27fec852a1f1a5e6f8fe16 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 18 Jun 2020 13:08:44 -0700 Subject: [PATCH 19/59] Fixed linting --- lib/api/src/module.rs | 2 +- lib/api/src/tunables.rs | 2 +- lib/c-api/src/wasm_c_api.rs | 19 +++++++------------ lib/compiler-cranelift/src/compiler.rs | 8 +++----- lib/compiler-singlepass/src/compiler.rs | 2 +- lib/compiler-singlepass/src/config.rs | 2 +- lib/compiler/src/compiler.rs | 4 +--- lib/engine-jit/src/builder.rs | 3 +-- lib/engine-jit/src/engine.rs | 4 ++-- lib/engine-jit/src/serialize.rs | 8 +------- lib/engine-native/src/builder.rs | 6 ++---- lib/engine-native/src/engine.rs | 4 ++-- lib/engine-native/src/serialize.rs | 8 +------- lib/engine/src/tunables.rs | 1 - src/commands/run.rs | 1 - 15 files changed, 24 insertions(+), 50 deletions(-) diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs index 9e66f9be1..7a481d949 100644 --- a/lib/api/src/module.rs +++ b/lib/api/src/module.rs @@ -8,7 +8,7 @@ use thiserror::Error; use wasmer_compiler::CompileError; #[cfg(feature = "wat")] use wasmer_compiler::WasmError; -use wasmer_engine::{Artifact, DeserializeError, Resolver, SerializeError, Tunables as _}; +use wasmer_engine::{Artifact, DeserializeError, Resolver, SerializeError}; use wasmer_runtime::{ExportsIterator, ImportsIterator, InstanceHandle, ModuleInfo}; #[derive(Error, Debug)] diff --git a/lib/api/src/tunables.rs b/lib/api/src/tunables.rs index dbcdb893b..b16e07018 100644 --- a/lib/api/src/tunables.rs +++ b/lib/api/src/tunables.rs @@ -4,7 +4,7 @@ use crate::{MemoryType, Pages, TableType}; use more_asserts::assert_ge; use std::cmp::min; use std::sync::Arc; -use target_lexicon::{OperatingSystem, PointerWidth, Triple, HOST}; +use target_lexicon::{OperatingSystem, PointerWidth}; use wasmer_compiler::Target; use wasmer_engine::Tunables as BaseTunables; use wasmer_runtime::MemoryError; diff --git a/lib/c-api/src/wasm_c_api.rs b/lib/c-api/src/wasm_c_api.rs index f49d6dcc6..b15f555da 100644 --- a/lib/c-api/src/wasm_c_api.rs +++ b/lib/c-api/src/wasm_c_api.rs @@ -7,15 +7,13 @@ use std::ptr::{self, NonNull}; use std::slice; use std::sync::Arc; -#[cfg(feature = "engine")] -use wasmer::Tunables; use wasmer::{ - Engine, ExportType, Extern, ExternType, Features, Function, FunctionType, Global, GlobalType, - Instance, Memory, MemoryType, Module, Mutability, OrderedResolver, Pages, RuntimeError, Store, - Table, TableType, Val, ValType, + Engine, ExportType, Extern, ExternType, Function, FunctionType, Global, GlobalType, Instance, + Memory, MemoryType, Module, Mutability, OrderedResolver, Pages, RuntimeError, Store, Table, + TableType, Val, ValType, }; #[cfg(feature = "jit")] -use wasmer_engine_jit::JITEngine; +use wasmer_engine_jit::JIT; use crate::error::update_last_error; @@ -48,7 +46,7 @@ pub extern "C" fn wasm_config_new() -> *mut wasm_config_t { #[repr(C)] pub struct wasm_engine_t { - pub(crate) inner: Box, + pub(crate) inner: Arc, } cfg_if! { @@ -72,9 +70,7 @@ cfg_if! { #[no_mangle] pub extern "C" fn wasm_engine_new() -> Box { let compiler_config: Box = get_default_compiler_config(); - let tunables = Tunables::default(); - let features = Features::default(); - let engine: Box = Box::new(JITEngine::new(compiler_config, tunables, features)); + let engine: Arc = Arc::new(JIT::new(&*compiler_config).engine()); Box::new(wasm_engine_t { inner: engine }) } } @@ -82,8 +78,7 @@ cfg_if! { // Headless JIT #[no_mangle] pub extern "C" fn wasm_engine_new() -> Box { - let tunables = Tunables::default(); - let engine: Box = Arc::new(JITEngine::headless(tunables)); + let engine: Arc = Arc::new(JIT::headless().engine()); Box::new(wasm_engine_t { inner: engine }) } } diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index 0bcf13b1a..fd8c68471 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -15,16 +15,14 @@ use crate::translator::{ }; use cranelift_codegen::ir; use cranelift_codegen::print_errors::pretty_error; -use cranelift_codegen::{binemit, isa, Context}; +use cranelift_codegen::{binemit, Context}; #[cfg(feature = "unwind")] use gimli::write::{Address, EhFrame, FrameTable}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use wasm_common::entity::{EntityRef, PrimaryMap}; -use wasm_common::{ - Features, FunctionIndex, LocalFunctionIndex, MemoryIndex, SignatureIndex, TableIndex, -}; +use wasm_common::{FunctionIndex, LocalFunctionIndex, SignatureIndex}; use wasmer_compiler::CompileError; -use wasmer_compiler::{CallingConvention, CompilerConfig, ModuleTranslationState, Target}; +use wasmer_compiler::{CallingConvention, ModuleTranslationState, Target}; use wasmer_compiler::{ Compilation, CompileModuleInfo, CompiledFunction, CompiledFunctionFrameInfo, CompiledFunctionUnwindInfo, Compiler, Dwarf, FunctionBody, FunctionBodyData, SectionIndex, diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index 235b8d7ab..e1f696bf6 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -46,7 +46,7 @@ impl Compiler for SinglepassCompiler { /// associated relocations. fn compile_module( &self, - target: &Target, + _target: &Target, compile_info: &CompileModuleInfo, _module_translation: &ModuleTranslationState, function_body_inputs: PrimaryMap>, diff --git a/lib/compiler-singlepass/src/config.rs b/lib/compiler-singlepass/src/config.rs index 4398b3c6c..c8c6d2ca1 100644 --- a/lib/compiler-singlepass/src/config.rs +++ b/lib/compiler-singlepass/src/config.rs @@ -59,7 +59,7 @@ impl CompilerConfig for Singlepass { } /// Gets the default features for this compiler in the given target - fn default_features_for_target(&self, target: &Target) -> Features { + fn default_features_for_target(&self, _target: &Target) -> Features { let mut features = Features::default(); features.multi_value(false); features diff --git a/lib/compiler/src/compiler.rs b/lib/compiler/src/compiler.rs index f7e271475..32f4c1c65 100644 --- a/lib/compiler/src/compiler.rs +++ b/lib/compiler/src/compiler.rs @@ -11,9 +11,7 @@ use crate::translator::FunctionMiddlewareGenerator; use crate::FunctionBodyData; use crate::ModuleTranslationState; use wasm_common::entity::PrimaryMap; -use wasm_common::{Features, LocalFunctionIndex, MemoryIndex, TableIndex}; -use wasmer_runtime::ModuleInfo; -use wasmer_runtime::{MemoryPlan, TablePlan}; +use wasm_common::{Features, LocalFunctionIndex}; use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig}; /// The compiler configuration options. diff --git a/lib/engine-jit/src/builder.rs b/lib/engine-jit/src/builder.rs index c8001122b..237441f7c 100644 --- a/lib/engine-jit/src/builder.rs +++ b/lib/engine-jit/src/builder.rs @@ -1,6 +1,5 @@ use crate::JITEngine; -use std::sync::Arc; -use wasmer_compiler::{Compiler, CompilerConfig, Features, Target}; +use wasmer_compiler::{CompilerConfig, Features, Target}; /// The JIT builder pub struct JIT<'a> { diff --git a/lib/engine-jit/src/engine.rs b/lib/engine-jit/src/engine.rs index 880cdadad..1a98da780 100644 --- a/lib/engine-jit/src/engine.rs +++ b/lib/engine-jit/src/engine.rs @@ -7,11 +7,11 @@ use std::sync::{Arc, Mutex}; use wasm_common::entity::PrimaryMap; use wasm_common::Features; use wasm_common::{FunctionIndex, FunctionType, LocalFunctionIndex, SignatureIndex}; +#[cfg(feature = "compiler")] +use wasmer_compiler::Compiler; use wasmer_compiler::{ CompileError, CustomSection, CustomSectionProtection, FunctionBody, SectionIndex, Target, }; -#[cfg(feature = "compiler")] -use wasmer_compiler::{Compiler, CompilerConfig}; use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables}; use wasmer_runtime::{ ModuleInfo, SignatureRegistry, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline, diff --git a/lib/engine-jit/src/serialize.rs b/lib/engine-jit/src/serialize.rs index 1aca0a01d..73df96f1e 100644 --- a/lib/engine-jit/src/serialize.rs +++ b/lib/engine-jit/src/serialize.rs @@ -1,17 +1,11 @@ use serde::{Deserialize, Serialize}; -use std::sync::Arc; use wasm_common::entity::PrimaryMap; -use wasm_common::{ - Features, FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, - TableIndex, -}; +use wasm_common::{FunctionIndex, LocalFunctionIndex, OwnedDataInitializer, SignatureIndex}; use wasmer_compiler::{ CompileModuleInfo, CustomSection, Dwarf, FunctionBody, JumpTableOffsets, Relocation, SectionIndex, }; use wasmer_engine::SerializableFunctionFrameInfo; -use wasmer_runtime::ModuleInfo; -use wasmer_runtime::{MemoryPlan, TablePlan}; // /// The serializable function data // #[derive(Serialize, Deserialize)] diff --git a/lib/engine-native/src/builder.rs b/lib/engine-native/src/builder.rs index c2f7a1aa2..2a62d2807 100644 --- a/lib/engine-native/src/builder.rs +++ b/lib/engine-native/src/builder.rs @@ -1,11 +1,9 @@ use crate::NativeEngine; -use std::sync::Arc; -use wasmer_compiler::{Compiler, CompilerConfig, Features, Target}; -use wasmer_engine::Tunables; +use wasmer_compiler::{CompilerConfig, Features, Target}; /// The Native builder pub struct Native<'a> { - compiler_config: Option<&'a CompilerConfig>, + compiler_config: Option<&'a dyn CompilerConfig>, target: Option, features: Option, } diff --git a/lib/engine-native/src/engine.rs b/lib/engine-native/src/engine.rs index 57acdce08..00e10876a 100644 --- a/lib/engine-native/src/engine.rs +++ b/lib/engine-native/src/engine.rs @@ -6,9 +6,9 @@ use std::path::Path; use std::sync::Arc; use std::sync::Mutex; use wasm_common::{Features, FunctionType}; -use wasmer_compiler::{CompileError, Target}; #[cfg(feature = "compiler")] -use wasmer_compiler::{Compiler, CompilerConfig}; +use wasmer_compiler::Compiler; +use wasmer_compiler::{CompileError, Target}; use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables}; use wasmer_runtime::{SignatureRegistry, VMSharedSignatureIndex, VMTrampoline}; diff --git a/lib/engine-native/src/serialize.rs b/lib/engine-native/src/serialize.rs index c9dffa2ab..51c78de40 100644 --- a/lib/engine-native/src/serialize.rs +++ b/lib/engine-native/src/serialize.rs @@ -1,13 +1,7 @@ use serde::{Deserialize, Serialize}; -use std::sync::Arc; use wasm_common::entity::{EntityRef, PrimaryMap}; -use wasm_common::{ - Features, FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, - TableIndex, -}; +use wasm_common::{FunctionIndex, LocalFunctionIndex, OwnedDataInitializer, SignatureIndex}; use wasmer_compiler::{CompileModuleInfo, SectionIndex}; -use wasmer_runtime::ModuleInfo; -use wasmer_runtime::{MemoryPlan, TablePlan}; /// Serializable struct that represents the compiled metadata. #[derive(Serialize, Deserialize, Debug)] diff --git a/lib/engine/src/tunables.rs b/lib/engine/src/tunables.rs index 17b625d45..dad9772e3 100644 --- a/lib/engine/src/tunables.rs +++ b/lib/engine/src/tunables.rs @@ -5,7 +5,6 @@ use wasm_common::{ LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, TableIndex, TableType, }; -use wasmer_compiler::Target; use wasmer_runtime::MemoryError; use wasmer_runtime::{Memory, ModuleInfo, Table, VMGlobalDefinition}; use wasmer_runtime::{MemoryPlan, TablePlan}; diff --git a/src/commands/run.rs b/src/commands/run.rs index 21231bd1a..340da2468 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -5,7 +5,6 @@ use crate::warning; use anyhow::{anyhow, Context, Result}; use std::path::PathBuf; use std::str::FromStr; -use std::sync::Arc; use wasmer::*; #[cfg(feature = "cache")] use wasmer_cache::{Cache, FileSystemCache, WasmHash}; From 895c70712fd31cd646b3923ff11f0a44d176b812 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 18 Jun 2020 13:17:46 -0700 Subject: [PATCH 20/59] Fixed lint error --- src/store.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/store.rs b/src/store.rs index 25a0f1cf1..3efd2649c 100644 --- a/src/store.rs +++ b/src/store.rs @@ -6,6 +6,7 @@ use anyhow::{Error, Result}; use std::path::PathBuf; use std::str::FromStr; use std::string::ToString; +#[cfg(feature = "engine")] use std::sync::Arc; use structopt::StructOpt; use wasmer::*; From 30516b59308eccff0e7ac7e2b0d5b41240a3f471 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 18 Jun 2020 13:24:41 -0700 Subject: [PATCH 21/59] Improved docs --- lib/compiler-cranelift/README.md | 23 ++++++++++++++++++++++- lib/compiler-llvm/README.md | 21 +++++++++++++++++++++ lib/compiler-singlepass/README.md | 21 +++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/compiler-cranelift/README.md b/lib/compiler-cranelift/README.md index 4c6115ada..4db9f4e37 100644 --- a/lib/compiler-cranelift/README.md +++ b/lib/compiler-cranelift/README.md @@ -3,7 +3,28 @@ This is the `wasmer-compiler-cranelift` crate, which contains a compiler implementation based on Cranelift. -We recommend using this compiler only for development proposes. +## Usage + +First, add this crate into your `Cargo.toml` dependencies: + +```toml +wasmer-compiler-cranelift = "1.0.0-alpha.1" +``` + +And then: + +```rust +use wasmer::{Store, JIT}; +use wasmer_compiler_cranelift::Cranelift; + +let compiler = Cranelift::new(); +// Put it into an engine and add it to the store +let store = Store::new(&JIT::new(&compiler).engine()); +``` + +## When to use Cranelift + +We recommend using this compiler crate **only for development proposes**. For production we recommend using `wasmer-compiler-llvm` as it offers a much better runtime speed (50% faster on average). diff --git a/lib/compiler-llvm/README.md b/lib/compiler-llvm/README.md index 979af4d75..4b79d5ebd 100644 --- a/lib/compiler-llvm/README.md +++ b/lib/compiler-llvm/README.md @@ -3,6 +3,27 @@ This is the `wasmer-compiler-llvm` crate, which contains a compiler implementation based on LLVM. +## Usage + +First, add this crate into your `Cargo.toml` dependencies: + +```toml +wasmer-compiler-llvm = "1.0.0-alpha.1" +``` + +And then: + +```rust +use wasmer::{Store, JIT}; +use wasmer_compiler_llvm::LLVM; + +let compiler = LLVM::new(); +// Put it into an engine and add it to the store +let store = Store::new(&JIT::new(&compiler).engine()); +``` + +## When to use LLVM + We recommend using LLVM as the default compiler when running WebAssembly files on any **production** system, as it offers maximum peformance near to native speeds. diff --git a/lib/compiler-singlepass/README.md b/lib/compiler-singlepass/README.md index cc2010b7a..f582fd1ea 100644 --- a/lib/compiler-singlepass/README.md +++ b/lib/compiler-singlepass/README.md @@ -3,6 +3,27 @@ This is the `wasmer-compiler-singlepass` crate, which contains a compiler implementation based on Singlepass. +## Usage + +Add this crate into your `Cargo.toml` dependencies: + +```toml +wasmer-compiler-singlepass = "1.0.0-alpha.1" +``` + +And then: + +```rust +use wasmer::{Store, JIT}; +use wasmer_compiler_singlepass::Singlepass; + +let compiler = Singlepass::new(); +// Put it into an engine and add it to the store +let store = Store::new(&JIT::new(&compiler).engine()); +``` + +## When to use Singlepass + Singlepass is designed to emit compiled code at linear time, as such is not prone to JIT bombs and also offers great compilation performance orders of magnitude faster than `wasmer-compiler-cranelift` and From d27fee87aac281554fd938dabd5b709cc0807911 Mon Sep 17 00:00:00 2001 From: Syrus Date: Thu, 18 Jun 2020 13:40:38 -0700 Subject: [PATCH 22/59] Trying to fix lint issue --- src/store.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store.rs b/src/store.rs index 3efd2649c..0ec16d2b0 100644 --- a/src/store.rs +++ b/src/store.rs @@ -6,7 +6,7 @@ use anyhow::{Error, Result}; use std::path::PathBuf; use std::str::FromStr; use std::string::ToString; -#[cfg(feature = "engine")] +#[allow(unused_imports)] use std::sync::Arc; use structopt::StructOpt; use wasmer::*; From 69ccd86b4ae4310de827c18e1fd694503a3d41be Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 17 Jun 2020 13:09:25 -0700 Subject: [PATCH 23/59] Enable the tests that are failing and will be fixed on this branch. --- tests/compilers/traps.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/compilers/traps.rs b/tests/compilers/traps.rs index 15be523f7..9f7146a0e 100644 --- a/tests/compilers/traps.rs +++ b/tests/compilers/traps.rs @@ -39,7 +39,7 @@ fn test_trap_return() -> Result<()> { } #[test] -#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)] +#[cfg_attr(feature = "test-singlepass", ignore)] fn test_trap_trace() -> Result<()> { let store = get_store(); let wat = r#" @@ -119,7 +119,7 @@ fn test_trap_trace_cb() -> Result<()> { } #[test] -#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)] +#[cfg_attr(feature = "test-singlepass", ignore)] fn test_trap_stack_overflow() -> Result<()> { let store = get_store(); let wat = r#" @@ -150,7 +150,7 @@ fn test_trap_stack_overflow() -> Result<()> { } #[test] -#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)] +#[cfg_attr(feature = "test-singlepass", ignore)] fn trap_display_pretty() -> Result<()> { let store = get_store(); let wat = r#" @@ -183,7 +183,7 @@ RuntimeError: unreachable } #[test] -#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)] +#[cfg_attr(feature = "test-singlepass", ignore)] fn trap_display_multi_module() -> Result<()> { let store = get_store(); let wat = r#" @@ -388,7 +388,7 @@ fn mismatched_arguments() -> Result<()> { } #[test] -#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)] +#[cfg_attr(feature = "test-singlepass", ignore)] fn call_signature_mismatch() -> Result<()> { let store = get_store(); let binary = r#" @@ -419,7 +419,7 @@ RuntimeError: indirect call type mismatch } #[ignore] -#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)] +#[cfg_attr(feature = "test-singlepass", ignore)] fn start_trap_pretty() -> Result<()> { let store = get_store(); let wat = r#" From 52eae576fce5f8cb67f696d38df75f7ff46183fc Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 13:17:58 -0700 Subject: [PATCH 24/59] Record the .eh_frame sections from each .o file. --- lib/compiler-llvm/src/compiler.rs | 2 +- lib/compiler-llvm/src/object_file.rs | 19 ++++++++++++++++++- lib/compiler-llvm/src/trampoline/wasm.rs | 4 ++-- lib/compiler-llvm/src/translator/code.rs | 4 ++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index 9e9e81366..4ea36d2aa 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -83,7 +83,7 @@ impl Compiler for LLVMCompiler { ) .collect::, CompileError>>()? .into_iter() - .map(|(mut compiled_function, function_custom_sections)| { + .map(|(mut compiled_function, function_custom_sections, _eh_frame_section_indices)| { let first_section = module_custom_sections.len() as u32; for (_, custom_section) in function_custom_sections.iter() { // TODO: remove this call to clone() diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs index 79b7c327c..d0ea72422 100644 --- a/lib/compiler-llvm/src/object_file.rs +++ b/lib/compiler-llvm/src/object_file.rs @@ -43,7 +43,7 @@ pub fn load_object_file( root_section: &str, self_referential_relocation_target: Option, mut symbol_name_to_relocation_target: F, -) -> Result<(CompiledFunction, CustomSections), CompileError> +) -> Result<(CompiledFunction, CustomSections, Vec), CompileError> where F: FnMut(&String) -> Result, CompileError>, { @@ -142,6 +142,20 @@ where // the sections we want to include. worklist.push(root_section_index); visited.insert(root_section_index); + + // Also add any .eh_frame sections. + let mut eh_frame_section_indices = vec![]; + // TODO: this constant has been added to goblin, now waiting for release + const SHT_X86_64_UNWIND: u64 = 0x7000_0001; + for (index, shdr) in elf.section_headers.iter().enumerate() { + if shdr.sh_flags & SHT_X86_64_UNWIND != 0 { + let index = ElfSectionIndex::from_usize(index)?; + worklist.push(index); + visited.insert(index); + eh_frame_section_indices.push(index); + } + } + while let Some(section_index) = worklist.pop() { for reloc in reloc_sections .get(§ion_index) @@ -241,6 +255,8 @@ where .map(|(_, v)| v) .collect::>(); + let eh_frame_section_indices = eh_frame_section_indices.iter().map(|index| section_to_custom_section.get(index).map_or_else(|| Err(CompileError::Codegen(format!(".eh_frame section with index={:?} was never loaded", index))), |idx| Ok(*idx))).collect::, _>>()?; + let function_body = FunctionBody { body: section_bytes(root_section_index), unwind_info: None, @@ -271,5 +287,6 @@ where }, }, custom_sections, + eh_frame_section_indices, )) } diff --git a/lib/compiler-llvm/src/trampoline/wasm.rs b/lib/compiler-llvm/src/trampoline/wasm.rs index afa1ba5df..ef2947fb2 100644 --- a/lib/compiler-llvm/src/trampoline/wasm.rs +++ b/lib/compiler-llvm/src/trampoline/wasm.rs @@ -94,7 +94,7 @@ impl FuncTrampoline { } let mem_buf_slice = memory_buffer.as_slice(); - let (function, sections) = + let (function, sections, _eh_frame_section_indices) = load_object_file(mem_buf_slice, FUNCTION_SECTION, None, |name: &String| { Err(CompileError::Codegen(format!( "trampoline generation produced reference to unknown function {}", @@ -175,7 +175,7 @@ impl FuncTrampoline { } let mem_buf_slice = memory_buffer.as_slice(); - let (function, sections) = + let (function, sections, _eh_frame_section_indices) = load_object_file(mem_buf_slice, FUNCTION_SECTION, None, |name: &String| { Err(CompileError::Codegen(format!( "trampoline generation produced reference to unknown function {}", diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 2a1c1951d..e4d228028 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -33,7 +33,7 @@ use wasmer_compiler::wasmparser::{MemoryImmediate, Operator}; use wasmer_compiler::{ to_wasm_error, wptype_to_type, CompileError, CompiledFunction, CustomSections, FunctionBodyData, GenerateMiddlewareChain, MiddlewareBinaryReader, ModuleTranslationState, - RelocationTarget, + RelocationTarget, SectionIndex, }; use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan}; @@ -76,7 +76,7 @@ impl FuncTranslator { memory_plans: &PrimaryMap, _table_plans: &PrimaryMap, func_names: &SecondaryMap, - ) -> Result<(CompiledFunction, CustomSections), CompileError> { + ) -> Result<(CompiledFunction, CustomSections, Vec), CompileError> { // The function type, used for the callbacks. let function = CompiledFunctionKind::Local(*local_func_index); let func_index = wasm_module.func_index(*local_func_index); From 77c3ce5a3321f01e69756689632f5b88f7f26afb Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 00:44:59 -0700 Subject: [PATCH 25/59] Add 8-byte PC-relative relocation. --- lib/compiler/src/relocation.rs | 14 +++++++++++++- lib/engine-jit/src/link.rs | 5 +++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/compiler/src/relocation.rs b/lib/compiler/src/relocation.rs index 32fbb07bf..db181ec04 100644 --- a/lib/compiler/src/relocation.rs +++ b/lib/compiler/src/relocation.rs @@ -29,6 +29,8 @@ pub enum RelocationKind { Abs8, /// x86 PC-relative 4-byte X86PCRel4, + /// x86 PC-relative 8-byte + X86PCRel8, /// x86 PC-relative 4-byte offset to trailing rodata X86PCRelRodata4, /// x86 call to PC-relative 4-byte @@ -62,6 +64,7 @@ impl fmt::Display for RelocationKind { Self::Abs4 => write!(f, "Abs4"), Self::Abs8 => write!(f, "Abs8"), Self::X86PCRel4 => write!(f, "PCRel4"), + Self::X86PCRel8 => write!(f, "PCRel8"), Self::X86PCRelRodata4 => write!(f, "PCRelRodata4"), Self::X86CallPCRel4 => write!(f, "CallPCRel4"), Self::X86CallPLTRel4 => write!(f, "CallPLTRel4"), @@ -112,7 +115,7 @@ impl Relocation { RelocationKind::Abs8 => { let reloc_address = start + self.offset as usize; let reloc_addend = self.addend as isize; - let reloc_abs = (target_func_address) + let reloc_abs = target_func_address .checked_add(reloc_addend as u64) .unwrap(); (reloc_address, reloc_abs) @@ -126,6 +129,15 @@ impl Relocation { .unwrap(); (reloc_address, reloc_delta_u32 as u64) } + RelocationKind::X86PCRel8 => { + let reloc_address = start + self.offset as usize; + let reloc_addend = self.addend as isize; + let reloc_delta = target_func_address + .wrapping_sub(reloc_address as u64) + .checked_add(reloc_addend as u64) + .unwrap(); + (reloc_address, reloc_delta) + } RelocationKind::X86CallPCRel4 | RelocationKind::X86CallPLTRel4 => { let reloc_address = start + self.offset as usize; let reloc_addend = self.addend as isize; diff --git a/lib/engine-jit/src/link.rs b/lib/engine-jit/src/link.rs index f151234db..8b67ac208 100644 --- a/lib/engine-jit/src/link.rs +++ b/lib/engine-jit/src/link.rs @@ -47,6 +47,11 @@ fn apply_relocation( let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64); write_unaligned(reloc_address as *mut u32, reloc_delta as _); }, + #[cfg(target_pointer_width = "64")] + RelocationKind::X86PCRel8 => unsafe { + let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64); + write_unaligned(reloc_address as *mut u64, reloc_delta); + }, #[cfg(target_pointer_width = "32")] RelocationKind::X86CallPCRel4 => unsafe { let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64); From e9d5c7896c675aa6d84a16fda28932d9853eec93 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 14:01:52 -0700 Subject: [PATCH 26/59] Merge .eh_frame without interpretation. Add a 0-CIE to the end. Add unfinished attempt at using gimli, to be deleted but recorded in case we need it in the future. --- lib/compiler-llvm/Cargo.toml | 1 + lib/compiler-llvm/src/compiler.rs | 86 ++++++++++++++++++++++-- lib/compiler-llvm/src/object_file.rs | 26 +++++-- lib/compiler-llvm/src/trampoline/wasm.rs | 8 ++- 4 files changed, 109 insertions(+), 12 deletions(-) diff --git a/lib/compiler-llvm/Cargo.toml b/lib/compiler-llvm/Cargo.toml index be6b72df7..ea49a9836 100644 --- a/lib/compiler-llvm/Cargo.toml +++ b/lib/compiler-llvm/Cargo.toml @@ -20,6 +20,7 @@ libc = { version = "0.2", default-features = false } byteorder = "1" itertools = "0.9" rayon = "1.3" +gimli = { version = "0.21" } [target.'cfg(target_arch = "x86_64")'.dependencies.inkwell] #version = "0.1.0-llvm8sample" diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index 4ea36d2aa..f5706c353 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -6,8 +6,11 @@ use wasm_common::entity::{EntityRef, PrimaryMap, SecondaryMap}; use wasm_common::LocalFunctionIndex; use wasmer_compiler::{ Compilation, CompileError, CompileModuleInfo, Compiler, FunctionBodyData, - ModuleTranslationState, RelocationTarget, SectionIndex, Target, + ModuleTranslationState, RelocationTarget, SectionIndex, Target, CustomSection, + SectionBody, CustomSectionProtection, Dwarf, }; +use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan}; +//use gimli::read::UnwindSection; //use std::sync::{Arc, Mutex}; @@ -31,6 +34,17 @@ impl LLVMCompiler { } } +/* +fn cie_to_cie(read_cie: gimli::read::CommonInformationEntry) -> gimli::write::CommonInformationEntry { + +} + +fn fde_to_fde(read_fde: gimli::read::FrameDescriptionEntry) -> gimli::write::FrameDescriptionEntry { + let mut write_fde = gimli::write::FrameDescriptionEntry::new(?, read_fde.len()) + +} + */ + impl Compiler for LLVMCompiler { /// Compile the module using LLVM, producing a compilation result with /// associated relocations. @@ -57,6 +71,9 @@ impl Compiler for LLVMCompiler { .unwrap_or_else(|| format!("fn{}", func_index.index())); } let mut module_custom_sections = PrimaryMap::new(); + //let mut frame_table = gimli::write::FrameTable::default(); + let mut frame_section_bytes = vec![]; + let mut frame_section_relocations = vec![]; let functions = function_body_inputs .into_iter() .collect::)>>() @@ -83,9 +100,9 @@ impl Compiler for LLVMCompiler { ) .collect::, CompileError>>()? .into_iter() - .map(|(mut compiled_function, function_custom_sections, _eh_frame_section_indices)| { + .map(|(mut compiled_function, function_custom_sections, eh_frame_section_indices)| { let first_section = module_custom_sections.len() as u32; - for (_, custom_section) in function_custom_sections.iter() { + for (section_index, custom_section) in function_custom_sections.iter() { // TODO: remove this call to clone() let mut custom_section = custom_section.clone(); for mut reloc in &mut custom_section.relocations { @@ -95,7 +112,42 @@ impl Compiler for LLVMCompiler { ) } } - module_custom_sections.push(custom_section); + if eh_frame_section_indices.contains(§ion_index) { + // TODO: pull endianness out of target + /* + let eh_frame = gimli::read::EhFrame::new(custom_section.bytes.as_slice(), gimli::NativeEndian); + let base_addresses = gimli::read::BaseAddresses::default(); + let mut entries = eh_frame.entries(&base_addresses); + let mut current_cie = None; + while let Some(entry) = entries.next().unwrap() { + match entry { + gimli::CieOrFde::Cie(cie) => { + current_cie = Some(cie); + frame_table.add_cie(cie.into()); + }, + gimli::CieOrFde::Fde(partial_fde) => { + // TODO: unwrap safety + let fde = partial_fde.parse(current_cie.unwrap()).unwrap(); + frame_table.add_fde(current_cie.unwrap().into(), fde.into()); + } + }; + } + */ + let offset = frame_section_bytes.len() as u32; + for mut reloc in &mut custom_section.relocations { + reloc.offset += offset; + } + frame_section_bytes.extend_from_slice(custom_section.bytes.as_slice()); + frame_section_relocations.extend(custom_section.relocations); + // TODO: we do this to keep the count right, remove it. + module_custom_sections.push(CustomSection { + protection: CustomSectionProtection::Read, + bytes: SectionBody::new_with_vec(vec![]), + relocations: vec![] + }); + } else { + module_custom_sections.push(custom_section); + } } for mut reloc in &mut compiled_function.relocations { if let RelocationTarget::CustomSection(index) = reloc.reloc_target { @@ -108,6 +160,30 @@ impl Compiler for LLVMCompiler { }) .collect::>(); + let dwarf = if !frame_section_bytes.is_empty() { + let dwarf = Some(Dwarf::new(SectionIndex::from_u32(module_custom_sections.len() as u32))); + // Terminator CIE. + frame_section_bytes.extend(vec! + [0x00, 0x00, 0x00, 0x00, // Length + 0x00, 0x00, 0x00, 0x00, // CIE ID + 0x10, // Version (must be 1) + 0x00, // Augmentation data + 0x00, 0x00, + 0xa4, 0x2e, 0x00, 0x00, + 0x30, 0x73, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00]); + module_custom_sections.push(CustomSection { + protection: CustomSectionProtection::Read, + bytes: SectionBody::new_with_vec(frame_section_bytes), + relocations: frame_section_relocations + }); + dwarf + } else { + None + }; + let function_call_trampolines = module .signatures .values() @@ -146,7 +222,7 @@ impl Compiler for LLVMCompiler { module_custom_sections, function_call_trampolines, dynamic_function_trampolines, - None, + dwarf, )) } } diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs index d0ea72422..c4d8ee102 100644 --- a/lib/compiler-llvm/src/object_file.rs +++ b/lib/compiler-llvm/src/object_file.rs @@ -146,15 +146,17 @@ where // Also add any .eh_frame sections. let mut eh_frame_section_indices = vec![]; // TODO: this constant has been added to goblin, now waiting for release - const SHT_X86_64_UNWIND: u64 = 0x7000_0001; + const SHT_X86_64_UNWIND: u32 = 0x7000_0001; for (index, shdr) in elf.section_headers.iter().enumerate() { - if shdr.sh_flags & SHT_X86_64_UNWIND != 0 { + if shdr.sh_type == SHT_X86_64_UNWIND { let index = ElfSectionIndex::from_usize(index)?; worklist.push(index); visited.insert(index); eh_frame_section_indices.push(index); + // This allocates a custom section index for the ELF section. + elf_section_to_target(index); } - } + } while let Some(section_index) = worklist.pop() { for reloc in reloc_sections @@ -166,6 +168,7 @@ where // TODO: these constants are not per-arch, we'll need to // make the whole match per-arch. goblin::elf::reloc::R_X86_64_64 => RelocationKind::Abs8, + goblin::elf::reloc::R_X86_64_PC64 => RelocationKind::X86PCRel8, goblin::elf::reloc::R_X86_64_GOT64 => { return Err(CompileError::Codegen( "unimplemented PIC relocation R_X86_64_GOT64".into(), @@ -234,6 +237,21 @@ where } } + let eh_frame_section_indices = eh_frame_section_indices + .iter() + .map(|index| { + section_to_custom_section.get(index).map_or_else( + || { + Err(CompileError::Codegen(format!( + ".eh_frame section with index={:?} was never loaded", + index + ))) + }, + |idx| Ok(*idx), + ) + }) + .collect::, _>>()?; + let mut custom_sections = section_to_custom_section .iter() .map(|(elf_section_index, custom_section_index)| { @@ -255,8 +273,6 @@ where .map(|(_, v)| v) .collect::>(); - let eh_frame_section_indices = eh_frame_section_indices.iter().map(|index| section_to_custom_section.get(index).map_or_else(|| Err(CompileError::Codegen(format!(".eh_frame section with index={:?} was never loaded", index))), |idx| Ok(*idx))).collect::, _>>()?; - let function_body = FunctionBody { body: section_bytes(root_section_index), unwind_info: None, diff --git a/lib/compiler-llvm/src/trampoline/wasm.rs b/lib/compiler-llvm/src/trampoline/wasm.rs index ef2947fb2..9b90e67d0 100644 --- a/lib/compiler-llvm/src/trampoline/wasm.rs +++ b/lib/compiler-llvm/src/trampoline/wasm.rs @@ -94,18 +94,20 @@ impl FuncTrampoline { } let mem_buf_slice = memory_buffer.as_slice(); - let (function, sections, _eh_frame_section_indices) = + let (function, _sections, _eh_frame_section_indices) = load_object_file(mem_buf_slice, FUNCTION_SECTION, None, |name: &String| { Err(CompileError::Codegen(format!( "trampoline generation produced reference to unknown function {}", name ))) })?; + /* if !sections.is_empty() { return Err(CompileError::Codegen( "trampoline generation produced custom sections".into(), )); } + */ if !function.relocations.is_empty() { return Err(CompileError::Codegen( "trampoline generation produced relocations".into(), @@ -175,18 +177,20 @@ impl FuncTrampoline { } let mem_buf_slice = memory_buffer.as_slice(); - let (function, sections, _eh_frame_section_indices) = + let (function, _sections, _eh_frame_section_indices) = load_object_file(mem_buf_slice, FUNCTION_SECTION, None, |name: &String| { Err(CompileError::Codegen(format!( "trampoline generation produced reference to unknown function {}", name ))) })?; + /* if !sections.is_empty() { return Err(CompileError::Codegen( "trampoline generation produced custom sections".into(), )); } + */ if !function.relocations.is_empty() { return Err(CompileError::Codegen( "trampoline generation produced relocations".into(), From 8d11d3fc5275f63ec2e1733025a12005568cfff9 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 14:04:50 -0700 Subject: [PATCH 27/59] Remove gimli leftovers. --- lib/compiler-llvm/Cargo.toml | 1 - lib/compiler-llvm/src/compiler.rs | 33 ------------------------------- 2 files changed, 34 deletions(-) diff --git a/lib/compiler-llvm/Cargo.toml b/lib/compiler-llvm/Cargo.toml index ea49a9836..be6b72df7 100644 --- a/lib/compiler-llvm/Cargo.toml +++ b/lib/compiler-llvm/Cargo.toml @@ -20,7 +20,6 @@ libc = { version = "0.2", default-features = false } byteorder = "1" itertools = "0.9" rayon = "1.3" -gimli = { version = "0.21" } [target.'cfg(target_arch = "x86_64")'.dependencies.inkwell] #version = "0.1.0-llvm8sample" diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index f5706c353..bea4045cb 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -10,7 +10,6 @@ use wasmer_compiler::{ SectionBody, CustomSectionProtection, Dwarf, }; use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan}; -//use gimli::read::UnwindSection; //use std::sync::{Arc, Mutex}; @@ -34,17 +33,6 @@ impl LLVMCompiler { } } -/* -fn cie_to_cie(read_cie: gimli::read::CommonInformationEntry) -> gimli::write::CommonInformationEntry { - -} - -fn fde_to_fde(read_fde: gimli::read::FrameDescriptionEntry) -> gimli::write::FrameDescriptionEntry { - let mut write_fde = gimli::write::FrameDescriptionEntry::new(?, read_fde.len()) - -} - */ - impl Compiler for LLVMCompiler { /// Compile the module using LLVM, producing a compilation result with /// associated relocations. @@ -71,7 +59,6 @@ impl Compiler for LLVMCompiler { .unwrap_or_else(|| format!("fn{}", func_index.index())); } let mut module_custom_sections = PrimaryMap::new(); - //let mut frame_table = gimli::write::FrameTable::default(); let mut frame_section_bytes = vec![]; let mut frame_section_relocations = vec![]; let functions = function_body_inputs @@ -113,26 +100,6 @@ impl Compiler for LLVMCompiler { } } if eh_frame_section_indices.contains(§ion_index) { - // TODO: pull endianness out of target - /* - let eh_frame = gimli::read::EhFrame::new(custom_section.bytes.as_slice(), gimli::NativeEndian); - let base_addresses = gimli::read::BaseAddresses::default(); - let mut entries = eh_frame.entries(&base_addresses); - let mut current_cie = None; - while let Some(entry) = entries.next().unwrap() { - match entry { - gimli::CieOrFde::Cie(cie) => { - current_cie = Some(cie); - frame_table.add_cie(cie.into()); - }, - gimli::CieOrFde::Fde(partial_fde) => { - // TODO: unwrap safety - let fde = partial_fde.parse(current_cie.unwrap()).unwrap(); - frame_table.add_fde(current_cie.unwrap().into(), fde.into()); - } - }; - } - */ let offset = frame_section_bytes.len() as u32; for mut reloc in &mut custom_section.relocations { reloc.offset += offset; From 21827d8f80d71a14b4d51005dee3a09ab6643e94 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 14:39:53 -0700 Subject: [PATCH 28/59] These three tests rely on sourcemap information too, which we aren't adding in this branch. --- tests/compilers/traps.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/compilers/traps.rs b/tests/compilers/traps.rs index 9f7146a0e..5af1e499c 100644 --- a/tests/compilers/traps.rs +++ b/tests/compilers/traps.rs @@ -150,7 +150,7 @@ fn test_trap_stack_overflow() -> Result<()> { } #[test] -#[cfg_attr(feature = "test-singlepass", ignore)] +#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)] fn trap_display_pretty() -> Result<()> { let store = get_store(); let wat = r#" @@ -183,7 +183,7 @@ RuntimeError: unreachable } #[test] -#[cfg_attr(feature = "test-singlepass", ignore)] +#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)] fn trap_display_multi_module() -> Result<()> { let store = get_store(); let wat = r#" @@ -388,7 +388,7 @@ fn mismatched_arguments() -> Result<()> { } #[test] -#[cfg_attr(feature = "test-singlepass", ignore)] +#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)] fn call_signature_mismatch() -> Result<()> { let store = get_store(); let binary = r#" From 310ac6b44c22253430886110489403250d0f83d8 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 14:40:20 -0700 Subject: [PATCH 29/59] Shrink the 0-length CIE. The previous one came from /bin/ls on my machine, the new one is based on the CIE description in the DWARF 3 spec (the LSB description leaves out too much detail, like the size of the version field). Formatting cleanup. --- lib/compiler-llvm/src/compiler.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index bea4045cb..06d40283a 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -5,9 +5,9 @@ use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use wasm_common::entity::{EntityRef, PrimaryMap, SecondaryMap}; use wasm_common::LocalFunctionIndex; use wasmer_compiler::{ - Compilation, CompileError, CompileModuleInfo, Compiler, FunctionBodyData, - ModuleTranslationState, RelocationTarget, SectionIndex, Target, CustomSection, - SectionBody, CustomSectionProtection, Dwarf, + Compilation, CompileError, CompileModuleInfo, Compiler, CustomSection, CustomSectionProtection, + Dwarf, FunctionBodyData, ModuleTranslationState, RelocationTarget, SectionBody, SectionIndex, + Target, }; use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan}; @@ -129,18 +129,17 @@ impl Compiler for LLVMCompiler { let dwarf = if !frame_section_bytes.is_empty() { let dwarf = Some(Dwarf::new(SectionIndex::from_u32(module_custom_sections.len() as u32))); - // Terminator CIE. - frame_section_bytes.extend(vec! - [0x00, 0x00, 0x00, 0x00, // Length - 0x00, 0x00, 0x00, 0x00, // CIE ID - 0x10, // Version (must be 1) - 0x00, // Augmentation data - 0x00, 0x00, - 0xa4, 0x2e, 0x00, 0x00, - 0x30, 0x73, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00]); + // Terminating zero-length CIE. + frame_section_bytes.extend(vec![ + 0x00, 0x00, 0x00, 0x00, // Length + 0x00, 0x00, 0x00, 0x00, // CIE ID + 0x10, // Version (must be 1) + 0x00, // Augmentation data + 0x00, // Code alignment factor + 0x00, // Data alignment factor + 0x00, // Return address register + 0x00, 0x00, 0x00, // Padding to a multiple of 4 bytes + ]); module_custom_sections.push(CustomSection { protection: CustomSectionProtection::Read, bytes: SectionBody::new_with_vec(frame_section_bytes), From 54c7b6f8760ec00643ba395e0688b931cd429a7b Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 15:32:50 -0700 Subject: [PATCH 30/59] In trampoline generation, ensure all custom sections are eh frames. .eh_frames may refer to the trampoline, but it is impossible to encode such a relocation. The optional relocation "self-referential" target is replaced with a better named mandatory argument. The value will be discarded in trampoline generation with the rest of the .eh_frame. --- lib/compiler-llvm/src/object_file.rs | 16 ++---- lib/compiler-llvm/src/trampoline/wasm.rs | 62 ++++++++++++++++++------ lib/compiler-llvm/src/translator/code.rs | 2 +- 3 files changed, 52 insertions(+), 28 deletions(-) diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs index c4d8ee102..976e1503e 100644 --- a/lib/compiler-llvm/src/object_file.rs +++ b/lib/compiler-llvm/src/object_file.rs @@ -41,7 +41,7 @@ fn map_goblin_err(error: goblin::error::Error) -> CompileError { pub fn load_object_file( contents: &[u8], root_section: &str, - self_referential_relocation_target: Option, + root_section_reloc_target: RelocationTarget, mut symbol_name_to_relocation_target: F, ) -> Result<(CompiledFunction, CustomSections, Vec), CompileError> where @@ -102,9 +102,7 @@ where let mut section_to_custom_section = HashMap::new(); - if let Some(reloc_target) = self_referential_relocation_target { - section_targets.insert(root_section_index, reloc_target); - }; + section_targets.insert(root_section_index, root_section_reloc_target); let mut next_custom_section: u32 = 0; let mut elf_section_to_target = |elf_section_index: ElfSectionIndex| { @@ -197,17 +195,13 @@ where )) })?; let elf_target_section = ElfSectionIndex::from_usize(elf_target.st_shndx)?; - let reloc_target = if elf_target.st_type() == goblin::elf::sym::STT_SECTION { + let reloc_target = if elf_target_section == root_section_index { + root_section_reloc_target + } else if elf_target.st_type() == goblin::elf::sym::STT_SECTION { if visited.insert(elf_target_section) { worklist.push(elf_target_section); } elf_section_to_target(elf_target_section) - } else if elf_target.st_type() == goblin::elf::sym::STT_FUNC - && elf_target_section == root_section_index - && self_referential_relocation_target.is_some() - { - // This is a function referencing its own byte stream. - self_referential_relocation_target.unwrap() } else if elf_target.st_type() == goblin::elf::sym::STT_NOTYPE && elf_target_section.is_undef() { diff --git a/lib/compiler-llvm/src/trampoline/wasm.rs b/lib/compiler-llvm/src/trampoline/wasm.rs index 9b90e67d0..8d2fad71c 100644 --- a/lib/compiler-llvm/src/trampoline/wasm.rs +++ b/lib/compiler-llvm/src/trampoline/wasm.rs @@ -17,8 +17,8 @@ use inkwell::{ }; use std::cmp; use std::convert::TryInto; -use wasm_common::{FunctionType, Type}; -use wasmer_compiler::{CompileError, FunctionBody}; +use wasm_common::{FunctionType, LocalFunctionIndex, Type}; +use wasmer_compiler::{CompileError, FunctionBody, RelocationTarget}; pub struct FuncTrampoline { ctx: Context, @@ -94,20 +94,35 @@ impl FuncTrampoline { } let mem_buf_slice = memory_buffer.as_slice(); - let (function, _sections, _eh_frame_section_indices) = - load_object_file(mem_buf_slice, FUNCTION_SECTION, None, |name: &String| { + let (function, sections, eh_frame_section_indices) = load_object_file( + mem_buf_slice, + FUNCTION_SECTION, + RelocationTarget::LocalFunc(LocalFunctionIndex::from_u32(0)), + |name: &String| { Err(CompileError::Codegen(format!( "trampoline generation produced reference to unknown function {}", name ))) - })?; - /* - if !sections.is_empty() { + }, + )?; + let mut all_sections_are_eh_sections = true; + if eh_frame_section_indices.len() != sections.len() { + all_sections_are_eh_sections = false; + } else { + let mut eh_frame_section_indices = eh_frame_section_indices.clone(); + eh_frame_section_indices.sort_unstable(); + for (idx, section_idx) in eh_frame_section_indices.iter().enumerate() { + if idx as u32 != section_idx.as_u32() { + all_sections_are_eh_sections = false; + break; + } + } + } + if !all_sections_are_eh_sections { return Err(CompileError::Codegen( - "trampoline generation produced custom sections".into(), + "trampoline generation produced non-eh custom sections".into(), )); } - */ if !function.relocations.is_empty() { return Err(CompileError::Codegen( "trampoline generation produced relocations".into(), @@ -177,20 +192,35 @@ impl FuncTrampoline { } let mem_buf_slice = memory_buffer.as_slice(); - let (function, _sections, _eh_frame_section_indices) = - load_object_file(mem_buf_slice, FUNCTION_SECTION, None, |name: &String| { + let (function, sections, eh_frame_section_indices) = load_object_file( + mem_buf_slice, + FUNCTION_SECTION, + RelocationTarget::LocalFunc(LocalFunctionIndex::from_u32(0)), + |name: &String| { Err(CompileError::Codegen(format!( "trampoline generation produced reference to unknown function {}", name ))) - })?; - /* - if !sections.is_empty() { + }, + )?; + let mut all_sections_are_eh_sections = true; + if eh_frame_section_indices.len() != sections.len() { + all_sections_are_eh_sections = false; + } else { + let mut eh_frame_section_indices = eh_frame_section_indices.clone(); + eh_frame_section_indices.sort_unstable(); + for (idx, section_idx) in eh_frame_section_indices.iter().enumerate() { + if idx as u32 != section_idx.as_u32() { + all_sections_are_eh_sections = false; + break; + } + } + } + if !all_sections_are_eh_sections { return Err(CompileError::Codegen( - "trampoline generation produced custom sections".into(), + "trampoline generation produced non-eh custom sections".into(), )); } - */ if !function.relocations.is_empty() { return Err(CompileError::Codegen( "trampoline generation produced relocations".into(), diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index e4d228028..7a1f3b46e 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -274,7 +274,7 @@ impl FuncTranslator { load_object_file( mem_buf_slice, ".wasmer_function", - Some(RelocationTarget::LocalFunc(*local_func_index)), + RelocationTarget::LocalFunc(*local_func_index), |name: &String| { if let Some((index, _)) = func_names .iter() From 8edaf2d61759b3870c55d4c19a57cddae7159467 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 15:46:11 -0700 Subject: [PATCH 31/59] cargo fmt --- lib/compiler-llvm/src/compiler.rs | 72 +++++++++++++++------------- lib/compiler-llvm/src/object_file.rs | 2 +- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index 06d40283a..f879d0f1c 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -87,48 +87,52 @@ impl Compiler for LLVMCompiler { ) .collect::, CompileError>>()? .into_iter() - .map(|(mut compiled_function, function_custom_sections, eh_frame_section_indices)| { - let first_section = module_custom_sections.len() as u32; - for (section_index, custom_section) in function_custom_sections.iter() { - // TODO: remove this call to clone() - let mut custom_section = custom_section.clone(); - for mut reloc in &mut custom_section.relocations { + .map( + |(mut compiled_function, function_custom_sections, eh_frame_section_indices)| { + let first_section = module_custom_sections.len() as u32; + for (section_index, custom_section) in function_custom_sections.iter() { + // TODO: remove this call to clone() + let mut custom_section = custom_section.clone(); + for mut reloc in &mut custom_section.relocations { + if let RelocationTarget::CustomSection(index) = reloc.reloc_target { + reloc.reloc_target = RelocationTarget::CustomSection( + SectionIndex::from_u32(first_section + index.as_u32()), + ) + } + } + if eh_frame_section_indices.contains(§ion_index) { + let offset = frame_section_bytes.len() as u32; + for mut reloc in &mut custom_section.relocations { + reloc.offset += offset; + } + frame_section_bytes.extend_from_slice(custom_section.bytes.as_slice()); + frame_section_relocations.extend(custom_section.relocations); + // TODO: we do this to keep the count right, remove it. + module_custom_sections.push(CustomSection { + protection: CustomSectionProtection::Read, + bytes: SectionBody::new_with_vec(vec![]), + relocations: vec![], + }); + } else { + module_custom_sections.push(custom_section); + } + } + for mut reloc in &mut compiled_function.relocations { if let RelocationTarget::CustomSection(index) = reloc.reloc_target { reloc.reloc_target = RelocationTarget::CustomSection( SectionIndex::from_u32(first_section + index.as_u32()), ) } } - if eh_frame_section_indices.contains(§ion_index) { - let offset = frame_section_bytes.len() as u32; - for mut reloc in &mut custom_section.relocations { - reloc.offset += offset; - } - frame_section_bytes.extend_from_slice(custom_section.bytes.as_slice()); - frame_section_relocations.extend(custom_section.relocations); - // TODO: we do this to keep the count right, remove it. - module_custom_sections.push(CustomSection { - protection: CustomSectionProtection::Read, - bytes: SectionBody::new_with_vec(vec![]), - relocations: vec![] - }); - } else { - module_custom_sections.push(custom_section); - } - } - for mut reloc in &mut compiled_function.relocations { - if let RelocationTarget::CustomSection(index) = reloc.reloc_target { - reloc.reloc_target = RelocationTarget::CustomSection( - SectionIndex::from_u32(first_section + index.as_u32()), - ) - } - } - compiled_function - }) + compiled_function + }, + ) .collect::>(); let dwarf = if !frame_section_bytes.is_empty() { - let dwarf = Some(Dwarf::new(SectionIndex::from_u32(module_custom_sections.len() as u32))); + let dwarf = Some(Dwarf::new(SectionIndex::from_u32( + module_custom_sections.len() as u32 + ))); // Terminating zero-length CIE. frame_section_bytes.extend(vec![ 0x00, 0x00, 0x00, 0x00, // Length @@ -143,7 +147,7 @@ impl Compiler for LLVMCompiler { module_custom_sections.push(CustomSection { protection: CustomSectionProtection::Read, bytes: SectionBody::new_with_vec(frame_section_bytes), - relocations: frame_section_relocations + relocations: frame_section_relocations, }); dwarf } else { diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs index 976e1503e..84819a94b 100644 --- a/lib/compiler-llvm/src/object_file.rs +++ b/lib/compiler-llvm/src/object_file.rs @@ -155,7 +155,7 @@ where elf_section_to_target(index); } } - + while let Some(section_index) = worklist.pop() { for reloc in reloc_sections .get(§ion_index) From 27a0613e57dc66abe20a2c2bf320e7a46a1d98a3 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 15:47:00 -0700 Subject: [PATCH 32/59] Remove unused `use` line. --- lib/compiler-llvm/src/compiler.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index f879d0f1c..2a1d9bb50 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -9,7 +9,6 @@ use wasmer_compiler::{ Dwarf, FunctionBodyData, ModuleTranslationState, RelocationTarget, SectionBody, SectionIndex, Target, }; -use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan}; //use std::sync::{Arc, Mutex}; From 30add1590498d1dcbcf528584a5cedf134e4c9cc Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 15:50:35 -0700 Subject: [PATCH 33/59] make lint cleanup --- lib/compiler-llvm/src/compiler.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index 2a1d9bb50..78b4a644f 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -86,7 +86,7 @@ impl Compiler for LLVMCompiler { ) .collect::, CompileError>>()? .into_iter() - .map( + .map( |(mut compiled_function, function_custom_sections, eh_frame_section_indices)| { let first_section = module_custom_sections.len() as u32; for (section_index, custom_section) in function_custom_sections.iter() { @@ -130,7 +130,7 @@ impl Compiler for LLVMCompiler { let dwarf = if !frame_section_bytes.is_empty() { let dwarf = Some(Dwarf::new(SectionIndex::from_u32( - module_custom_sections.len() as u32 + module_custom_sections.len() as u32, ))); // Terminating zero-length CIE. frame_section_bytes.extend(vec![ From b527127d0fdc426f092e3c83a8170e59f920b99e Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 16:43:43 -0700 Subject: [PATCH 34/59] load_object_file is returning an increasingly complex object. Group the data from compilation of a function into its own struct and return that. --- lib/compiler-llvm/src/compiler.rs | 66 ++++++++++++------------ lib/compiler-llvm/src/object_file.rs | 16 ++++-- lib/compiler-llvm/src/trampoline/wasm.rs | 26 +++++----- lib/compiler-llvm/src/translator/code.rs | 9 ++-- 4 files changed, 60 insertions(+), 57 deletions(-) diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index 78b4a644f..7559ae7d8 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -86,46 +86,44 @@ impl Compiler for LLVMCompiler { ) .collect::, CompileError>>()? .into_iter() - .map( - |(mut compiled_function, function_custom_sections, eh_frame_section_indices)| { - let first_section = module_custom_sections.len() as u32; - for (section_index, custom_section) in function_custom_sections.iter() { - // TODO: remove this call to clone() - let mut custom_section = custom_section.clone(); - for mut reloc in &mut custom_section.relocations { - if let RelocationTarget::CustomSection(index) = reloc.reloc_target { - reloc.reloc_target = RelocationTarget::CustomSection( - SectionIndex::from_u32(first_section + index.as_u32()), - ) - } - } - if eh_frame_section_indices.contains(§ion_index) { - let offset = frame_section_bytes.len() as u32; - for mut reloc in &mut custom_section.relocations { - reloc.offset += offset; - } - frame_section_bytes.extend_from_slice(custom_section.bytes.as_slice()); - frame_section_relocations.extend(custom_section.relocations); - // TODO: we do this to keep the count right, remove it. - module_custom_sections.push(CustomSection { - protection: CustomSectionProtection::Read, - bytes: SectionBody::new_with_vec(vec![]), - relocations: vec![], - }); - } else { - module_custom_sections.push(custom_section); - } - } - for mut reloc in &mut compiled_function.relocations { + .map(|mut compiled_function| { + let first_section = module_custom_sections.len() as u32; + for (section_index, custom_section) in compiled_function.custom_sections.iter() { + // TODO: remove this call to clone() + let mut custom_section = custom_section.clone(); + for mut reloc in &mut custom_section.relocations { if let RelocationTarget::CustomSection(index) = reloc.reloc_target { reloc.reloc_target = RelocationTarget::CustomSection( SectionIndex::from_u32(first_section + index.as_u32()), ) } } - compiled_function - }, - ) + if compiled_function.eh_frame_section_indices.contains(§ion_index) { + let offset = frame_section_bytes.len() as u32; + for mut reloc in &mut custom_section.relocations { + reloc.offset += offset; + } + frame_section_bytes.extend_from_slice(custom_section.bytes.as_slice()); + frame_section_relocations.extend(custom_section.relocations); + // TODO: we do this to keep the count right, remove it. + module_custom_sections.push(CustomSection { + protection: CustomSectionProtection::Read, + bytes: SectionBody::new_with_vec(vec![]), + relocations: vec![], + }); + } else { + module_custom_sections.push(custom_section); + } + } + for mut reloc in &mut compiled_function.compiled_function.relocations { + if let RelocationTarget::CustomSection(index) = reloc.reloc_target { + reloc.reloc_target = RelocationTarget::CustomSection( + SectionIndex::from_u32(first_section + index.as_u32()), + ) + } + } + compiled_function.compiled_function + }) .collect::>(); let dwarf = if !frame_section_bytes.is_empty() { diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs index 84819a94b..62584e5b3 100644 --- a/lib/compiler-llvm/src/object_file.rs +++ b/lib/compiler-llvm/src/object_file.rs @@ -3,7 +3,7 @@ use std::convert::TryFrom; use wasm_common::entity::{PrimaryMap, SecondaryMap}; use wasmer_compiler::{ - CompileError, CompiledFunction, CompiledFunctionFrameInfo, CustomSection, + CompileError, CompiledFunctionFrameInfo, CustomSection, CustomSectionProtection, CustomSections, FunctionAddressMap, FunctionBody, InstructionAddressMap, Relocation, RelocationKind, RelocationTarget, SectionBody, SectionIndex, SourceLoc, @@ -38,12 +38,18 @@ fn map_goblin_err(error: goblin::error::Error) -> CompileError { CompileError::Codegen(format!("error parsing ELF file: {}", error)) } +pub struct CompiledFunction { + pub compiled_function: wasmer_compiler::CompiledFunction, + pub custom_sections: CustomSections, + pub eh_frame_section_indices: Vec, +} + pub fn load_object_file( contents: &[u8], root_section: &str, root_section_reloc_target: RelocationTarget, mut symbol_name_to_relocation_target: F, -) -> Result<(CompiledFunction, CustomSections, Vec), CompileError> +) -> Result where F: FnMut(&String) -> Result, CompileError>, { @@ -284,8 +290,8 @@ where body_len: function_body.body.len(), }; - Ok(( - CompiledFunction { + Ok(CompiledFunction { + compiled_function: wasmer_compiler::CompiledFunction { body: function_body, jt_offsets: SecondaryMap::new(), relocations: relocations @@ -298,5 +304,5 @@ where }, custom_sections, eh_frame_section_indices, - )) + }) } diff --git a/lib/compiler-llvm/src/trampoline/wasm.rs b/lib/compiler-llvm/src/trampoline/wasm.rs index 8d2fad71c..556f98963 100644 --- a/lib/compiler-llvm/src/trampoline/wasm.rs +++ b/lib/compiler-llvm/src/trampoline/wasm.rs @@ -1,5 +1,5 @@ use crate::config::{CompiledFunctionKind, LLVM}; -use crate::object_file::load_object_file; +use crate::object_file::{load_object_file, CompiledFunction}; use crate::translator::abi::{ func_type_to_llvm, get_vmctx_ptr_param, is_sret, pack_values_for_register_return, rets_from_call, @@ -94,7 +94,7 @@ impl FuncTrampoline { } let mem_buf_slice = memory_buffer.as_slice(); - let (function, sections, eh_frame_section_indices) = load_object_file( + let CompiledFunction{compiled_function, custom_sections, eh_frame_section_indices} = load_object_file( mem_buf_slice, FUNCTION_SECTION, RelocationTarget::LocalFunc(LocalFunctionIndex::from_u32(0)), @@ -106,7 +106,7 @@ impl FuncTrampoline { }, )?; let mut all_sections_are_eh_sections = true; - if eh_frame_section_indices.len() != sections.len() { + if eh_frame_section_indices.len() != custom_sections.len() { all_sections_are_eh_sections = false; } else { let mut eh_frame_section_indices = eh_frame_section_indices.clone(); @@ -123,12 +123,12 @@ impl FuncTrampoline { "trampoline generation produced non-eh custom sections".into(), )); } - if !function.relocations.is_empty() { + if !compiled_function.relocations.is_empty() { return Err(CompileError::Codegen( "trampoline generation produced relocations".into(), )); } - if !function.jt_offsets.is_empty() { + if !compiled_function.jt_offsets.is_empty() { return Err(CompileError::Codegen( "trampoline generation produced jump tables".into(), )); @@ -136,8 +136,8 @@ impl FuncTrampoline { // Ignore CompiledFunctionFrameInfo. Extra frame info isn't a problem. Ok(FunctionBody { - body: function.body.body, - unwind_info: function.body.unwind_info, + body: compiled_function.body.body, + unwind_info: compiled_function.body.unwind_info, }) } @@ -192,7 +192,7 @@ impl FuncTrampoline { } let mem_buf_slice = memory_buffer.as_slice(); - let (function, sections, eh_frame_section_indices) = load_object_file( + let CompiledFunction{compiled_function, custom_sections, eh_frame_section_indices} = load_object_file( mem_buf_slice, FUNCTION_SECTION, RelocationTarget::LocalFunc(LocalFunctionIndex::from_u32(0)), @@ -204,7 +204,7 @@ impl FuncTrampoline { }, )?; let mut all_sections_are_eh_sections = true; - if eh_frame_section_indices.len() != sections.len() { + if eh_frame_section_indices.len() != custom_sections.len() { all_sections_are_eh_sections = false; } else { let mut eh_frame_section_indices = eh_frame_section_indices.clone(); @@ -221,12 +221,12 @@ impl FuncTrampoline { "trampoline generation produced non-eh custom sections".into(), )); } - if !function.relocations.is_empty() { + if !compiled_function.relocations.is_empty() { return Err(CompileError::Codegen( "trampoline generation produced relocations".into(), )); } - if !function.jt_offsets.is_empty() { + if !compiled_function.jt_offsets.is_empty() { return Err(CompileError::Codegen( "trampoline generation produced jump tables".into(), )); @@ -234,8 +234,8 @@ impl FuncTrampoline { // Ignore CompiledFunctionFrameInfo. Extra frame info isn't a problem. Ok(FunctionBody { - body: function.body.body, - unwind_info: function.body.unwind_info, + body: compiled_function.body.body, + unwind_info: compiled_function.body.unwind_info, }) } } diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 7a1f3b46e..0d7b1c874 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -23,7 +23,7 @@ use inkwell::{ use smallvec::SmallVec; use crate::config::{CompiledFunctionKind, LLVM}; -use crate::object_file::load_object_file; +use crate::object_file::{load_object_file, CompiledFunction}; use wasm_common::entity::{PrimaryMap, SecondaryMap}; use wasm_common::{ FunctionIndex, FunctionType, GlobalIndex, LocalFunctionIndex, MemoryIndex, SignatureIndex, @@ -31,9 +31,8 @@ use wasm_common::{ }; use wasmer_compiler::wasmparser::{MemoryImmediate, Operator}; use wasmer_compiler::{ - to_wasm_error, wptype_to_type, CompileError, CompiledFunction, CustomSections, - FunctionBodyData, GenerateMiddlewareChain, MiddlewareBinaryReader, ModuleTranslationState, - RelocationTarget, SectionIndex, + to_wasm_error, wptype_to_type, CompileError, FunctionBodyData, GenerateMiddlewareChain, + MiddlewareBinaryReader, ModuleTranslationState, RelocationTarget, }; use wasmer_runtime::{MemoryPlan, ModuleInfo, TablePlan}; @@ -76,7 +75,7 @@ impl FuncTranslator { memory_plans: &PrimaryMap, _table_plans: &PrimaryMap, func_names: &SecondaryMap, - ) -> Result<(CompiledFunction, CustomSections, Vec), CompileError> { + ) -> Result { // The function type, used for the callbacks. let function = CompiledFunctionKind::Local(*local_func_index); let func_index = wasm_module.func_index(*local_func_index); From 84b32ed2cd4d4983f8f0c344276aef594b5e1394 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 16:46:45 -0700 Subject: [PATCH 35/59] cargo fmt --- lib/compiler-llvm/src/compiler.rs | 5 ++++- lib/compiler-llvm/src/object_file.rs | 7 +++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index 7559ae7d8..eb729f6d1 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -98,7 +98,10 @@ impl Compiler for LLVMCompiler { ) } } - if compiled_function.eh_frame_section_indices.contains(§ion_index) { + if compiled_function + .eh_frame_section_indices + .contains(§ion_index) + { let offset = frame_section_bytes.len() as u32; for mut reloc in &mut custom_section.relocations { reloc.offset += offset; diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs index 62584e5b3..c69aaa6c0 100644 --- a/lib/compiler-llvm/src/object_file.rs +++ b/lib/compiler-llvm/src/object_file.rs @@ -3,10 +3,9 @@ use std::convert::TryFrom; use wasm_common::entity::{PrimaryMap, SecondaryMap}; use wasmer_compiler::{ - CompileError, CompiledFunctionFrameInfo, CustomSection, - CustomSectionProtection, CustomSections, FunctionAddressMap, FunctionBody, - InstructionAddressMap, Relocation, RelocationKind, RelocationTarget, SectionBody, SectionIndex, - SourceLoc, + CompileError, CompiledFunctionFrameInfo, CustomSection, CustomSectionProtection, + CustomSections, FunctionAddressMap, FunctionBody, InstructionAddressMap, Relocation, + RelocationKind, RelocationTarget, SectionBody, SectionIndex, SourceLoc, }; use wasmer_runtime::libcalls::LibCall; From 914da3266b627ba2969bacf38a2a4ee5311add6d Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 16:48:44 -0700 Subject: [PATCH 36/59] cargo fmt --- lib/compiler-llvm/src/trampoline/wasm.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/compiler-llvm/src/trampoline/wasm.rs b/lib/compiler-llvm/src/trampoline/wasm.rs index 556f98963..4d3eeaa11 100644 --- a/lib/compiler-llvm/src/trampoline/wasm.rs +++ b/lib/compiler-llvm/src/trampoline/wasm.rs @@ -94,7 +94,11 @@ impl FuncTrampoline { } let mem_buf_slice = memory_buffer.as_slice(); - let CompiledFunction{compiled_function, custom_sections, eh_frame_section_indices} = load_object_file( + let CompiledFunction { + compiled_function, + custom_sections, + eh_frame_section_indices + } = load_object_file( mem_buf_slice, FUNCTION_SECTION, RelocationTarget::LocalFunc(LocalFunctionIndex::from_u32(0)), @@ -192,7 +196,11 @@ impl FuncTrampoline { } let mem_buf_slice = memory_buffer.as_slice(); - let CompiledFunction{compiled_function, custom_sections, eh_frame_section_indices} = load_object_file( + let CompiledFunction { + compiled_function, + custom_sections, + eh_frame_section_indices + } = load_object_file( mem_buf_slice, FUNCTION_SECTION, RelocationTarget::LocalFunc(LocalFunctionIndex::from_u32(0)), From c0b2f968e2a581a223bb8704d7c220c88274fe2d Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 18 Jun 2020 16:50:56 -0700 Subject: [PATCH 37/59] more formatting --- lib/compiler-llvm/src/trampoline/wasm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compiler-llvm/src/trampoline/wasm.rs b/lib/compiler-llvm/src/trampoline/wasm.rs index 4d3eeaa11..38efa1351 100644 --- a/lib/compiler-llvm/src/trampoline/wasm.rs +++ b/lib/compiler-llvm/src/trampoline/wasm.rs @@ -97,7 +97,7 @@ impl FuncTrampoline { let CompiledFunction { compiled_function, custom_sections, - eh_frame_section_indices + eh_frame_section_indices, } = load_object_file( mem_buf_slice, FUNCTION_SECTION, @@ -199,7 +199,7 @@ impl FuncTrampoline { let CompiledFunction { compiled_function, custom_sections, - eh_frame_section_indices + eh_frame_section_indices, } = load_object_file( mem_buf_slice, FUNCTION_SECTION, From 4afdd94d7adbd6d8915d6790ec3c691976694de7 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 19 Jun 2020 10:57:56 +0200 Subject: [PATCH 38/59] feat(wasm-common) Trap properly with `raise_user_trap` and `resume_panic`. --- lib/wasm-common/src/native.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/wasm-common/src/native.rs b/lib/wasm-common/src/native.rs index 159818126..ba444fe40 100644 --- a/lib/wasm-common/src/native.rs +++ b/lib/wasm-common/src/native.rs @@ -5,6 +5,7 @@ use crate::types::{FunctionType, Type}; use crate::values::Value; use std::convert::Infallible; use std::marker::PhantomData; +use std::panic::{self, AssertUnwindSafe}; /// `NativeWasmType` represents a native Wasm type. /// It uses the Rust Type system to automatically detect the @@ -484,11 +485,14 @@ macro_rules! impl_traits { FN: Fn( $( $x ),* ) -> Trap + 'static { let f: &FN = unsafe { &*(&() as *const () as *const FN) }; - let results = f( $( WasmExternType::from_native($x) ),* ).report(); + let result = panic::catch_unwind(AssertUnwindSafe(|| { + f( $( WasmExternType::from_native($x) ),* ).report() + })); - match results { - Ok(results) => return results.into_c_struct(), - Err(error) => panic!(error), + match result { + Ok(Ok(result)) => return result.into_c_struct(), + Ok(Err(trap)) => wasmer_runtime::raise_user_trap(Box::new(trap)), + Err(panic) => wasmer_runtime::resume_panic(panic), } } @@ -516,11 +520,15 @@ macro_rules! impl_traits { FN: Fn(&mut T, $( $x ),* ) -> Trap + 'static { let f: &FN = unsafe { &*(&() as *const () as *const FN) }; - let results = f(ctx, $( WasmExternType::from_native($x) ),* ).report(); - match results { - Ok(results) => return results.into_c_struct(), - Err(error) => panic!(error), + let result = panic::catch_unwind(AssertUnwindSafe(|| { + f(ctx, $( WasmExternType::from_native($x) ),* ).report() + })); + + match result { + Ok(Ok(result)) => return result.into_c_struct(), + Ok(Err(trap)) => wasmer_runtime::raise_user_trap(Box::new(trap)), + Err(panic) => wasmer_runtime::resume_panic(panic), } } From 5e26d9a74b71773c0c3aeaee47a1ce65baedcfcc Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 19 Jun 2020 15:20:28 +0200 Subject: [PATCH 39/59] !temp Move `HostFunction`, `Func` & co. into `wasmer`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because `Func` needs an access to the runtime API (`wasmer-runtime`) to trap properly, either we move parts of `wasmer-runtime` to `wasm-common`, or we move parts of `wasm-common` into `wasmer`. I decided to go with the second approach since `wasmer` is the only crate to use `HostFunction` & co. It's not “common” by definition, and it's way easier (for the moment). --- lib/api/src/exports.rs | 2 +- lib/api/src/externals/function.rs | 493 +++++++++++++++++++++++++++++- lib/api/src/externals/mod.rs | 2 +- lib/api/src/lib.rs | 6 +- lib/api/src/native.rs | 4 +- lib/wasm-common/src/lib.rs | 5 +- lib/wasm-common/src/native.rs | 472 +--------------------------- 7 files changed, 495 insertions(+), 489 deletions(-) diff --git a/lib/api/src/exports.rs b/lib/api/src/exports.rs index a961b47f5..5fd11bf0b 100644 --- a/lib/api/src/exports.rs +++ b/lib/api/src/exports.rs @@ -1,13 +1,13 @@ use crate::externals::{Extern, Function, Global, Memory, Table}; use crate::import_object::LikeNamespace; use crate::native::NativeFunc; +use crate::WasmTypeList; use indexmap::IndexMap; use std::{ iter::{ExactSizeIterator, FromIterator}, sync::Arc, }; use thiserror::Error; -use wasm_common::WasmTypeList; use wasmer_runtime::Export; /// The `ExportError` can happen when trying to get a specific diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 3ae9f982c..bd3bf7dbe 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -5,12 +5,14 @@ use crate::types::Val; use crate::FunctionType; use crate::NativeFunc; use crate::RuntimeError; +pub use inner::{HostFunction, WasmTypeList}; +use inner::{WithEnv, WithoutEnv}; use std::cell::RefCell; use std::cmp::max; -use wasm_common::{HostFunction, WasmTypeList, WithEnv, WithoutEnv}; use wasmer_runtime::{ - wasmer_call_trampoline, Export, ExportFunction, VMCallerCheckedAnyfunc, VMContext, - VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind, VMTrampoline, + raise_user_trap, resume_panic, wasmer_call_trampoline, Export, ExportFunction, + VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind, + VMTrampoline, }; /// A function defined in the Wasm module @@ -58,7 +60,7 @@ impl Function { Rets: WasmTypeList, Env: Sized + 'static, { - let func: wasm_common::Func = wasm_common::Func::new(func); + let func: inner::Func = inner::Func::new(func); let address = func.address() as *const VMFunctionBody; let vmctx = std::ptr::null_mut() as *mut _ as *mut VMContext; let signature = func.ty(); @@ -143,7 +145,7 @@ impl Function { Rets: WasmTypeList, Env: Sized + 'static, { - let func: wasm_common::Func = wasm_common::Func::new(func); + let func: inner::Func = inner::Func::new(func); let address = func.address() as *const VMFunctionBody; // TODO: We need to refactor the Function context. // Right now is structured as it's always a `VMContext`. However, only @@ -441,8 +443,485 @@ impl VMDynamicFunctionCall for VMDynamicFunctionContext match result { Ok(Ok(())) => {} - Ok(Err(trap)) => wasmer_runtime::raise_user_trap(Box::new(trap)), - Err(panic) => wasmer_runtime::resume_panic(panic), + Ok(Err(trap)) => raise_user_trap(Box::new(trap)), + Err(panic) => resume_panic(panic), + } + } +} + +mod inner { + use std::convert::Infallible; + use std::error::Error; + use std::marker::PhantomData; + use std::panic::{self, AssertUnwindSafe}; + use wasm_common::{FunctionType, NativeWasmType, Type, WasmExternType}; + use wasmer_runtime::{raise_user_trap, resume_panic}; + + /// Represents a list of WebAssembly values. + pub trait WasmTypeList { + /// CStruct type. + type CStruct; + + /// Array of return values. + type Array: AsMut<[i128]>; + + /// Construct `Self` based on an array of returned values. + fn from_array(array: Self::Array) -> Self; + + /// Transforms Rust values into an Array + fn into_array(self) -> Self::Array; + + /// Generates an empty array that will hold the returned values of + /// the WebAssembly function. + fn empty_array() -> Self::Array; + + /// Transforms C values into Rust values. + fn from_c_struct(c_struct: Self::CStruct) -> Self; + + /// Transforms Rust values into C values. + fn into_c_struct(self) -> Self::CStruct; + + /// Get types of the current values. + fn wasm_types() -> &'static [Type]; + } + + /// Represents a TrapEarly type. + pub trait TrapEarly + where + Rets: WasmTypeList, + { + /// The error type for this trait. + type Error: Error + Sync + Send + 'static; + + /// Get returns or error result. + fn report(self) -> Result; + } + + impl TrapEarly for Rets + where + Rets: WasmTypeList, + { + type Error = Infallible; + + fn report(self) -> Result { + Ok(self) + } + } + + impl TrapEarly for Result + where + Rets: WasmTypeList, + E: Error + Sync + Send + 'static, + { + type Error = E; + + fn report(self) -> Self { + self + } + } + + /// Empty trait to specify the kind of `HostFunction`: With or + /// without a `vm::Ctx` argument. See the `ExplicitVmCtx` and the + /// `ImplicitVmCtx` structures. + /// + /// This trait is never aimed to be used by a user. It is used by the + /// trait system to automatically generate an appropriate `wrap` + /// function. + #[doc(hidden)] + pub trait HostFunctionKind {} + + /// An empty struct to help Rust typing to determine + /// when a `HostFunction` doesn't take an Environment + pub struct WithEnv {} + + impl HostFunctionKind for WithEnv {} + + /// An empty struct to help Rust typing to determine + /// when a `HostFunction` takes an Environment + pub struct WithoutEnv {} + + impl HostFunctionKind for WithoutEnv {} + + /// Represents a function that can be converted to a `vm::Func` + /// (function pointer) that can be called within WebAssembly. + pub trait HostFunction + where + Args: WasmTypeList, + Rets: WasmTypeList, + Kind: HostFunctionKind, + T: Sized, + Self: Sized, + { + /// Convert to function pointer. + fn to_raw(self) -> *const FunctionBody; + } + + #[repr(transparent)] + pub struct FunctionBody(*mut u8); + + /// Represents a function that can be used by WebAssembly. + #[derive(Clone, Debug, Hash, PartialEq, Eq)] + pub struct Func { + address: *const FunctionBody, + _phantom: PhantomData<(Args, Rets)>, + } + + unsafe impl Send for Func {} + + impl Func + where + Args: WasmTypeList, + Rets: WasmTypeList, + { + /// Creates a new `Func`. + pub fn new(func: F) -> Self + where + F: HostFunction, + T: HostFunctionKind, + E: Sized, + { + Self { + address: func.to_raw(), + _phantom: PhantomData, + } + } + + /// Get the type of the Func + pub fn ty(&self) -> FunctionType { + FunctionType::new(Args::wasm_types(), Rets::wasm_types()) + } + + /// Get the address of the Func + pub fn address(&self) -> *const FunctionBody { + self.address + } + } + + impl WasmTypeList for Infallible { + type CStruct = Self; + type Array = [i128; 0]; + + fn from_array(_: Self::Array) -> Self { + unreachable!() + } + + fn into_array(self) -> Self::Array { + [] + } + + fn empty_array() -> Self::Array { + unreachable!() + } + + fn from_c_struct(_: Self::CStruct) -> Self { + unreachable!() + } + + fn into_c_struct(self) -> Self::CStruct { + unreachable!() + } + + fn wasm_types() -> &'static [Type] { + &[] + } + } + + macro_rules! impl_traits { + ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => { + /// Struct for typed funcs. + #[repr($repr)] + pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* ) + where + $( $x: WasmExternType ),*; + + #[allow(unused_parens, dead_code)] + impl< $( $x ),* > WasmTypeList for ( $( $x ),* ) + where + $( $x: WasmExternType ),* + { + type CStruct = $struct_name<$( $x ),*>; + + type Array = [i128; count_idents!( $( $x ),* )]; + + fn from_array(array: Self::Array) -> Self { + #[allow(non_snake_case)] + let [ $( $x ),* ] = array; + + ( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* ) + } + + fn into_array(self) -> Self::Array { + #[allow(non_snake_case)] + let ( $( $x ),* ) = self; + [ $( WasmExternType::to_native($x).to_binary() ),* ] + } + + fn empty_array() -> Self::Array { + [0; count_idents!( $( $x ),* )] + } + + fn from_c_struct(c_struct: Self::CStruct) -> Self { + #[allow(non_snake_case)] + let $struct_name ( $( $x ),* ) = c_struct; + + ( $( WasmExternType::from_native($x) ),* ) + } + + #[allow(unused_parens, non_snake_case)] + fn into_c_struct(self) -> Self::CStruct { + let ( $( $x ),* ) = self; + + $struct_name ( $( WasmExternType::to_native($x) ),* ) + } + + fn wasm_types() -> &'static [Type] { + &[$( $x::Native::WASM_TYPE ),*] + } + } + + #[allow(unused_parens)] + impl< $( $x, )* Rets, Trap, FN > HostFunction<( $( $x ),* ), Rets, WithoutEnv, ()> for FN + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn($( $x , )*) -> Trap + 'static + Send, + { + #[allow(non_snake_case)] + fn to_raw(self) -> *const FunctionBody { + extern fn wrap<$( $x, )* Rets, Trap, FN>( _: usize, $($x: $x::Native, )* ) -> Rets::CStruct + where + Rets: WasmTypeList, + Trap: TrapEarly, + $( $x: WasmExternType, )* + FN: Fn( $( $x ),* ) -> Trap + 'static + { + let f: &FN = unsafe { &*(&() as *const () as *const FN) }; + let result = panic::catch_unwind(AssertUnwindSafe(|| { + f( $( WasmExternType::from_native($x) ),* ).report() + })); + + match result { + Ok(Ok(result)) => return result.into_c_struct(), + Ok(Err(trap)) => unsafe { raise_user_trap(Box::new(trap)) }, + Err(panic) => unsafe { resume_panic(panic) }, + } + } + + wrap::<$( $x, )* Rets, Trap, Self> as *const FunctionBody + } + } + + #[allow(unused_parens)] + impl< $( $x, )* Rets, Trap, T, FN > HostFunction<( $( $x ),* ), Rets, WithEnv, T> for FN + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + T: Sized, + FN: Fn(&mut T, $( $x , )*) -> Trap + 'static + Send + { + #[allow(non_snake_case)] + fn to_raw(self) -> *const FunctionBody { + extern fn wrap<$( $x, )* Rets, Trap, T, FN>( ctx: &mut T, $($x: $x::Native, )* ) -> Rets::CStruct + where + Rets: WasmTypeList, + Trap: TrapEarly, + $( $x: WasmExternType, )* + T: Sized, + FN: Fn(&mut T, $( $x ),* ) -> Trap + 'static + { + let f: &FN = unsafe { &*(&() as *const () as *const FN) }; + + let result = panic::catch_unwind(AssertUnwindSafe(|| { + f(ctx, $( WasmExternType::from_native($x) ),* ).report() + })); + + match result { + Ok(Ok(result)) => return result.into_c_struct(), + Ok(Err(trap)) => unsafe { raise_user_trap(Box::new(trap)) }, + Err(panic) => unsafe { resume_panic(panic) }, + } + } + + wrap::<$( $x, )* Rets, Trap, T, Self> as *const FunctionBody + } + } + }; + } + + macro_rules! count_idents { + ( $($idents:ident),* ) => {{ + #[allow(dead_code, non_camel_case_types)] + enum Idents { $($idents,)* __CountIdentsLast } + const COUNT: usize = Idents::__CountIdentsLast as usize; + COUNT + }}; + } + + //impl_traits!([C] S0,); + //impl_traits!([transparent] S1, A1); + impl_traits!([C] S2, A1, A2); + impl_traits!([C] S3, A1, A2, A3); + impl_traits!([C] S4, A1, A2, A3, A4); + impl_traits!([C] S5, A1, A2, A3, A4, A5); + impl_traits!([C] S6, A1, A2, A3, A4, A5, A6); + impl_traits!([C] S7, A1, A2, A3, A4, A5, A6, A7); + impl_traits!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8); + impl_traits!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9); + impl_traits!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); + impl_traits!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); + impl_traits!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); + impl_traits!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); + impl_traits!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); + impl_traits!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); + impl_traits!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); + impl_traits!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); + impl_traits!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18); + impl_traits!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19); + impl_traits!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20); + impl_traits!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21); + impl_traits!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22); + impl_traits!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23); + impl_traits!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24); + impl_traits!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25); + impl_traits!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26); + + #[cfg(test)] + mod test_wasm_type_list { + use super::*; + use crate::types::Type; + // WasmTypeList + + #[test] + fn test_simple_values() { + // Simple values + assert_eq!(::wasm_types(), [Type::I32]); + assert_eq!(::wasm_types(), [Type::I64]); + assert_eq!(::wasm_types(), [Type::F32]); + assert_eq!(::wasm_types(), [Type::F64]); + + // Multi values + assert_eq!(<(i32, i32)>::wasm_types(), [Type::I32, Type::I32]); + assert_eq!(<(i64, i64)>::wasm_types(), [Type::I64, Type::I64]); + assert_eq!(<(f32, f32)>::wasm_types(), [Type::F32, Type::F32]); + assert_eq!(<(f64, f64)>::wasm_types(), [Type::F64, Type::F64]); + + // Mixed values + // assert_eq!(<(i32, i64, f32, f64)>::wasm_types(), [Type::I32, Type::I64, Type::F32, Type::F64]); + } + + #[test] + fn test_empty_array() { + assert_eq!(<()>::empty_array().len(), 0); + assert_eq!(::empty_array().len(), 1); + assert_eq!(<(i32, i64)>::empty_array().len(), 2); + } + + // #[test] + // fn test_from_array() { + // assert_eq!(<()>::from_array([]), ()); + // assert_eq!(<(i32)>::from_array([1]), (1)); + // assert_eq!(<(i32, i32)>::from_array([1, 1]), (1, 1)); + // // This doesn't work + // // assert_eq!(<(i32, i64, f32, f64)>::from_array([1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()]), (1, 2, 3.1f32, 4.2f64)); + // } + + // #[test] + // fn test_into_array() { + // assert_eq!(().into_array(), []); + // assert_eq!((1).into_array(), [1]); + // assert_eq!((1, 2).into_array(), [1, 2]); + // assert_eq!((1, 2, 3).into_array(), [1, 2, 3]); + // // This doesn't work + // // assert_eq!(<(i32, i64, f32, f64)>::from_array([1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()]), (1, 2, 3.1f32, 4.2f64)); + // } + + #[test] + fn test_into_c_struct() { + // assert_eq!(<()>::into_c_struct(), &[]); + } + } + + #[allow(non_snake_case)] + #[cfg(test)] + mod test_func { + use super::*; + use crate::types::Type; + use std::ptr; + // WasmTypeList + + fn func() {} + fn func__i32() -> i32 { + 0 + } + fn func_i32(_a: i32) {} + fn func_i32__i32(a: i32) -> i32 { + a * 2 + } + fn func_i32_i32__i32(a: i32, b: i32) -> i32 { + a + b + } + fn func_i32_i32__i32_i32(a: i32, b: i32) -> (i32, i32) { + (a, b) + } + fn func_f32_i32__i32_f32(a: f32, b: i32) -> (i32, f32) { + (b, a) + } + + #[test] + fn test_function_types() { + assert_eq!(Func::new(func).ty(), FunctionType::new(vec![], vec![])); + assert_eq!( + Func::new(func__i32).ty(), + FunctionType::new(vec![], vec![Type::I32]) + ); + assert_eq!( + Func::new(func_i32).ty(), + FunctionType::new(vec![Type::I32], vec![]) + ); + assert_eq!( + Func::new(func_i32__i32).ty(), + FunctionType::new(vec![Type::I32], vec![Type::I32]) + ); + assert_eq!( + Func::new(func_i32_i32__i32).ty(), + FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]) + ); + assert_eq!( + Func::new(func_i32_i32__i32_i32).ty(), + FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32]) + ); + assert_eq!( + Func::new(func_f32_i32__i32_f32).ty(), + FunctionType::new(vec![Type::F32, Type::I32], vec![Type::I32, Type::F32]) + ); + } + + #[test] + fn test_function_pointer() { + let f = Func::new(func_i32__i32); + let function = unsafe { + std::mem::transmute::<*const FunctionBody, fn(usize, i32) -> i32>(f.address) + }; + assert_eq!(function(0, 3), 6); + } + + #[test] + fn test_function_call() { + let f = Func::new(func_i32__i32); + let x = |args: <(i32, i32) as WasmTypeList>::Array, + rets: &mut <(i32, i32) as WasmTypeList>::Array| { + let result = func_i32_i32__i32_i32(args[0] as _, args[1] as _); + rets[0] = result.0 as _; + rets[1] = result.1 as _; + }; + let mut rets = <(i64, i64)>::empty_array(); + x([20, 10], &mut rets); + // panic!("Rets: {:?}",rets); + let mut rets = <(i64)>::empty_array(); + // let result = f.call([1], &mut rets); + // assert_eq!(result.is_err(), true); } } } diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs index 881bae009..fc6982ad8 100644 --- a/lib/api/src/externals/mod.rs +++ b/lib/api/src/externals/mod.rs @@ -3,7 +3,7 @@ mod global; mod memory; mod table; -pub use self::function::Function; +pub use self::function::{Function, HostFunction, WasmTypeList}; pub use self::global::Global; pub use self::memory::Memory; pub use self::table::Table; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 03c7d5b33..feb65852f 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -18,7 +18,7 @@ mod types; mod utils; pub use crate::exports::{ExportError, Exportable, Exports}; -pub use crate::externals::{Extern, Function, Global, Memory, Table}; +pub use crate::externals::{Extern, Function, Global, HostFunction, Memory, Table, WasmTypeList}; pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace}; pub use crate::instance::Instance; pub use crate::memory_view::{Atomically, MemoryView}; @@ -37,8 +37,8 @@ pub use crate::utils::is_wasm; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; pub use wasm_common::{ - Bytes, GlobalInit, LocalFunctionIndex, Pages, ValueType, WasmExternType, WasmTypeList, - WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE, + Bytes, GlobalInit, LocalFunctionIndex, Pages, ValueType, WasmExternType, WASM_MAX_PAGES, + WASM_MIN_PAGES, WASM_PAGE_SIZE, }; #[cfg(feature = "compiler")] pub use wasmer_compiler::CompilerConfig; diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index 9ca966db1..c35d9e7b6 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -13,9 +13,9 @@ use crate::externals::function::{ FunctionDefinition, HostFunctionDefinition, VMDynamicFunction, VMDynamicFunctionWithEnv, VMDynamicFunctionWithoutEnv, WasmFunctionDefinition, }; -use crate::{Function, FunctionType, RuntimeError, Store}; +use crate::{Function, FunctionType, RuntimeError, Store, WasmTypeList}; use std::panic::{catch_unwind, AssertUnwindSafe}; -use wasm_common::{NativeWasmType, WasmExternType, WasmTypeList}; +use wasm_common::{NativeWasmType, WasmExternType}; use wasmer_runtime::{ ExportFunction, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind, }; diff --git a/lib/wasm-common/src/lib.rs b/lib/wasm-common/src/lib.rs index 7ce591e25..b2227f8f8 100644 --- a/lib/wasm-common/src/lib.rs +++ b/lib/wasm-common/src/lib.rs @@ -43,10 +43,7 @@ pub use crate::indexes::{ LocalFunctionIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, SignatureIndex, TableIndex, }; -pub use crate::native::{ - Func, HostFunction, NativeWasmType, ValueType, WasmExternType, WasmTypeList, WithEnv, - WithoutEnv, -}; +pub use crate::native::{NativeWasmType, ValueType, WasmExternType}; pub use crate::r#ref::{ExternRef, HostInfo, HostRef}; pub use crate::units::{Bytes, Pages, WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE}; pub use crate::values::Value; diff --git a/lib/wasm-common/src/native.rs b/lib/wasm-common/src/native.rs index ba444fe40..196be00f2 100644 --- a/lib/wasm-common/src/native.rs +++ b/lib/wasm-common/src/native.rs @@ -1,11 +1,8 @@ //! This module permits to create native functions //! easily in Rust, thanks to its advanced typing system. -use crate::types::{FunctionType, Type}; +use crate::types::Type; use crate::values::Value; -use std::convert::Infallible; -use std::marker::PhantomData; -use std::panic::{self, AssertUnwindSafe}; /// `NativeWasmType` represents a native Wasm type. /// It uses the Rust Type system to automatically detect the @@ -244,470 +241,3 @@ macro_rules! impl_value_type_for { } impl_value_type_for!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64); - -/// Represents a list of WebAssembly values. -pub trait WasmTypeList { - /// CStruct type. - type CStruct; - - /// Array of return values. - type Array: AsMut<[i128]>; - - /// Construct `Self` based on an array of returned values. - fn from_array(array: Self::Array) -> Self; - - /// Transforms Rust values into an Array - fn into_array(self) -> Self::Array; - - /// Generates an empty array that will hold the returned values of - /// the WebAssembly function. - fn empty_array() -> Self::Array; - - /// Transforms C values into Rust values. - fn from_c_struct(c_struct: Self::CStruct) -> Self; - - /// Transforms Rust values into C values. - fn into_c_struct(self) -> Self::CStruct; - - /// Get types of the current values. - fn wasm_types() -> &'static [Type]; -} - -/// Represents a TrapEarly type. -pub trait TrapEarly -where - Rets: WasmTypeList, -{ - /// The error type for this trait. - type Error: Send + 'static; - - /// Get returns or error result. - fn report(self) -> Result; -} - -impl TrapEarly for Rets -where - Rets: WasmTypeList, -{ - type Error = Infallible; - - fn report(self) -> Result { - Ok(self) - } -} - -impl TrapEarly for Result -where - Rets: WasmTypeList, - E: Send + 'static, -{ - type Error = E; - - fn report(self) -> Self { - self - } -} - -/// Empty trait to specify the kind of `HostFunction`: With or -/// without a `vm::Ctx` argument. See the `ExplicitVmCtx` and the -/// `ImplicitVmCtx` structures. -/// -/// This trait is never aimed to be used by a user. It is used by the -/// trait system to automatically generate an appropriate `wrap` -/// function. -#[doc(hidden)] -pub trait HostFunctionKind {} - -/// An empty struct to help Rust typing to determine -/// when a `HostFunction` doesn't take an Environment -pub struct WithEnv {} - -impl HostFunctionKind for WithEnv {} - -/// An empty struct to help Rust typing to determine -/// when a `HostFunction` takes an Environment -pub struct WithoutEnv {} - -impl HostFunctionKind for WithoutEnv {} - -/// Represents a function that can be converted to a `vm::Func` -/// (function pointer) that can be called within WebAssembly. -pub trait HostFunction -where - Args: WasmTypeList, - Rets: WasmTypeList, - Kind: HostFunctionKind, - T: Sized, - Self: Sized, -{ - /// Convert to function pointer. - fn to_raw(self) -> *const FunctionBody; -} - -#[repr(transparent)] -pub struct FunctionBody(*mut u8); - -/// Represents a function that can be used by WebAssembly. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub struct Func { - address: *const FunctionBody, - _phantom: PhantomData<(Args, Rets)>, -} - -unsafe impl Send for Func {} - -impl Func -where - Args: WasmTypeList, - Rets: WasmTypeList, -{ - /// Creates a new `Func`. - pub fn new(func: F) -> Self - where - F: HostFunction, - T: HostFunctionKind, - E: Sized, - { - Self { - address: func.to_raw(), - _phantom: PhantomData, - } - } - - /// Get the type of the Func - pub fn ty(&self) -> FunctionType { - FunctionType::new(Args::wasm_types(), Rets::wasm_types()) - } - - /// Get the address of the Func - pub fn address(&self) -> *const FunctionBody { - self.address - } -} - -impl WasmTypeList for Infallible { - type CStruct = Self; - type Array = [i128; 0]; - - fn from_array(_: Self::Array) -> Self { - unreachable!() - } - - fn into_array(self) -> Self::Array { - [] - } - - fn empty_array() -> Self::Array { - unreachable!() - } - - fn from_c_struct(_: Self::CStruct) -> Self { - unreachable!() - } - - fn into_c_struct(self) -> Self::CStruct { - unreachable!() - } - - fn wasm_types() -> &'static [Type] { - &[] - } -} - -macro_rules! impl_traits { - ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => { - /// Struct for typed funcs. - #[repr($repr)] - pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* ) - where - $( $x: WasmExternType ),*; - - #[allow(unused_parens, dead_code)] - impl< $( $x ),* > WasmTypeList for ( $( $x ),* ) - where - $( $x: WasmExternType ),* - { - type CStruct = $struct_name<$( $x ),*>; - - type Array = [i128; count_idents!( $( $x ),* )]; - - fn from_array(array: Self::Array) -> Self { - #[allow(non_snake_case)] - let [ $( $x ),* ] = array; - - ( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* ) - } - - fn into_array(self) -> Self::Array { - #[allow(non_snake_case)] - let ( $( $x ),* ) = self; - [ $( WasmExternType::to_native($x).to_binary() ),* ] - } - - fn empty_array() -> Self::Array { - [0; count_idents!( $( $x ),* )] - } - - fn from_c_struct(c_struct: Self::CStruct) -> Self { - #[allow(non_snake_case)] - let $struct_name ( $( $x ),* ) = c_struct; - - ( $( WasmExternType::from_native($x) ),* ) - } - - #[allow(unused_parens, non_snake_case)] - fn into_c_struct(self) -> Self::CStruct { - let ( $( $x ),* ) = self; - - $struct_name ( $( WasmExternType::to_native($x) ),* ) - } - - fn wasm_types() -> &'static [Type] { - &[$( $x::Native::WASM_TYPE ),*] - } - } - - #[allow(unused_parens)] - impl< $( $x, )* Rets, Trap, FN > HostFunction<( $( $x ),* ), Rets, WithoutEnv, ()> for FN - where - $( $x: WasmExternType, )* - Rets: WasmTypeList, - Trap: TrapEarly, - FN: Fn($( $x , )*) -> Trap + 'static + Send, - { - #[allow(non_snake_case)] - fn to_raw(self) -> *const FunctionBody { - extern fn wrap<$( $x, )* Rets, Trap, FN>( _: usize, $($x: $x::Native, )* ) -> Rets::CStruct - where - Rets: WasmTypeList, - Trap: TrapEarly, - $( $x: WasmExternType, )* - FN: Fn( $( $x ),* ) -> Trap + 'static - { - let f: &FN = unsafe { &*(&() as *const () as *const FN) }; - let result = panic::catch_unwind(AssertUnwindSafe(|| { - f( $( WasmExternType::from_native($x) ),* ).report() - })); - - match result { - Ok(Ok(result)) => return result.into_c_struct(), - Ok(Err(trap)) => wasmer_runtime::raise_user_trap(Box::new(trap)), - Err(panic) => wasmer_runtime::resume_panic(panic), - } - } - - wrap::<$( $x, )* Rets, Trap, Self> as *const FunctionBody - } - } - - #[allow(unused_parens)] - impl< $( $x, )* Rets, Trap, T, FN > HostFunction<( $( $x ),* ), Rets, WithEnv, T> for FN - where - $( $x: WasmExternType, )* - Rets: WasmTypeList, - Trap: TrapEarly, - T: Sized, - FN: Fn(&mut T, $( $x , )*) -> Trap + 'static + Send - { - #[allow(non_snake_case)] - fn to_raw(self) -> *const FunctionBody { - extern fn wrap<$( $x, )* Rets, Trap, T, FN>( ctx: &mut T, $($x: $x::Native, )* ) -> Rets::CStruct - where - Rets: WasmTypeList, - Trap: TrapEarly, - $( $x: WasmExternType, )* - T: Sized, - FN: Fn(&mut T, $( $x ),* ) -> Trap + 'static - { - let f: &FN = unsafe { &*(&() as *const () as *const FN) }; - - let result = panic::catch_unwind(AssertUnwindSafe(|| { - f(ctx, $( WasmExternType::from_native($x) ),* ).report() - })); - - match result { - Ok(Ok(result)) => return result.into_c_struct(), - Ok(Err(trap)) => wasmer_runtime::raise_user_trap(Box::new(trap)), - Err(panic) => wasmer_runtime::resume_panic(panic), - } - } - - wrap::<$( $x, )* Rets, Trap, T, Self> as *const FunctionBody - } - } - }; -} - -macro_rules! count_idents { - ( $($idents:ident),* ) => {{ - #[allow(dead_code, non_camel_case_types)] - enum Idents { $($idents,)* __CountIdentsLast } - const COUNT: usize = Idents::__CountIdentsLast as usize; - COUNT - }}; -} - -impl_traits!([C] S0,); -impl_traits!([transparent] S1, A1); -impl_traits!([C] S2, A1, A2); -impl_traits!([C] S3, A1, A2, A3); -impl_traits!([C] S4, A1, A2, A3, A4); -impl_traits!([C] S5, A1, A2, A3, A4, A5); -impl_traits!([C] S6, A1, A2, A3, A4, A5, A6); -impl_traits!([C] S7, A1, A2, A3, A4, A5, A6, A7); -impl_traits!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8); -impl_traits!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9); -impl_traits!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); -impl_traits!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); -impl_traits!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); -impl_traits!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); -impl_traits!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); -impl_traits!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); -impl_traits!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); -impl_traits!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); -impl_traits!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18); -impl_traits!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19); -impl_traits!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20); -// impl_traits!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21); -// impl_traits!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22); -// impl_traits!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23); -// impl_traits!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24); -// impl_traits!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25); -// impl_traits!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26); - -#[cfg(test)] -mod test_wasm_type_list { - use super::*; - use crate::types::Type; - // WasmTypeList - - #[test] - fn test_simple_values() { - // Simple values - assert_eq!(::wasm_types(), [Type::I32]); - assert_eq!(::wasm_types(), [Type::I64]); - assert_eq!(::wasm_types(), [Type::F32]); - assert_eq!(::wasm_types(), [Type::F64]); - - // Multi values - assert_eq!(<(i32, i32)>::wasm_types(), [Type::I32, Type::I32]); - assert_eq!(<(i64, i64)>::wasm_types(), [Type::I64, Type::I64]); - assert_eq!(<(f32, f32)>::wasm_types(), [Type::F32, Type::F32]); - assert_eq!(<(f64, f64)>::wasm_types(), [Type::F64, Type::F64]); - - // Mixed values - // assert_eq!(<(i32, i64, f32, f64)>::wasm_types(), [Type::I32, Type::I64, Type::F32, Type::F64]); - } - - #[test] - fn test_empty_array() { - assert_eq!(<()>::empty_array().len(), 0); - assert_eq!(::empty_array().len(), 1); - assert_eq!(<(i32, i64)>::empty_array().len(), 2); - } - - // #[test] - // fn test_from_array() { - // assert_eq!(<()>::from_array([]), ()); - // assert_eq!(<(i32)>::from_array([1]), (1)); - // assert_eq!(<(i32, i32)>::from_array([1, 1]), (1, 1)); - // // This doesn't work - // // assert_eq!(<(i32, i64, f32, f64)>::from_array([1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()]), (1, 2, 3.1f32, 4.2f64)); - // } - - // #[test] - // fn test_into_array() { - // assert_eq!(().into_array(), []); - // assert_eq!((1).into_array(), [1]); - // assert_eq!((1, 2).into_array(), [1, 2]); - // assert_eq!((1, 2, 3).into_array(), [1, 2, 3]); - // // This doesn't work - // // assert_eq!(<(i32, i64, f32, f64)>::from_array([1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()]), (1, 2, 3.1f32, 4.2f64)); - // } - - #[test] - fn test_into_c_struct() { - // assert_eq!(<()>::into_c_struct(), &[]); - } -} - -#[allow(non_snake_case)] -#[cfg(test)] -mod test_func { - use super::*; - use crate::types::Type; - use std::ptr; - // WasmTypeList - - fn func() {} - fn func__i32() -> i32 { - 0 - } - fn func_i32(_a: i32) {} - fn func_i32__i32(a: i32) -> i32 { - a * 2 - } - fn func_i32_i32__i32(a: i32, b: i32) -> i32 { - a + b - } - fn func_i32_i32__i32_i32(a: i32, b: i32) -> (i32, i32) { - (a, b) - } - fn func_f32_i32__i32_f32(a: f32, b: i32) -> (i32, f32) { - (b, a) - } - - #[test] - fn test_function_types() { - assert_eq!(Func::new(func).ty(), FunctionType::new(vec![], vec![])); - assert_eq!( - Func::new(func__i32).ty(), - FunctionType::new(vec![], vec![Type::I32]) - ); - assert_eq!( - Func::new(func_i32).ty(), - FunctionType::new(vec![Type::I32], vec![]) - ); - assert_eq!( - Func::new(func_i32__i32).ty(), - FunctionType::new(vec![Type::I32], vec![Type::I32]) - ); - assert_eq!( - Func::new(func_i32_i32__i32).ty(), - FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]) - ); - assert_eq!( - Func::new(func_i32_i32__i32_i32).ty(), - FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32]) - ); - assert_eq!( - Func::new(func_f32_i32__i32_f32).ty(), - FunctionType::new(vec![Type::F32, Type::I32], vec![Type::I32, Type::F32]) - ); - } - - #[test] - fn test_function_pointer() { - let f = Func::new(func_i32__i32); - let function = - unsafe { std::mem::transmute::<*const FunctionBody, fn(usize, i32) -> i32>(f.address) }; - assert_eq!(function(0, 3), 6); - } - - #[test] - fn test_function_call() { - let f = Func::new(func_i32__i32); - let x = |args: <(i32, i32) as WasmTypeList>::Array, - rets: &mut <(i32, i32) as WasmTypeList>::Array| { - let result = func_i32_i32__i32_i32(args[0] as _, args[1] as _); - rets[0] = result.0 as _; - rets[1] = result.1 as _; - }; - let mut rets = <(i64, i64)>::empty_array(); - x([20, 10], &mut rets); - // panic!("Rets: {:?}",rets); - let mut rets = <(i64)>::empty_array(); - // let result = f.call([1], &mut rets); - // assert_eq!(result.is_err(), true); - } -} From 35737cf9bb0d37647dc5a707a31497a38ec26ae2 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 19 Jun 2020 09:25:23 -0700 Subject: [PATCH 40/59] Update README.md --- lib/compiler/README.md | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/compiler/README.md b/lib/compiler/README.md index a8f3e1460..dc884e294 100644 --- a/lib/compiler/README.md +++ b/lib/compiler/README.md @@ -5,8 +5,41 @@ This crate is the base for Compiler implementations. It performs the translation from a Wasm module into a basic ModuleInfo, but leaves the Wasm function bytecode translation to the compiler implementor. +Here are some of the Compilers provided by Wasmer: +* [Singlepass](https://github.com/wasmerio/wasmer-reborn/tree/master/lib/compiler-singlepass) +* [Cranelift](https://github.com/wasmerio/wasmer-reborn/tree/master/lib/compiler-cranelift) +* [LLVM](https://github.com/wasmerio/wasmer-reborn/tree/master/lib/compiler-llvm) + +## How to create a compiler + +Creating a new compiler is quite easy, you just need to impement two traits: `CompilerConfig` and `Compiler`: + +```rust +/// The compiler configuration options. +pub trait CompilerConfig { + /// Gets the custom compiler config + fn compiler(&self) -> Box; +} + +/// An implementation of a Compiler from parsed WebAssembly module to Compiled native code. +pub trait Compiler { + /// Compiles a parsed module. + /// + /// It returns the [`Compilation`] or a [`CompileError`]. + fn compile_module<'data, 'module>( + &self, + target: &Target, + compile_info: &'module CompileModuleInfo, + module_translation: &ModuleTranslationState, + // The list of function bodies + function_body_inputs: PrimaryMap>, + ) -> Result; +} +``` + + ### Acknowledgments -This project borrowed some of the code strucutre from the [cranelift-wasm](https://crates.io/crates/cranelift-wasm), however it's been adapted to not depend on any specific IR and be abstract of any compiler. +This project borrowed some of the code strucutre from the [cranelift-wasm](https://crates.io/crates/cranelift-wasm) crate, however it's been adapted to not depend on any specific IR and be abstract of any compiler. Please check [Wasmer ATTRIBUTIONS](https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md) to further see licenses and other attributions of the project. From 2017acf99e8fef394c659a5fdb0c0f2006288c33 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Sat, 20 Jun 2020 13:43:46 -0700 Subject: [PATCH 41/59] Some clippy cleanup. --- lib/api/src/memory.rs | 1 - .../src/translator/code_translator.rs | 6 +- .../src/translator/unwind.rs | 2 +- lib/compiler-llvm/src/trampoline/wasm.rs | 4 +- lib/compiler-singlepass/src/codegen_x64.rs | 207 ++++++++---------- lib/compiler-singlepass/src/common_decl.rs | 4 +- lib/compiler-singlepass/src/emitter_x64.rs | 9 +- lib/compiler-singlepass/src/machine.rs | 52 ++--- lib/compiler/src/translator/middleware.rs | 3 +- lib/compiler/src/translator/sections.rs | 39 ++-- lib/emscripten/src/env/unix/mod.rs | 4 +- lib/emscripten/src/io/mod.rs | 2 +- lib/emscripten/src/lib.rs | 6 +- lib/emscripten/src/memory.rs | 2 +- lib/emscripten/src/pthread.rs | 6 +- lib/emscripten/src/syscalls/unix.rs | 4 +- lib/emscripten/src/time.rs | 2 +- lib/emscripten/src/utils.rs | 4 +- lib/engine-jit/src/code_memory.rs | 3 +- lib/runtime/src/module.rs | 22 +- lib/wasm-common/src/native.rs | 1 - src/commands/compile.rs | 2 +- src/commands/config.rs | 4 +- src/commands/run.rs | 6 +- src/utils.rs | 2 +- tests/lib/test-generator/src/lib.rs | 2 +- tests/lib/test-generator/src/processors.rs | 2 +- tests/lib/wast/src/wast.rs | 4 +- 28 files changed, 185 insertions(+), 220 deletions(-) diff --git a/lib/api/src/memory.rs b/lib/api/src/memory.rs index 1f4f36fba..6fa2862e8 100644 --- a/lib/api/src/memory.rs +++ b/lib/api/src/memory.rs @@ -107,7 +107,6 @@ impl Memory for LinearMemory { /// of wasm pages. fn grow(&self, delta: Pages) -> Result { // Optimization of memory.grow 0 calls. - let delta: Pages = delta.into(); let mut mmap = self.mmap.borrow_mut(); if delta.0 == 0 { return Ok(mmap.size); diff --git a/lib/compiler-cranelift/src/translator/code_translator.rs b/lib/compiler-cranelift/src/translator/code_translator.rs index fc183855b..ba6c91112 100644 --- a/lib/compiler-cranelift/src/translator/code_translator.rs +++ b/lib/compiler-cranelift/src/translator/code_translator.rs @@ -1290,12 +1290,12 @@ pub fn translate_operator( } Operator::I8x16ExtractLaneS { lane } | Operator::I16x8ExtractLaneS { lane } => { let vector = pop1_with_bitcast(state, type_of(op), builder); - let extracted = builder.ins().extractlane(vector, lane.clone()); + let extracted = builder.ins().extractlane(vector, *lane); state.push1(builder.ins().sextend(I32, extracted)) } Operator::I8x16ExtractLaneU { lane } | Operator::I16x8ExtractLaneU { lane } => { let vector = pop1_with_bitcast(state, type_of(op), builder); - let extracted = builder.ins().extractlane(vector, lane.clone()); + let extracted = builder.ins().extractlane(vector, *lane); state.push1(builder.ins().uextend(I32, extracted)); // On x86, PEXTRB zeroes the upper bits of the destination register of extractlane so // uextend could be elided; for now, uextend is needed for Cranelift's type checks to @@ -1306,7 +1306,7 @@ pub fn translate_operator( | Operator::F32x4ExtractLane { lane } | Operator::F64x2ExtractLane { lane } => { let vector = pop1_with_bitcast(state, type_of(op), builder); - state.push1(builder.ins().extractlane(vector, lane.clone())) + state.push1(builder.ins().extractlane(vector, *lane)) } Operator::I8x16ReplaceLane { lane } | Operator::I16x8ReplaceLane { lane } => { let (vector, replacement) = state.pop2(); diff --git a/lib/compiler-cranelift/src/translator/unwind.rs b/lib/compiler-cranelift/src/translator/unwind.rs index 97b1fb15e..50b61b0e9 100644 --- a/lib/compiler-cranelift/src/translator/unwind.rs +++ b/lib/compiler-cranelift/src/translator/unwind.rs @@ -24,7 +24,7 @@ impl CraneliftUnwindInfo { /// main users of this function) pub fn maybe_into_to_windows_unwind(self) -> Option { match self { - CraneliftUnwindInfo::WindowsX64(unwind_info) => { + Self::WindowsX64(unwind_info) => { Some(CompiledFunctionUnwindInfo::WindowsX64(unwind_info)) } _ => None, diff --git a/lib/compiler-llvm/src/trampoline/wasm.rs b/lib/compiler-llvm/src/trampoline/wasm.rs index 38efa1351..06b912b90 100644 --- a/lib/compiler-llvm/src/trampoline/wasm.rs +++ b/lib/compiler-llvm/src/trampoline/wasm.rs @@ -113,7 +113,7 @@ impl FuncTrampoline { if eh_frame_section_indices.len() != custom_sections.len() { all_sections_are_eh_sections = false; } else { - let mut eh_frame_section_indices = eh_frame_section_indices.clone(); + let mut eh_frame_section_indices = eh_frame_section_indices; eh_frame_section_indices.sort_unstable(); for (idx, section_idx) in eh_frame_section_indices.iter().enumerate() { if idx as u32 != section_idx.as_u32() { @@ -215,7 +215,7 @@ impl FuncTrampoline { if eh_frame_section_indices.len() != custom_sections.len() { all_sections_are_eh_sections = false; } else { - let mut eh_frame_section_indices = eh_frame_section_indices.clone(); + let mut eh_frame_section_indices = eh_frame_section_indices; eh_frame_section_indices.sort_unstable(); for (idx, section_idx) in eh_frame_section_indices.iter().enumerate() { if idx as u32 != section_idx.as_u32() { diff --git a/lib/compiler-singlepass/src/codegen_x64.rs b/lib/compiler-singlepass/src/codegen_x64.rs index 47279ff71..2d1c0bbfc 100644 --- a/lib/compiler-singlepass/src/codegen_x64.rs +++ b/lib/compiler-singlepass/src/codegen_x64.rs @@ -408,7 +408,7 @@ impl<'a> FuncGen<'a> { let inner = |m: &mut Machine, a: &mut Assembler, src: Location| match dst { Location::Imm32(_) | Location::Imm64(_) => { return Err(CodegenError { - message: format!("emit_relaxed_zx_sx dst Imm: unreachable code"), + message: "emit_relaxed_zx_sx dst Imm: unreachable code".to_string(), }) } Location::Memory(_, _) => { @@ -425,7 +425,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("emit_relaxed_zx_sx dst: unreachable code"), + message: "emit_relaxed_zx_sx dst: unreachable code".to_string(), }) } }; @@ -446,7 +446,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("emit_relaxed_zx_sx src: unreachable code"), + message: "emit_relaxed_zx_sx src: unreachable code".to_string(), }) } } @@ -582,7 +582,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("emit_relaxed_avx_base src1: unreachable code"), + message: "emit_relaxed_avx_base src1: unreachable code".to_string(), }) } }; @@ -611,7 +611,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("emit_relaxed_avx_base src2: unreachable code"), + message: "emit_relaxed_avx_base src2: unreachable code".to_string(), }) } }; @@ -626,7 +626,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("emit_relaxed_avx_base dst: unreachable code"), + message: "emit_relaxed_avx_base dst: unreachable code".to_string(), }) } } @@ -701,7 +701,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("emit_cmpop_i32_dynamic_b ret: unreachable code"), + message: "emit_cmpop_i32_dynamic_b ret: unreachable code".to_string(), }) } } @@ -748,7 +748,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("emit_cmpop_i64_dynamic_b ret: unreachable code"), + message: "emit_cmpop_i64_dynamic_b ret: unreachable code".to_string(), }) } } @@ -808,7 +808,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("emit_xcnt_i32 loc: unreachable code"), + message: "emit_xcnt_i32 loc: unreachable code".to_string(), }) } } @@ -861,7 +861,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("emit_xcnt_i64 loc: unreachable code"), + message: "emit_xcnt_i64 loc: unreachable code".to_string(), }) } } @@ -965,7 +965,7 @@ impl<'a> FuncGen<'a> { self.machine.state.register_values[X64Register::GPR(*r).to_index().0].clone(); if content == MachineValue::Undefined { return Err(CodegenError { - message: format!("emit_call_sysv: Undefined used_gprs content"), + message: "emit_call_sysv: Undefined used_gprs content".to_string(), }); } self.machine.state.stack_values.push(content); @@ -992,7 +992,7 @@ impl<'a> FuncGen<'a> { self.machine.state.register_values[X64Register::XMM(*r).to_index().0].clone(); if content == MachineValue::Undefined { return Err(CodegenError { - message: format!("emit_call_sysv: Undefined used_xmms content"), + message: "emit_call_sysv: Undefined used_xmms content".to_string(), }); } self.machine.state.stack_values.push(content); @@ -1003,12 +1003,8 @@ impl<'a> FuncGen<'a> { // Calculate stack offset. for (i, _param) in params.iter().enumerate() { - let loc = Machine::get_param_location(1 + i); - match loc { - Location::Memory(_, _) => { - stack_offset += 8; - } - _ => {} + if let Location::Memory(_, _) = Machine::get_param_location(1 + i) { + stack_offset += 8; } } @@ -1060,7 +1056,8 @@ impl<'a> FuncGen<'a> { Location::Memory(reg, offset) => { if reg != GPR::RBP { return Err(CodegenError { - message: format!("emit_call_sysv loc param: unreachable code"), + message: "emit_call_sysv loc param: unreachable code" + .to_string(), }); } self.machine @@ -1110,7 +1107,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("emit_call_sysv loc: unreachable code"), + message: "emit_call_sysv loc: unreachable code".to_string(), }) } } @@ -1135,7 +1132,7 @@ impl<'a> FuncGen<'a> { if (self.machine.state.stack_values.len() % 2) != 1 { return Err(CodegenError { - message: format!("emit_call_sysv: explicit shadow takes one slot"), + message: "emit_call_sysv: explicit shadow takes one slot".to_string(), }); } @@ -1169,7 +1166,7 @@ impl<'a> FuncGen<'a> { ); if (stack_offset % 8) != 0 { return Err(CodegenError { - message: format!("emit_call_sysv: Bad restoring stack alignement"), + message: "emit_call_sysv: Bad restoring stack alignement".to_string(), }); } for _ in 0..stack_offset / 8 { @@ -1178,7 +1175,7 @@ impl<'a> FuncGen<'a> { } // Restore XMMs. - if used_xmms.len() > 0 { + if !used_xmms.is_empty() { for (i, r) in used_xmms.iter().enumerate() { self.assembler.emit_mov( Size::S64, @@ -1204,7 +1201,7 @@ impl<'a> FuncGen<'a> { if self.machine.state.stack_values.pop().unwrap() != MachineValue::ExplicitShadow { return Err(CodegenError { - message: format!("emit_call_sysv: Popped value is not ExplicitShadow"), + message: "emit_call_sysv: Popped value is not ExplicitShadow".to_string(), }); } Ok(()) @@ -1328,7 +1325,7 @@ impl<'a> FuncGen<'a> { 3 => 8, _ => { return Err(CodegenError { - message: format!("emit_memory_op align: unreachable value"), + message: "emit_memory_op align: unreachable value".to_string(), }) } }; @@ -1369,7 +1366,7 @@ impl<'a> FuncGen<'a> { ) -> Result<(), CodegenError> { if memory_sz > stack_sz { return Err(CodegenError { - message: format!("emit_compare_and_swap: memory size > stac size"), + message: "emit_compare_and_swap: memory size > stack size".to_string(), }); } @@ -1771,7 +1768,7 @@ impl<'a> FuncGen<'a> { if self.machine.state.wasm_inst_offset != std::usize::MAX { return Err(CodegenError { - message: format!("emit_head: wasm_inst_offset not std::usize::MAX"), + message: "emit_head: wasm_inst_offset not std::usize::MAX".to_string(), }); } Ok(()) @@ -1840,7 +1837,7 @@ impl<'a> FuncGen<'a> { } pub fn has_control_frames(&self) -> bool { - self.control_stack.len() > 0 + !self.control_stack.is_empty() } pub fn feed_operator(&mut self, op: Operator) -> Result<(), CodegenError> { @@ -2158,7 +2155,7 @@ impl<'a> FuncGen<'a> { Location::GPR(reg) => reg, _ => { return Err(CodegenError { - message: format!("I32Clz src: unreachable code"), + message: "I32Clz src: unreachable code".to_string(), }) } }; @@ -2175,7 +2172,7 @@ impl<'a> FuncGen<'a> { Location::GPR(reg) => reg, _ => { return Err(CodegenError { - message: format!("I32Clz dst: unreachable code"), + message: "I32Clz dst: unreachable code".to_string(), }) } }; @@ -2209,12 +2206,9 @@ impl<'a> FuncGen<'a> { } _ => {} }; - match ret { - Location::Memory(_, _) => { - self.assembler.emit_mov(Size::S32, Location::GPR(dst), ret); - self.machine.release_temp_gpr(dst); - } - _ => {} + if let Location::Memory(_, _) = ret { + self.assembler.emit_mov(Size::S32, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); }; } Operator::I32Ctz => { @@ -2228,7 +2222,7 @@ impl<'a> FuncGen<'a> { Location::GPR(reg) => reg, _ => { return Err(CodegenError { - message: format!("I32Ctz src: unreachable code"), + message: "I32Ctz src: unreachable code".to_string(), }) } }; @@ -2245,7 +2239,7 @@ impl<'a> FuncGen<'a> { Location::GPR(reg) => reg, _ => { return Err(CodegenError { - message: format!("I32Ctz dst: unreachable code"), + message: "I32Ctz dst: unreachable code".to_string(), }) } }; @@ -2277,12 +2271,9 @@ impl<'a> FuncGen<'a> { } _ => {} }; - match ret { - Location::Memory(_, _) => { - self.assembler.emit_mov(Size::S32, Location::GPR(dst), ret); - self.machine.release_temp_gpr(dst); - } - _ => {} + if let Location::Memory(_, _) = ret { + self.assembler.emit_mov(Size::S32, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); }; } Operator::I32Popcnt => self.emit_xcnt_i32(Assembler::emit_popcnt)?, @@ -2403,7 +2394,7 @@ impl<'a> FuncGen<'a> { Location::GPR(reg) => reg, _ => { return Err(CodegenError { - message: format!("I64Clz src: unreachable code"), + message: "I64Clz src: unreachable code".to_string(), }) } }; @@ -2420,7 +2411,7 @@ impl<'a> FuncGen<'a> { Location::GPR(reg) => reg, _ => { return Err(CodegenError { - message: format!("I64Clz dst: unreachable code"), + message: "I64Clz dst: unreachable code".to_string(), }) } }; @@ -2454,12 +2445,9 @@ impl<'a> FuncGen<'a> { } _ => {} }; - match ret { - Location::Memory(_, _) => { - self.assembler.emit_mov(Size::S64, Location::GPR(dst), ret); - self.machine.release_temp_gpr(dst); - } - _ => {} + if let Location::Memory(_, _) = ret { + self.assembler.emit_mov(Size::S64, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); }; } Operator::I64Ctz => { @@ -2473,7 +2461,7 @@ impl<'a> FuncGen<'a> { Location::GPR(reg) => reg, _ => { return Err(CodegenError { - message: format!("I64Ctz src: unreachable code"), + message: "I64Ctz src: unreachable code".to_string(), }) } }; @@ -2490,7 +2478,7 @@ impl<'a> FuncGen<'a> { Location::GPR(reg) => reg, _ => { return Err(CodegenError { - message: format!("I64Ctz dst: unreachable code"), + message: "I64Ctz dst: unreachable code".to_string(), }) } }; @@ -2522,12 +2510,9 @@ impl<'a> FuncGen<'a> { } _ => {} }; - match ret { - Location::Memory(_, _) => { - self.assembler.emit_mov(Size::S64, Location::GPR(dst), ret); - self.machine.release_temp_gpr(dst); - } - _ => {} + if let Location::Memory(_, _) = ret { + self.assembler.emit_mov(Size::S64, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); }; } Operator::I64Popcnt => self.emit_xcnt_i64(Assembler::emit_popcnt)?, @@ -2719,7 +2704,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F32Max src1: unreachable code"), + message: "F32Max src1: unreachable code".to_string(), }) } }; @@ -2752,7 +2737,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F32Max src2: unreachable code"), + message: "F32Max src2: unreachable code".to_string(), }) } }; @@ -2809,7 +2794,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F32Max ret: unreachable code"), + message: "F32Max ret: unreachable code".to_string(), }) } } @@ -2863,7 +2848,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F32Min src1: unreachable code"), + message: "F32Min src1: unreachable code".to_string(), }) } }; @@ -2896,7 +2881,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F32Min src2: unreachable code"), + message: "F32Min src2: unreachable code".to_string(), }) } }; @@ -2962,7 +2947,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F32Min ret: unreachable code"), + message: "F32Min ret: unreachable code".to_string(), }) } } @@ -3209,7 +3194,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F64Max src1: unreachable code"), + message: "F64Max src1: unreachable code".to_string(), }) } }; @@ -3242,7 +3227,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F64Max src2: unreachable code"), + message: "F64Max src2: unreachable code".to_string(), }) } }; @@ -3299,7 +3284,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F64Max ret: unreachable code"), + message: "F64Max ret: unreachable code".to_string(), }) } } @@ -3354,7 +3339,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F64Min src1: unreachable code"), + message: "F64Min src1: unreachable code".to_string(), }) } }; @@ -3387,7 +3372,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F64Min src2: unreachable code"), + message: "F64Min src2: unreachable code".to_string(), }) } }; @@ -3453,7 +3438,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("F64Min ret: unreachable code"), + message: "F64Min ret: unreachable code".to_string(), }) } } @@ -5185,13 +5170,13 @@ impl<'a> FuncGen<'a> { |this| { this.assembler.emit_call_location(Location::GPR(GPR::RAX)); }, - params.iter().map(|x| *x), + params.iter().copied(), )?; self.machine .release_locations_only_stack(&mut self.assembler, ¶ms); - if return_types.len() > 0 { + if !return_types.is_empty() { let ret = self.machine.acquire_locations( &mut self.assembler, &[( @@ -5215,7 +5200,7 @@ impl<'a> FuncGen<'a> { Operator::CallIndirect { index, table_index } => { if table_index != 0 { return Err(CodegenError { - message: format!("CallIndirect: table_index is not 0"), + message: "CallIndirect: table_index is not 0".to_string(), }); } let table_index = TableIndex::new(table_index as _); @@ -5385,13 +5370,13 @@ impl<'a> FuncGen<'a> { )); } }, - params.iter().map(|x| *x), + params.iter().copied(), )?; self.machine .release_locations_only_stack(&mut self.assembler, ¶ms); - if return_types.len() > 0 { + if !return_types.is_empty() { let ret = self.machine.acquire_locations( &mut self.assembler, &[( @@ -5427,7 +5412,7 @@ impl<'a> FuncGen<'a> { WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], _ => { return Err(CodegenError { - message: format!("If: multi-value returns not yet implemented"), + message: "If: multi-value returns not yet implemented".to_string(), }) } }, @@ -5443,7 +5428,7 @@ impl<'a> FuncGen<'a> { Operator::Else => { let frame = self.control_stack.last_mut().unwrap(); - if !was_unreachable && frame.returns.len() > 0 { + if !was_unreachable && !frame.returns.is_empty() { let first_return = frame.returns[0]; let loc = *self.value_stack.last().unwrap(); if first_return.is_float() { @@ -5495,7 +5480,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("Else: frame.if_else unreachable code"), + message: "Else: frame.if_else unreachable code".to_string(), }) } } @@ -5568,7 +5553,8 @@ impl<'a> FuncGen<'a> { WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], _ => { return Err(CodegenError { - message: format!("Block: multi-value returns not yet implemented"), + message: "Block: multi-value returns not yet implemented" + .to_string(), }) } }, @@ -5596,7 +5582,7 @@ impl<'a> FuncGen<'a> { let _activate_offset = self.assembler.get_offset().0; self.control_stack.push(ControlFrame { - label: label, + label, loop_like: true, if_else: IfElseState::None, returns: match ty { @@ -5604,7 +5590,8 @@ impl<'a> FuncGen<'a> { WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty], _ => { return Err(CodegenError { - message: format!("Loop: multi-value returns not yet implemented"), + message: "Loop: multi-value returns not yet implemented" + .to_string(), }) } }, @@ -5625,7 +5612,7 @@ impl<'a> FuncGen<'a> { Location::Memory( Machine::get_vmctx_reg(), self.vmoffsets.vmctx_builtin_function( - if let Some(_) = self.module.local_memory_index(memory_index) { + if self.module.local_memory_index(memory_index).is_some() { VMBuiltinFunctionIndex::get_memory32_size_index() } else { VMBuiltinFunctionIndex::get_imported_memory32_size_index() @@ -5667,7 +5654,7 @@ impl<'a> FuncGen<'a> { Location::Memory( Machine::get_vmctx_reg(), self.vmoffsets.vmctx_builtin_function( - if let Some(_) = self.module.local_memory_index(memory_index) { + if self.module.local_memory_index(memory_index).is_some() { VMBuiltinFunctionIndex::get_memory32_grow_index() } else { VMBuiltinFunctionIndex::get_imported_memory32_grow_index() @@ -6033,7 +6020,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("I64Load32U ret: unreachable code"), + message: "I64Load32U ret: unreachable code".to_string(), }) } } @@ -6156,10 +6143,10 @@ impl<'a> FuncGen<'a> { } Operator::Return => { let frame = &self.control_stack[0]; - if frame.returns.len() > 0 { + if !frame.returns.is_empty() { if frame.returns.len() != 1 { return Err(CodegenError { - message: format!("Return: incorrect frame.returns"), + message: "Return: incorrect frame.returns".to_string(), }); } let first_return = frame.returns[0]; @@ -6206,10 +6193,10 @@ impl<'a> FuncGen<'a> { Operator::Br { relative_depth } => { let frame = &self.control_stack[self.control_stack.len() - 1 - (relative_depth as usize)]; - if !frame.loop_like && frame.returns.len() > 0 { + if !frame.loop_like && !frame.returns.is_empty() { if frame.returns.len() != 1 { return Err(CodegenError { - message: format!("Br: incorrect frame.returns"), + message: "Br: incorrect frame.returns".to_string(), }); } let first_return = frame.returns[0]; @@ -6260,10 +6247,10 @@ impl<'a> FuncGen<'a> { let frame = &self.control_stack[self.control_stack.len() - 1 - (relative_depth as usize)]; - if !frame.loop_like && frame.returns.len() > 0 { + if !frame.loop_like && !frame.returns.is_empty() { if frame.returns.len() != 1 { return Err(CodegenError { - message: format!("BrIf: incorrect frame.returns"), + message: "BrIf: incorrect frame.returns".to_string(), }); } @@ -6343,7 +6330,7 @@ impl<'a> FuncGen<'a> { table.push(label); let frame = &self.control_stack[self.control_stack.len() - 1 - (*target as usize)]; - if !frame.loop_like && frame.returns.len() > 0 { + if !frame.loop_like && !frame.returns.is_empty() { if frame.returns.len() != 1 { return Err(CodegenError { message: format!( @@ -6395,10 +6382,10 @@ impl<'a> FuncGen<'a> { { let frame = &self.control_stack [self.control_stack.len() - 1 - (default_target as usize)]; - if !frame.loop_like && frame.returns.len() > 0 { + if !frame.loop_like && !frame.returns.is_empty() { if frame.returns.len() != 1 { return Err(CodegenError { - message: format!("BrTable: incorrect frame.returns"), + message: "BrTable: incorrect frame.returns".to_string(), }); } @@ -6457,7 +6444,7 @@ impl<'a> FuncGen<'a> { Operator::End => { let frame = self.control_stack.pop().unwrap(); - if !was_unreachable && frame.returns.len() > 0 { + if !was_unreachable && !frame.returns.is_empty() { let loc = *self.value_stack.last().unwrap(); if frame.returns[0].is_float() { let fp = self.fp_stack.peek1()?; @@ -6492,7 +6479,7 @@ impl<'a> FuncGen<'a> { } } - if self.control_stack.len() == 0 { + if self.control_stack.is_empty() { self.assembler.emit_label(frame.label); self.machine .finalize_locals(&mut self.assembler, &self.locals); @@ -6530,10 +6517,10 @@ impl<'a> FuncGen<'a> { self.assembler.emit_label(label); } - if frame.returns.len() > 0 { + if !frame.returns.is_empty() { if frame.returns.len() != 1 { return Err(CodegenError { - message: format!("End: incorrect frame.returns"), + message: "End: incorrect frame.returns".to_string(), }); } let loc = self.machine.acquire_locations( @@ -6745,7 +6732,7 @@ impl<'a> FuncGen<'a> { } _ => { return Err(CodegenError { - message: format!("I64AtomicLoad32U ret: unreachable code"), + message: "I64AtomicLoad32U ret: unreachable code".to_string(), }) } } @@ -8260,12 +8247,8 @@ pub fn gen_std_trampoline(sig: &FunctionType) -> FunctionBody { // Calculate stack offset. let mut stack_offset: u32 = 0; for (i, _param) in sig.params().iter().enumerate() { - let loc = Machine::get_param_location(1 + i); - match loc { - Location::Memory(_, _) => { - stack_offset += 8; - } - _ => {} + if let Location::Memory(_, _) = Machine::get_param_location(1 + i) { + stack_offset += 8; } } @@ -8336,7 +8319,7 @@ pub fn gen_std_trampoline(sig: &FunctionType) -> FunctionBody { ); // Write return value. - if sig.results().len() > 0 { + if !sig.results().is_empty() { a.emit_mov( Size::S64, Location::GPR(GPR::RAX), @@ -8372,7 +8355,7 @@ pub fn gen_std_dynamic_import_trampoline( ); // Copy arguments. - if sig.params().len() > 0 { + if !sig.params().is_empty() { let mut argalloc = ArgumentRegisterAllocator::default(); argalloc.next(Type::I64).unwrap(); // skip VMContext @@ -8424,7 +8407,7 @@ pub fn gen_std_dynamic_import_trampoline( a.emit_call_location(Location::GPR(GPR::RAX)); // Fetch return value. - if sig.results().len() > 0 { + if !sig.results().is_empty() { assert_eq!(sig.results().len(), 1); a.emit_mov( Size::S64, @@ -8468,8 +8451,7 @@ pub fn gen_import_call_trampoline( if sig .params() .iter() - .find(|&&x| x == Type::F32 || x == Type::F64) - .is_some() + .any(|&x| x == Type::F32 || x == Type::F64) { let mut param_locations: Vec = vec![]; @@ -8491,8 +8473,7 @@ pub fn gen_import_call_trampoline( for i in 0..sig.params().len() { let loc = match i { 0..=4 => { - static PARAM_REGS: &'static [GPR] = - &[GPR::RSI, GPR::RDX, GPR::RCX, GPR::R8, GPR::R9]; + static PARAM_REGS: &[GPR] = &[GPR::RSI, GPR::RDX, GPR::RCX, GPR::R8, GPR::R9]; let loc = Location::Memory(GPR::RSP, (i * 8) as i32); a.emit_mov(Size::S64, Location::GPR(PARAM_REGS[i]), loc); loc diff --git a/lib/compiler-singlepass/src/common_decl.rs b/lib/compiler-singlepass/src/common_decl.rs index 70d7feaf8..e59095822 100644 --- a/lib/compiler-singlepass/src/common_decl.rs +++ b/lib/compiler-singlepass/src/common_decl.rs @@ -161,7 +161,7 @@ impl MachineState { .enumerate() .find(|&(_, (a, b))| a != b) .map(|x| x.0) - .unwrap_or(old.stack_values.len().min(self.stack_values.len())); + .unwrap_or_else(|| old.stack_values.len().min(self.stack_values.len())); assert_eq!(self.register_values.len(), old.register_values.len()); let reg_diff: Vec<_> = self .register_values @@ -196,7 +196,7 @@ impl MachineState { .enumerate() .find(|&(_, (a, b))| a != b) .map(|x| x.0) - .unwrap_or(old.wasm_stack.len().min(self.wasm_stack.len())); + .unwrap_or_else(|| old.wasm_stack.len().min(self.wasm_stack.len())); MachineStateDiff { last: None, stack_push: self.stack_values[first_diff_stack_depth..].to_vec(), diff --git a/lib/compiler-singlepass/src/emitter_x64.rs b/lib/compiler-singlepass/src/emitter_x64.rs index a57ef1c45..a4c0ceecd 100644 --- a/lib/compiler-singlepass/src/emitter_x64.rs +++ b/lib/compiler-singlepass/src/emitter_x64.rs @@ -702,12 +702,9 @@ impl Emitter for Assembler { fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) { // fast path - match (src, dst) { - (Location::Imm32(0), Location::GPR(x)) => { - dynasm!(self ; xor Rd(x as u8), Rd(x as u8)); - return; - } - _ => {} + if let (Location::Imm32(0), Location::GPR(x)) = (src, dst) { + dynasm!(self ; xor Rd(x as u8), Rd(x as u8)); + return; } binop_all_nofp!(mov, self, sz, src, dst, { diff --git a/lib/compiler-singlepass/src/machine.rs b/lib/compiler-singlepass/src/machine.rs index a1b41849b..17374f818 100644 --- a/lib/compiler-singlepass/src/machine.rs +++ b/lib/compiler-singlepass/src/machine.rs @@ -50,7 +50,7 @@ impl Machine { /// This method does not mark the register as used. pub fn pick_gpr(&self) -> Option { use GPR::*; - static REGS: &'static [GPR] = &[RSI, RDI, R8, R9, R10, R11]; + static REGS: &[GPR] = &[RSI, RDI, R8, R9, R10, R11]; for r in REGS { if !self.used_gprs.contains(r) { return Some(*r); @@ -64,7 +64,7 @@ impl Machine { /// This method does not mark the register as used. pub fn pick_temp_gpr(&self) -> Option { use GPR::*; - static REGS: &'static [GPR] = &[RAX, RCX, RDX]; + static REGS: &[GPR] = &[RAX, RCX, RDX]; for r in REGS { if !self.used_gprs.contains(r) { return Some(*r); @@ -99,7 +99,7 @@ impl Machine { /// This method does not mark the register as used. pub fn pick_xmm(&self) -> Option { use XMM::*; - static REGS: &'static [XMM] = &[XMM3, XMM4, XMM5, XMM6, XMM7]; + static REGS: &[XMM] = &[XMM3, XMM4, XMM5, XMM6, XMM7]; for r in REGS { if !self.used_xmms.contains(r) { return Some(*r); @@ -113,7 +113,7 @@ impl Machine { /// This method does not mark the register as used. pub fn pick_temp_xmm(&self) -> Option { use XMM::*; - static REGS: &'static [XMM] = &[XMM0, XMM1, XMM2]; + static REGS: &[XMM] = &[XMM0, XMM1, XMM2]; for r in REGS { if !self.used_xmms.contains(r) { return Some(*r); @@ -260,20 +260,17 @@ impl Machine { let mut delta_stack_offset: usize = 0; for loc in locs.iter().rev() { - match *loc { - Location::Memory(GPR::RBP, x) => { - if x >= 0 { - unreachable!(); - } - let offset = (-x) as usize; - if offset != self.stack_offset.0 { - unreachable!(); - } - self.stack_offset.0 -= 8; - delta_stack_offset += 8; - self.state.stack_values.pop().unwrap(); + if let Location::Memory(GPR::RBP, x) = *loc { + if x >= 0 { + unreachable!(); } - _ => {} + let offset = (-x) as usize; + if offset != self.stack_offset.0 { + unreachable!(); + } + self.stack_offset.0 -= 8; + delta_stack_offset += 8; + self.state.stack_values.pop().unwrap(); } // Wasm state popping is deferred to `release_locations_only_osr_state`. } @@ -302,19 +299,16 @@ impl Machine { let mut stack_offset = self.stack_offset.0; for loc in locs.iter().rev() { - match *loc { - Location::Memory(GPR::RBP, x) => { - if x >= 0 { - unreachable!(); - } - let offset = (-x) as usize; - if offset != stack_offset { - unreachable!(); - } - stack_offset -= 8; - delta_stack_offset += 8; + if let Location::Memory(GPR::RBP, x) = *loc { + if x >= 0 { + unreachable!(); } - _ => {} + let offset = (-x) as usize; + if offset != stack_offset { + unreachable!(); + } + stack_offset -= 8; + delta_stack_offset += 8; } } diff --git a/lib/compiler/src/translator/middleware.rs b/lib/compiler/src/translator/middleware.rs index 36fc27563..21619d59d 100644 --- a/lib/compiler/src/translator/middleware.rs +++ b/lib/compiler/src/translator/middleware.rs @@ -11,8 +11,7 @@ use wasmparser::{BinaryReader, Operator, Result as WpResult, Type}; /// A shared builder for function middlewares. pub trait FunctionMiddlewareGenerator: Debug + Send + Sync { /// Generates a `FunctionMiddleware` for a given function. - fn generate<'a>(&self, local_function_index: LocalFunctionIndex) - -> Box; + fn generate(&self, local_function_index: LocalFunctionIndex) -> Box; } /// A function middleware specialized for a single function. diff --git a/lib/compiler/src/translator/sections.rs b/lib/compiler/src/translator/sections.rs index 8d4a32c59..ddb32364a 100644 --- a/lib/compiler/src/translator/sections.rs +++ b/lib/compiler/src/translator/sections.rs @@ -61,27 +61,24 @@ pub fn parse_type_section( environ.reserve_signatures(count)?; for entry in types { - match entry.map_err(to_wasm_error)? { - WPFunctionType { params, returns } => { - let sig_params: Vec = params - .iter() - .map(|ty| { - wptype_to_type(*ty) - .expect("only numeric types are supported in function signatures") - }) - .collect(); - let sig_returns: Vec = returns - .iter() - .map(|ty| { - wptype_to_type(*ty) - .expect("only numeric types are supported in function signatures") - }) - .collect(); - let sig = FunctionType::new(sig_params, sig_returns); - environ.declare_signature(sig)?; - module_translation_state.wasm_types.push((params, returns)); - } - } + let WPFunctionType { params, returns } = entry.map_err(to_wasm_error)?; + let sig_params: Vec = params + .iter() + .map(|ty| { + wptype_to_type(*ty) + .expect("only numeric types are supported in function signatures") + }) + .collect(); + let sig_returns: Vec = returns + .iter() + .map(|ty| { + wptype_to_type(*ty) + .expect("only numeric types are supported in function signatures") + }) + .collect(); + let sig = FunctionType::new(sig_params, sig_returns); + environ.declare_signature(sig)?; + module_translation_state.wasm_types.push((params, returns)); } Ok(()) } diff --git a/lib/emscripten/src/env/unix/mod.rs b/lib/emscripten/src/env/unix/mod.rs index 92fc3b1e4..775805d67 100644 --- a/lib/emscripten/src/env/unix/mod.rs +++ b/lib/emscripten/src/env/unix/mod.rs @@ -263,7 +263,7 @@ pub fn _getaddrinfo( .get_mut(); guest_sockaddr.sa_family = (*host_sockaddr_ptr).sa_family as i16; - guest_sockaddr.sa_data = (*host_sockaddr_ptr).sa_data.clone(); + guest_sockaddr.sa_data = (*host_sockaddr_ptr).sa_data; guest_sockaddr_ptr }; @@ -308,7 +308,7 @@ pub fn _getaddrinfo( } // this frees all connected nodes on the linked list freeaddrinfo(out_ptr); - head_of_list.unwrap_or(WasmPtr::new(0)) + head_of_list.unwrap_or_else(|| WasmPtr::new(0)) }; res_val_ptr.deref(ctx.memory(0)).unwrap().set(head_of_list); diff --git a/lib/emscripten/src/io/mod.rs b/lib/emscripten/src/io/mod.rs index 37d7c5bd7..e783bf29b 100644 --- a/lib/emscripten/src/io/mod.rs +++ b/lib/emscripten/src/io/mod.rs @@ -31,7 +31,7 @@ pub fn sigdelset(ctx: &mut EmEnv, set: i32, signum: i32) -> i32 { #[allow(clippy::cast_ptr_alignment)] let ptr = emscripten_memory_pointer!(memory, set) as *mut i32; - unsafe { *ptr = *ptr & !(1 << (signum - 1)) } + unsafe { *ptr &= !(1 << (signum - 1)) } 0 } diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index e06b17a0a..89f7b63c8 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -105,7 +105,7 @@ const STATIC_BUMP: u32 = 215_536; lazy_static! { static ref OLD_ABORT_ON_CANNOT_GROW_MEMORY_SIG: FunctionType = - { FunctionType::new(vec![], vec![ValType::I32]) }; + FunctionType::new(vec![], vec![ValType::I32]); } // The address globals begin at. Very low in memory, for code size and optimization opportunities. @@ -465,7 +465,7 @@ pub fn emscripten_call_main( } /// Top level function to execute emscripten -pub fn run_emscripten_instance<'a>( +pub fn run_emscripten_instance( instance: &mut Instance, env: &mut EmEnv, globals: &mut EmscriptenGlobals, @@ -1105,7 +1105,7 @@ pub fn generate_emscripten_env( // Compatibility with newer versions of Emscripten let mut to_insert: Vec<(String, _)> = vec![]; for (k, v) in env_ns.iter() { - if k.starts_with("_") { + if k.starts_with('_') { let k = &k[1..]; if !env_ns.contains(k) { to_insert.push((k.to_string(), v.clone())); diff --git a/lib/emscripten/src/memory.rs b/lib/emscripten/src/memory.rs index ef199d144..066cb1669 100644 --- a/lib/emscripten/src/memory.rs +++ b/lib/emscripten/src/memory.rs @@ -93,7 +93,7 @@ pub fn sbrk(ctx: &mut EmEnv, increment: i32) -> i32 { } } ctx.memory(0).view::()[dynamictop_ptr].set(new_dynamic_top as u32); - return old_dynamic_top as _; + old_dynamic_top as _ } /// emscripten: getTotalMemory diff --git a/lib/emscripten/src/pthread.rs b/lib/emscripten/src/pthread.rs index 6e5ae66b2..17c14f6ef 100644 --- a/lib/emscripten/src/pthread.rs +++ b/lib/emscripten/src/pthread.rs @@ -33,11 +33,11 @@ pub fn _pthread_attr_setstacksize(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 { 0 } -pub fn _pthread_cleanup_pop(_ctx: &mut EmEnv, _a: i32) -> () { +pub fn _pthread_cleanup_pop(_ctx: &mut EmEnv, _a: i32) { trace!("emscripten::_pthread_cleanup_pop"); } -pub fn _pthread_cleanup_push(_ctx: &mut EmEnv, _a: i32, _b: i32) -> () { +pub fn _pthread_cleanup_push(_ctx: &mut EmEnv, _a: i32, _b: i32) { trace!("emscripten::_pthread_cleanup_push"); } @@ -97,7 +97,7 @@ pub fn _pthread_equal(_ctx: &mut EmEnv, _a: i32, _b: i32) -> i32 { 0 } -pub fn _pthread_exit(_ctx: &mut EmEnv, _a: i32) -> () { +pub fn _pthread_exit(_ctx: &mut EmEnv, _a: i32) { trace!("emscripten::_pthread_exit"); } diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index 357d4d465..fac1cb30a 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -646,7 +646,7 @@ pub fn ___syscall102(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_ let address_addr = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() }; address_addr.sa_family = host_address.sa_family as _; - address_addr.sa_data = host_address.sa_data.clone(); + address_addr.sa_data = host_address.sa_data; // why is this here? // set_cloexec @@ -686,7 +686,7 @@ pub fn ___syscall102(ctx: &mut EmEnv, _which: c_int, mut varargs: VarArgs) -> c_ // translate from host data into emscripten data let mut address_mut = unsafe { address.deref_mut(ctx.memory(0)).unwrap().get_mut() }; address_mut.sa_family = sock_addr_host.sa_family as _; - address_mut.sa_data = sock_addr_host.sa_data.clone(); + address_mut.sa_data = sock_addr_host.sa_data; debug!( "=> socket: {}, address, {:?}, address_len: {}, result = {}", diff --git a/lib/emscripten/src/time.rs b/lib/emscripten/src/time.rs index 239f8da89..50b1091df 100644 --- a/lib/emscripten/src/time.rs +++ b/lib/emscripten/src/time.rs @@ -241,7 +241,7 @@ pub fn _localtime(ctx: &mut EmEnv, time_p: u32) -> c_int { let timespec = unsafe { let time_p_addr = emscripten_memory_pointer!(ctx.memory(0), time_p) as *mut i64; - let seconds = *time_p_addr.clone(); + let seconds = *time_p_addr; time::Timespec::new(seconds, 0) }; let result_tm = time::at(timespec); diff --git a/lib/emscripten/src/utils.rs b/lib/emscripten/src/utils.rs index c8a3c381c..3b052196c 100644 --- a/lib/emscripten/src/utils.rs +++ b/lib/emscripten/src/utils.rs @@ -31,7 +31,7 @@ pub fn get_emscripten_table_size(module: &Module) -> Result<(u32, Option), let ty = import.ty(); Ok((ty.minimum, ty.maximum)) } else { - return Err("Emscripten requires at least one imported table".to_string()); + Err("Emscripten requires at least one imported table".to_string()) } } @@ -40,7 +40,7 @@ pub fn get_emscripten_memory_size(module: &Module) -> Result<(Pages, Option { - let signature = self.functions.get(i.clone()).unwrap(); + let signature = self.functions.get(*i).unwrap(); let func_type = self.signatures.get(signature.clone()).unwrap(); Some(func_type.clone()) } @@ -169,20 +169,20 @@ impl ModuleInfo { let iter = self.exports.iter().map(move |(name, export_index)| { let extern_type = match export_index { ExportIndex::Function(i) => { - let signature = self.functions.get(i.clone()).unwrap(); - let func_type = self.signatures.get(signature.clone()).unwrap(); + let signature = self.functions.get(*i).unwrap(); + let func_type = self.signatures.get(*signature).unwrap(); ExternType::Function(func_type.clone()) } ExportIndex::Table(i) => { - let table_type = self.tables.get(i.clone()).unwrap(); + let table_type = self.tables.get(*i).unwrap(); ExternType::Table(*table_type) } ExportIndex::Memory(i) => { - let memory_type = self.memories.get(i.clone()).unwrap(); + let memory_type = self.memories.get(*i).unwrap(); ExternType::Memory(*memory_type) } ExportIndex::Global(i) => { - let global_type = self.globals.get(i.clone()).unwrap(); + let global_type = self.globals.get(*i).unwrap(); ExternType::Global(*global_type) } }; @@ -202,20 +202,20 @@ impl ModuleInfo { .map(move |((module, field, _), import_index)| { let extern_type = match import_index { ImportIndex::Function(i) => { - let signature = self.functions.get(i.clone()).unwrap(); - let func_type = self.signatures.get(signature.clone()).unwrap(); + let signature = self.functions.get(*i).unwrap(); + let func_type = self.signatures.get(*signature).unwrap(); ExternType::Function(func_type.clone()) } ImportIndex::Table(i) => { - let table_type = self.tables.get(i.clone()).unwrap(); + let table_type = self.tables.get(*i).unwrap(); ExternType::Table(*table_type) } ImportIndex::Memory(i) => { - let memory_type = self.memories.get(i.clone()).unwrap(); + let memory_type = self.memories.get(*i).unwrap(); ExternType::Memory(*memory_type) } ImportIndex::Global(i) => { - let global_type = self.globals.get(i.clone()).unwrap(); + let global_type = self.globals.get(*i).unwrap(); ExternType::Global(*global_type) } }; diff --git a/lib/wasm-common/src/native.rs b/lib/wasm-common/src/native.rs index 7c09ad548..d098983d4 100644 --- a/lib/wasm-common/src/native.rs +++ b/lib/wasm-common/src/native.rs @@ -679,7 +679,6 @@ mod test_wasm_type_list { mod test_func { use super::*; use crate::types::Type; - use std::ptr; // WasmTypeList fn func() {} diff --git a/src/commands/compile.rs b/src/commands/compile.rs index b08c92097..60aab6aa7 100644 --- a/src/commands/compile.rs +++ b/src/commands/compile.rs @@ -45,7 +45,7 @@ impl Compile { .fold(CpuFeature::set(), |a, b| a | b); // Cranelift requires SSE2, so we have this "hack" for now to facilitate // usage - features = features | CpuFeature::SSE2; + features |= CpuFeature::SSE2; Target::new(target_triple.clone(), features) }) .unwrap_or_default(); diff --git a/src/commands/config.rs b/src/commands/config.rs index 071b00178..f96dcc8e0 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -41,7 +41,7 @@ impl Config { /// Runs logic for the `config` subcommand pub fn execute(&self) -> Result<()> { self.inner_execute() - .context(format!("failed to retrieve the wasmer config")) + .context("failed to retrieve the wasmer config".to_string()) } fn inner_execute(&self) -> Result<()> { let key = "WASMER_DIR"; @@ -64,7 +64,7 @@ impl Config { println!("exec_prefix={}", bindir); println!("includedir={}", includedir); println!("libdir={}", libdir); - println!(""); + println!(); println!("Name: wasmer"); println!("Description: The Wasmer library for running WebAssembly"); println!("Version: {}", VERSION); diff --git a/src/commands/run.rs b/src/commands/run.rs index 340da2468..2ca771452 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -78,10 +78,10 @@ impl Run { format!( "failed to run `{}`{}", self.path.display(), - if compilers.len() > 0 { - "" - } else { + if compilers.is_empty() { " (no compilers enabled)" + } else { + "" } ) }) diff --git a/src/utils.rs b/src/utils.rs index 697caffad..3fbebf65c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -33,7 +33,7 @@ pub fn parse_mapdir(entry: &str) -> Result<(String, PathBuf)> { /// Parses a mapdir from an env var pub fn parse_envvar(entry: &str) -> Result<(String, String)> { if let [env_var, value] = entry.split('=').collect::>()[..] { - return Ok((env_var.to_string(), value.to_string())); + Ok((env_var.to_string(), value.to_string())) } else { bail!( "Env vars must be of the form =. Found {}", diff --git a/tests/lib/test-generator/src/lib.rs b/tests/lib/test-generator/src/lib.rs index b810a2fb3..0396fe8b9 100644 --- a/tests/lib/test-generator/src/lib.rs +++ b/tests/lib/test-generator/src/lib.rs @@ -50,7 +50,7 @@ pub fn build_ignores_from_textfile(path: PathBuf) -> anyhow::Result { for line in reader.lines() { let line = line.unwrap(); // If the line has a `#` we discard all the content that comes after - let line = if line.contains("#") { + let line = if line.contains('#') { let l: Vec<&str> = line.split('#').collect(); l.get(0).unwrap().to_string() } else { diff --git a/tests/lib/test-generator/src/processors.rs b/tests/lib/test-generator/src/processors.rs index 4d36db63c..43b312071 100644 --- a/tests/lib/test-generator/src/processors.rs +++ b/tests/lib/test-generator/src/processors.rs @@ -12,7 +12,7 @@ pub fn wast_processor(out: &mut Testsuite, p: PathBuf) -> Option { } // Ignore files starting with `.`, which could be editor temporary files - if p.file_stem()?.to_str()?.starts_with(".") { + if p.file_stem()?.to_str()?.starts_with('.') { return None; } diff --git a/tests/lib/wast/src/wast.rs b/tests/lib/wast/src/wast.rs index 2bdc4ce2e..8ddaf69f3 100644 --- a/tests/lib/wast/src/wast.rs +++ b/tests/lib/wast/src/wast.rs @@ -340,7 +340,7 @@ impl Wast { field: &str, args: &[Val], ) -> Result> { - let instance = self.get_instance(instance_name.as_ref().map(|x| &**x))?; + let instance = self.get_instance(instance_name.as_deref())?; let func: &Function = instance.exports.get(field)?; match func.call(args) { Ok(result) => Ok(result.into()), @@ -350,7 +350,7 @@ impl Wast { /// Get the value of an exported global from an instance. fn get(&mut self, instance_name: Option<&str>, field: &str) -> Result> { - let instance = self.get_instance(instance_name.as_ref().map(|x| &**x))?; + let instance = self.get_instance(instance_name.as_deref())?; let global: &Global = instance.exports.get(field)?; Ok(vec![global.get()]) } From ad7c618193c33155ae6f6fa43bb34f8feb740bb0 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 10:48:15 +0200 Subject: [PATCH 42/59] !temp Remove impl of `WasmTypeList` for `Infallible`. I don't think it is necessary anymore. --- lib/api/src/externals/function.rs | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index bd3bf7dbe..cd371cbfd 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -597,35 +597,6 @@ mod inner { } } - impl WasmTypeList for Infallible { - type CStruct = Self; - type Array = [i128; 0]; - - fn from_array(_: Self::Array) -> Self { - unreachable!() - } - - fn into_array(self) -> Self::Array { - [] - } - - fn empty_array() -> Self::Array { - unreachable!() - } - - fn from_c_struct(_: Self::CStruct) -> Self { - unreachable!() - } - - fn into_c_struct(self) -> Self::CStruct { - unreachable!() - } - - fn wasm_types() -> &'static [Type] { - &[] - } - } - macro_rules! impl_traits { ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => { /// Struct for typed funcs. @@ -759,7 +730,7 @@ mod inner { }}; } - //impl_traits!([C] S0,); + impl_traits!([C] S0,); //impl_traits!([transparent] S1, A1); impl_traits!([C] S2, A1, A2); impl_traits!([C] S3, A1, A2, A3); From 63ec941dac172c047e5fb194e74ae8424017445f Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 11:05:48 +0200 Subject: [PATCH 43/59] Revert "!temp Remove impl of `WasmTypeList` for `Infallible`." This reverts commit ad7c618193c33155ae6f6fa43bb34f8feb740bb0. --- lib/api/src/externals/function.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index cd371cbfd..bd3bf7dbe 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -597,6 +597,35 @@ mod inner { } } + impl WasmTypeList for Infallible { + type CStruct = Self; + type Array = [i128; 0]; + + fn from_array(_: Self::Array) -> Self { + unreachable!() + } + + fn into_array(self) -> Self::Array { + [] + } + + fn empty_array() -> Self::Array { + unreachable!() + } + + fn from_c_struct(_: Self::CStruct) -> Self { + unreachable!() + } + + fn into_c_struct(self) -> Self::CStruct { + unreachable!() + } + + fn wasm_types() -> &'static [Type] { + &[] + } + } + macro_rules! impl_traits { ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => { /// Struct for typed funcs. @@ -730,7 +759,7 @@ mod inner { }}; } - impl_traits!([C] S0,); + //impl_traits!([C] S0,); //impl_traits!([transparent] S1, A1); impl_traits!([C] S2, A1, A2); impl_traits!([C] S3, A1, A2, A3); From 07aff22c306a4b373e594a9264bf7a4e9c12908a Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 11:10:18 +0200 Subject: [PATCH 44/59] feat(api/wasm-common) Move `WasmExternType` from `wasm-common` to `wasmer`. Because there is a trait implementation conflicts for the implementations `WasmTypeList` for `$x*` where `$x: WasmExternType`. --- lib/api/src/externals/function.rs | 53 ++++++++++++++++++++++++++++--- lib/api/src/externals/mod.rs | 2 +- lib/api/src/lib.rs | 9 +++--- lib/api/src/native.rs | 4 +-- lib/api/src/ptr.rs | 5 ++- lib/wasm-common/src/lib.rs | 2 +- lib/wasm-common/src/native.rs | 47 --------------------------- 7 files changed, 60 insertions(+), 62 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index bd3bf7dbe..ce226636d 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -5,7 +5,7 @@ use crate::types::Val; use crate::FunctionType; use crate::NativeFunc; use crate::RuntimeError; -pub use inner::{HostFunction, WasmTypeList}; +pub use inner::{HostFunction, WasmExternType, WasmTypeList}; use inner::{WithEnv, WithoutEnv}; use std::cell::RefCell; use std::cmp::max; @@ -454,9 +454,54 @@ mod inner { use std::error::Error; use std::marker::PhantomData; use std::panic::{self, AssertUnwindSafe}; - use wasm_common::{FunctionType, NativeWasmType, Type, WasmExternType}; + use wasm_common::{FunctionType, NativeWasmType, Type}; use wasmer_runtime::{raise_user_trap, resume_panic}; + /// A trait to represent a wasm extern type. + pub unsafe trait WasmExternType: Copy + where + Self: Sized, + { + /// Native wasm type for this `WasmExternType`. + type Native: NativeWasmType; + + /// Convert from given `Native` type to self. + fn from_native(native: Self::Native) -> Self; + + /// Convert self to `Native` type. + fn to_native(self) -> Self::Native; + } + + macro_rules! wasm_extern_type { + ($type:ty => $native_type:ty) => { + #[allow(clippy::use_self)] + unsafe impl WasmExternType for $type { + type Native = $native_type; + + #[inline] + fn from_native(native: Self::Native) -> Self { + native as _ + } + + #[inline] + fn to_native(self) -> Self::Native { + self as _ + } + } + }; + } + + wasm_extern_type!(i8 => i32); + wasm_extern_type!(u8 => i32); + wasm_extern_type!(i16 => i32); + wasm_extern_type!(u16 => i32); + wasm_extern_type!(i32 => i32); + wasm_extern_type!(u32 => i32); + wasm_extern_type!(i64 => i64); + wasm_extern_type!(u64 => i64); + wasm_extern_type!(f32 => f32); + wasm_extern_type!(f64 => f64); + /// Represents a list of WebAssembly values. pub trait WasmTypeList { /// CStruct type. @@ -759,8 +804,8 @@ mod inner { }}; } - //impl_traits!([C] S0,); - //impl_traits!([transparent] S1, A1); + impl_traits!([C] S0,); + impl_traits!([transparent] S1, A1); impl_traits!([C] S2, A1, A2); impl_traits!([C] S3, A1, A2, A3); impl_traits!([C] S4, A1, A2, A3, A4); diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs index fc6982ad8..368d3134c 100644 --- a/lib/api/src/externals/mod.rs +++ b/lib/api/src/externals/mod.rs @@ -3,7 +3,7 @@ mod global; mod memory; mod table; -pub use self::function::{Function, HostFunction, WasmTypeList}; +pub use self::function::{Function, HostFunction, WasmExternType, WasmTypeList}; pub use self::global::Global; pub use self::memory::Memory; pub use self::table::Table; diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index feb65852f..5e73953ad 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -18,7 +18,9 @@ mod types; mod utils; pub use crate::exports::{ExportError, Exportable, Exports}; -pub use crate::externals::{Extern, Function, Global, HostFunction, Memory, Table, WasmTypeList}; +pub use crate::externals::{ + Extern, Function, Global, HostFunction, Memory, Table, WasmExternType, WasmTypeList, +}; pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace}; pub use crate::instance::Instance; pub use crate::memory_view::{Atomically, MemoryView}; @@ -34,11 +36,10 @@ pub use crate::types::{ }; pub use crate::types::{Val as Value, ValType as Type}; pub use crate::utils::is_wasm; - pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; pub use wasm_common::{ - Bytes, GlobalInit, LocalFunctionIndex, Pages, ValueType, WasmExternType, WASM_MAX_PAGES, - WASM_MIN_PAGES, WASM_PAGE_SIZE, + Bytes, GlobalInit, LocalFunctionIndex, Pages, ValueType, WASM_MAX_PAGES, WASM_MIN_PAGES, + WASM_PAGE_SIZE, }; #[cfg(feature = "compiler")] pub use wasmer_compiler::CompilerConfig; diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index c35d9e7b6..faf3b87d7 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -13,9 +13,9 @@ use crate::externals::function::{ FunctionDefinition, HostFunctionDefinition, VMDynamicFunction, VMDynamicFunctionWithEnv, VMDynamicFunctionWithoutEnv, WasmFunctionDefinition, }; -use crate::{Function, FunctionType, RuntimeError, Store, WasmTypeList}; +use crate::{Function, FunctionType, RuntimeError, Store, WasmExternType, WasmTypeList}; use std::panic::{catch_unwind, AssertUnwindSafe}; -use wasm_common::{NativeWasmType, WasmExternType}; +use wasm_common::NativeWasmType; use wasmer_runtime::{ ExportFunction, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind, }; diff --git a/lib/api/src/ptr.rs b/lib/api/src/ptr.rs index 91a6b8d46..4d181e217 100644 --- a/lib/api/src/ptr.rs +++ b/lib/api/src/ptr.rs @@ -6,10 +6,9 @@ //! Therefore, you should use this abstraction whenever possible to avoid memory //! related bugs when implementing an ABI. -use crate::externals::Memory; -use wasm_common::{ValueType, WasmExternType}; - +use crate::{externals::Memory, WasmExternType}; use std::{cell::Cell, fmt, marker::PhantomData, mem}; +use wasm_common::ValueType; /// The `Array` marker type. This type can be used like `WasmPtr` /// to get access to methods diff --git a/lib/wasm-common/src/lib.rs b/lib/wasm-common/src/lib.rs index b2227f8f8..eca1927cd 100644 --- a/lib/wasm-common/src/lib.rs +++ b/lib/wasm-common/src/lib.rs @@ -43,7 +43,7 @@ pub use crate::indexes::{ LocalFunctionIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, SignatureIndex, TableIndex, }; -pub use crate::native::{NativeWasmType, ValueType, WasmExternType}; +pub use crate::native::{NativeWasmType, ValueType}; pub use crate::r#ref::{ExternRef, HostInfo, HostRef}; pub use crate::units::{Bytes, Pages, WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE}; pub use crate::values::Value; diff --git a/lib/wasm-common/src/native.rs b/lib/wasm-common/src/native.rs index 196be00f2..1f20993cd 100644 --- a/lib/wasm-common/src/native.rs +++ b/lib/wasm-common/src/native.rs @@ -152,53 +152,6 @@ mod test_native_type { } } -/// A trait to represent a wasm extern type. -pub unsafe trait WasmExternType: Copy -where - Self: Sized, -{ - /// Native wasm type for this `WasmExternType`. - type Native: NativeWasmType; - - /// Convert from given `Native` type to self. - fn from_native(native: Self::Native) -> Self; - - /// Convert self to `Native` type. - fn to_native(self) -> Self::Native; -} - -macro_rules! wasm_extern_type { - ($type:ty => $native_type:ty) => { - #[allow(clippy::use_self)] - unsafe impl WasmExternType for $type { - type Native = $native_type; - - #[inline] - fn from_native(native: Self::Native) -> Self { - native as _ - } - - #[inline] - fn to_native(self) -> Self::Native { - self as _ - } - } - }; -} - -wasm_extern_type!(i8 => i32); -wasm_extern_type!(u8 => i32); -wasm_extern_type!(i16 => i32); -wasm_extern_type!(u16 => i32); -wasm_extern_type!(i32 => i32); -wasm_extern_type!(u32 => i32); -wasm_extern_type!(i64 => i64); -wasm_extern_type!(u64 => i64); -wasm_extern_type!(f32 => f32); -wasm_extern_type!(f64 => f64); -// wasm_extern_type!(u128 => i128); -// wasm_extern_type!(i128 => i128); - // pub trait IntegerAtomic // where // Self: Sized From a623b9531e2c35647aae874a744b9e534edc36d1 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 11:33:49 +0200 Subject: [PATCH 45/59] chore(api) Rename `inner::Func` to `inner::Function` and improve documentation. --- lib/api/src/externals/function.rs | 144 ++++++++++++++++++------------ 1 file changed, 86 insertions(+), 58 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index ce226636d..f425471aa 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -49,10 +49,13 @@ pub struct Function { } impl Function { - /// Creates a new `Func` with the given parameters. + /// Creates a new `Function` that is: /// - /// * `store` - a global cache to store information in - /// * `func` - the function. + /// 1. Static/Monomorphic, i.e. all inputs and outputs have a + /// unique _statically declared type_. The outputs can be + /// wrapped in a `Result`. + /// 2. Independent, i.e. the function _does not_ receive an + /// environment argument. pub fn new(store: &Store, func: F) -> Self where F: HostFunction, @@ -60,10 +63,11 @@ impl Function { Rets: WasmTypeList, Env: Sized + 'static, { - let func: inner::Func = inner::Func::new(func); - let address = func.address() as *const VMFunctionBody; + let function = inner::Function::::new(func); + let address = function.address() as *const VMFunctionBody; let vmctx = std::ptr::null_mut() as *mut _ as *mut VMContext; - let signature = func.ty(); + let signature = function.ty(); + Self { store: store.clone(), owned_by_store: true, @@ -77,6 +81,53 @@ impl Function { } } + /// Creates a new `Function` that is: + /// + /// 1. Static/Monomorphic, i.e. all inputs and outputs have a + /// unique statically declared type. The outputs can be wrapped + /// in a `Result`. + /// 2. Dependent, i.e. the function _does_ receive an environment + /// argument (given by `env`). + pub fn new_env(store: &Store, env: Env, func: F) -> Self + where + F: HostFunction, + Args: WasmTypeList, + Rets: WasmTypeList, + Env: Sized + 'static, + { + let function = inner::Function::::new(func); + let address = function.address() as *const VMFunctionBody; + + // TODO: We need to refactor the Function context. + // Right now is structured as it's always a `VMContext`. However, only + // Wasm-defined functions have a `VMContext`. + // In the case of Host-defined functions `VMContext` is whatever environment + // the user want to attach to the function. + let box_env = Box::new(env); + let vmctx = Box::into_raw(box_env) as *mut _ as *mut VMContext; + let signature = function.ty(); + + Self { + store: store.clone(), + owned_by_store: true, + definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), + exported: ExportFunction { + address, + kind: VMFunctionKind::Static, + vmctx, + signature, + }, + } + } + + /// Creates a new `Function` that is: + /// + /// 1. Dynamic/Polymorphic, i.e. all inputs are received in a + /// slice of `Val` (the set of all Wasm values), and all + /// outputs are stored in a vector of `Val`, wrapped in a + /// `Result`. + /// 2. Independent, i.e. the function _does not_ receive an + /// environment argument. #[allow(clippy::cast_ptr_alignment)] pub fn new_dynamic(store: &Store, ty: &FunctionType, func: F) -> Self where @@ -91,6 +142,7 @@ impl Function { // generated dynamic trampoline. let address = std::ptr::null() as *const VMFunctionBody; let vmctx = Box::into_raw(Box::new(dynamic_ctx)) as *mut VMContext; + Self { store: store.clone(), owned_by_store: true, @@ -104,6 +156,14 @@ impl Function { } } + /// Creates a new `Function` that is: + /// + /// 1. Dynamic/Polymorphic, i.e. all inputs are received in a + /// slice of `Val` (the set of all Wasm values), and all + /// outputs are stored in a vector of `Val`, wrapped in a + /// `Result`. + /// 2. Dependent, i.e. the function _does_ receive an environment + /// argument (given by `env`). #[allow(clippy::cast_ptr_alignment)] pub fn new_dynamic_env(store: &Store, ty: &FunctionType, env: Env, func: F) -> Self where @@ -120,6 +180,7 @@ impl Function { // generated dynamic trampoline. let address = std::ptr::null() as *const VMFunctionBody; let vmctx = Box::into_raw(Box::new(dynamic_ctx)) as *mut VMContext; + Self { store: store.clone(), owned_by_store: true, @@ -133,41 +194,6 @@ impl Function { } } - /// Creates a new `Func` with the given parameters. - /// - /// * `store` - a global cache to store information in. - /// * `env` - the function environment. - /// * `func` - the function. - pub fn new_env(store: &Store, env: Env, func: F) -> Self - where - F: HostFunction, - Args: WasmTypeList, - Rets: WasmTypeList, - Env: Sized + 'static, - { - let func: inner::Func = inner::Func::new(func); - let address = func.address() as *const VMFunctionBody; - // TODO: We need to refactor the Function context. - // Right now is structured as it's always a `VMContext`. However, only - // Wasm-defined functions have a `VMContext`. - // In the case of Host-defined functions `VMContext` is whatever environment - // the user want to attach to the function. - let box_env = Box::new(env); - let vmctx = Box::into_raw(box_env) as *mut _ as *mut VMContext; - let signature = func.ty(); - Self { - store: store.clone(), - owned_by_store: true, - definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), - exported: ExportFunction { - address, - kind: VMFunctionKind::Static, - vmctx, - signature, - }, - } - } - /// Returns the underlying type of this function. pub fn ty(&self) -> &FunctionType { &self.exported.signature @@ -449,6 +475,8 @@ impl VMDynamicFunctionCall for VMDynamicFunctionContext } } +/// This private inner module contains the low-level implementation +/// for `Func` and its siblings. mod inner { use std::convert::Infallible; use std::error::Error; @@ -606,27 +634,27 @@ mod inner { /// Represents a function that can be used by WebAssembly. #[derive(Clone, Debug, Hash, PartialEq, Eq)] - pub struct Func { + pub struct Function { address: *const FunctionBody, _phantom: PhantomData<(Args, Rets)>, } - unsafe impl Send for Func {} + unsafe impl Send for Function {} - impl Func + impl Function where Args: WasmTypeList, Rets: WasmTypeList, { - /// Creates a new `Func`. - pub fn new(func: F) -> Self + /// Creates a new `Function`. + pub fn new(function: F) -> Self where F: HostFunction, T: HostFunctionKind, E: Sized, { Self { - address: func.to_raw(), + address: function.to_raw(), _phantom: PhantomData, } } @@ -835,7 +863,7 @@ mod inner { #[cfg(test)] mod test_wasm_type_list { use super::*; - use crate::types::Type; + use wasm_common::Type; // WasmTypeList #[test] @@ -892,8 +920,8 @@ mod inner { #[cfg(test)] mod test_func { use super::*; - use crate::types::Type; use std::ptr; + use wasm_common::Type; // WasmTypeList fn func() {} @@ -916,36 +944,36 @@ mod inner { #[test] fn test_function_types() { - assert_eq!(Func::new(func).ty(), FunctionType::new(vec![], vec![])); + assert_eq!(Function::new(func).ty(), FunctionType::new(vec![], vec![])); assert_eq!( - Func::new(func__i32).ty(), + Function::new(func__i32).ty(), FunctionType::new(vec![], vec![Type::I32]) ); assert_eq!( - Func::new(func_i32).ty(), + Function::new(func_i32).ty(), FunctionType::new(vec![Type::I32], vec![]) ); assert_eq!( - Func::new(func_i32__i32).ty(), + Function::new(func_i32__i32).ty(), FunctionType::new(vec![Type::I32], vec![Type::I32]) ); assert_eq!( - Func::new(func_i32_i32__i32).ty(), + Function::new(func_i32_i32__i32).ty(), FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]) ); assert_eq!( - Func::new(func_i32_i32__i32_i32).ty(), + Function::new(func_i32_i32__i32_i32).ty(), FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32]) ); assert_eq!( - Func::new(func_f32_i32__i32_f32).ty(), + Function::new(func_f32_i32__i32_f32).ty(), FunctionType::new(vec![Type::F32, Type::I32], vec![Type::I32, Type::F32]) ); } #[test] fn test_function_pointer() { - let f = Func::new(func_i32__i32); + let f = Function::new(func_i32__i32); let function = unsafe { std::mem::transmute::<*const FunctionBody, fn(usize, i32) -> i32>(f.address) }; @@ -954,7 +982,7 @@ mod inner { #[test] fn test_function_call() { - let f = Func::new(func_i32__i32); + let f = Function::new(func_i32__i32); let x = |args: <(i32, i32) as WasmTypeList>::Array, rets: &mut <(i32, i32) as WasmTypeList>::Array| { let result = func_i32_i32__i32_i32(args[0] as _, args[1] as _); From 32e02f32dc6024f332f0b6fbedfb2165219cda2c Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 11:42:12 +0200 Subject: [PATCH 46/59] test(api) Clean up tests. --- lib/api/src/externals/function.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index f425471aa..cb37d3ab5 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -920,9 +920,7 @@ mod inner { #[cfg(test)] mod test_func { use super::*; - use std::ptr; use wasm_common::Type; - // WasmTypeList fn func() {} fn func__i32() -> i32 { @@ -974,9 +972,7 @@ mod inner { #[test] fn test_function_pointer() { let f = Function::new(func_i32__i32); - let function = unsafe { - std::mem::transmute::<*const FunctionBody, fn(usize, i32) -> i32>(f.address) - }; + let function = unsafe { std::mem::transmute::<_, fn(usize, i32) -> i32>(f.address) }; assert_eq!(function(0, 3), 6); } From 58c83734f216e23daa398cf41d096deba14016fc Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 11:42:42 +0200 Subject: [PATCH 47/59] test(api) Remove the `function_call` test. This test does nothing. It's not using the `Function` API. --- lib/api/src/externals/function.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index cb37d3ab5..8de0114f3 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -975,22 +975,5 @@ mod inner { let function = unsafe { std::mem::transmute::<_, fn(usize, i32) -> i32>(f.address) }; assert_eq!(function(0, 3), 6); } - - #[test] - fn test_function_call() { - let f = Function::new(func_i32__i32); - let x = |args: <(i32, i32) as WasmTypeList>::Array, - rets: &mut <(i32, i32) as WasmTypeList>::Array| { - let result = func_i32_i32__i32_i32(args[0] as _, args[1] as _); - rets[0] = result.0 as _; - rets[1] = result.1 as _; - }; - let mut rets = <(i64, i64)>::empty_array(); - x([20, 10], &mut rets); - // panic!("Rets: {:?}",rets); - let mut rets = <(i64)>::empty_array(); - // let result = f.call([1], &mut rets); - // assert_eq!(result.is_err(), true); - } } } From ef3e43dcff021e26533dd811acbd1bed6a89c619 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 11:46:30 +0200 Subject: [PATCH 48/59] feat(api) Rewrite the `wasm_extern_type` macro to avoid repetition. --- lib/api/src/externals/function.rs | 50 +++++++++++++++++-------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 8de0114f3..b30d01648 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -501,34 +501,38 @@ mod inner { } macro_rules! wasm_extern_type { - ($type:ty => $native_type:ty) => { - #[allow(clippy::use_self)] - unsafe impl WasmExternType for $type { - type Native = $native_type; + ( $( $type:ty => $native_type:ty ),* ) => { + $( + #[allow(clippy::use_self)] + unsafe impl WasmExternType for $type { + type Native = $native_type; - #[inline] - fn from_native(native: Self::Native) -> Self { - native as _ - } + #[inline] + fn from_native(native: Self::Native) -> Self { + native as _ + } - #[inline] - fn to_native(self) -> Self::Native { - self as _ + #[inline] + fn to_native(self) -> Self::Native { + self as _ + } } - } + )* }; } - wasm_extern_type!(i8 => i32); - wasm_extern_type!(u8 => i32); - wasm_extern_type!(i16 => i32); - wasm_extern_type!(u16 => i32); - wasm_extern_type!(i32 => i32); - wasm_extern_type!(u32 => i32); - wasm_extern_type!(i64 => i64); - wasm_extern_type!(u64 => i64); - wasm_extern_type!(f32 => f32); - wasm_extern_type!(f64 => f64); + wasm_extern_type!( + i8 => i32, + u8 => i32, + i16 => i32, + u16 => i32, + i32 => i32, + u32 => i32, + i64 => i64, + u64 => i64, + f32 => f32, + f64 => f64 + ); /// Represents a list of WebAssembly values. pub trait WasmTypeList { @@ -918,7 +922,7 @@ mod inner { #[allow(non_snake_case)] #[cfg(test)] - mod test_func { + mod test_function { use super::*; use wasm_common::Type; From 996135ae31940bd44627a3d9bd0acec3907f31a8 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 13:05:04 +0200 Subject: [PATCH 49/59] doc(api) Improve documentation of `WasmTypeList`. --- lib/api/src/externals/function.rs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index b30d01648..155bcd095 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -534,31 +534,41 @@ mod inner { f64 => f64 ); - /// Represents a list of WebAssembly values. + /// The `WasmTypeList` trait represents a tuple (list) of Wasm + /// typed values. It is used to get low-level representation of + /// such a tuple. pub trait WasmTypeList { - /// CStruct type. + /// The C type (a struct) that can hold/represent all the + /// represented values. type CStruct; - /// Array of return values. + /// The array type that can hold all the represented values. + /// + /// Note that all values are stored in their binary form. type Array: AsMut<[i128]>; - /// Construct `Self` based on an array of returned values. + /// Constructs `Self` based on an array of values. fn from_array(array: Self::Array) -> Self; - /// Transforms Rust values into an Array + /// Builds and returns an array of type `Array` from a tuple + /// (list) of values. fn into_array(self) -> Self::Array; - /// Generates an empty array that will hold the returned values of - /// the WebAssembly function. + /// Allocates and return an empty array of type `Array` that + /// will hold a tuple (list) of values, usually to hold the + /// returned values of a WebAssembly function call. fn empty_array() -> Self::Array; - /// Transforms C values into Rust values. + /// Builds a tuple (list) of values from a C struct of type + /// `CStruct`. fn from_c_struct(c_struct: Self::CStruct) -> Self; - /// Transforms Rust values into C values. + /// Builds and returns a C struct of type `CStruct` from a + /// tuple (list) of values. fn into_c_struct(self) -> Self::CStruct; - /// Get types of the current values. + /// Get the Wasm types for the tuple (list) of currently + /// represented values. fn wasm_types() -> &'static [Type]; } From e906621e49458da8e9d8cfebf8b88989d1749b3b Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 13:05:16 +0200 Subject: [PATCH 50/59] doc(runtime) Fix a typo. --- lib/runtime/src/vmcontext.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime/src/vmcontext.rs b/lib/runtime/src/vmcontext.rs index fb544ec9b..cafe31838 100644 --- a/lib/runtime/src/vmcontext.rs +++ b/lib/runtime/src/vmcontext.rs @@ -118,7 +118,7 @@ mod test_vmfunction_body { #[derive(Debug, Copy, Clone, PartialEq)] #[repr(C)] pub enum VMFunctionKind { - /// A function is static when it's address matches the signature: + /// A function is static when its address matches the signature: /// (vmctx, vmctx, arg1, arg2...) -> (result1, result2, ...) /// /// This is the default for functions that are defined: From 8479f53329bd6a77648541f313f05b045dcd9019 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 13:20:02 +0200 Subject: [PATCH 51/59] feat(api) Rename `TrapEarly` to `IntoResult`. And improve its doc. --- lib/api/src/externals/function.rs | 40 ++++++++++++++++++------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 155bcd095..7559d9c26 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -572,37 +572,43 @@ mod inner { fn wasm_types() -> &'static [Type]; } - /// Represents a TrapEarly type. - pub trait TrapEarly + /// The `IntoResult` trait turns a `WasmTypeList` into a + /// `Result`. + /// + /// It is mostly used to turn result values of a Wasm function + /// call into a `Result`. + pub trait IntoResult where - Rets: WasmTypeList, + T: WasmTypeList, { /// The error type for this trait. type Error: Error + Sync + Send + 'static; - /// Get returns or error result. - fn report(self) -> Result; + /// Transforms `Self` into a `Result`. + fn into_result(self) -> Result; } - impl TrapEarly for Rets + impl IntoResult for T where - Rets: WasmTypeList, + T: WasmTypeList, { + // `T` is not a `Result`, it's already a value, so no error + // can be built. type Error = Infallible; - fn report(self) -> Result { + fn into_result(self) -> Result { Ok(self) } } - impl TrapEarly for Result + impl IntoResult for Result where - Rets: WasmTypeList, + T: WasmTypeList, E: Error + Sync + Send + 'static, { type Error = E; - fn report(self) -> Self { + fn into_result(self) -> Self { self } } @@ -771,7 +777,7 @@ mod inner { where $( $x: WasmExternType, )* Rets: WasmTypeList, - Trap: TrapEarly, + Trap: IntoResult, FN: Fn($( $x , )*) -> Trap + 'static + Send, { #[allow(non_snake_case)] @@ -779,13 +785,13 @@ mod inner { extern fn wrap<$( $x, )* Rets, Trap, FN>( _: usize, $($x: $x::Native, )* ) -> Rets::CStruct where Rets: WasmTypeList, - Trap: TrapEarly, + Trap: IntoResult, $( $x: WasmExternType, )* FN: Fn( $( $x ),* ) -> Trap + 'static { let f: &FN = unsafe { &*(&() as *const () as *const FN) }; let result = panic::catch_unwind(AssertUnwindSafe(|| { - f( $( WasmExternType::from_native($x) ),* ).report() + f( $( WasmExternType::from_native($x) ),* ).into_result() })); match result { @@ -804,7 +810,7 @@ mod inner { where $( $x: WasmExternType, )* Rets: WasmTypeList, - Trap: TrapEarly, + Trap: IntoResult, T: Sized, FN: Fn(&mut T, $( $x , )*) -> Trap + 'static + Send { @@ -813,7 +819,7 @@ mod inner { extern fn wrap<$( $x, )* Rets, Trap, T, FN>( ctx: &mut T, $($x: $x::Native, )* ) -> Rets::CStruct where Rets: WasmTypeList, - Trap: TrapEarly, + Trap: IntoResult, $( $x: WasmExternType, )* T: Sized, FN: Fn(&mut T, $( $x ),* ) -> Trap + 'static @@ -821,7 +827,7 @@ mod inner { let f: &FN = unsafe { &*(&() as *const () as *const FN) }; let result = panic::catch_unwind(AssertUnwindSafe(|| { - f(ctx, $( WasmExternType::from_native($x) ),* ).report() + f(ctx, $( WasmExternType::from_native($x) ),* ).into_result() })); match result { From a3f22afddcb86c4cbdc75cfe9e41ffc7eaa4b6d2 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 13:40:22 +0200 Subject: [PATCH 52/59] =?UTF-8?q?feat(api)=20Improve=20doc'=20+=20rename?= =?UTF-8?q?=20`HostFunction.to=5Fraw`=20to=20`=E2=80=A6.function=5Fbody=5F?= =?UTF-8?q?ptr`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/api/src/externals/function.rs | 44 +++++++++++++++++-------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 7559d9c26..a53ab53dc 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -613,6 +613,27 @@ mod inner { } } + /// `FunctionBody` is a transparent type representing a pointer to + /// a function, i.e. a function address. + #[repr(transparent)] + pub struct FunctionBody(*mut u8); + + /// The `HostFunction` trait represents the set of functions that + /// can be used as host function. To uphold this statement, it is + /// necessary for a function to be transformed into a pointer to + /// `FunctionBody`. + pub trait HostFunction + where + Args: WasmTypeList, + Rets: WasmTypeList, + Kind: HostFunctionKind, + T: Sized, + Self: Sized, + { + /// Get the pointer to the function body. + fn function_body_ptr(self) -> *const FunctionBody; + } + /// Empty trait to specify the kind of `HostFunction`: With or /// without a `vm::Ctx` argument. See the `ExplicitVmCtx` and the /// `ImplicitVmCtx` structures. @@ -635,23 +656,6 @@ mod inner { impl HostFunctionKind for WithoutEnv {} - /// Represents a function that can be converted to a `vm::Func` - /// (function pointer) that can be called within WebAssembly. - pub trait HostFunction - where - Args: WasmTypeList, - Rets: WasmTypeList, - Kind: HostFunctionKind, - T: Sized, - Self: Sized, - { - /// Convert to function pointer. - fn to_raw(self) -> *const FunctionBody; - } - - #[repr(transparent)] - pub struct FunctionBody(*mut u8); - /// Represents a function that can be used by WebAssembly. #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Function { @@ -674,7 +678,7 @@ mod inner { E: Sized, { Self { - address: function.to_raw(), + address: function.function_body_ptr(), _phantom: PhantomData, } } @@ -781,7 +785,7 @@ mod inner { FN: Fn($( $x , )*) -> Trap + 'static + Send, { #[allow(non_snake_case)] - fn to_raw(self) -> *const FunctionBody { + fn function_body_ptr(self) -> *const FunctionBody { extern fn wrap<$( $x, )* Rets, Trap, FN>( _: usize, $($x: $x::Native, )* ) -> Rets::CStruct where Rets: WasmTypeList, @@ -815,7 +819,7 @@ mod inner { FN: Fn(&mut T, $( $x , )*) -> Trap + 'static + Send { #[allow(non_snake_case)] - fn to_raw(self) -> *const FunctionBody { + fn function_body_ptr(self) -> *const FunctionBody { extern fn wrap<$( $x, )* Rets, Trap, T, FN>( ctx: &mut T, $($x: $x::Native, )* ) -> Rets::CStruct where Rets: WasmTypeList, From f8dfdae5209750539766f37dbf5dae54552906aa Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 14:04:29 +0200 Subject: [PATCH 53/59] feat(api) Remove `FunctionBody` and use `VMFunctionBody` instead. Avoid having multiple types for the same purpose. --- lib/api/src/externals/function.rs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index a53ab53dc..96397e68b 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -96,7 +96,7 @@ impl Function { Env: Sized + 'static, { let function = inner::Function::::new(func); - let address = function.address() as *const VMFunctionBody; + let address = function.address(); // TODO: We need to refactor the Function context. // Right now is structured as it's always a `VMContext`. However, only @@ -483,7 +483,7 @@ mod inner { use std::marker::PhantomData; use std::panic::{self, AssertUnwindSafe}; use wasm_common::{FunctionType, NativeWasmType, Type}; - use wasmer_runtime::{raise_user_trap, resume_panic}; + use wasmer_runtime::{raise_user_trap, resume_panic, VMFunctionBody}; /// A trait to represent a wasm extern type. pub unsafe trait WasmExternType: Copy @@ -613,15 +613,10 @@ mod inner { } } - /// `FunctionBody` is a transparent type representing a pointer to - /// a function, i.e. a function address. - #[repr(transparent)] - pub struct FunctionBody(*mut u8); - /// The `HostFunction` trait represents the set of functions that /// can be used as host function. To uphold this statement, it is /// necessary for a function to be transformed into a pointer to - /// `FunctionBody`. + /// `VMFunctionBody`. pub trait HostFunction where Args: WasmTypeList, @@ -631,7 +626,7 @@ mod inner { Self: Sized, { /// Get the pointer to the function body. - fn function_body_ptr(self) -> *const FunctionBody; + fn function_body_ptr(self) -> *const VMFunctionBody; } /// Empty trait to specify the kind of `HostFunction`: With or @@ -659,7 +654,7 @@ mod inner { /// Represents a function that can be used by WebAssembly. #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Function { - address: *const FunctionBody, + address: *const VMFunctionBody, _phantom: PhantomData<(Args, Rets)>, } @@ -689,7 +684,7 @@ mod inner { } /// Get the address of the Func - pub fn address(&self) -> *const FunctionBody { + pub fn address(&self) -> *const VMFunctionBody { self.address } } @@ -785,7 +780,7 @@ mod inner { FN: Fn($( $x , )*) -> Trap + 'static + Send, { #[allow(non_snake_case)] - fn function_body_ptr(self) -> *const FunctionBody { + fn function_body_ptr(self) -> *const VMFunctionBody { extern fn wrap<$( $x, )* Rets, Trap, FN>( _: usize, $($x: $x::Native, )* ) -> Rets::CStruct where Rets: WasmTypeList, @@ -805,7 +800,7 @@ mod inner { } } - wrap::<$( $x, )* Rets, Trap, Self> as *const FunctionBody + wrap::<$( $x, )* Rets, Trap, Self> as *const VMFunctionBody } } @@ -819,7 +814,7 @@ mod inner { FN: Fn(&mut T, $( $x , )*) -> Trap + 'static + Send { #[allow(non_snake_case)] - fn function_body_ptr(self) -> *const FunctionBody { + fn function_body_ptr(self) -> *const VMFunctionBody { extern fn wrap<$( $x, )* Rets, Trap, T, FN>( ctx: &mut T, $($x: $x::Native, )* ) -> Rets::CStruct where Rets: WasmTypeList, @@ -841,7 +836,7 @@ mod inner { } } - wrap::<$( $x, )* Rets, Trap, T, Self> as *const FunctionBody + wrap::<$( $x, )* Rets, Trap, T, Self> as *const VMFunctionBody } } }; From 818706b3186e708534fe19d60f7b4c892822da4c Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 14:05:19 +0200 Subject: [PATCH 54/59] doc(api) Improve documentation of `HostFunctionKind` and impls. --- lib/api/src/externals/function.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 96397e68b..afc7f8479 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -630,28 +630,27 @@ mod inner { } /// Empty trait to specify the kind of `HostFunction`: With or - /// without a `vm::Ctx` argument. See the `ExplicitVmCtx` and the - /// `ImplicitVmCtx` structures. + /// without an environment. /// - /// This trait is never aimed to be used by a user. It is used by the - /// trait system to automatically generate an appropriate `wrap` - /// function. + /// This trait is never aimed to be used by a user. It is used by + /// the trait system to automatically generate the appropriate + /// host functions. #[doc(hidden)] pub trait HostFunctionKind {} /// An empty struct to help Rust typing to determine - /// when a `HostFunction` doesn't take an Environment - pub struct WithEnv {} + /// when a `HostFunction` does have an environment. + pub struct WithEnv; impl HostFunctionKind for WithEnv {} /// An empty struct to help Rust typing to determine - /// when a `HostFunction` takes an Environment - pub struct WithoutEnv {} + /// when a `HostFunction` does not have an environment. + pub struct WithoutEnv; impl HostFunctionKind for WithoutEnv {} - /// Represents a function that can be used by WebAssembly. + /// Represents a low-level Wasm host function. #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Function { address: *const VMFunctionBody, From d1e4f7c5ceaa79098b5341d17ee85ea936562a2d Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 15:05:55 +0200 Subject: [PATCH 55/59] feat(api) Improve the `impl_traits` macro + improve documentation. The macro has been renamed `impl_host_function`, because it's basically what it does. It implements other types and traits, but it's all related to host functions. The documentation has been improved. The generic parameters have been renamed to be more self-explanatory. The code has been rewritten a little bit to be easier to read. etc. --- lib/api/src/externals/function.rs | 386 +++++++++++++++++------------- 1 file changed, 222 insertions(+), 164 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index afc7f8479..6b9aa6bef 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -650,7 +650,9 @@ mod inner { impl HostFunctionKind for WithoutEnv {} - /// Represents a low-level Wasm host function. + /// Represents a low-level Wasm static host function. See + /// `super::Function::new` and `super::Function::new_env` to learn + /// more. #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Function { address: *const VMFunctionBody, @@ -677,17 +679,234 @@ mod inner { } } - /// Get the type of the Func + /// Get the function type of this `Function`. pub fn ty(&self) -> FunctionType { FunctionType::new(Args::wasm_types(), Rets::wasm_types()) } - /// Get the address of the Func + /// Get the address of this `Function`. pub fn address(&self) -> *const VMFunctionBody { self.address } } + macro_rules! impl_host_function { + ( [$c_struct_representation:ident] + $c_struct_name:ident, + $( $x:ident ),* ) => { + + /// A structure with a C-compatible representation that can hold a set of Wasm values. + /// This type is used by `WasmTypeList::CStruct`. + #[repr($c_struct_representation)] + pub struct $c_struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* ) + where + $( $x: WasmExternType ),*; + + // Implement `WasmTypeList` for a specific tuple. + #[allow(unused_parens, dead_code)] + impl< $( $x ),* > + WasmTypeList + for + ( $( $x ),* ) + where + $( $x: WasmExternType ),* + { + type CStruct = $c_struct_name< $( $x ),* >; + + type Array = [i128; count_idents!( $( $x ),* )]; + + fn from_array(array: Self::Array) -> Self { + // Unpack items of the array. + #[allow(non_snake_case)] + let [ $( $x ),* ] = array; + + // Build the tuple. + ( + $( + WasmExternType::from_native(NativeWasmType::from_binary($x)) + ),* + ) + } + + fn into_array(self) -> Self::Array { + // Unpack items of the tuple. + #[allow(non_snake_case)] + let ( $( $x ),* ) = self; + + // Build the array. + [ + $( + WasmExternType::to_native($x).to_binary() + ),* + ] + } + + fn empty_array() -> Self::Array { + // Build an array initialized with `0`. + [0; count_idents!( $( $x ),* )] + } + + fn from_c_struct(c_struct: Self::CStruct) -> Self { + // Unpack items of the C structure. + #[allow(non_snake_case)] + let $c_struct_name( $( $x ),* ) = c_struct; + + ( + $( + WasmExternType::from_native($x) + ),* + ) + } + + #[allow(unused_parens, non_snake_case)] + fn into_c_struct(self) -> Self::CStruct { + // Unpack items of the tuple. + let ( $( $x ),* ) = self; + + // Build the C structure. + $c_struct_name( + $( + WasmExternType::to_native($x) + ),* + ) + } + + fn wasm_types() -> &'static [Type] { + &[ + $( + $x::Native::WASM_TYPE + ),* + ] + } + } + + // Implement `HostFunction` for a function that has the same arity than the tuple. + // This specific function has no environment. + #[allow(unused_parens)] + impl< $( $x, )* Rets, RetsAsResult, Func > + HostFunction<( $( $x ),* ), Rets, WithoutEnv, ()> + for + Func + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + RetsAsResult: IntoResult, + Func: Fn($( $x , )*) -> RetsAsResult + 'static + Send, + { + #[allow(non_snake_case)] + fn function_body_ptr(self) -> *const VMFunctionBody { + /// This is a function that wraps the real host + /// function. Its address will be used inside the + /// runtime. + extern fn func_wrapper<$( $x, )* Rets, RetsAsResult, Func>( _: usize, $($x: $x::Native, )* ) -> Rets::CStruct + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + RetsAsResult: IntoResult, + Func: Fn( $( $x ),* ) -> RetsAsResult + 'static + { + let func: &Func = unsafe { &*(&() as *const () as *const Func) }; + let result = panic::catch_unwind(AssertUnwindSafe(|| { + func( $( WasmExternType::from_native($x) ),* ).into_result() + })); + + match result { + Ok(Ok(result)) => return result.into_c_struct(), + Ok(Err(trap)) => unsafe { raise_user_trap(Box::new(trap)) }, + Err(panic) => unsafe { resume_panic(panic) }, + } + } + + func_wrapper::<$( $x, )* Rets, RetsAsResult, Self> as *const VMFunctionBody + } + } + + #[allow(unused_parens)] + impl< $( $x, )* Rets, RetsAsResult, Env, Func > + HostFunction<( $( $x ),* ), Rets, WithEnv, Env> + for + Func + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + RetsAsResult: IntoResult, + Env: Sized, + Func: Fn(&mut Env, $( $x , )*) -> RetsAsResult + Send + 'static, + { + #[allow(non_snake_case)] + fn function_body_ptr(self) -> *const VMFunctionBody { + /// This is a function that wraps the real host + /// function. Its address will be used inside the + /// runtime. + extern fn func_wrapper<$( $x, )* Rets, RetsAsResult, Env, Func>( env: &mut Env, $( $x: $x::Native, )* ) -> Rets::CStruct + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + RetsAsResult: IntoResult, + Env: Sized, + Func: Fn(&mut Env, $( $x ),* ) -> RetsAsResult + 'static + { + let func: &Func = unsafe { &*(&() as *const () as *const Func) }; + + let result = panic::catch_unwind(AssertUnwindSafe(|| { + func(env, $( WasmExternType::from_native($x) ),* ).into_result() + })); + + match result { + Ok(Ok(result)) => return result.into_c_struct(), + Ok(Err(trap)) => unsafe { raise_user_trap(Box::new(trap)) }, + Err(panic) => unsafe { resume_panic(panic) }, + } + } + + func_wrapper::<$( $x, )* Rets, RetsAsResult, Env, Self> as *const VMFunctionBody + } + } + }; + } + + // Black-magic to count the number of identifiers at compile-time. + macro_rules! count_idents { + ( $($idents:ident),* ) => { + { + #[allow(dead_code, non_camel_case_types)] + enum Idents { $( $idents, )* __CountIdentsLast } + const COUNT: usize = Idents::__CountIdentsLast as usize; + COUNT + } + }; + } + + // Here we go! Let's generate all the C struct, `WasmTypeList` + // implementations and `HostFunction` implementations. + impl_host_function!([C] S0,); + impl_host_function!([transparent] S1, A1); + impl_host_function!([C] S2, A1, A2); + impl_host_function!([C] S3, A1, A2, A3); + impl_host_function!([C] S4, A1, A2, A3, A4); + impl_host_function!([C] S5, A1, A2, A3, A4, A5); + impl_host_function!([C] S6, A1, A2, A3, A4, A5, A6); + impl_host_function!([C] S7, A1, A2, A3, A4, A5, A6, A7); + impl_host_function!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8); + impl_host_function!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9); + impl_host_function!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); + impl_host_function!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); + impl_host_function!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); + impl_host_function!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); + impl_host_function!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); + impl_host_function!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); + impl_host_function!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); + impl_host_function!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); + impl_host_function!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18); + impl_host_function!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19); + impl_host_function!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20); + impl_host_function!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21); + impl_host_function!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22); + impl_host_function!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23); + impl_host_function!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24); + impl_host_function!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25); + impl_host_function!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26); + impl WasmTypeList for Infallible { type CStruct = Self; type Array = [i128; 0]; @@ -717,167 +936,6 @@ mod inner { } } - macro_rules! impl_traits { - ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => { - /// Struct for typed funcs. - #[repr($repr)] - pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* ) - where - $( $x: WasmExternType ),*; - - #[allow(unused_parens, dead_code)] - impl< $( $x ),* > WasmTypeList for ( $( $x ),* ) - where - $( $x: WasmExternType ),* - { - type CStruct = $struct_name<$( $x ),*>; - - type Array = [i128; count_idents!( $( $x ),* )]; - - fn from_array(array: Self::Array) -> Self { - #[allow(non_snake_case)] - let [ $( $x ),* ] = array; - - ( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* ) - } - - fn into_array(self) -> Self::Array { - #[allow(non_snake_case)] - let ( $( $x ),* ) = self; - [ $( WasmExternType::to_native($x).to_binary() ),* ] - } - - fn empty_array() -> Self::Array { - [0; count_idents!( $( $x ),* )] - } - - fn from_c_struct(c_struct: Self::CStruct) -> Self { - #[allow(non_snake_case)] - let $struct_name ( $( $x ),* ) = c_struct; - - ( $( WasmExternType::from_native($x) ),* ) - } - - #[allow(unused_parens, non_snake_case)] - fn into_c_struct(self) -> Self::CStruct { - let ( $( $x ),* ) = self; - - $struct_name ( $( WasmExternType::to_native($x) ),* ) - } - - fn wasm_types() -> &'static [Type] { - &[$( $x::Native::WASM_TYPE ),*] - } - } - - #[allow(unused_parens)] - impl< $( $x, )* Rets, Trap, FN > HostFunction<( $( $x ),* ), Rets, WithoutEnv, ()> for FN - where - $( $x: WasmExternType, )* - Rets: WasmTypeList, - Trap: IntoResult, - FN: Fn($( $x , )*) -> Trap + 'static + Send, - { - #[allow(non_snake_case)] - fn function_body_ptr(self) -> *const VMFunctionBody { - extern fn wrap<$( $x, )* Rets, Trap, FN>( _: usize, $($x: $x::Native, )* ) -> Rets::CStruct - where - Rets: WasmTypeList, - Trap: IntoResult, - $( $x: WasmExternType, )* - FN: Fn( $( $x ),* ) -> Trap + 'static - { - let f: &FN = unsafe { &*(&() as *const () as *const FN) }; - let result = panic::catch_unwind(AssertUnwindSafe(|| { - f( $( WasmExternType::from_native($x) ),* ).into_result() - })); - - match result { - Ok(Ok(result)) => return result.into_c_struct(), - Ok(Err(trap)) => unsafe { raise_user_trap(Box::new(trap)) }, - Err(panic) => unsafe { resume_panic(panic) }, - } - } - - wrap::<$( $x, )* Rets, Trap, Self> as *const VMFunctionBody - } - } - - #[allow(unused_parens)] - impl< $( $x, )* Rets, Trap, T, FN > HostFunction<( $( $x ),* ), Rets, WithEnv, T> for FN - where - $( $x: WasmExternType, )* - Rets: WasmTypeList, - Trap: IntoResult, - T: Sized, - FN: Fn(&mut T, $( $x , )*) -> Trap + 'static + Send - { - #[allow(non_snake_case)] - fn function_body_ptr(self) -> *const VMFunctionBody { - extern fn wrap<$( $x, )* Rets, Trap, T, FN>( ctx: &mut T, $($x: $x::Native, )* ) -> Rets::CStruct - where - Rets: WasmTypeList, - Trap: IntoResult, - $( $x: WasmExternType, )* - T: Sized, - FN: Fn(&mut T, $( $x ),* ) -> Trap + 'static - { - let f: &FN = unsafe { &*(&() as *const () as *const FN) }; - - let result = panic::catch_unwind(AssertUnwindSafe(|| { - f(ctx, $( WasmExternType::from_native($x) ),* ).into_result() - })); - - match result { - Ok(Ok(result)) => return result.into_c_struct(), - Ok(Err(trap)) => unsafe { raise_user_trap(Box::new(trap)) }, - Err(panic) => unsafe { resume_panic(panic) }, - } - } - - wrap::<$( $x, )* Rets, Trap, T, Self> as *const VMFunctionBody - } - } - }; - } - - macro_rules! count_idents { - ( $($idents:ident),* ) => {{ - #[allow(dead_code, non_camel_case_types)] - enum Idents { $($idents,)* __CountIdentsLast } - const COUNT: usize = Idents::__CountIdentsLast as usize; - COUNT - }}; - } - - impl_traits!([C] S0,); - impl_traits!([transparent] S1, A1); - impl_traits!([C] S2, A1, A2); - impl_traits!([C] S3, A1, A2, A3); - impl_traits!([C] S4, A1, A2, A3, A4); - impl_traits!([C] S5, A1, A2, A3, A4, A5); - impl_traits!([C] S6, A1, A2, A3, A4, A5, A6); - impl_traits!([C] S7, A1, A2, A3, A4, A5, A6, A7); - impl_traits!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8); - impl_traits!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9); - impl_traits!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); - impl_traits!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); - impl_traits!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); - impl_traits!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); - impl_traits!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); - impl_traits!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); - impl_traits!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); - impl_traits!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); - impl_traits!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18); - impl_traits!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19); - impl_traits!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20); - impl_traits!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21); - impl_traits!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22); - impl_traits!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23); - impl_traits!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24); - impl_traits!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25); - impl_traits!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26); - #[cfg(test)] mod test_wasm_type_list { use super::*; From 3b03d7071bfe12682794a9efb037a7dad81f4fc3 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 15:09:18 +0200 Subject: [PATCH 56/59] doc(api) Improve documentation. --- lib/api/src/externals/function.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 6b9aa6bef..80305d9dc 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -907,6 +907,9 @@ mod inner { impl_host_function!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25); impl_host_function!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26); + // Implement `WasmTypeList` on `Infallible`, which means that + // `Infallible` can be used as a returned type of a host function + // to express that it doesn't return. impl WasmTypeList for Infallible { type CStruct = Self; type Array = [i128; 0]; From 1cd6eb8a215a7b3a40ffe6386f587718a39750b4 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 15:25:10 +0200 Subject: [PATCH 57/59] test(api) Write more test cases for `WasmTypeList`. --- lib/api/src/externals/function.rs | 87 ++++++++++++++++++------------- 1 file changed, 52 insertions(+), 35 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 80305d9dc..8a8984b09 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -862,6 +862,7 @@ mod inner { func_wrapper::<$( $x, )* Rets, RetsAsResult, Env, Self> as *const VMFunctionBody } } + }; } @@ -943,24 +944,32 @@ mod inner { mod test_wasm_type_list { use super::*; use wasm_common::Type; - // WasmTypeList #[test] - fn test_simple_values() { - // Simple values - assert_eq!(::wasm_types(), [Type::I32]); - assert_eq!(::wasm_types(), [Type::I64]); - assert_eq!(::wasm_types(), [Type::F32]); - assert_eq!(::wasm_types(), [Type::F64]); + fn test_from_array() { + assert_eq!(<()>::from_array([]), ()); + assert_eq!(::from_array([1]), (1i32)); + assert_eq!(<(i32, i64)>::from_array([1, 2]), (1i32, 2i64)); + assert_eq!( + <(i32, i64, f32, f64)>::from_array([ + 1, + 2, + (3.1f32).to_bits().into(), + (4.2f64).to_bits().into() + ]), + (1, 2, 3.1f32, 4.2f64) + ); + } - // Multi values - assert_eq!(<(i32, i32)>::wasm_types(), [Type::I32, Type::I32]); - assert_eq!(<(i64, i64)>::wasm_types(), [Type::I64, Type::I64]); - assert_eq!(<(f32, f32)>::wasm_types(), [Type::F32, Type::F32]); - assert_eq!(<(f64, f64)>::wasm_types(), [Type::F64, Type::F64]); - - // Mixed values - // assert_eq!(<(i32, i64, f32, f64)>::wasm_types(), [Type::I32, Type::I64, Type::F32, Type::F64]); + #[test] + fn test_into_array() { + assert_eq!(().into_array(), []); + assert_eq!((1).into_array(), [1]); + assert_eq!((1i32, 2i64).into_array(), [1, 2]); + assert_eq!( + (1i32, 2i32, 3.1f32, 4.2f64).into_array(), + [1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()] + ); } #[test] @@ -970,28 +979,36 @@ mod inner { assert_eq!(<(i32, i64)>::empty_array().len(), 2); } - // #[test] - // fn test_from_array() { - // assert_eq!(<()>::from_array([]), ()); - // assert_eq!(<(i32)>::from_array([1]), (1)); - // assert_eq!(<(i32, i32)>::from_array([1, 1]), (1, 1)); - // // This doesn't work - // // assert_eq!(<(i32, i64, f32, f64)>::from_array([1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()]), (1, 2, 3.1f32, 4.2f64)); - // } - - // #[test] - // fn test_into_array() { - // assert_eq!(().into_array(), []); - // assert_eq!((1).into_array(), [1]); - // assert_eq!((1, 2).into_array(), [1, 2]); - // assert_eq!((1, 2, 3).into_array(), [1, 2, 3]); - // // This doesn't work - // // assert_eq!(<(i32, i64, f32, f64)>::from_array([1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()]), (1, 2, 3.1f32, 4.2f64)); - // } + #[test] + fn test_from_c_struct() { + assert_eq!(<()>::from_c_struct(S0()), ()); + assert_eq!(::from_c_struct(S1(1)), (1i32)); + assert_eq!(<(i32, i64)>::from_c_struct(S2(1, 2)), (1i32, 2i64)); + assert_eq!( + <(i32, i64, f32, f64)>::from_c_struct(S4(1, 2, 3.1, 4.2)), + (1i32, 2i64, 3.1f32, 4.2f64) + ); + } #[test] - fn test_into_c_struct() { - // assert_eq!(<()>::into_c_struct(), &[]); + fn test_wasm_types_for_uni_values() { + assert_eq!(::wasm_types(), [Type::I32]); + assert_eq!(::wasm_types(), [Type::I64]); + assert_eq!(::wasm_types(), [Type::F32]); + assert_eq!(::wasm_types(), [Type::F64]); + } + + #[test] + fn test_wasm_types_for_multi_values() { + assert_eq!(<(i32, i32)>::wasm_types(), [Type::I32, Type::I32]); + assert_eq!(<(i64, i64)>::wasm_types(), [Type::I64, Type::I64]); + assert_eq!(<(f32, f32)>::wasm_types(), [Type::F32, Type::F32]); + assert_eq!(<(f64, f64)>::wasm_types(), [Type::F64, Type::F64]); + + assert_eq!( + <(i32, i64, f32, f64)>::wasm_types(), + [Type::I32, Type::I64, Type::F32, Type::F64] + ); } } From f7493ff358c5024fb624b81ab1c545fc7ef813f7 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 22 Jun 2020 15:26:45 +0200 Subject: [PATCH 58/59] doc(api) Update. --- lib/api/src/externals/function.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 8a8984b09..3cfee3c5c 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -476,7 +476,7 @@ impl VMDynamicFunctionCall for VMDynamicFunctionContext } /// This private inner module contains the low-level implementation -/// for `Func` and its siblings. +/// for `Function` and its siblings. mod inner { use std::convert::Infallible; use std::error::Error; From 01563ad06c48a93be180419f69770cf1c3ec17bd Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 22 Jun 2020 13:39:50 -0700 Subject: [PATCH 59/59] Update native.rs --- lib/wasm-common/src/native.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/wasm-common/src/native.rs b/lib/wasm-common/src/native.rs index b467e2593..1f20993cd 100644 --- a/lib/wasm-common/src/native.rs +++ b/lib/wasm-common/src/native.rs @@ -194,4 +194,3 @@ macro_rules! impl_value_type_for { } impl_value_type_for!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64); -