diff --git a/Cargo.lock b/Cargo.lock index 815f04419e0..f2ae14ceb21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2900,6 +2900,7 @@ name = "wasmer-engine" version = "2.0.0" dependencies = [ "backtrace", + "enumset", "lazy_static", "loupe", "memmap2", @@ -2919,6 +2920,7 @@ name = "wasmer-engine-dummy" version = "2.0.0" dependencies = [ "bincode", + "enumset", "loupe", "serde", "serde_bytes", @@ -2933,6 +2935,7 @@ name = "wasmer-engine-dylib" version = "2.0.0" dependencies = [ "cfg-if 1.0.0", + "enumset", "leb128", "libloading", "loupe", @@ -2954,6 +2957,7 @@ version = "2.0.0" dependencies = [ "bincode", "cfg-if 1.0.0", + "enumset", "leb128", "libloading", "loupe", @@ -2972,6 +2976,7 @@ name = "wasmer-engine-universal" version = "2.0.0" dependencies = [ "cfg-if 1.0.0", + "enumset", "leb128", "loupe", "region", diff --git a/lib/api/src/sys/instance.rs b/lib/api/src/sys/instance.rs index c67518aef0b..7368c5549e6 100644 --- a/lib/api/src/sys/instance.rs +++ b/lib/api/src/sys/instance.rs @@ -58,6 +58,11 @@ pub enum InstantiationError { #[error(transparent)] Start(RuntimeError), + /// The module was compiled with a CPU feature that is not available on + /// the current host. + #[error("missing requires CPU features: {0:?}")] + CpuFeature(String), + /// Error occurred when initializing the host environment. #[error(transparent)] HostEnvInitialization(HostEnvInitError), @@ -68,6 +73,7 @@ impl From for InstantiationError { match other { wasmer_engine::InstantiationError::Link(e) => Self::Link(e), wasmer_engine::InstantiationError::Start(e) => Self::Start(e), + wasmer_engine::InstantiationError::CpuFeature(e) => Self::CpuFeature(e), } } } diff --git a/lib/c-api/src/error.rs b/lib/c-api/src/error.rs index acf921a1023..cdf3e155ca1 100644 --- a/lib/c-api/src/error.rs +++ b/lib/c-api/src/error.rs @@ -49,13 +49,12 @@ use libc::{c_char, c_int}; use std::cell::RefCell; -use std::error::Error; -use std::fmt::{self, Display, Formatter}; +use std::fmt::Display; use std::ptr::{self, NonNull}; use std::slice; thread_local! { - static LAST_ERROR: RefCell>> = RefCell::new(None); + static LAST_ERROR: RefCell> = RefCell::new(None); } /// Rust function to register a new error. @@ -63,24 +62,23 @@ thread_local! { /// # Example /// /// ```rust,no_run -/// # use wasmer::error::{update_last_error, CApiError}; +/// # use wasmer::error::update_last_error; /// -/// update_last_error(CApiError { -/// msg: "Hello, World!".to_string(), -/// }); +/// update_last_error("Hello, World!"); /// ``` -pub fn update_last_error(err: E) { +pub fn update_last_error(err: E) { LAST_ERROR.with(|prev| { - *prev.borrow_mut() = Some(Box::new(err)); + *prev.borrow_mut() = Some(err.to_string()); }); } /// Retrieve the most recent error, clearing it in the process. -pub(crate) fn take_last_error() -> Option> { +pub(crate) fn take_last_error() -> Option { LAST_ERROR.with(|prev| prev.borrow_mut().take()) } -/// Gets the length in bytes of the last error if any, zero otherwise. +/// Gets the length in bytes of the last error if any, zero otherwise. This +/// includes th NUL terminator byte. /// /// This can be used to dynamically allocate a buffer with the correct number of /// bytes needed to store a message. @@ -88,10 +86,11 @@ pub(crate) fn take_last_error() -> Option> { /// # Example /// /// See this module's documentation to get a complete example. +// TODO(Amanieu): This should use size_t #[no_mangle] pub extern "C" fn wasmer_last_error_length() -> c_int { LAST_ERROR.with(|prev| match *prev.borrow() { - Some(ref err) => err.to_string().len() as c_int + 1, + Some(ref err) => err.len() as c_int + 1, None => 0, }) } @@ -118,6 +117,7 @@ pub extern "C" fn wasmer_last_error_length() -> c_int { /// # Example /// /// See this module's documentation to get a complete example. +// TODO(Amanieu): This should use size_t #[no_mangle] pub unsafe extern "C" fn wasmer_last_error_message( buffer: Option>, @@ -156,18 +156,3 @@ pub unsafe extern "C" fn wasmer_last_error_message( error_message.len() as c_int + 1 } - -/// Rust type to represent a C API error. -#[derive(Debug)] -pub struct CApiError { - /// The error message. - pub msg: String, -} - -impl Display for CApiError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}", &self.msg) - } -} - -impl Error for CApiError {} diff --git a/lib/c-api/src/wasm_c_api/engine.rs b/lib/c-api/src/wasm_c_api/engine.rs index 4fed7897b3c..bd77346a54c 100644 --- a/lib/c-api/src/wasm_c_api/engine.rs +++ b/lib/c-api/src/wasm_c_api/engine.rs @@ -9,7 +9,7 @@ pub use super::unstable::middlewares::wasm_config_push_middleware; #[cfg(feature = "middlewares")] use super::unstable::middlewares::wasmer_middleware_t; use super::unstable::target_lexicon::wasmer_target_t; -use crate::error::{update_last_error, CApiError}; +use crate::error::update_last_error; use cfg_if::cfg_if; use std::sync::Arc; use wasmer_api::Engine; @@ -433,13 +433,8 @@ pub extern "C" fn wasm_engine_new_with_config( config: Option>, ) -> Option> { #[allow(dead_code)] - fn return_with_error(msg: M) -> Option> - where - M: ToString, - { - update_last_error(CApiError { - msg: msg.to_string(), - }); + fn return_with_error(msg: &str) -> Option> { + update_last_error(msg); return None; } diff --git a/lib/c-api/src/wasm_c_api/instance.rs b/lib/c-api/src/wasm_c_api/instance.rs index 047dd18ee5b..c75746d4db8 100644 --- a/lib/c-api/src/wasm_c_api/instance.rs +++ b/lib/c-api/src/wasm_c_api/instance.rs @@ -73,6 +73,12 @@ pub unsafe extern "C" fn wasm_instance_new( return None; } + Err(e @ InstantiationError::CpuFeature(_)) => { + crate::error::update_last_error(e); + + return None; + } + Err(InstantiationError::HostEnvInitialization(error)) => { crate::error::update_last_error(error); diff --git a/lib/c-api/src/wasm_c_api/unstable/target_lexicon.rs b/lib/c-api/src/wasm_c_api/unstable/target_lexicon.rs index 269ec426ec8..ed8e9b2a589 100644 --- a/lib/c-api/src/wasm_c_api/unstable/target_lexicon.rs +++ b/lib/c-api/src/wasm_c_api/unstable/target_lexicon.rs @@ -54,7 +54,6 @@ //! ``` use super::super::types::wasm_name_t; -use crate::error::CApiError; use enumset::EnumSet; use std::slice; use std::str::{self, FromStr}; @@ -153,7 +152,7 @@ pub unsafe extern "C" fn wasmer_triple_new( ))); Some(Box::new(wasmer_triple_t { - inner: c_try!(Triple::from_str(triple).map_err(|e| CApiError { msg: e.to_string() })), + inner: c_try!(Triple::from_str(triple)), })) } diff --git a/lib/c-api/src/wasm_c_api/unstable/wasi.rs b/lib/c-api/src/wasm_c_api/unstable/wasi.rs index 9a860af04a7..5a1085016ec 100644 --- a/lib/c-api/src/wasm_c_api/unstable/wasi.rs +++ b/lib/c-api/src/wasm_c_api/unstable/wasi.rs @@ -5,7 +5,6 @@ use super::super::{ externals::wasm_extern_t, module::wasm_module_t, store::wasm_store_t, types::wasm_name_t, wasi::wasi_env_t, }; -use crate::error::CApiError; use wasmer_api::Extern; use wasmer_wasi::{generate_import_object_from_env, get_wasi_version}; @@ -168,11 +167,8 @@ fn wasi_get_unordered_imports_inner( let store = &store.inner; - let version = c_try!( - get_wasi_version(&module.inner, false).ok_or_else(|| CApiError { - msg: "could not detect a WASI version on the given module".to_string(), - }) - ); + let version = c_try!(get_wasi_version(&module.inner, false) + .ok_or("could not detect a WASI version on the given module")); let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version); diff --git a/lib/c-api/src/wasm_c_api/value.rs b/lib/c-api/src/wasm_c_api/value.rs index da6b508af45..3ead5c0cc40 100644 --- a/lib/c-api/src/wasm_c_api/value.rs +++ b/lib/c-api/src/wasm_c_api/value.rs @@ -1,5 +1,5 @@ use super::types::{wasm_ref_t, wasm_valkind_enum}; -use crate::error::{update_last_error, CApiError}; +use crate::error::update_last_error; use std::convert::{TryFrom, TryInto}; use wasmer_api::Val; @@ -156,7 +156,7 @@ pub unsafe extern "C" fn wasm_val_copy( }, Err(e) => { - update_last_error(CApiError { msg: e.to_string() }); + update_last_error(e); return; } diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index a2a890608d0..8d53ac79adb 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -11,7 +11,7 @@ use super::{ module::wasm_module_t, store::wasm_store_t, }; -use crate::error::{update_last_error, CApiError}; +use crate::error::update_last_error; use std::cmp::min; use std::convert::TryFrom; use std::ffi::CStr; @@ -212,9 +212,7 @@ pub unsafe extern "C" fn wasi_env_read_stdout( if let Some(stdout) = stdout.as_mut() { stdout } else { - update_last_error(CApiError { - msg: "could not find a file handle for `stdout`".to_string(), - }); + update_last_error("could not find a file handle for `stdout`"); return -1; } } else { @@ -235,15 +233,11 @@ pub unsafe extern "C" fn wasi_env_read_stderr( if let Some(stderr) = stderr.as_mut() { stderr } else { - update_last_error(CApiError { - msg: "could not find a file handle for `stderr`".to_string(), - }); + update_last_error("could not find a file handle for `stderr`"); return -1; } } else { - update_last_error(CApiError { - msg: "could not find a file handle for `stderr`".to_string(), - }); + update_last_error("could not find a file handle for `stderr`"); return -1; }; read_inner(stderr, inner_buffer) @@ -348,11 +342,8 @@ fn wasi_get_imports_inner( let store = &store.inner; - let version = c_try!( - get_wasi_version(&module.inner, false).ok_or_else(|| CApiError { - msg: "could not detect a WASI version on the given module".to_string(), - }) - ); + let version = c_try!(get_wasi_version(&module.inner, false) + .ok_or("could not detect a WASI version on the given module")); let import_object = generate_import_object_from_env(store, wasi_env.inner.clone(), version); @@ -362,18 +353,18 @@ fn wasi_get_imports_inner( .map(|import_type| { let export = import_object .resolve_by_name(import_type.module(), import_type.name()) - .ok_or_else(|| CApiError { - msg: format!( + .ok_or_else(|| { + format!( "Failed to resolve import \"{}\" \"{}\"", import_type.module(), import_type.name() - ), + ) })?; let inner = Extern::from_vm_export(store, export); Ok(Some(Box::new(inner.into()))) }) - .collect::, CApiError>>())); + .collect::, String>>())); Some(()) } diff --git a/lib/compiler-cranelift/Cargo.toml b/lib/compiler-cranelift/Cargo.toml index 0405665c2e9..d687c123048 100644 --- a/lib/compiler-cranelift/Cargo.toml +++ b/lib/compiler-cranelift/Cargo.toml @@ -25,9 +25,9 @@ more-asserts = "0.2" gimli = { version = "0.25", optional = true } smallvec = "1.6" loupe = "0.1" +target-lexicon = { version = "0.12.2", default-features = false } [dev-dependencies] -target-lexicon = { version = "0.12.2", default-features = false } cranelift-codegen = { version = "0.76", features = ["all-arch"] } lazy_static = "1.4" diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index c836b9ce106..8187dbab2fc 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -21,6 +21,7 @@ use gimli::write::{Address, EhFrame, FrameTable}; use loupe::MemoryUsage; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use std::sync::Arc; +use target_lexicon::{Architecture, OperatingSystem}; use wasmer_compiler::CompileError; use wasmer_compiler::{CallingConvention, ModuleTranslationState, Target}; use wasmer_compiler::{ @@ -29,14 +30,12 @@ use wasmer_compiler::{ FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain, SectionIndex, }; -#[cfg(all(target_arch = "x86_64", target_os = "linux"))] use wasmer_compiler::{ CustomSection, CustomSectionProtection, Relocation, RelocationKind, RelocationTarget, SectionBody, }; use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::{FunctionIndex, LocalFunctionIndex, SignatureIndex}; -#[cfg(all(target_arch = "x86_64", target_os = "linux"))] use wasmer_vm::libcalls::LibCall; /// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR, @@ -111,28 +110,34 @@ impl Compiler for CraneliftCompiler { let mut custom_sections = PrimaryMap::new(); - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] - let probestack_trampoline = CustomSection { - protection: CustomSectionProtection::ReadExecute, - // We create a jump to an absolute 64bits address - // with an indrect jump immediatly followed but the absolute address - // JMP [IP+0] FF 25 00 00 00 00 - // 64bits ADDR 00 00 00 00 00 00 00 00 preset to 0 until the relocation takes place - bytes: SectionBody::new_with_vec(vec![ - 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]), - relocations: vec![Relocation { - kind: RelocationKind::Abs8, - reloc_target: RelocationTarget::LibCall(LibCall::Probestack), - // 6 is the size of the jmp instruction. The relocated address must follow - offset: 6, - addend: 0, - }], + let probestack_trampoline_relocation_target = if target.triple().operating_system + == OperatingSystem::Linux + && target.triple().architecture == Architecture::X86_64 + { + let probestack_trampoline = CustomSection { + protection: CustomSectionProtection::ReadExecute, + // We create a jump to an absolute 64bits address + // with an indrect jump immediatly followed but the absolute address + // JMP [IP+0] FF 25 00 00 00 00 + // 64bits ADDR 00 00 00 00 00 00 00 00 preset to 0 until the relocation takes place + bytes: SectionBody::new_with_vec(vec![ + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + ]), + relocations: vec![Relocation { + kind: RelocationKind::Abs8, + reloc_target: RelocationTarget::LibCall(LibCall::Probestack), + // 6 is the size of the jmp instruction. The relocated address must follow + offset: 6, + addend: 0, + }], + }; + custom_sections.push(probestack_trampoline); + + Some(SectionIndex::new(custom_sections.len() - 1)) + } else { + None }; - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] - custom_sections.push(probestack_trampoline); - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] - let probestack_trampoline_relocation_target = SectionIndex::new(custom_sections.len() - 1); let functions = function_body_inputs .iter() @@ -170,12 +175,8 @@ impl Compiler for CraneliftCompiler { )?; let mut code_buf: Vec = Vec::new(); - let mut reloc_sink = RelocSink::new( - &module, - func_index, - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] - probestack_trampoline_relocation_target, - ); + let mut reloc_sink = + RelocSink::new(&module, func_index, probestack_trampoline_relocation_target); let mut trap_sink = TrapSink::new(); let mut stackmap_sink = binemit::NullStackMapSink {}; context diff --git a/lib/compiler-cranelift/src/sink.rs b/lib/compiler-cranelift/src/sink.rs index cf9f6f89e03..9640e2614f0 100644 --- a/lib/compiler-cranelift/src/sink.rs +++ b/lib/compiler-cranelift/src/sink.rs @@ -2,12 +2,10 @@ use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind}; use cranelift_codegen::binemit; -#[cfg(target_arch = "x86_64")] use cranelift_codegen::ir::LibCall; use cranelift_codegen::ir::{self, ExternalName}; use cranelift_entity::EntityRef as CraneliftEntityRef; use wasmer_compiler::{JumpTable, Relocation, RelocationTarget, TrapInformation}; -#[cfg(all(target_arch = "x86_64", target_os = "linux"))] use wasmer_compiler::{RelocationKind, SectionIndex}; use wasmer_types::entity::EntityRef; use wasmer_types::{FunctionIndex, LocalFunctionIndex, ModuleInfo}; @@ -24,8 +22,7 @@ pub(crate) struct RelocSink<'a> { pub func_relocs: Vec, /// The section where the probestack trampoline call is located - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] - pub probestack_trampoline_relocation_target: SectionIndex, + pub probestack_trampoline_relocation_target: Option, } impl<'a> binemit::RelocSink for RelocSink<'a> { @@ -45,13 +42,12 @@ impl<'a> binemit::RelocSink for RelocSink<'a> { .expect("The provided function should be local"), ) } else if let ExternalName::LibCall(libcall) = *name { - match libcall { - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] - LibCall::Probestack => { + match (libcall, self.probestack_trampoline_relocation_target) { + (LibCall::Probestack, Some(probestack_trampoline_relocation_target)) => { self.func_relocs.push(Relocation { kind: RelocationKind::X86CallPCRel4, reloc_target: RelocationTarget::CustomSection( - self.probestack_trampoline_relocation_target, + probestack_trampoline_relocation_target, ), offset: offset, addend: addend, @@ -100,8 +96,7 @@ impl<'a> RelocSink<'a> { pub fn new( module: &'a ModuleInfo, func_index: FunctionIndex, - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] - probestack_trampoline_relocation_target: SectionIndex, + probestack_trampoline_relocation_target: Option, ) -> Self { let local_func_index = module .local_func_index(func_index) @@ -110,7 +105,6 @@ impl<'a> RelocSink<'a> { module, local_func_index, func_relocs: Vec::new(), - #[cfg(all(target_arch = "x86_64", target_os = "linux"))] probestack_trampoline_relocation_target, } } diff --git a/lib/compiler-singlepass/src/codegen_x64.rs b/lib/compiler-singlepass/src/codegen_x64.rs index d44f3be569d..59b44ec9fe0 100644 --- a/lib/compiler-singlepass/src/codegen_x64.rs +++ b/lib/compiler-singlepass/src/codegen_x64.rs @@ -91,6 +91,9 @@ pub struct FuncGen<'a> { /// // Ordered by increasing InstructionAddressMap::srcloc. instructions_address_map: Vec, + + /// Calling convention to use. + calling_convention: CallingConvention, } struct SpecialLabelSet { @@ -1012,7 +1015,7 @@ impl<'a> FuncGen<'a> { self.machine.state.stack_values.push(content); } } - let calling_convention = self.config.calling_convention; + let calling_convention = self.calling_convention; let stack_padding: usize = match calling_convention { CallingConvention::WindowsFastcall => 32, @@ -1758,7 +1761,7 @@ impl<'a> FuncGen<'a> { &mut self.assembler, self.local_types.len(), self.signature.params().len(), - self.config.calling_convention, + self.calling_convention, ); // Mark vmctx register. The actual loading of the vmctx value is handled by init_local. @@ -1825,6 +1828,7 @@ impl<'a> FuncGen<'a> { _table_styles: &'a PrimaryMap, local_func_index: LocalFunctionIndex, local_types_excluding_arguments: &[WpType], + calling_convention: CallingConvention, ) -> Result, CodegenError> { let func_index = module.func_index(local_func_index); let sig_index = module.functions[func_index]; @@ -1876,6 +1880,7 @@ impl<'a> FuncGen<'a> { special_labels, src_loc: 0, instructions_address_map: vec![], + calling_convention, }; fg.emit_head()?; Ok(fg) @@ -5406,7 +5411,7 @@ impl<'a> FuncGen<'a> { self.vmoffsets.vmcaller_checked_anyfunc_func_ptr() as usize; let vmcaller_checked_anyfunc_vmctx = self.vmoffsets.vmcaller_checked_anyfunc_vmctx() as usize; - let calling_convention = self.config.calling_convention; + let calling_convention = self.calling_convention; self.emit_call_native( |this| { @@ -6700,7 +6705,7 @@ impl<'a> FuncGen<'a> { self.machine.finalize_locals( &mut self.assembler, &self.locals, - self.config.calling_convention, + self.calling_convention, ); self.assembler.emit_mov( Size::S64, diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index 37feb7c8e63..ba48a665531 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -13,7 +13,7 @@ use rayon::prelude::{IntoParallelIterator, ParallelIterator}; use std::sync::Arc; use wasmer_compiler::{ Architecture, CallingConvention, Compilation, CompileError, CompileModuleInfo, - CompiledFunction, Compiler, CompilerConfig, FunctionBinaryReader, FunctionBody, + CompiledFunction, Compiler, CompilerConfig, CpuFeature, FunctionBinaryReader, FunctionBody, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain, ModuleTranslationState, OperatingSystem, SectionIndex, Target, TrapInformation, }; @@ -62,8 +62,15 @@ impl Compiler for SinglepassCompiler { OperatingSystem::Windows.to_string(), )); }*/ - if let Architecture::X86_32(arch) = target.triple().architecture { - return Err(CompileError::UnsupportedTarget(arch.to_string())); + if target.triple().architecture != Architecture::X86_64 { + return Err(CompileError::UnsupportedTarget( + target.triple().architecture.to_string(), + )); + } + if !target.cpu_features().contains(CpuFeature::AVX) { + return Err(CompileError::UnsupportedTarget( + "x86_64 without AVX".to_string(), + )); } if compile_info.features.multi_value { return Err(CompileError::UnsupportedFeature("multivalue".to_string())); @@ -125,6 +132,7 @@ impl Compiler for SinglepassCompiler { &table_styles, i, &locals, + calling_convention, ) .map_err(to_compile_error)?; diff --git a/lib/compiler-singlepass/src/config.rs b/lib/compiler-singlepass/src/config.rs index c3fa980dbf3..78496e83d40 100644 --- a/lib/compiler-singlepass/src/config.rs +++ b/lib/compiler-singlepass/src/config.rs @@ -4,9 +4,7 @@ use crate::compiler::SinglepassCompiler; use loupe::MemoryUsage; use std::sync::Arc; -use wasmer_compiler::{ - CallingConvention, Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target, -}; +use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target}; use wasmer_types::Features; #[derive(Debug, Clone, MemoryUsage)] @@ -15,8 +13,6 @@ pub struct Singlepass { pub(crate) enable_stack_check: bool, /// The middleware chain. pub(crate) middlewares: Vec>, - #[loupe(skip)] - pub(crate) calling_convention: CallingConvention, } impl Singlepass { @@ -27,12 +23,6 @@ impl Singlepass { enable_nan_canonicalization: true, enable_stack_check: false, middlewares: vec![], - calling_convention: match Target::default().triple().default_calling_convention() { - Ok(CallingConvention::WindowsFastcall) => CallingConvention::WindowsFastcall, - Ok(CallingConvention::SystemV) => CallingConvention::SystemV, - //Ok(CallingConvention::AppleAarch64) => AppleAarch64, - _ => panic!("Unsupported Calling convention for Singlepass"), - }, } } diff --git a/lib/compiler-singlepass/src/emitter_x64.rs b/lib/compiler-singlepass/src/emitter_x64.rs index 6ed4a7412b0..0d75b612057 100644 --- a/lib/compiler-singlepass/src/emitter_x64.rs +++ b/lib/compiler-singlepass/src/emitter_x64.rs @@ -483,7 +483,7 @@ macro_rules! binop_shift { macro_rules! jmp_op { ($ins:ident, $assembler:tt, $label:ident) => { - dynasm!($assembler ; $ins =>$label); + dynasm!($assembler ; $ins =>$label) } } diff --git a/lib/engine-dylib/Cargo.toml b/lib/engine-dylib/Cargo.toml index 1b356e07020..6df13e49164 100644 --- a/lib/engine-dylib/Cargo.toml +++ b/lib/engine-dylib/Cargo.toml @@ -25,6 +25,7 @@ tempfile = "3.1" which = "4.0" rkyv = "0.6.1" loupe = "0.1" +enumset = "1.0" [features] # Enable the `compiler` feature if you want the engine to compile diff --git a/lib/engine-dylib/src/artifact.rs b/lib/engine-dylib/src/artifact.rs index 1469a373363..3a8d9a7f911 100644 --- a/lib/engine-dylib/src/artifact.rs +++ b/lib/engine-dylib/src/artifact.rs @@ -3,6 +3,7 @@ use crate::engine::{DylibEngine, DylibEngineInner}; use crate::serialize::{ArchivedModuleMetadata, ModuleMetadata}; +use enumset::EnumSet; use libloading::{Library, Symbol as LibrarySymbol}; use loupe::MemoryUsage; use std::error::Error; @@ -17,8 +18,8 @@ use tracing::log::error; #[cfg(feature = "compiler")] use tracing::trace; use wasmer_compiler::{ - Architecture, CompileError, CompiledFunctionFrameInfo, Features, FunctionAddressMap, - OperatingSystem, Symbol, SymbolRegistry, Triple, + Architecture, CompileError, CompiledFunctionFrameInfo, CpuFeature, Features, + FunctionAddressMap, OperatingSystem, Symbol, SymbolRegistry, Triple, }; #[cfg(feature = "compiler")] use wasmer_compiler::{ @@ -211,6 +212,7 @@ impl DylibArtifact { prefix: engine_inner.get_prefix(&data), data_initializers, function_body_lengths, + cpu_features: target.cpu_features().as_u64(), }; let serialized_data = metadata.serialize()?; @@ -800,6 +802,10 @@ impl Artifact for DylibArtifact { &self.metadata.compile_info.features } + fn cpu_features(&self) -> enumset::EnumSet { + EnumSet::from_u64(self.metadata.cpu_features) + } + fn data_initializers(&self) -> &[OwnedDataInitializer] { &*self.metadata.data_initializers } diff --git a/lib/engine-dylib/src/serialize.rs b/lib/engine-dylib/src/serialize.rs index 7021834a8a2..33df08a6a90 100644 --- a/lib/engine-dylib/src/serialize.rs +++ b/lib/engine-dylib/src/serialize.rs @@ -35,6 +35,7 @@ pub struct ModuleMetadata { pub data_initializers: Box<[OwnedDataInitializer]>, // The function body lengths (used to find function by address) pub function_body_lengths: PrimaryMap, + pub cpu_features: u64, } pub struct ModuleMetadataSymbolRegistry<'a> { diff --git a/lib/engine-staticlib/Cargo.toml b/lib/engine-staticlib/Cargo.toml index 860b8637a9f..cac5c24159a 100644 --- a/lib/engine-staticlib/Cargo.toml +++ b/lib/engine-staticlib/Cargo.toml @@ -24,6 +24,7 @@ leb128 = "0.2" libloading = "0.7" tempfile = "3.1" loupe = "0.1" +enumset = "1.0" [features] # Enable the `compiler` feature if you want the engine to compile diff --git a/lib/engine-staticlib/src/artifact.rs b/lib/engine-staticlib/src/artifact.rs index 3615dac7952..cf25fb4808f 100644 --- a/lib/engine-staticlib/src/artifact.rs +++ b/lib/engine-staticlib/src/artifact.rs @@ -3,12 +3,15 @@ use crate::engine::{StaticlibEngine, StaticlibEngineInner}; use crate::serialize::{ModuleMetadata, ModuleMetadataSymbolRegistry}; +use enumset::EnumSet; use loupe::MemoryUsage; use std::collections::BTreeMap; use std::error::Error; use std::mem; use std::sync::Arc; -use wasmer_compiler::{CompileError, Features, OperatingSystem, SymbolRegistry, Triple}; +use wasmer_compiler::{ + CompileError, CpuFeature, Features, OperatingSystem, SymbolRegistry, Triple, +}; #[cfg(feature = "compiler")] use wasmer_compiler::{ CompileModuleInfo, Compiler, FunctionBodyData, ModuleEnvironment, ModuleMiddlewareChain, @@ -46,6 +49,7 @@ pub struct StaticlibArtifact { /// Length of the serialized metadata metadata_length: usize, symbol_registry: ModuleMetadataSymbolRegistry, + is_compiled: bool, } #[allow(dead_code)] @@ -181,6 +185,7 @@ impl StaticlibArtifact { prefix: engine_inner.get_prefix(&data), data_initializers, function_body_lengths, + cpu_features: target.cpu_features().as_u64(), }; /* @@ -295,6 +300,7 @@ impl StaticlibArtifact { func_data_registry: engine_inner.func_data().clone(), metadata_length, symbol_registry, + is_compiled: true, }) } @@ -415,6 +421,7 @@ impl StaticlibArtifact { func_data_registry, metadata_length: 0, symbol_registry, + is_compiled: false, }) } @@ -450,6 +457,10 @@ impl Artifact for StaticlibArtifact { &self.metadata.compile_info.features } + fn cpu_features(&self) -> EnumSet { + EnumSet::from_u64(self.metadata.cpu_features) + } + fn data_initializers(&self) -> &[OwnedDataInitializer] { &*self.metadata.data_initializers } @@ -483,6 +494,12 @@ impl Artifact for StaticlibArtifact { } fn preinstantiate(&self) -> Result<(), InstantiationError> { + if self.is_compiled { + panic!( + "a module built with the staticlib engine must be linked \ + into the current executable" + ); + } Ok(()) } diff --git a/lib/engine-staticlib/src/serialize.rs b/lib/engine-staticlib/src/serialize.rs index cee443a457c..3bd2fd799e4 100644 --- a/lib/engine-staticlib/src/serialize.rs +++ b/lib/engine-staticlib/src/serialize.rs @@ -12,6 +12,7 @@ pub struct ModuleMetadata { pub data_initializers: Box<[OwnedDataInitializer]>, // The function body lengths (used to find function by address) pub function_body_lengths: PrimaryMap, + pub cpu_features: u64, } #[derive(MemoryUsage)] diff --git a/lib/engine-universal/Cargo.toml b/lib/engine-universal/Cargo.toml index 683acc8fb23..c76c4154c46 100644 --- a/lib/engine-universal/Cargo.toml +++ b/lib/engine-universal/Cargo.toml @@ -11,8 +11,13 @@ readme = "README.md" edition = "2018" [dependencies] -wasmer-types = { path = "../types", version = "2.0.0", features = ["enable-rkyv"] } -wasmer-compiler = { path = "../compiler", version = "2.0.0", features = ["translator", "enable-rkyv"] } +wasmer-types = { path = "../types", version = "2.0.0", features = [ + "enable-rkyv", +] } +wasmer-compiler = { path = "../compiler", version = "2.0.0", features = [ + "translator", + "enable-rkyv", +] } wasmer-vm = { path = "../vm", version = "2.0.0", features = ["enable-rkyv"] } wasmer-engine = { path = "../engine", version = "2.0.0" } # flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" } @@ -21,6 +26,7 @@ cfg-if = "1.0" leb128 = "0.2" rkyv = "0.6.1" loupe = "0.1" +enumset = "1.0" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["winnt", "impl-default"] } diff --git a/lib/engine-universal/src/artifact.rs b/lib/engine-universal/src/artifact.rs index 6e0d4bac908..61a7aeabe0d 100644 --- a/lib/engine-universal/src/artifact.rs +++ b/lib/engine-universal/src/artifact.rs @@ -6,9 +6,10 @@ use crate::link::link_module; #[cfg(feature = "compiler")] use crate::serialize::SerializableCompilation; use crate::serialize::SerializableModule; +use enumset::EnumSet; use loupe::MemoryUsage; use std::sync::{Arc, Mutex}; -use wasmer_compiler::{CompileError, Features, Triple}; +use wasmer_compiler::{CompileError, CpuFeature, Features, Triple}; #[cfg(feature = "compiler")] use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment, ModuleMiddlewareChain}; use wasmer_engine::{ @@ -128,6 +129,7 @@ impl UniversalArtifact { compilation: serializable_compilation, compile_info, data_initializers, + cpu_features: engine.target().cpu_features().as_u64(), }; Self::from_parts(&mut inner_engine, serializable) } @@ -307,6 +309,10 @@ impl Artifact for UniversalArtifact { &self.serializable.compile_info.features } + fn cpu_features(&self) -> EnumSet { + EnumSet::from_u64(self.serializable.cpu_features) + } + fn data_initializers(&self) -> &[OwnedDataInitializer] { &*self.serializable.data_initializers } diff --git a/lib/engine-universal/src/serialize.rs b/lib/engine-universal/src/serialize.rs index 6e3c768d452..fa0cfc79fc5 100644 --- a/lib/engine-universal/src/serialize.rs +++ b/lib/engine-universal/src/serialize.rs @@ -38,6 +38,7 @@ pub struct SerializableModule { pub compilation: SerializableCompilation, pub compile_info: CompileModuleInfo, pub data_initializers: Box<[OwnedDataInitializer]>, + pub cpu_features: u64, } fn to_serialize_error(err: impl std::error::Error) -> SerializeError { diff --git a/lib/engine/Cargo.toml b/lib/engine/Cargo.toml index 39d058e5d91..0e19974c4bb 100644 --- a/lib/engine/Cargo.toml +++ b/lib/engine/Cargo.toml @@ -25,6 +25,7 @@ serde = { version = "1.0", features = ["derive", "rc"] } serde_bytes = { version = "0.11" } lazy_static = "1.4" loupe = "0.1" +enumset = "1.0" [badges] maintenance = { status = "actively-developed" } diff --git a/lib/engine/src/artifact.rs b/lib/engine/src/artifact.rs index e8185d14a7f..21e53c90a18 100644 --- a/lib/engine/src/artifact.rs +++ b/lib/engine/src/artifact.rs @@ -1,12 +1,13 @@ use crate::{ resolve_imports, InstantiationError, Resolver, RuntimeError, SerializeError, Tunables, }; +use enumset::EnumSet; use loupe::MemoryUsage; use std::any::Any; use std::fs; use std::path::Path; use std::sync::Arc; -use wasmer_compiler::Features; +use wasmer_compiler::{CpuFeature, Features}; use wasmer_types::entity::{BoxedSlice, PrimaryMap}; use wasmer_types::{ DataInitializer, FunctionIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo, @@ -43,6 +44,9 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage { /// Returns the features for this Artifact fn features(&self) -> &Features; + /// Returns the CPU features for this Artifact + fn cpu_features(&self) -> EnumSet; + /// Returns the memory styles associated with this `Artifact`. fn memory_styles(&self) -> &PrimaryMap; @@ -96,6 +100,16 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage { resolver: &dyn Resolver, host_state: Box, ) -> Result { + // Validate the CPU features this module was compiled with against the + // host CPU features. + let host_cpu_features = CpuFeature::for_host(); + if !host_cpu_features.is_superset(self.cpu_features()) { + Err(InstantiationError::CpuFeature(format!( + "{:?}", + self.cpu_features().difference(host_cpu_features) + )))?; + } + self.preinstantiate()?; let module = self.module(); diff --git a/lib/engine/src/error.rs b/lib/engine/src/error.rs index 87f771ebef5..5874e5d8bea 100644 --- a/lib/engine/src/error.rs +++ b/lib/engine/src/error.rs @@ -91,6 +91,11 @@ pub enum InstantiationError { #[error(transparent)] Link(LinkError), + /// The module was compiled with a CPU feature that is not available on + /// the current host. + #[error("module compiled with CPU feature that is missing from host")] + CpuFeature(String), + /// A runtime error occured while invoking the start function #[error(transparent)] Start(RuntimeError), diff --git a/tests/compilers/traps.rs b/tests/compilers/traps.rs index 145bc2529da..493090c7e9a 100644 --- a/tests/compilers/traps.rs +++ b/tests/compilers/traps.rs @@ -257,7 +257,9 @@ fn trap_start_function_import(config: crate::Config) -> Result<()> { .err() .unwrap(); match err { - InstantiationError::Link(_) | InstantiationError::HostEnvInitialization(_) => { + InstantiationError::Link(_) + | InstantiationError::HostEnvInitialization(_) + | InstantiationError::CpuFeature(_) => { panic!("It should be a start error") } InstantiationError::Start(err) => { diff --git a/tests/lib/engine-dummy/Cargo.toml b/tests/lib/engine-dummy/Cargo.toml index ae30b2aeffb..5bb1369b2bb 100644 --- a/tests/lib/engine-dummy/Cargo.toml +++ b/tests/lib/engine-dummy/Cargo.toml @@ -16,19 +16,14 @@ serde = { version = "1.0", features = ["derive", "rc"], optional = true } serde_bytes = { version = "0.11", optional = true } bincode = { version = "1.2", optional = true } loupe = "0.1" +enumset = "1.0" [features] # Enable the `compiler` feature if you want the engine to compile # and not be only on headless mode. default = ["serialize", "compiler"] -compiler = [ - "wasmer-compiler/translator" -] -serialize = [ - "serde", - "serde_bytes", - "bincode" -] +compiler = ["wasmer-compiler/translator"] +serialize = ["serde", "serde_bytes", "bincode"] [badges] # TODO: publish this crate again and deprecate it diff --git a/tests/lib/engine-dummy/src/artifact.rs b/tests/lib/engine-dummy/src/artifact.rs index 72fc3d4552e..9b7523afbb6 100644 --- a/tests/lib/engine-dummy/src/artifact.rs +++ b/tests/lib/engine-dummy/src/artifact.rs @@ -2,13 +2,14 @@ //! done as separate steps. use crate::engine::DummyEngine; +use enumset::EnumSet; use loupe::MemoryUsage; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; use std::sync::Arc; -use wasmer_compiler::CompileError; #[cfg(feature = "compiler")] use wasmer_compiler::ModuleEnvironment; +use wasmer_compiler::{CompileError, CpuFeature}; use wasmer_engine::{Artifact, DeserializeError, Engine as _, SerializeError, Tunables}; use wasmer_types::entity::{BoxedSlice, PrimaryMap}; use wasmer_types::{ @@ -30,6 +31,7 @@ pub struct DummyArtifactMetadata { // Plans for that module pub memory_styles: PrimaryMap, pub table_styles: PrimaryMap, + pub cpu_features: u64, } /// A Dummy artifact. @@ -104,6 +106,7 @@ impl DummyArtifact { data_initializers, memory_styles, table_styles, + cpu_features: engine.target().cpu_features().as_u64(), }; Self::from_parts(&engine, metadata) } @@ -211,6 +214,10 @@ impl Artifact for DummyArtifact { &self.metadata.features } + fn cpu_features(&self) -> EnumSet { + EnumSet::from_u64(self.metadata.cpu_features) + } + fn data_initializers(&self) -> &[OwnedDataInitializer] { &*self.metadata.data_initializers }