diff --git a/CHANGELOG.md b/CHANGELOG.md index d4511d11819..4621db71a3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ## **[Unreleased]** +- [#1710](https://github.com/wasmerio/wasmer/pull/1710) Memory for function call trampolines is now owned by the Artifact. ### Added - [#1741](https://github.com/wasmerio/wasmer/pull/1741) Implement `wasm_memory_type` in the Wasm C API. diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index fcf00b74342..32af4b6cc3f 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -18,7 +18,7 @@ use wasmer_vm::{ /// A function defined in the Wasm module #[derive(Clone, PartialEq)] pub struct WasmFunctionDefinition { - // The trampoline to do the call + // Address of the trampoline to do the call. pub(crate) trampoline: VMTrampoline, } @@ -95,6 +95,7 @@ impl Function { kind: VMFunctionKind::Dynamic, vmctx, signature: ty.clone(), + call_trampoline: None, }, } } @@ -144,6 +145,7 @@ impl Function { kind: VMFunctionKind::Dynamic, vmctx, signature: ty.clone(), + call_trampoline: None, }, } } @@ -185,6 +187,7 @@ impl Function { vmctx, signature, kind: VMFunctionKind::Static, + call_trampoline: None, }, } } @@ -238,6 +241,7 @@ impl Function { kind: VMFunctionKind::Static, vmctx, signature, + call_trampoline: None, }, } } @@ -351,15 +355,20 @@ impl Function { } pub(crate) fn from_export(store: &Store, wasmer_export: ExportFunction) -> Self { - let vmsignature = store.engine().register_signature(&wasmer_export.signature); - let trampoline = store - .engine() - .function_call_trampoline(vmsignature) - .expect("Can't get call trampoline for the function"); - Self { - store: store.clone(), - definition: FunctionDefinition::Wasm(WasmFunctionDefinition { trampoline }), - exported: wasmer_export, + if let Some(trampoline) = wasmer_export.call_trampoline { + Self { + store: store.clone(), + definition: FunctionDefinition::Wasm(WasmFunctionDefinition { trampoline }), + exported: wasmer_export, + } + } else { + Self { + store: store.clone(), + definition: FunctionDefinition::Host(HostFunctionDefinition { + has_env: !wasmer_export.vmctx.is_null(), + }), + exported: wasmer_export, + } } } diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index 5a73083f2cb..733bfd67e9c 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -69,6 +69,7 @@ where vmctx: other.vmctx, signature, kind: other.arg_kind, + call_trampoline: None, } } } @@ -88,6 +89,7 @@ where vmctx: other.vmctx, signature, kind: other.arg_kind, + call_trampoline: None, }, } } diff --git a/lib/api/src/types.rs b/lib/api/src/types.rs index b085f6a2419..5eac35f3bba 100644 --- a/lib/api/src/types.rs +++ b/lib/api/src/types.rs @@ -78,6 +78,7 @@ impl ValFuncRef for Val { // are converted to use the trampolines with static signatures). kind: wasmer_vm::VMFunctionKind::Static, vmctx: item.vmctx, + call_trampoline: None, }; let f = Function::from_export(store, export); Self::FuncRef(f) diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index b4c9af239e8..f7bca8910a5 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -20,12 +20,15 @@ use wasmer_types::{ FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex, }; -use wasmer_vm::{FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMSharedSignatureIndex}; +use wasmer_vm::{ + FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMSharedSignatureIndex, VMTrampoline, +}; /// A compiled wasm module, ready to be instantiated. pub struct JITArtifact { serializable: SerializableModule, finished_functions: BoxedSlice, + finished_function_call_trampolines: BoxedSlice, finished_dynamic_function_trampolines: BoxedSlice, signatures: BoxedSlice, frame_info_registration: Mutex>, @@ -150,7 +153,7 @@ impl JITArtifact { ) -> Result { let ( finished_functions, - _finished_function_call_trampolines, + finished_function_call_trampolines, finished_dynamic_function_trampolines, custom_sections, ) = inner_jit.allocate( @@ -201,6 +204,8 @@ impl JITArtifact { inner_jit.publish_eh_frame(eh_frame)?; let finished_functions = finished_functions.into_boxed_slice(); + let finished_function_call_trampolines = + finished_function_call_trampolines.into_boxed_slice(); let finished_dynamic_function_trampolines = finished_dynamic_function_trampolines.into_boxed_slice(); let signatures = signatures.into_boxed_slice(); @@ -208,6 +213,7 @@ impl JITArtifact { Ok(Self { serializable, finished_functions, + finished_function_call_trampolines, finished_dynamic_function_trampolines, signatures, frame_info_registration: Mutex::new(None), @@ -270,6 +276,10 @@ impl Artifact for JITArtifact { &self.finished_functions } + fn finished_function_call_trampolines(&self) -> &BoxedSlice { + &self.finished_function_call_trampolines + } + // TODO: return *const instead of *mut fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice { &self.finished_dynamic_function_trampolines diff --git a/lib/engine-jit/src/engine.rs b/lib/engine-jit/src/engine.rs index 0a4dbdf83ad..82624fec6ca 100644 --- a/lib/engine-jit/src/engine.rs +++ b/lib/engine-jit/src/engine.rs @@ -1,7 +1,6 @@ //! JIT compilation. use crate::{CodeMemory, JITArtifact}; -use std::collections::HashMap; use std::sync::{Arc, Mutex}; #[cfg(feature = "compiler")] use wasmer_compiler::Compiler; @@ -33,7 +32,6 @@ impl JITEngine { Self { inner: Arc::new(Mutex::new(JITEngineInner { compiler: Some(compiler), - function_call_trampolines: HashMap::new(), code_memory: vec![], signatures: SignatureRegistry::new(), features, @@ -61,7 +59,6 @@ impl JITEngine { inner: Arc::new(Mutex::new(JITEngineInner { #[cfg(feature = "compiler")] compiler: None, - function_call_trampolines: HashMap::new(), code_memory: vec![], signatures: SignatureRegistry::new(), features: Features::default(), @@ -98,11 +95,6 @@ impl Engine for JITEngine { compiler.signatures().lookup(sig) } - /// Retrieves a trampoline given a signature - fn function_call_trampoline(&self, sig: VMSharedSignatureIndex) -> Option { - self.inner().function_call_trampoline(sig) - } - /// Validates a WebAssembly module fn validate(&self, binary: &[u8]) -> Result<(), CompileError> { self.inner().validate(binary) @@ -150,8 +142,6 @@ pub struct JITEngineInner { /// The compiler #[cfg(feature = "compiler")] 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 @@ -196,7 +186,7 @@ impl JITEngineInner { #[allow(clippy::type_complexity)] pub(crate) fn allocate( &mut self, - module: &ModuleInfo, + _module: &ModuleInfo, functions: &PrimaryMap, function_call_trampolines: &PrimaryMap, dynamic_function_trampolines: &PrimaryMap, @@ -204,7 +194,7 @@ impl JITEngineInner { ) -> Result< ( PrimaryMap, - PrimaryMap, + PrimaryMap, PrimaryMap, PrimaryMap, ), @@ -241,20 +231,15 @@ impl JITEngineInner { .map(|slice| FunctionBodyPtr(slice as *mut [_])) .collect::>(); - let mut allocated_function_call_trampolines: PrimaryMap = + let mut allocated_function_call_trampolines: PrimaryMap = PrimaryMap::new(); - for ((sig_index, _), ptr) in function_call_trampolines.iter().zip( - allocated_functions - .drain(0..function_call_trampolines.len()) - .map(|slice| FunctionBodyPtr(slice as *mut [_])), - ) { - let func_type = &module.signatures[sig_index]; - let index = self.signatures.register(&func_type); - allocated_function_call_trampolines.push(ptr); - let trampoline = unsafe { - std::mem::transmute::<*const VMFunctionBody, VMTrampoline>((**ptr).as_ptr()) - }; - self.function_call_trampolines.insert(index, trampoline); + for ptr in allocated_functions + .drain(0..function_call_trampolines.len()) + .map(|slice| slice.as_ptr()) + { + let trampoline = + unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) }; + allocated_function_call_trampolines.push(trampoline); } let allocated_dynamic_function_trampolines = allocated_functions @@ -309,9 +294,4 @@ impl JITEngineInner { pub fn signatures(&self) -> &SignatureRegistry { &self.signatures } - - /// Gets the trampoline pre-registered for a particular signature - pub fn function_call_trampoline(&self, sig: VMSharedSignatureIndex) -> Option { - self.function_call_trampolines.get(&sig).cloned() - } } diff --git a/lib/engine-native/src/artifact.rs b/lib/engine-native/src/artifact.rs index cefde4d8d6a..54e4fb5d6b4 100644 --- a/lib/engine-native/src/artifact.rs +++ b/lib/engine-native/src/artifact.rs @@ -19,9 +19,7 @@ use wasmer_compiler::{CompileError, Features, OperatingSystem, Symbol, SymbolReg use wasmer_compiler::{ CompileModuleInfo, FunctionBodyData, ModuleEnvironment, ModuleTranslationState, }; -use wasmer_engine::{ - Artifact, DeserializeError, InstantiationError, LinkError, RuntimeError, SerializeError, -}; +use wasmer_engine::{Artifact, DeserializeError, InstantiationError, SerializeError}; #[cfg(feature = "compiler")] use wasmer_engine::{Engine, Tunables}; #[cfg(feature = "compiler")] @@ -42,9 +40,8 @@ use wasmer_vm::{ pub struct NativeArtifact { sharedobject_path: PathBuf, metadata: ModuleMetadata, - #[allow(dead_code)] - library: Option, finished_functions: BoxedSlice, + finished_function_call_trampolines: BoxedSlice, finished_dynamic_function_trampolines: BoxedSlice, signatures: BoxedSlice, } @@ -324,14 +321,17 @@ impl NativeArtifact { sharedobject_path: PathBuf, ) -> Result { let finished_functions: PrimaryMap = PrimaryMap::new(); + let finished_function_call_trampolines: PrimaryMap = + PrimaryMap::new(); let finished_dynamic_function_trampolines: PrimaryMap = PrimaryMap::new(); let signatures: PrimaryMap = PrimaryMap::new(); Ok(Self { sharedobject_path, metadata, - library: None, finished_functions: finished_functions.into_boxed_slice(), + finished_function_call_trampolines: finished_function_call_trampolines + .into_boxed_slice(), finished_dynamic_function_trampolines: finished_dynamic_function_trampolines .into_boxed_slice(), signatures: signatures.into_boxed_slice(), @@ -367,14 +367,17 @@ impl NativeArtifact { } } - // Retrieve function call trampolines (for all signatures in the module) - for (sig_index, func_type) in metadata.compile_info.module.signatures.iter() { + // Retrieve function call trampolines + let mut finished_function_call_trampolines: PrimaryMap = + PrimaryMap::with_capacity(metadata.compile_info.module.signatures.len()); + for sig_index in metadata.compile_info.module.signatures.keys() { let function_name = metadata.symbol_to_name(Symbol::FunctionCallTrampoline(sig_index)); unsafe { let trampoline: LibrarySymbol = lib .get(function_name.as_bytes()) .map_err(to_compile_error)?; - engine_inner.add_trampoline(&func_type, *trampoline); + let raw = *trampoline.into_raw(); + finished_function_call_trampolines.push(raw); } } @@ -418,21 +421,23 @@ impl NativeArtifact { // Compute indices into the shared signature table. let signatures = { - let signature_registry = engine_inner.signatures(); metadata .compile_info .module .signatures .values() - .map(|sig| signature_registry.register(sig)) + .map(|sig| engine_inner.signatures().register(sig)) .collect::>() }; + engine_inner.add_library(lib); + Ok(Self { sharedobject_path, metadata, - library: Some(lib), finished_functions: finished_functions.into_boxed_slice(), + finished_function_call_trampolines: finished_function_call_trampolines + .into_boxed_slice(), finished_dynamic_function_trampolines: finished_dynamic_function_trampolines .into_boxed_slice(), signatures: signatures.into_boxed_slice(), @@ -571,6 +576,10 @@ impl Artifact for NativeArtifact { &self.finished_functions } + fn finished_function_call_trampolines(&self) -> &BoxedSlice { + &self.finished_function_call_trampolines + } + fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice { &self.finished_dynamic_function_trampolines } @@ -580,11 +589,6 @@ impl Artifact for NativeArtifact { } fn preinstantiate(&self) -> Result<(), InstantiationError> { - if self.library.is_none() { - return Err(InstantiationError::Link(LinkError::Trap( - RuntimeError::new("Cross compiled artifacts can't be instantiated."), - ))); - } Ok(()) } diff --git a/lib/engine-native/src/engine.rs b/lib/engine-native/src/engine.rs index 4950a19a84b..220609c025e 100644 --- a/lib/engine-native/src/engine.rs +++ b/lib/engine-native/src/engine.rs @@ -1,7 +1,7 @@ //! Native Engine. use crate::NativeArtifact; -use std::collections::HashMap; +use libloading::Library; use std::path::Path; use std::sync::Arc; use std::sync::Mutex; @@ -12,7 +12,7 @@ use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables}; #[cfg(feature = "compiler")] use wasmer_types::Features; use wasmer_types::FunctionType; -use wasmer_vm::{SignatureRegistry, VMSharedSignatureIndex, VMTrampoline}; +use wasmer_vm::{SignatureRegistry, VMSharedSignatureIndex}; #[cfg(feature = "compiler")] use which::which; @@ -49,12 +49,12 @@ impl NativeEngine { Self { inner: Arc::new(Mutex::new(NativeEngineInner { compiler: Some(compiler), - trampolines: HashMap::new(), signatures: SignatureRegistry::new(), prefixer: None, features, is_cross_compiling, linker, + libraries: vec![], })), target: Arc::new(target), engine_id: EngineId::default(), @@ -81,11 +81,11 @@ impl NativeEngine { compiler: None, #[cfg(feature = "compiler")] features: Features::default(), - trampolines: HashMap::new(), signatures: SignatureRegistry::new(), prefixer: None, is_cross_compiling: false, linker: Linker::None, + libraries: vec![], })), target: Arc::new(Target::default()), engine_id: EngineId::default(), @@ -137,11 +137,6 @@ impl Engine for NativeEngine { compiler.signatures().lookup(sig) } - /// Retrieves a trampoline given a signature - fn function_call_trampoline(&self, sig: VMSharedSignatureIndex) -> Option { - self.inner().trampoline(sig) - } - /// Validates a WebAssembly module fn validate(&self, binary: &[u8]) -> Result<(), CompileError> { self.inner().validate(binary) @@ -222,8 +217,6 @@ pub struct NativeEngineInner { /// The WebAssembly features to use #[cfg(feature = "compiler")] features: Features, - /// Pointers to trampoline functions used to enter particular signatures - trampolines: HashMap, /// The signature registry is used mainly to operate with trampolines /// performantly. signatures: SignatureRegistry, @@ -235,6 +228,8 @@ pub struct NativeEngineInner { is_cross_compiling: bool, /// The linker to use. linker: Linker, + /// List of libraries loaded by this engine. + libraries: Vec, } impl NativeEngineInner { @@ -283,19 +278,6 @@ impl NativeEngineInner { &self.signatures } - /// Gets the trampoline pre-registered for a particular signature - pub fn trampoline(&self, sig: VMSharedSignatureIndex) -> Option { - self.trampolines.get(&sig).cloned() - } - - pub(crate) fn add_trampoline(&mut self, func_type: &FunctionType, trampoline: VMTrampoline) { - let index = self.signatures.register(&func_type); - // We always use (for now) the latest trampoline compiled - // TODO: we need to deallocate trampolines as the compiled modules - // where they belong become unallocated. - self.trampolines.insert(index, trampoline); - } - pub(crate) fn is_cross_compiling(&self) -> bool { self.is_cross_compiling } @@ -303,4 +285,8 @@ impl NativeEngineInner { pub(crate) fn linker(&self) -> Linker { self.linker } + + pub(crate) fn add_library(&mut self, library: Library) { + self.libraries.push(library); + } } diff --git a/lib/engine-object-file/src/artifact.rs b/lib/engine-object-file/src/artifact.rs index 2ba207659a0..18ca4d129ae 100644 --- a/lib/engine-object-file/src/artifact.rs +++ b/lib/engine-object-file/src/artifact.rs @@ -34,6 +34,7 @@ pub struct ObjectFileArtifact { metadata: ModuleMetadata, module_bytes: Vec, finished_functions: BoxedSlice, + finished_function_call_trampolines: BoxedSlice, finished_dynamic_function_trampolines: BoxedSlice, signatures: BoxedSlice, /// Length of the serialized metadata @@ -247,6 +248,8 @@ impl ObjectFileArtifact { metadata_length: usize, ) -> Result { let finished_functions: PrimaryMap = PrimaryMap::new(); + let finished_function_call_trampolines: PrimaryMap = + PrimaryMap::new(); let finished_dynamic_function_trampolines: PrimaryMap = PrimaryMap::new(); let signature_registry = engine_inner.signatures(); @@ -262,6 +265,8 @@ impl ObjectFileArtifact { metadata, module_bytes, finished_functions: finished_functions.into_boxed_slice(), + finished_function_call_trampolines: finished_function_call_trampolines + .into_boxed_slice(), finished_dynamic_function_trampolines: finished_dynamic_function_trampolines .into_boxed_slice(), signatures: signatures.into_boxed_slice(), @@ -307,7 +312,7 @@ impl ObjectFileArtifact { len: usize, } - let mut engine_inner = engine.inner_mut(); + let engine_inner = engine.inner(); let signature_registry = engine_inner.signatures(); let mut sig_map: BTreeMap = BTreeMap::new(); @@ -339,20 +344,18 @@ impl ObjectFileArtifact { } // read trampolines in order + let mut finished_function_call_trampolines = PrimaryMap::new(); byte_buffer[0..WORD_SIZE].clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]); cur_offset += WORD_SIZE; let num_function_trampolines = usize::from_ne_bytes(byte_buffer); - for i in 0..num_function_trampolines { + for _ in 0..num_function_trampolines { byte_buffer[0..WORD_SIZE] .clone_from_slice(&bytes[cur_offset..(cur_offset + WORD_SIZE)]); cur_offset += WORD_SIZE; let trampoline_ptr_bytes = usize::from_ne_bytes(byte_buffer); let trampoline = mem::transmute::(trampoline_ptr_bytes); - - let func_type = &metadata.compile_info.module.signatures[SignatureIndex::new(i)]; - - engine_inner.add_trampoline(func_type, trampoline); - // TODO: we can read back the length here if we serialize it. This will improve debug output. + finished_function_call_trampolines.push(trampoline); + // TODO: we can read back the length here if we serialize it. This will improve debug output. } // read dynamic function trampolines in order now... @@ -377,6 +380,8 @@ impl ObjectFileArtifact { metadata, module_bytes: bytes.to_owned(), finished_functions: finished_functions.into_boxed_slice(), + finished_function_call_trampolines: finished_function_call_trampolines + .into_boxed_slice(), finished_dynamic_function_trampolines: finished_dynamic_function_trampolines .into_boxed_slice(), signatures: signatures.into_boxed_slice(), @@ -432,6 +437,10 @@ impl Artifact for ObjectFileArtifact { &self.finished_functions } + fn finished_function_call_trampolines(&self) -> &BoxedSlice { + &self.finished_function_call_trampolines + } + fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice { &self.finished_dynamic_function_trampolines } diff --git a/lib/engine-object-file/src/engine.rs b/lib/engine-object-file/src/engine.rs index 3c83a275fde..a24fe358b63 100644 --- a/lib/engine-object-file/src/engine.rs +++ b/lib/engine-object-file/src/engine.rs @@ -1,5 +1,4 @@ use crate::ObjectFileArtifact; -use std::collections::HashMap; use std::io::Read; use std::path::Path; use std::sync::{Arc, Mutex}; @@ -10,7 +9,7 @@ use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables}; #[cfg(feature = "compiler")] use wasmer_types::Features; use wasmer_types::FunctionType; -use wasmer_vm::{SignatureRegistry, VMSharedSignatureIndex, VMTrampoline}; +use wasmer_vm::{SignatureRegistry, VMSharedSignatureIndex}; /// A WebAssembly `ObjectFile` Engine. #[derive(Clone)] @@ -28,7 +27,6 @@ impl ObjectFileEngine { Self { inner: Arc::new(Mutex::new(ObjectFileEngineInner { compiler: Some(compiler), - trampolines: HashMap::new(), signatures: SignatureRegistry::new(), prefixer: None, features, @@ -58,7 +56,6 @@ impl ObjectFileEngine { compiler: None, #[cfg(feature = "compiler")] features: Features::default(), - trampolines: HashMap::new(), signatures: SignatureRegistry::new(), prefixer: None, })), @@ -112,11 +109,6 @@ impl Engine for ObjectFileEngine { compiler.signatures().lookup(sig) } - /// Retrieves a trampoline given a signature - fn function_call_trampoline(&self, sig: VMSharedSignatureIndex) -> Option { - self.inner().trampoline(sig) - } - /// Validates a WebAssembly module fn validate(&self, binary: &[u8]) -> Result<(), CompileError> { self.inner().validate(binary) @@ -180,8 +172,6 @@ pub struct ObjectFileEngineInner { /// The WebAssembly features to use #[cfg(feature = "compiler")] features: Features, - /// Pointers to trampoline functions used to enter particular signatures - trampolines: HashMap, /// The signature registry is used mainly to operate with trampolines /// performantly. signatures: SignatureRegistry, @@ -236,17 +226,4 @@ impl ObjectFileEngineInner { pub fn signatures(&self) -> &SignatureRegistry { &self.signatures } - - /// Gets the trampoline pre-registered for a particular signature - pub fn trampoline(&self, sig: VMSharedSignatureIndex) -> Option { - self.trampolines.get(&sig).cloned() - } - - pub(crate) fn add_trampoline(&mut self, func_type: &FunctionType, trampoline: VMTrampoline) { - let index = self.signatures.register(&func_type); - // We always use (for now) the latest trampoline compiled - // TODO: we need to deallocate trampolines as the compiled modules - // where they belong become unallocated. - self.trampolines.insert(index, trampoline); - } } diff --git a/lib/engine/src/artifact.rs b/lib/engine/src/artifact.rs index f74fc4717bf..31ba2da4e94 100644 --- a/lib/engine/src/artifact.rs +++ b/lib/engine/src/artifact.rs @@ -13,6 +13,7 @@ use wasmer_types::{ }; use wasmer_vm::{ FunctionBodyPtr, InstanceHandle, MemoryStyle, ModuleInfo, TableStyle, VMSharedSignatureIndex, + VMTrampoline, }; /// An `Artifact` is the product that the `Engine` @@ -54,8 +55,12 @@ pub trait Artifact: Send + Sync + Upcastable { /// ready to be run. fn finished_functions(&self) -> &BoxedSlice; + /// Returns the function call trampolines allocated in memory of this + /// `Artifact`, ready to be run. + fn finished_function_call_trampolines(&self) -> &BoxedSlice; + /// Returns the dynamic function trampolines allocated in memory - /// for this `Artifact`, ready to be run. + /// of this `Artifact`, ready to be run. fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice; /// Returns the associated VM signatures for this `Artifact`. @@ -116,6 +121,7 @@ pub trait Artifact: Send + Sync + Upcastable { InstanceHandle::new( module, self.finished_functions().clone(), + self.finished_function_call_trampolines().clone(), finished_memories, finished_tables, finished_globals, diff --git a/lib/engine/src/engine.rs b/lib/engine/src/engine.rs index 17978b351f2..2828bfc52a3 100644 --- a/lib/engine/src/engine.rs +++ b/lib/engine/src/engine.rs @@ -7,7 +7,7 @@ use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use std::sync::Arc; use wasmer_compiler::{CompileError, Target}; use wasmer_types::FunctionType; -use wasmer_vm::{VMSharedSignatureIndex, VMTrampoline}; +use wasmer_vm::VMSharedSignatureIndex; /// A unimplemented Wasmer `Engine`. /// @@ -25,9 +25,6 @@ pub trait Engine { /// Lookup a signature fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option; - /// Retrieves a trampoline given a signature - fn function_call_trampoline(&self, sig: VMSharedSignatureIndex) -> Option; - /// Validates a WebAssembly module fn validate(&self, binary: &[u8]) -> Result<(), CompileError>; diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index 7879c92d16a..32eb3ca64c7 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -4,7 +4,7 @@ use crate::global::Global; use crate::memory::{Memory, MemoryStyle}; use crate::table::{Table, TableStyle}; -use crate::vmcontext::{VMContext, VMFunctionBody, VMFunctionKind}; +use crate::vmcontext::{VMContext, VMFunctionBody, VMFunctionKind, VMTrampoline}; use std::sync::Arc; use wasmer_types::{FunctionType, MemoryType, TableType}; @@ -35,6 +35,9 @@ pub struct ExportFunction { pub signature: FunctionType, /// The function kind (it defines how it's the signature that provided `address` have) pub kind: VMFunctionKind, + /// Address of the function call trampoline owned by the same VMContext that owns the VMFunctionBody. + /// May be None when the function is an host-function (FunctionType == Dynamic or vmctx == nullptr). + pub call_trampoline: Option, } /// # Safety diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index d5a674ceee3..9777d51e46c 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -13,7 +13,7 @@ use crate::trap::{catch_traps, init_traps, Trap, TrapCode}; use crate::vmcontext::{ VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition, VMMemoryImport, - VMSharedSignatureIndex, VMTableDefinition, VMTableImport, + VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, }; use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable}; use crate::{FunctionBodyPtr, ModuleInfo, VMOffsets}; @@ -85,6 +85,9 @@ pub(crate) struct Instance { /// Pointers to functions in executable memory. functions: BoxedSlice, + /// Pointers to function call trampolines in executable memory. + function_call_trampolines: BoxedSlice, + /// Passive elements in this instantiation. As `elem.drop`s happen, these /// entries get removed. A missing entry is considered equivalent to an /// empty slice. @@ -298,6 +301,7 @@ impl Instance { let import = self.imported_function(*index); (import.body, import.vmctx) }; + let call_trampoline = Some(self.function_call_trampolines[*sig_index]); let signature = self.module.signatures[*sig_index].clone(); ExportFunction { address, @@ -308,6 +312,7 @@ impl Instance { kind: VMFunctionKind::Static, signature, vmctx, + call_trampoline, } .into() } @@ -791,6 +796,7 @@ impl InstanceHandle { pub unsafe fn new( module: Arc, finished_functions: BoxedSlice, + finished_function_call_trampolines: BoxedSlice, finished_memories: BoxedSlice>, finished_tables: BoxedSlice>, finished_globals: BoxedSlice>, @@ -837,6 +843,7 @@ impl InstanceHandle { tables: finished_tables, globals: finished_globals, functions: finished_functions, + function_call_trampolines: finished_function_call_trampolines, passive_elements: Default::default(), passive_data, host_state, diff --git a/tests/compilers/traps.rs b/tests/compilers/traps.rs index a9fb846c67f..e84d98a9aea 100644 --- a/tests/compilers/traps.rs +++ b/tests/compilers/traps.rs @@ -495,7 +495,6 @@ RuntimeError: unreachable } #[test] -#[cfg_attr(feature = "test-native", ignore)] fn present_after_module_drop() -> Result<()> { let store = get_store(false); let module = Module::new(&store, r#"(func (export "foo") unreachable)"#)?; diff --git a/tests/ignores.txt b/tests/ignores.txt index f8b426a02a8..6fcd597d8ed 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -24,8 +24,6 @@ llvm::spec::skip_stack_guard_page on darwin # TODO(https://github.com/wasmerio/wasmer/issues/1727): Traps in native engine cranelift::spec::linking on native -# TODO(https://github.com/wasmerio/wasmer/pull/1710): Library is dropped too soon. -llvm::spec::linking on native # https://github.com/wasmerio/wasmer/issues/1722 llvm::spec::skip_stack_guard_page on native diff --git a/tests/lib/engine-dummy/src/artifact.rs b/tests/lib/engine-dummy/src/artifact.rs index 42cda621a0d..e8e693661bb 100644 --- a/tests/lib/engine-dummy/src/artifact.rs +++ b/tests/lib/engine-dummy/src/artifact.rs @@ -16,7 +16,7 @@ use wasmer_types::{ }; use wasmer_vm::{ FunctionBodyPtr, MemoryStyle, ModuleInfo, TableStyle, VMContext, VMFunctionBody, - VMSharedSignatureIndex, + VMSharedSignatureIndex, VMTrampoline, }; /// Serializable struct for the artifact @@ -38,6 +38,7 @@ pub struct DummyArtifact { metadata: DummyArtifactMetadata, finished_functions: BoxedSlice, + finished_function_call_trampolines: BoxedSlice, finished_dynamic_function_trampolines: BoxedSlice, signatures: BoxedSlice, } @@ -131,7 +132,7 @@ impl DummyArtifact { ) -> Result { let num_local_functions = metadata.module.functions.len() - metadata.module.num_imported_functions; - // We prepare the pointers for the finished functions + // We prepare the pointers for the finished functions. let finished_functions: PrimaryMap = (0 ..num_local_functions) .map(|_| unsafe { @@ -141,7 +142,13 @@ impl DummyArtifact { }) .collect::>(); - // We prepare the pointers for the finished dynamic function trampolines + // We prepare the pointers for the finished function call trampolines. + let finished_function_call_trampolines: PrimaryMap = (0 + ..metadata.module.signatures.len()) + .map(|_| unsafe { std::mem::transmute::<_, VMTrampoline>(&dummy_function) }) + .collect::>(); + + // We prepare the pointers for the finished dynamic function trampolines. let finished_dynamic_function_trampolines: PrimaryMap = (0 ..metadata.module.num_imported_functions) .map(|_| { @@ -165,6 +172,8 @@ impl DummyArtifact { }; let finished_functions = finished_functions.into_boxed_slice(); + let finished_function_call_trampolines = + finished_function_call_trampolines.into_boxed_slice(); let finished_dynamic_function_trampolines = finished_dynamic_function_trampolines.into_boxed_slice(); let signatures = signatures.into_boxed_slice(); @@ -172,6 +181,7 @@ impl DummyArtifact { Ok(Self { metadata, finished_functions, + finished_function_call_trampolines, finished_dynamic_function_trampolines, signatures, }) @@ -215,6 +225,10 @@ impl Artifact for DummyArtifact { &self.finished_functions } + fn finished_function_call_trampolines(&self) -> &BoxedSlice { + &self.finished_function_call_trampolines + } + fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice { &self.finished_dynamic_function_trampolines } diff --git a/tests/lib/engine-dummy/src/engine.rs b/tests/lib/engine-dummy/src/engine.rs index 0a8a3e255c5..14c5c0beceb 100644 --- a/tests/lib/engine-dummy/src/engine.rs +++ b/tests/lib/engine-dummy/src/engine.rs @@ -5,9 +5,7 @@ use std::sync::Arc; use wasmer_compiler::{CompileError, Features, Target}; use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables}; use wasmer_types::FunctionType; -use wasmer_vm::{ - SignatureRegistry, VMContext, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline, -}; +use wasmer_vm::{SignatureRegistry, VMContext, VMFunctionBody, VMSharedSignatureIndex}; extern "C" fn dummy_trampoline( _context: *mut VMContext, @@ -58,11 +56,6 @@ impl Engine for DummyEngine { self.signatures.lookup(sig) } - /// Retrieves a trampoline given a signature - fn function_call_trampoline(&self, _sig: VMSharedSignatureIndex) -> Option { - Some(dummy_trampoline) - } - #[cfg(feature = "compiler")] /// Validates a WebAssembly module fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {