From 839a1d78eaacf44a0bbdb5ab9dd252b1620af495 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 12:20:18 -0700 Subject: [PATCH 01/27] Improved wast print text --- tests/wast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/wast.rs b/tests/wast.rs index db992408a..4aefd35c4 100644 --- a/tests/wast.rs +++ b/tests/wast.rs @@ -16,7 +16,7 @@ use wasmer_wast::Wast; include!(concat!(env!("OUT_DIR"), "/generated_spectests.rs")); fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { - println!("Running wast {} with {}", wast_path, compiler); + println!("Running wast `{}` with the {} compiler", wast_path, compiler); let try_nan_canonicalization = wast_path.contains("nan-canonicalization"); let mut features = Features::default(); if wast_path.contains("bulk-memory") { From ab27b7ff3a0a7df70958afd32f250f1784f217d6 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 14:37:53 -0700 Subject: [PATCH 02/27] Fixed singlepass compilation --- lib/compiler-singlepass/src/compiler.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index 07c65c967..b57d4a6cb 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -9,7 +9,7 @@ use wasm_common::Features; use wasm_common::{FuncIndex, FuncType, LocalFuncIndex, MemoryIndex, TableIndex}; use wasmer_compiler::FunctionBodyData; use wasmer_compiler::TrapInformation; -use wasmer_compiler::{Compilation, CompileError, CompiledFunction, Compiler}; +use wasmer_compiler::{Compilation, CompileError, FunctionBody, Compiler}; use wasmer_compiler::{CompilerConfig, ModuleTranslationState, Target}; use wasmer_runtime::Module; use wasmer_runtime::TrapCode; @@ -68,7 +68,7 @@ impl Compiler for SinglepassCompiler { fn compile_wasm_trampolines( &self, _signatures: &[FuncType], - ) -> Result, CompileError> { + ) -> Result, CompileError> { // Note: do not implement this yet Err(CompileError::Codegen( "Singlepass trampoline compilation not supported yet".to_owned(), From 8d3cfa769a60dac0f1a726c4b7d7ad8d7209c7fa Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 14:40:29 -0700 Subject: [PATCH 03/27] Fixed linting --- lib/compiler-singlepass/src/compiler.rs | 2 +- tests/wast.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index b57d4a6cb..6c7151146 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -9,7 +9,7 @@ use wasm_common::Features; use wasm_common::{FuncIndex, FuncType, LocalFuncIndex, MemoryIndex, TableIndex}; use wasmer_compiler::FunctionBodyData; use wasmer_compiler::TrapInformation; -use wasmer_compiler::{Compilation, CompileError, FunctionBody, Compiler}; +use wasmer_compiler::{Compilation, CompileError, Compiler, FunctionBody}; use wasmer_compiler::{CompilerConfig, ModuleTranslationState, Target}; use wasmer_runtime::Module; use wasmer_runtime::TrapCode; diff --git a/tests/wast.rs b/tests/wast.rs index 4aefd35c4..f5384aefe 100644 --- a/tests/wast.rs +++ b/tests/wast.rs @@ -16,7 +16,10 @@ use wasmer_wast::Wast; include!(concat!(env!("OUT_DIR"), "/generated_spectests.rs")); fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { - println!("Running wast `{}` with the {} compiler", wast_path, compiler); + println!( + "Running wast `{}` with the {} compiler", + wast_path, compiler + ); let try_nan_canonicalization = wast_path.contains("nan-canonicalization"); let mut features = Features::default(); if wast_path.contains("bulk-memory") { From db72d19f5d0721a8e93ff6ed0c4bffa12181e5be Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Sun, 3 May 2020 15:24:16 -0700 Subject: [PATCH 04/27] Add SectionBody which holds the bytes of a section. Wire it up to CompiledModule::new(). --- lib/compiler/src/lib.rs | 2 +- lib/compiler/src/section.rs | 7 +++++-- lib/jit/src/module.rs | 1 + lib/jit/src/serialize.rs | 6 +++++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/compiler/src/lib.rs b/lib/compiler/src/lib.rs index 7b5ed1c13..432df3633 100644 --- a/lib/compiler/src/lib.rs +++ b/lib/compiler/src/lib.rs @@ -64,7 +64,7 @@ pub use crate::function::{ }; pub use crate::jump_table::{JumpTable, JumpTableOffsets}; pub use crate::relocation::{Relocation, RelocationKind, RelocationTarget, Relocations}; -pub use crate::section::{CustomSection, CustomSectionProtection, SectionIndex}; +pub use crate::section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex}; pub use crate::sourceloc::SourceLoc; pub use crate::translator::{ to_wasm_error, translate_module, FunctionBodyData, ModuleEnvironment, ModuleTranslation, diff --git a/lib/compiler/src/section.rs b/lib/compiler/src/section.rs index 0908f1b90..9794e6123 100644 --- a/lib/compiler/src/section.rs +++ b/lib/compiler/src/section.rs @@ -41,6 +41,9 @@ pub struct CustomSection { /// > (the start of the memory pointer). /// > We might need to create another field for alignment in case it's /// > needed in the future. - #[serde(with = "serde_bytes")] - pub bytes: Vec, + pub bytes: SectionBody, } + +/// The bytes in the section. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct SectionBody(#[serde(with = "serde_bytes")] Vec); diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index 655980303..a1156577e 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -89,6 +89,7 @@ impl CompiledModule { function_relocations: compilation.get_relocations(), function_jt_offsets: compilation.get_jt_offsets(), function_frame_info: frame_infos, + custom_sections: PrimaryMap::new(), }; let serializable = SerializableModule { compilation: serializable_compilation, diff --git a/lib/jit/src/serialize.rs b/lib/jit/src/serialize.rs index 835775c47..c07bbe1ae 100644 --- a/lib/jit/src/serialize.rs +++ b/lib/jit/src/serialize.rs @@ -3,7 +3,10 @@ use serde::ser::Serializer; use serde::{Deserialize, Serialize}; use std::fmt; use std::sync::Arc; -use wasmer_compiler::{CompiledFunctionFrameInfo, FunctionBody, JumpTableOffsets, Relocation}; +use wasmer_compiler::{ + CompiledFunctionFrameInfo, FunctionBody, JumpTableOffsets, Relocation, SectionBody, + SectionIndex, +}; use wasmer_runtime::Module; use wasm_common::entity::PrimaryMap; @@ -20,6 +23,7 @@ pub struct SerializableCompilation { // to allow lazy frame_info deserialization, we convert it to it's lazy binary // format upon serialization. pub function_frame_info: PrimaryMap, + pub custom_sections: PrimaryMap, } /// Serializable struct that is able to serialize from and to From 182b0802ec061b89d673a8e4adc4a422c2975241 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Sun, 3 May 2020 15:34:54 -0700 Subject: [PATCH 05/27] Fill custom section data in CompiledModule. --- lib/compiler/src/function.rs | 10 +++++++++- lib/jit/src/module.rs | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/compiler/src/function.rs b/lib/compiler/src/function.rs index 60e1fe255..ac63404df 100644 --- a/lib/compiler/src/function.rs +++ b/lib/compiler/src/function.rs @@ -5,7 +5,7 @@ //! * `jit`: to generate a JIT //! * `obj`: to generate a native object -use crate::section::{CustomSection, SectionIndex}; +use crate::section::{CustomSection, SectionBody, SectionIndex}; use crate::std::vec::Vec; use crate::trap::TrapInformation; use crate::{CompiledFunctionUnwindInfo, FunctionAddressMap, JumpTableOffsets, Relocation}; @@ -130,6 +130,14 @@ impl Compilation { .map(|(_, func)| func.frame_info.clone()) .collect::>() } + + /// Gets custom section data. + pub fn get_custom_sections(&self) -> PrimaryMap { + self.custom_sections + .iter() + .map(|(_, section)| section.bytes.clone()) + .collect::>() + } } impl<'a> IntoIterator for &'a Compilation { diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index a1156577e..28969fd3b 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -89,7 +89,7 @@ impl CompiledModule { function_relocations: compilation.get_relocations(), function_jt_offsets: compilation.get_jt_offsets(), function_frame_info: frame_infos, - custom_sections: PrimaryMap::new(), + custom_sections: compilation.get_custom_sections(), }; let serializable = SerializableModule { compilation: serializable_compilation, From 861958a4ab583fbf2e5f7f9748dbe7d8c986d73e Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Sun, 3 May 2020 15:48:08 -0700 Subject: [PATCH 06/27] Add SectionBody::as_ptr() to get the pointer to the section data. Implement custom section relocations with it. --- lib/compiler/src/section.rs | 7 +++++++ lib/jit/src/link.rs | 10 +++++++--- lib/jit/src/module.rs | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/compiler/src/section.rs b/lib/compiler/src/section.rs index 9794e6123..ab96bb831 100644 --- a/lib/compiler/src/section.rs +++ b/lib/compiler/src/section.rs @@ -47,3 +47,10 @@ pub struct CustomSection { /// The bytes in the section. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct SectionBody(#[serde(with = "serde_bytes")] Vec); + +impl SectionBody { + /// Returns a raw pointer to the section's buffer. + pub fn as_ptr(&self) -> *const u8 { + self.0.as_ptr() + } +} diff --git a/lib/jit/src/link.rs b/lib/jit/src/link.rs index 12430189e..145e17e59 100644 --- a/lib/jit/src/link.rs +++ b/lib/jit/src/link.rs @@ -3,7 +3,10 @@ use std::ptr::write_unaligned; use wasm_common::entity::{EntityRef, PrimaryMap}; use wasm_common::LocalFuncIndex; -use wasmer_compiler::{JumpTable, JumpTableOffsets, RelocationKind, RelocationTarget, Relocations}; +use wasmer_compiler::{ + JumpTable, JumpTableOffsets, RelocationKind, RelocationTarget, Relocations, SectionBody, + SectionIndex, +}; use wasmer_runtime::Module; use wasmer_runtime::VMFunctionBody; @@ -15,6 +18,7 @@ pub fn link_module( allocated_functions: &PrimaryMap, jt_offsets: &PrimaryMap, relocations: Relocations, + allocated_sections: &PrimaryMap, ) { for (i, function_relocs) in relocations.into_iter() { for r in function_relocs { @@ -24,8 +28,8 @@ pub fn link_module( fatptr as *const VMFunctionBody as usize } RelocationTarget::LibCall(libcall) => libcall.function_pointer(), - RelocationTarget::CustomSection(_custom_section) => { - unimplemented!("Custom Sections not yet implemented"); + RelocationTarget::CustomSection(custom_section) => { + allocated_sections[custom_section].as_ptr() as usize } RelocationTarget::JumpTable(func_index, jt) => { let offset = *jt_offsets diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index 28969fd3b..315988cf2 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -137,6 +137,7 @@ impl CompiledModule { &finished_functions, &serializable.compilation.function_jt_offsets, serializable.compilation.function_relocations.clone(), + &serializable.compilation.custom_sections, ); // Compute indices into the shared signature table. From 3a004b3e826af2151e04fd8040a34cfc88b37487 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Sun, 3 May 2020 16:08:05 -0700 Subject: [PATCH 07/27] Fix build of compiler-llvm by growing the interface to SectionBody. --- lib/compiler-llvm/src/compiler.rs | 6 +++--- lib/compiler-llvm/src/translator/code.rs | 4 ++-- lib/compiler/src/section.rs | 17 ++++++++++++++++- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index a5e45d84a..7588ffe19 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -12,7 +12,7 @@ use wasm_common::{FuncIndex, FuncType, LocalFuncIndex, MemoryIndex, TableIndex}; use wasmer_compiler::{ Compilation, CompileError, CompiledFunction, Compiler, CompilerConfig, CustomSection, CustomSectionProtection, FunctionBody, FunctionBodyData, ModuleTranslationState, Relocation, - RelocationTarget, SectionIndex, Target, TrapInformation, + RelocationTarget, SectionBody, SectionIndex, Target, TrapInformation, }; use wasmer_runtime::{MemoryPlan, Module, TablePlan, TrapCode}; @@ -71,7 +71,7 @@ impl Compiler for LLVMCompiler { let mut used_readonly_section = false; let mut readonly_section = CustomSection { protection: CustomSectionProtection::Read, - bytes: Vec::new(), + bytes: SectionBody::default(), }; for (func_index, _) in &module.functions { @@ -112,7 +112,7 @@ impl Compiler for LLVMCompiler { } }; let offset = section.bytes.len() as i64; - section.bytes.extend(&custom_section.bytes); + section.bytes.append(&custom_section.bytes); // TODO: we're needlessly rescanning the whole list. for local_relocation in &local_relocations { if local_relocation.local_section_index == local_idx { diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 0eec20fd7..2da28b43c 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -40,7 +40,7 @@ use wasmer_compiler::{ to_wasm_error, wasm_unsupported, Addend, CodeOffset, CompileError, CompiledFunction, CompiledFunctionFrameInfo, CompiledFunctionUnwindInfo, CustomSection, CustomSectionProtection, FunctionAddressMap, FunctionBody, FunctionBodyData, Relocation, RelocationKind, - RelocationTarget, SourceLoc, WasmResult, + RelocationTarget, SectionBody, SourceLoc, WasmResult, }; use wasmer_runtime::libcalls::LibCall; use wasmer_runtime::Module as WasmerCompilerModule; @@ -384,7 +384,7 @@ impl FuncTranslator { required_custom_sections.len(), CustomSection { protection: CustomSectionProtection::Read, - bytes: vec![], + bytes: SectionBody::default(), }, ); for section in object.get_sections() { diff --git a/lib/compiler/src/section.rs b/lib/compiler/src/section.rs index ab96bb831..36a0e4405 100644 --- a/lib/compiler/src/section.rs +++ b/lib/compiler/src/section.rs @@ -45,12 +45,27 @@ pub struct CustomSection { } /// The bytes in the section. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)] pub struct SectionBody(#[serde(with = "serde_bytes")] Vec); impl SectionBody { + /// Extend the section with the bytes given. + pub fn extend(&mut self, contents: &[u8]) { + self.0.extend(contents); + } + + /// Extends the section by appending bytes from another section. + pub fn append(&mut self, body: &SectionBody) { + self.0.extend(&body.0); + } + /// Returns a raw pointer to the section's buffer. pub fn as_ptr(&self) -> *const u8 { self.0.as_ptr() } + + /// Returns the length of this section in bytes. + pub fn len(&self) -> usize { + self.0.len() + } } From e2f4ec657df30366948b7d290014b19af2e57bc3 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 18:36:41 -0700 Subject: [PATCH 08/27] Make trampolines serializable --- lib/jit/src/engine.rs | 52 ++++++++++++++++++++++------------------ lib/jit/src/module.rs | 5 +++- lib/jit/src/serialize.rs | 3 ++- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/lib/jit/src/engine.rs b/lib/jit/src/engine.rs index 7c94cb5ef..cf0e1c4b9 100644 --- a/lib/jit/src/engine.rs +++ b/lib/jit/src/engine.rs @@ -9,7 +9,7 @@ use std::cell::RefCell; use std::collections::HashMap; use std::sync::Arc; use wasm_common::entity::PrimaryMap; -use wasm_common::{FuncType, LocalFuncIndex, MemoryIndex, TableIndex}; +use wasm_common::{FuncType, LocalFuncIndex, MemoryIndex, SignatureIndex, TableIndex}; use wasmer_compiler::{ Compilation, CompileError, Compiler as BaseCompiler, CompilerConfig, FunctionBody, FunctionBodyData, ModuleTranslationState, Target, @@ -166,11 +166,25 @@ impl JITEngineInner { ) } + /// Compile the module trampolines + pub(crate) fn compile_trampolines( + &self, + signatures: &PrimaryMap, + ) -> Result, CompileError> { + let func_types = signatures.values().cloned().collect::>(); + Ok(self + .compiler + .compile_wasm_trampolines(&func_types)? + .into_iter() + .collect::>()) + } + /// Compile the given function bodies. - pub(crate) fn compile<'data>( + pub(crate) fn allocate<'data>( &mut self, module: &Module, functions: &PrimaryMap, + trampolines: &PrimaryMap, ) -> Result, CompileError> { // Allocate all of the compiled functions into executable memory, // copying over their contents. @@ -184,35 +198,27 @@ impl JITEngineInner { )) })?; - // Trampoline generation. - // We do it in two steps: - // 1. Generate only the trampolines for the signatures that are unique - // 2. Push the compiled code to memory - let mut unique_signatures: HashMap = HashMap::new(); - // for sig in module.exported_signatures() { - for sig in module.signatures.values() { - let index = self.signatures.register(&sig); - if unique_signatures.contains_key(&index) { + for (sig_index, compiled_function) in trampolines.iter() { + let func_type = module.signatures.get(sig_index).unwrap(); + let index = self.signatures.register(&func_type); + if self.trampolines.contains_key(&index) { + // We don't need to allocate the trampoline in case + // it's signature is already allocated. continue; } - unique_signatures.insert(index, sig.clone()); - } - - let compiled_trampolines = self - .compiler - .compile_wasm_trampolines(&unique_signatures.values().cloned().collect::>())?; - - for ((index, _), compiled_function) in - unique_signatures.iter().zip(compiled_trampolines.iter()) - { let ptr = self .code_memory .allocate_for_function(&compiled_function) - .map_err(|message| CompileError::Resource(message))? + .map_err(|message| { + CompileError::Resource(format!( + "failed to allocate memory for trampolines: {}", + message + )) + })? .as_ptr(); let trampoline = unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) }; - self.trampolines.insert(*index, trampoline); + self.trampolines.insert(index, trampoline); } Ok(allocated_functions) } diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index 315988cf2..5f115e148 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -71,6 +71,7 @@ impl CompiledModule { memory_plans.clone(), table_plans.clone(), )?; + let trampolines = jit_compiler.compile_trampolines(&translation.module.signatures)?; let data_initializers = translation .data_initializers .iter() @@ -89,6 +90,7 @@ impl CompiledModule { function_relocations: compilation.get_relocations(), function_jt_offsets: compilation.get_jt_offsets(), function_frame_info: frame_infos, + trampolines, custom_sections: compilation.get_custom_sections(), }; let serializable = SerializableModule { @@ -127,9 +129,10 @@ impl CompiledModule { jit_compiler: &mut JITEngineInner, serializable: SerializableModule, ) -> Result { - let finished_functions = jit_compiler.compile( + let finished_functions = jit_compiler.allocate( &serializable.module, &serializable.compilation.function_bodies, + &serializable.compilation.trampolines, )?; link_module( diff --git a/lib/jit/src/serialize.rs b/lib/jit/src/serialize.rs index c07bbe1ae..2d7e0cde3 100644 --- a/lib/jit/src/serialize.rs +++ b/lib/jit/src/serialize.rs @@ -10,7 +10,7 @@ use wasmer_compiler::{ use wasmer_runtime::Module; use wasm_common::entity::PrimaryMap; -use wasm_common::{LocalFuncIndex, MemoryIndex, OwnedDataInitializer, TableIndex}; +use wasm_common::{LocalFuncIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex}; use wasmer_runtime::{MemoryPlan, TablePlan}; /// The compilation related data for a serialized modules @@ -23,6 +23,7 @@ pub struct SerializableCompilation { // to allow lazy frame_info deserialization, we convert it to it's lazy binary // format upon serialization. pub function_frame_info: PrimaryMap, + pub trampolines: PrimaryMap, pub custom_sections: PrimaryMap, } From d23a0fb76bee2aa247b64edc6ca2ac3a9334854f Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 19:19:21 -0700 Subject: [PATCH 09/27] A step closer into headless engines --- lib/jit/src/engine.rs | 44 +++++++++++++++++++++++++++------ lib/jit/src/module.rs | 3 ++- lib/jit/src/serialize.rs | 5 +++- lib/wasm-common/src/features.rs | 4 +++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/lib/jit/src/engine.rs b/lib/jit/src/engine.rs index cf0e1c4b9..c450b381b 100644 --- a/lib/jit/src/engine.rs +++ b/lib/jit/src/engine.rs @@ -29,7 +29,7 @@ pub struct JITEngine { impl JITEngine { const MAGIC_HEADER: &'static [u8] = b"\0wasmer-jit"; - /// Create a new JIT Engine given config + /// Create a new `JITEngine` with the given config pub fn new(config: &C, tunables: impl Tunables + 'static) -> Self where C: ?Sized, @@ -37,7 +37,32 @@ impl JITEngine { let compiler = config.compiler(); Self { inner: Arc::new(RefCell::new(JITEngineInner { - compiler, + compiler: Some(compiler), + trampolines: HashMap::new(), + code_memory: CodeMemory::new(), + signatures: SignatureRegistry::new(), + })), + tunables: Arc::new(Box::new(tunables)), + } + } + + /// Create a headless `JITEngine` + /// + /// A headless engine is an engine without any compiler attached. + /// This is useful for assuring a minimal runtime for running + /// WebAssembly modules. + /// + /// For example, for running in IoT devices where compilers are very + /// expensive, or also to optimize startup speed. + /// + /// # Important + /// + /// 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) -> Self { + Self { + inner: Arc::new(RefCell::new(JITEngineInner { + compiler: None, trampolines: HashMap::new(), code_memory: CodeMemory::new(), signatures: SignatureRegistry::new(), @@ -126,7 +151,7 @@ impl JITEngine { /// The inner contents of `JITEngine` pub struct JITEngineInner { /// The compiler - compiler: Box, + compiler: Option>, /// Pointers to trampoline functions used to enter particular signatures trampolines: HashMap, /// The code memory is responsible of publishing the compiled @@ -139,13 +164,16 @@ pub struct JITEngineInner { impl JITEngineInner { /// Gets the compiler associated to this JIT - pub fn compiler(&self) -> &dyn BaseCompiler { - &*self.compiler + pub fn compiler(&self) -> Result<&dyn BaseCompiler, CompileError> { + if self.compiler.is_none() { + return Err(CompileError::Codegen("The JITEngine is operating in headless mode, so it can only execute already compiled Modules.".to_string())); + } + Ok(&**self.compiler.as_ref().unwrap()) } /// Validate the module pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> { - self.compiler().validate_module(data) + self.compiler()?.validate_module(data) } /// Compile the given function bodies. @@ -157,7 +185,7 @@ impl JITEngineInner { memory_plans: PrimaryMap, table_plans: PrimaryMap, ) -> Result { - self.compiler.compile_module( + self.compiler()?.compile_module( module, module_translation, function_body_inputs, @@ -173,7 +201,7 @@ impl JITEngineInner { ) -> Result, CompileError> { let func_types = signatures.values().cloned().collect::>(); Ok(self - .compiler + .compiler()? .compile_wasm_trampolines(&func_types)? .into_iter() .collect::>()) diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index 5f115e148..f8985b004 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -96,6 +96,7 @@ impl CompiledModule { let serializable = SerializableModule { compilation: serializable_compilation, module: Arc::new(translation.module), + features: jit_compiler.compiler()?.features().clone(), data_initializers, memory_plans, table_plans, @@ -189,7 +190,7 @@ impl CompiledModule { host_state: Box, ) -> Result { let jit_compiler = jit.compiler(); - let is_bulk_memory: bool = jit_compiler.compiler().features().bulk_memory; + let is_bulk_memory: bool = self.serializable.features.bulk_memory; let sig_registry: &SignatureRegistry = jit_compiler.signatures(); let data_initializers = self .serializable diff --git a/lib/jit/src/serialize.rs b/lib/jit/src/serialize.rs index 2d7e0cde3..0da2363a4 100644 --- a/lib/jit/src/serialize.rs +++ b/lib/jit/src/serialize.rs @@ -10,7 +10,9 @@ use wasmer_compiler::{ use wasmer_runtime::Module; use wasm_common::entity::PrimaryMap; -use wasm_common::{LocalFuncIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex}; +use wasm_common::{ + Features, LocalFuncIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex, +}; use wasmer_runtime::{MemoryPlan, TablePlan}; /// The compilation related data for a serialized modules @@ -32,6 +34,7 @@ pub struct SerializableCompilation { #[derive(Serialize, Deserialize)] pub struct SerializableModule { pub compilation: SerializableCompilation, + pub features: Features, pub module: Arc, pub data_initializers: Box<[OwnedDataInitializer]>, // Plans for that module diff --git a/lib/wasm-common/src/features.rs b/lib/wasm-common/src/features.rs index d4436f5a0..82c49b000 100644 --- a/lib/wasm-common/src/features.rs +++ b/lib/wasm-common/src/features.rs @@ -1,8 +1,12 @@ +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + /// Controls which experimental features will be enabled. /// Features usually have a corresponding [WebAssembly proposal]. /// /// [WebAssembly proposal]: https://github.com/WebAssembly/proposals #[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct Features { /// Threads proposal should be enabled pub threads: bool, From f94e2d6bcc461b832b398543f42a20fb81d3d724 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 19:37:11 -0700 Subject: [PATCH 10/27] Improve Tunables memory/table creation --- lib/api/src/externals.rs | 9 +++++++-- lib/api/src/tunables.rs | 6 ++---- lib/jit/src/tunables.rs | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/api/src/externals.rs b/lib/api/src/externals.rs index 18629f329..5e684247d 100644 --- a/lib/api/src/externals.rs +++ b/lib/api/src/externals.rs @@ -231,7 +231,9 @@ fn set_table_item( impl Table { pub fn new(store: &Store, ty: TableType, init: Val) -> Result { let item = init.into_checked_anyfunc(store)?; - let table = store.engine().tunables().create_table(ty); + let tunables = store.engine().tunables(); + let table_plan = tunables.table_plan(ty); + let table = tunables.create_table(table_plan); let definition = table.vmtable(); for i in 0..definition.current_elements { @@ -345,7 +347,10 @@ pub struct Memory { impl Memory { pub fn new(store: &Store, ty: MemoryType) -> Memory { - let memory = store.engine().tunables().create_memory(ty).unwrap(); + let tunables = store.engine().tunables(); + let memory_plan = tunables.memory_plan(ty); + let memory = tunables.create_memory(memory_plan).unwrap(); + let definition = memory.vmmemory(); Memory { diff --git a/lib/api/src/tunables.rs b/lib/api/src/tunables.rs index 1e73824ec..3f948dbed 100644 --- a/lib/api/src/tunables.rs +++ b/lib/api/src/tunables.rs @@ -92,14 +92,12 @@ impl wasmer_jit::Tunables for Tunables { } /// Create a memory given a memory type - fn create_memory(&self, memory_type: MemoryType) -> Result { - let plan = self.memory_plan(memory_type); + fn create_memory(&self, plan: MemoryPlan) -> Result { LinearMemory::new(&plan) } /// Create a memory given a memory type - fn create_table(&self, table_type: TableType) -> Table { - let plan = self.table_plan(table_type); + fn create_table(&self, plan: TablePlan) -> Table { Table::new(&plan) } } diff --git a/lib/jit/src/tunables.rs b/lib/jit/src/tunables.rs index 0f5408ef7..d31787e77 100644 --- a/lib/jit/src/tunables.rs +++ b/lib/jit/src/tunables.rs @@ -11,8 +11,8 @@ pub trait Tunables { fn table_plan(&self, table: TableType) -> TablePlan; /// Create a memory given a memory type - fn create_memory(&self, memory_type: MemoryType) -> Result; + fn create_memory(&self, memory_type: MemoryPlan) -> Result; /// Create a memory given a memory type - fn create_table(&self, table_type: TableType) -> Table; + fn create_table(&self, table_type: TablePlan) -> Table; } From a1d0d13f71758a6a131a44ad20b0638bc1acd944 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 19:53:04 -0700 Subject: [PATCH 11/27] Moved memory/table/globals creation into Tunables --- lib/jit/src/module.rs | 59 +++++++++-------------------------------- lib/jit/src/tunables.rs | 54 +++++++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 49 deletions(-) diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index f8985b004..8d5791bc3 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -14,6 +14,7 @@ use crate::serialize::{ use crate::trap::register as register_frame_info; use crate::trap::GlobalFrameInfoRegistration; use crate::trap::RuntimeError; +use crate::tunables::Tunables; use serde::{Deserialize, Serialize}; use std::any::Any; use std::sync::{Arc, Mutex}; @@ -190,6 +191,7 @@ impl CompiledModule { host_state: Box, ) -> Result { let jit_compiler = jit.compiler(); + let tunables = jit.tunables(); let is_bulk_memory: bool = self.serializable.features.bulk_memory; let sig_registry: &SignatureRegistry = jit_compiler.signatures(); let data_initializers = self @@ -210,10 +212,16 @@ impl CompiledModule { ) .map_err(InstantiationError::Link)?; - let finished_memories = create_memories(&self.serializable.module, self.memory_plans()) - .map_err(InstantiationError::Link)?; - let finished_tables = create_tables(&self.serializable.module, self.table_plans()); - let finished_globals = create_globals(&self.serializable.module); + let finished_memories = tunables + .create_memories(&self.serializable.module, self.memory_plans()) + .map_err(InstantiationError::Link)? + .into_boxed_slice(); + let finished_tables = tunables + .create_tables(&self.serializable.module, self.table_plans()) + .into_boxed_slice(); + let finished_globals = tunables + .create_globals(&self.serializable.module) + .into_boxed_slice(); // Register the frame info for the module self.register_frame_info(); @@ -265,46 +273,3 @@ impl CompiledModule { )); } } - -/// Allocate memory for just the memories of the current module. -fn create_memories( - module: &Module, - memory_plans: &PrimaryMap, -) -> Result, LinkError> { - let num_imports = module.num_imported_memories; - let mut memories: PrimaryMap = - PrimaryMap::with_capacity(module.memories.len() - num_imports); - for index in num_imports..module.memories.len() { - let plan = memory_plans[MemoryIndex::new(index)].clone(); - memories.push(LinearMemory::new(&plan).map_err(LinkError::Resource)?); - } - Ok(memories.into_boxed_slice()) -} - -/// Allocate memory for just the tables of the current module. -fn create_tables( - module: &Module, - table_plans: &PrimaryMap, -) -> BoxedSlice { - let num_imports = module.num_imported_tables; - let mut tables: PrimaryMap = - PrimaryMap::with_capacity(module.tables.len() - num_imports); - for index in num_imports..module.tables.len() { - let plan = table_plans[TableIndex::new(index)].clone(); - tables.push(Table::new(&plan)); - } - tables.into_boxed_slice() -} - -/// Allocate memory for just the globals of the current module, -/// with initializers applied. -fn create_globals(module: &Module) -> BoxedSlice { - let num_imports = module.num_imported_globals; - let mut vmctx_globals = PrimaryMap::with_capacity(module.globals.len() - num_imports); - - for _ in &module.globals.values().as_slice()[num_imports..] { - vmctx_globals.push(VMGlobalDefinition::new()); - } - - vmctx_globals.into_boxed_slice() -} diff --git a/lib/jit/src/tunables.rs b/lib/jit/src/tunables.rs index d31787e77..a1b8a21c5 100644 --- a/lib/jit/src/tunables.rs +++ b/lib/jit/src/tunables.rs @@ -1,5 +1,10 @@ -use wasm_common::{MemoryType, TableType}; -use wasmer_runtime::{LinearMemory, Table}; +use crate::error::LinkError; +use wasm_common::entity::{EntityRef, PrimaryMap}; +use wasm_common::{ + GlobalIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, + TableIndex, TableType, +}; +use wasmer_runtime::{LinearMemory, Module, Table, VMGlobalDefinition}; use wasmer_runtime::{MemoryPlan, TablePlan}; /// Tunables for an engine @@ -15,4 +20,49 @@ pub trait Tunables { /// Create a memory given a memory type fn create_table(&self, table_type: TablePlan) -> Table; + + /// Allocate memory for just the memories of the current module. + fn create_memories( + &self, + module: &Module, + memory_plans: &PrimaryMap, + ) -> Result, LinkError> { + let num_imports = module.num_imported_memories; + let mut memories: PrimaryMap = + PrimaryMap::with_capacity(module.memories.len() - num_imports); + for index in num_imports..module.memories.len() { + let plan = memory_plans[MemoryIndex::new(index)].clone(); + memories.push(self.create_memory(plan).map_err(LinkError::Resource)?); + } + Ok(memories) + } + + /// Allocate memory for just the tables of the current module. + fn create_tables( + &self, + module: &Module, + table_plans: &PrimaryMap, + ) -> PrimaryMap { + let num_imports = module.num_imported_tables; + let mut tables: PrimaryMap = + PrimaryMap::with_capacity(module.tables.len() - num_imports); + for index in num_imports..module.tables.len() { + let plan = table_plans[TableIndex::new(index)].clone(); + tables.push(self.create_table(plan)); + } + tables + } + + /// Allocate memory for just the globals of the current module, + /// with initializers applied. + fn create_globals(&self, module: &Module) -> PrimaryMap { + let num_imports = module.num_imported_globals; + let mut vmctx_globals = PrimaryMap::with_capacity(module.globals.len() - num_imports); + + for _ in &module.globals.values().as_slice()[num_imports..] { + vmctx_globals.push(VMGlobalDefinition::new()); + } + + vmctx_globals + } } From 8b1b1592d52bfeba5c060893e5caf694e628b655 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 19:57:14 -0700 Subject: [PATCH 12/27] Improved docs --- lib/jit/src/module.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index 8d5791bc3..6c14f82c3 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -1,7 +1,5 @@ -//! Define the `instantiate` function, which takes a byte array containing an -//! encoded wasm module and returns a live wasm instance. Also, define -//! `CompiledModule` to allow compiling and instantiating to be done as separate -//! steps. +//! Define `CompiledModule` to allow compiling and instantiating to be +//! done as separate steps. use crate::engine::{JITEngine, JITEngineInner}; use crate::error::{DeserializeError, SerializeError}; @@ -177,10 +175,6 @@ impl CompiledModule { /// Crate an `Instance` from this `CompiledModule`. /// - /// Note that if only one instance of this module is needed, it may be more - /// efficient to call the top-level `instantiate`, since that avoids copying - /// the data initializers. - /// /// # Unsafety /// /// See `InstanceHandle::new` From c97443abe6fb1c772a19e08937c5c2cff6137b26 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 20:07:08 -0700 Subject: [PATCH 13/27] Removed forgotten Compiler struct --- src/common.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/common.rs b/src/common.rs index c9c6b9df7..57e45e6aa 100644 --- a/src/common.rs +++ b/src/common.rs @@ -34,25 +34,6 @@ pub struct WasmFeatures { pub all: bool, } -#[derive(Debug, Clone, StructOpt)] -/// The compiler options -pub struct Compiler { - /// Use Singlepass compiler - #[structopt(long, conflicts_with_all = &["cranelift", "llvm"])] - singlepass: bool, - - /// Use Cranelift compiler - #[structopt(long, conflicts_with_all = &["singlepass", "llvm"])] - cranelift: bool, - - /// Use LLVM compiler - #[structopt(long, conflicts_with_all = &["singlepass", "cranelifft"])] - llvm: bool, - - #[structopt(flatten)] - features: WasmFeatures, -} - /// Get the cache dir pub fn get_cache_dir() -> PathBuf { match env::var("WASMER_CACHE_DIR") { From b5b8d88a6b4204eb2f77e0024af768b433e875bb Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 20:12:05 -0700 Subject: [PATCH 14/27] =?UTF-8?q?Wasmer=20can=20now=20run=20headless=20?= =?UTF-8?q?=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/run.rs | 6 +++--- src/store.rs | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/commands/run.rs b/src/commands/run.rs index d3f28b6a3..9a90d8bd5 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -129,9 +129,9 @@ impl Run { fn get_module(&self) -> Result { let contents = std::fs::read(self.path.clone())?; if Engine::is_deserializable(&contents) { - let (compiler_config, _compiler_name) = self.compiler.get_compiler_config()?; - let tunables = self.compiler.get_tunables(&*compiler_config); - let engine = Engine::new(&*compiler_config, tunables); + // We get the tunables for the current host + let tunables = Tunables::default(); + let engine = Engine::headless(tunables); let store = Store::new(&engine); let module = unsafe { Module::deserialize(&store, &contents)? }; return Ok(module); diff --git a/src/store.rs b/src/store.rs index a6f1f0c34..5cdd5674b 100644 --- a/src/store.rs +++ b/src/store.rs @@ -91,6 +91,7 @@ impl StoreOptions { } /// Get the Compiler Config for the current options + #[allow(unused_variables)] fn get_config(&self, compiler: Compiler) -> Result> { let config: Box = match compiler { #[cfg(feature = "compiler-singlepass")] From 5531bda767541085b5915e17fabcd07742a6d8ce Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 20:46:07 -0700 Subject: [PATCH 15/27] Improved WASI compilation --- src/commands/run.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/run.rs b/src/commands/run.rs index 9a90d8bd5..41d2d4e7e 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -99,7 +99,8 @@ impl Run { } // If WASI is enabled, try to execute it with it - if cfg!(feature = "wasi") { + #[cfg(feature = "wasi")] + { let wasi_version = Wasi::get_version(&module); if let Some(version) = wasi_version { let program_name = self From 65b6eb2edafd66a0655728647d7e90f315e3755c Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 20:55:07 -0700 Subject: [PATCH 16/27] Removed unused file # Conflicts: # lib/api/src/resolver.rs --- lib/api/src/resolver.rs | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 lib/api/src/resolver.rs diff --git a/lib/api/src/resolver.rs b/lib/api/src/resolver.rs deleted file mode 100644 index 1d3d30baf..000000000 --- a/lib/api/src/resolver.rs +++ /dev/null @@ -1,21 +0,0 @@ -use wasmer_jit::Resolver; -use std::iter::FromIterator; - -pub struct IndexResolver { - externs: Vec, -} -impl Resolver for IndexResolver { - fn resolve(&self, index: u32, _module: &str, _name: &str) -> Option { - self.externs.get(index as usize).map(|extern_| extern_.to_export()) - } -} - -impl FromIterator for IndexResolver { - fn from_iter>(iter: I) -> Self { - let mut externs = Vec::new(); - for extern_ in iter { - externs.push(extern_); - } - IndexResolver { externs } - } -} From 8b2a4495df7147f23da92a4ca6627c71e86ce7a7 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 21:06:42 -0700 Subject: [PATCH 17/27] Move WasmError to root compiler --- lib/compiler/src/error.rs | 37 ++++++++++++++++++++++++- lib/compiler/src/lib.rs | 4 +-- lib/compiler/src/translator/environ.rs | 2 +- lib/compiler/src/translator/error.rs | 37 +------------------------ lib/compiler/src/translator/mod.rs | 2 +- lib/compiler/src/translator/module.rs | 3 +- lib/compiler/src/translator/sections.rs | 3 +- 7 files changed, 45 insertions(+), 43 deletions(-) diff --git a/lib/compiler/src/error.rs b/lib/compiler/src/error.rs index 5bec35cb0..c43aac8c4 100644 --- a/lib/compiler/src/error.rs +++ b/lib/compiler/src/error.rs @@ -1,5 +1,4 @@ use crate::std::string::String; -use crate::translator::WasmError; use thiserror::Error; // Compilation Errors @@ -28,3 +27,39 @@ pub enum CompileError { #[error("Insufficient resources: {0}")] Resource(String), } + +/// A WebAssembly translation error. +/// +/// When a WebAssembly function can't be translated, one of these error codes will be returned +/// to describe the failure. +#[derive(Error, Debug)] +pub enum WasmError { + /// The input WebAssembly code is invalid. + /// + /// This error code is used by a WebAssembly translator when it encounters invalid WebAssembly + /// code. This should never happen for validated WebAssembly code. + #[error("Invalid input WebAssembly code at offset {offset}: {message}")] + InvalidWebAssembly { + /// A string describing the validation error. + message: String, + /// The bytecode offset where the error occurred. + offset: usize, + }, + + /// A feature used by the WebAssembly code is not supported by the embedding environment. + /// + /// Embedding environments may have their own limitations and feature restrictions. + #[error("Unsupported feature: {0}")] + Unsupported(String), + + /// An implementation limit was exceeded. + #[error("Implementation limit exceeded")] + ImplLimitExceeded, + + /// A generic error. + #[error("{0}")] + Generic(String), +} + +/// A convenient alias for a `Result` that uses `WasmError` as the error type. +pub type WasmResult = Result; diff --git a/lib/compiler/src/lib.rs b/lib/compiler/src/lib.rs index 432df3633..75ffc4080 100644 --- a/lib/compiler/src/lib.rs +++ b/lib/compiler/src/lib.rs @@ -57,7 +57,7 @@ pub use crate::config::{ Architecture, CallingConvention, CompilerConfig, CpuFeature, Features, OperatingSystem, Target, Triple, }; -pub use crate::error::CompileError; +pub use crate::error::{CompileError, WasmError, WasmResult}; pub use crate::function::{ Compilation, CompiledFunction, CompiledFunctionFrameInfo, CustomSections, FunctionBody, Functions, @@ -68,7 +68,7 @@ pub use crate::section::{CustomSection, CustomSectionProtection, SectionBody, Se pub use crate::sourceloc::SourceLoc; pub use crate::translator::{ to_wasm_error, translate_module, FunctionBodyData, ModuleEnvironment, ModuleTranslation, - ModuleTranslationState, WasmError, WasmResult, + ModuleTranslationState, }; pub use crate::trap::TrapInformation; pub use crate::unwind::{CompiledFunctionUnwindInfo, FDERelocEntry, FunctionTableReloc}; diff --git a/lib/compiler/src/translator/environ.rs b/lib/compiler/src/translator/environ.rs index f5a39e39b..a281e0043 100644 --- a/lib/compiler/src/translator/environ.rs +++ b/lib/compiler/src/translator/environ.rs @@ -1,9 +1,9 @@ -use super::error::{WasmError, WasmResult}; use super::module::translate_module; use super::state::ModuleTranslationState; use crate::std::borrow::ToOwned; use crate::std::string::ToString; use crate::std::{boxed::Box, string::String, vec::Vec}; +use crate::{WasmError, WasmResult}; use std::convert::TryFrom; use std::sync::Arc; use wasm_common::entity::PrimaryMap; diff --git a/lib/compiler/src/translator/error.rs b/lib/compiler/src/translator/error.rs index 8aa6e0de6..d114adea7 100644 --- a/lib/compiler/src/translator/error.rs +++ b/lib/compiler/src/translator/error.rs @@ -1,39 +1,7 @@ -use crate::std::string::String; +use crate::WasmError; use thiserror::Error; use wasmparser::BinaryReaderError; -/// A WebAssembly translation error. -/// -/// When a WebAssembly function can't be translated, one of these error codes will be returned -/// to describe the failure. -#[derive(Error, Debug)] -pub enum WasmError { - /// The input WebAssembly code is invalid. - /// - /// This error code is used by a WebAssembly translator when it encounters invalid WebAssembly - /// code. This should never happen for validated WebAssembly code. - #[error("Invalid input WebAssembly code at offset {offset}: {message}")] - InvalidWebAssembly { - /// A string describing the validation error. - message: String, - /// The bytecode offset where the error occurred. - offset: usize, - }, - - /// A feature used by the WebAssembly code is not supported by the embedding environment. - /// - /// Embedding environments may have their own limitations and feature restrictions. - #[error("Unsupported feature: {0}")] - Unsupported(String), - - /// An implementation limit was exceeded. - #[error("Implementation limit exceeded")] - ImplLimitExceeded, - - /// A generic error. - #[error("{0}")] - Generic(String), -} /// Return an `Err(WasmError::Unsupported(msg))` where `msg` the string built by calling `format!` /// on the arguments to this macro. #[macro_export] @@ -48,6 +16,3 @@ pub fn to_wasm_error(e: BinaryReaderError) -> WasmError { offset: e.offset(), } } - -/// A convenient alias for a `Result` that uses `WasmError` as the error type. -pub type WasmResult = Result; diff --git a/lib/compiler/src/translator/mod.rs b/lib/compiler/src/translator/mod.rs index 75b58abae..bcd3d5000 100644 --- a/lib/compiler/src/translator/mod.rs +++ b/lib/compiler/src/translator/mod.rs @@ -13,6 +13,6 @@ mod error; mod sections; pub use self::environ::{FunctionBodyData, ModuleEnvironment, ModuleTranslation}; -pub use self::error::{to_wasm_error, WasmError, WasmResult}; +pub use self::error::to_wasm_error; pub use self::module::translate_module; pub use self::state::ModuleTranslationState; diff --git a/lib/compiler/src/translator/module.rs b/lib/compiler/src/translator/module.rs index 39b06f70e..ddb222568 100644 --- a/lib/compiler/src/translator/module.rs +++ b/lib/compiler/src/translator/module.rs @@ -1,13 +1,14 @@ //! Translation skeleton that traverses the whole WebAssembly module and call helper functions //! to deal with each part of it. use super::environ::ModuleEnvironment; -use super::error::{to_wasm_error, WasmResult}; +use super::error::to_wasm_error; use super::sections::{ parse_code_section, parse_data_section, parse_element_section, parse_export_section, parse_function_section, parse_global_section, parse_import_section, parse_memory_section, parse_name_section, parse_start_section, parse_table_section, parse_type_section, }; use super::state::ModuleTranslationState; +use crate::WasmResult; use wasmparser::{CustomSectionContent, ModuleReader, SectionContent}; /// Translate a sequence of bytes forming a valid Wasm binary into a diff --git a/lib/compiler/src/translator/sections.rs b/lib/compiler/src/translator/sections.rs index 1d12caea0..98a31b364 100644 --- a/lib/compiler/src/translator/sections.rs +++ b/lib/compiler/src/translator/sections.rs @@ -8,9 +8,10 @@ //! is handled, according to the semantics of WebAssembly, to only specific expressions that are //! interpreted on the fly. use super::environ::ModuleEnvironment; -use super::error::{to_wasm_error, WasmError, WasmResult}; +use super::error::to_wasm_error; use super::state::ModuleTranslationState; use crate::{wasm_unsupported, HashMap}; +use crate::{WasmError, WasmResult}; use core::convert::TryFrom; use std::boxed::Box; use std::vec::Vec; From 106db13c328052e30dd29b7275594561882b7243 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 21:18:11 -0700 Subject: [PATCH 18/27] Removed compiler config from root --- lib/jit/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/jit/src/lib.rs b/lib/jit/src/lib.rs index c1bcc8114..2e265fc8a 100644 --- a/lib/jit/src/lib.rs +++ b/lib/jit/src/lib.rs @@ -48,7 +48,5 @@ pub use crate::resolver::{resolve_imports, NullResolver, Resolver}; pub use crate::trap::*; pub use crate::tunables::Tunables; -pub use wasmer_compiler::CompilerConfig; - /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); From 759561e0c52cf39b5eb2501e526ca277f015c093 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 21:28:35 -0700 Subject: [PATCH 19/27] Expose Compiler and CompilerConfig only on translator mode --- lib/compiler-cranelift/Cargo.toml | 2 +- lib/compiler-llvm/Cargo.toml | 2 +- lib/compiler-singlepass/Cargo.toml | 2 +- lib/compiler/Cargo.toml | 4 ++++ lib/compiler/src/compiler.rs | 19 ++++++++++++++++++- lib/compiler/src/lib.rs | 17 +++++++++++------ lib/compiler/src/{config.rs => target.rs} | 22 ++-------------------- 7 files changed, 38 insertions(+), 30 deletions(-) rename lib/compiler/src/{config.rs => target.rs} (88%) diff --git a/lib/compiler-cranelift/Cargo.toml b/lib/compiler-cranelift/Cargo.toml index e23d6e001..f53351e4f 100644 --- a/lib/compiler-cranelift/Cargo.toml +++ b/lib/compiler-cranelift/Cargo.toml @@ -16,7 +16,7 @@ hashbrown = { version = "0.7.2", optional = true } tracing = "0.1" cranelift-codegen = { version = "0.62.0", default-features = false } cranelift-frontend = { version = "0.62.0", default-features = false } -wasmer-compiler = { path = "../compiler", version = "0.16.2", default-features = false } +wasmer-compiler = { path = "../compiler", version = "0.16.2", features = ["translator"], default-features = false } wasmer-runtime = { path = "../runtime", version = "0.16.2" } wasm-common = { path = "../wasm-common", version = "0.16.2", default-features = false } rayon = "1.3.0" diff --git a/lib/compiler-llvm/Cargo.toml b/lib/compiler-llvm/Cargo.toml index 71bd6c978..bb886713b 100644 --- a/lib/compiler-llvm/Cargo.toml +++ b/lib/compiler-llvm/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-compiler = { path = "../compiler", version = "0.16.2" } +wasmer-compiler = { path = "../compiler", version = "0.16.2", features = ["translator"] } wasmer-runtime = { path = "../runtime", version = "0.16.2" } wasm-common = { path = "../wasm-common", version = "0.16.2" } target-lexicon = { version = "0.10.0", default-features = false } diff --git a/lib/compiler-singlepass/Cargo.toml b/lib/compiler-singlepass/Cargo.toml index bae393e16..b04f114cd 100644 --- a/lib/compiler-singlepass/Cargo.toml +++ b/lib/compiler-singlepass/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" [dependencies] hashbrown = { version = "0.7.2", optional = true } -wasmer-compiler = { path = "../compiler", version = "0.16.2", default-features = false } +wasmer-compiler = { path = "../compiler", version = "0.16.2", features = ["translator"], default-features = false } wasmer-runtime = { path = "../runtime", version = "0.16.2" } wasm-common = { path = "../wasm-common", version = "0.16.2", default-features = false } rayon = "1.3.0" diff --git a/lib/compiler/Cargo.toml b/lib/compiler/Cargo.toml index 9a2b7740c..2c541def9 100644 --- a/lib/compiler/Cargo.toml +++ b/lib/compiler/Cargo.toml @@ -26,6 +26,10 @@ raw-cpuid = "7.0.3" [features] default = ["std", "enable-serde"] +# This feature is for compiler implementors, it enables using `Compiler` and +# `CompilerConfig`, as well as the included wasmparser. +# Disable this feature if you just want a headless engine. +translator = [] std = [] core = ["hashbrown"] enable-serde = ["serde", "serde_bytes"] diff --git a/lib/compiler/src/compiler.rs b/lib/compiler/src/compiler.rs index 3da9e1735..e34e3ae84 100644 --- a/lib/compiler/src/compiler.rs +++ b/lib/compiler/src/compiler.rs @@ -1,10 +1,11 @@ //! This module mainly outputs the `Compiler` trait that custom //! compilers will need to implement. -use crate::config::Target; use crate::error::CompileError; use crate::function::{Compilation, FunctionBody}; +use crate::std::boxed::Box; use crate::std::vec::Vec; +use crate::target::Target; use crate::FunctionBodyData; use crate::ModuleTranslationState; use wasm_common::entity::PrimaryMap; @@ -13,6 +14,22 @@ use wasmer_runtime::Module; 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 { + /// Gets the WebAssembly features + fn features(&self) -> &Features; + + /// 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; +} + /// An implementation of a Compiler from parsed WebAssembly module to Compiled native code. pub trait Compiler { /// Gets the target associated with this compiler diff --git a/lib/compiler/src/lib.rs b/lib/compiler/src/lib.rs index 75ffc4080..19edf11b0 100644 --- a/lib/compiler/src/lib.rs +++ b/lib/compiler/src/lib.rs @@ -38,25 +38,24 @@ use hashbrown::HashMap; use std::collections::HashMap; mod address_map; +#[cfg(feature = "translator")] mod compiler; -mod config; mod error; mod function; mod jump_table; mod relocation; +mod target; mod trap; mod unwind; +#[cfg(feature = "translator")] #[macro_use] mod translator; mod section; mod sourceloc; pub use crate::address_map::{FunctionAddressMap, InstructionAddressMap}; -pub use crate::compiler::Compiler; -pub use crate::config::{ - Architecture, CallingConvention, CompilerConfig, CpuFeature, Features, OperatingSystem, Target, - Triple, -}; +#[cfg(feature = "translator")] +pub use crate::compiler::{Compiler, CompilerConfig}; pub use crate::error::{CompileError, WasmError, WasmResult}; pub use crate::function::{ Compilation, CompiledFunction, CompiledFunctionFrameInfo, CustomSections, FunctionBody, @@ -66,6 +65,10 @@ pub use crate::jump_table::{JumpTable, JumpTableOffsets}; pub use crate::relocation::{Relocation, RelocationKind, RelocationTarget, Relocations}; pub use crate::section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex}; pub use crate::sourceloc::SourceLoc; +pub use crate::target::{ + Architecture, CallingConvention, CpuFeature, OperatingSystem, Target, Triple, +}; +#[cfg(feature = "translator")] pub use crate::translator::{ to_wasm_error, translate_module, FunctionBodyData, ModuleEnvironment, ModuleTranslation, ModuleTranslationState, @@ -73,6 +76,8 @@ pub use crate::translator::{ pub use crate::trap::TrapInformation; pub use crate::unwind::{CompiledFunctionUnwindInfo, FDERelocEntry, FunctionTableReloc}; +pub use wasm_common::Features; + /// wasmparser is exported as a module to slim compiler dependencies pub mod wasmparser { pub use wasmparser::*; diff --git a/lib/compiler/src/config.rs b/lib/compiler/src/target.rs similarity index 88% rename from lib/compiler/src/config.rs rename to lib/compiler/src/target.rs index edb585382..19c046b73 100644 --- a/lib/compiler/src/config.rs +++ b/lib/compiler/src/target.rs @@ -1,10 +1,8 @@ -//! The configuration for the -use crate::compiler::Compiler; -use crate::std::boxed::Box; +//! Target configuration use enumset::{EnumSet, EnumSetType}; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple}; -pub use wasm_common::Features; +use crate::std::boxed::Box; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use raw_cpuid::CpuId; @@ -140,19 +138,3 @@ impl Default for Target { } } } - -/// The compiler configuration options. -/// -/// This options must have WebAssembly `Features` and a specific -/// `Target` to compile to. -pub trait CompilerConfig { - /// Gets the WebAssembly features - fn features(&self) -> &Features; - - /// 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; -} From 98779f4b532e59b3f5171ee604964a40cc37d74a Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 21:44:29 -0700 Subject: [PATCH 20/27] Simplified Engine --- lib/jit/src/engine.rs | 40 +++------------------------------------- lib/jit/src/module.rs | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 39 deletions(-) diff --git a/lib/jit/src/engine.rs b/lib/jit/src/engine.rs index c450b381b..077e7f3fd 100644 --- a/lib/jit/src/engine.rs +++ b/lib/jit/src/engine.rs @@ -10,10 +10,7 @@ use std::collections::HashMap; use std::sync::Arc; use wasm_common::entity::PrimaryMap; use wasm_common::{FuncType, LocalFuncIndex, MemoryIndex, SignatureIndex, TableIndex}; -use wasmer_compiler::{ - Compilation, CompileError, Compiler as BaseCompiler, CompilerConfig, FunctionBody, - FunctionBodyData, ModuleTranslationState, Target, -}; +use wasmer_compiler::{Compilation, CompileError, Compiler, CompilerConfig, FunctionBody, Target}; use wasmer_runtime::{ InstanceHandle, MemoryPlan, Module, SignatureRegistry, TablePlan, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline, @@ -151,7 +148,7 @@ impl JITEngine { /// The inner contents of `JITEngine` pub struct JITEngineInner { /// The compiler - compiler: Option>, + compiler: Option>, /// Pointers to trampoline functions used to enter particular signatures trampolines: HashMap, /// The code memory is responsible of publishing the compiled @@ -164,7 +161,7 @@ pub struct JITEngineInner { impl JITEngineInner { /// Gets the compiler associated to this JIT - pub fn compiler(&self) -> Result<&dyn BaseCompiler, CompileError> { + pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> { if self.compiler.is_none() { return Err(CompileError::Codegen("The JITEngine is operating in headless mode, so it can only execute already compiled Modules.".to_string())); } @@ -176,37 +173,6 @@ impl JITEngineInner { self.compiler()?.validate_module(data) } - /// Compile the given function bodies. - pub(crate) fn compile_module<'data>( - &self, - module: &Module, - module_translation: &ModuleTranslationState, - function_body_inputs: PrimaryMap>, - memory_plans: PrimaryMap, - table_plans: PrimaryMap, - ) -> Result { - self.compiler()?.compile_module( - module, - module_translation, - function_body_inputs, - memory_plans, - table_plans, - ) - } - - /// Compile the module trampolines - pub(crate) fn compile_trampolines( - &self, - signatures: &PrimaryMap, - ) -> Result, CompileError> { - let func_types = signatures.values().cloned().collect::>(); - Ok(self - .compiler()? - .compile_wasm_trampolines(&func_types)? - .into_iter() - .collect::>()) - } - /// Compile the given function bodies. pub(crate) fn allocate<'data>( &mut self, diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index 6c14f82c3..b44a6a791 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -63,14 +63,29 @@ impl CompiledModule { .map(|(_index, table_type)| tunables.table_plan(*table_type)) .collect(); - let compilation = jit_compiler.compile_module( + let compiler = jit_compiler.compiler()?; + + // Compile the Module + let compilation = compiler.compile_module( &translation.module, translation.module_translation.as_ref().unwrap(), translation.function_body_inputs, memory_plans.clone(), table_plans.clone(), )?; - let trampolines = jit_compiler.compile_trampolines(&translation.module.signatures)?; + + // Compile the trampolines + let func_types = translation + .module + .signatures + .values() + .cloned() + .collect::>(); + let trampolines = compiler + .compile_wasm_trampolines(&func_types)? + .into_iter() + .collect::>(); + let data_initializers = translation .data_initializers .iter() From f8e73f5411c42d15b37b793a10225680b6165d0f Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 22:09:52 -0700 Subject: [PATCH 21/27] Improved Tunables API --- lib/api/src/externals.rs | 2 +- lib/api/src/tunables.rs | 2 +- lib/jit/src/module.rs | 2 ++ lib/jit/src/tunables.rs | 15 +++++++++------ lib/runtime/src/table.rs | 12 +++++++----- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/lib/api/src/externals.rs b/lib/api/src/externals.rs index 5e684247d..3ffa3eb15 100644 --- a/lib/api/src/externals.rs +++ b/lib/api/src/externals.rs @@ -233,7 +233,7 @@ impl Table { let item = init.into_checked_anyfunc(store)?; let tunables = store.engine().tunables(); let table_plan = tunables.table_plan(ty); - let table = tunables.create_table(table_plan); + let table = tunables.create_table(table_plan).unwrap(); let definition = table.vmtable(); for i in 0..definition.current_elements { diff --git a/lib/api/src/tunables.rs b/lib/api/src/tunables.rs index 3f948dbed..d57bd8bf4 100644 --- a/lib/api/src/tunables.rs +++ b/lib/api/src/tunables.rs @@ -97,7 +97,7 @@ impl wasmer_jit::Tunables for Tunables { } /// Create a memory given a memory type - fn create_table(&self, plan: TablePlan) -> Table { + fn create_table(&self, plan: TablePlan) -> Result { Table::new(&plan) } } diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index b44a6a791..00721582e 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -227,9 +227,11 @@ impl CompiledModule { .into_boxed_slice(); let finished_tables = tunables .create_tables(&self.serializable.module, self.table_plans()) + .map_err(InstantiationError::Link)? .into_boxed_slice(); let finished_globals = tunables .create_globals(&self.serializable.module) + .map_err(InstantiationError::Link)? .into_boxed_slice(); // Register the frame info for the module diff --git a/lib/jit/src/tunables.rs b/lib/jit/src/tunables.rs index a1b8a21c5..080f44977 100644 --- a/lib/jit/src/tunables.rs +++ b/lib/jit/src/tunables.rs @@ -19,7 +19,7 @@ pub trait Tunables { fn create_memory(&self, memory_type: MemoryPlan) -> Result; /// Create a memory given a memory type - fn create_table(&self, table_type: TablePlan) -> Table; + fn create_table(&self, table_type: TablePlan) -> Result; /// Allocate memory for just the memories of the current module. fn create_memories( @@ -42,20 +42,23 @@ pub trait Tunables { &self, module: &Module, table_plans: &PrimaryMap, - ) -> PrimaryMap { + ) -> Result, LinkError> { let num_imports = module.num_imported_tables; let mut tables: PrimaryMap = PrimaryMap::with_capacity(module.tables.len() - num_imports); for index in num_imports..module.tables.len() { let plan = table_plans[TableIndex::new(index)].clone(); - tables.push(self.create_table(plan)); + tables.push(self.create_table(plan).map_err(LinkError::Resource)?); } - tables + Ok(tables) } /// Allocate memory for just the globals of the current module, /// with initializers applied. - fn create_globals(&self, module: &Module) -> PrimaryMap { + fn create_globals( + &self, + module: &Module, + ) -> Result, LinkError> { let num_imports = module.num_imported_globals; let mut vmctx_globals = PrimaryMap::with_capacity(module.globals.len() - num_imports); @@ -63,6 +66,6 @@ pub trait Tunables { vmctx_globals.push(VMGlobalDefinition::new()); } - vmctx_globals + Ok(vmctx_globals) } } diff --git a/lib/runtime/src/table.rs b/lib/runtime/src/table.rs index f77c1f8da..6ec58f962 100644 --- a/lib/runtime/src/table.rs +++ b/lib/runtime/src/table.rs @@ -19,20 +19,22 @@ pub struct Table { impl Table { /// Create a new table instance with specified minimum and maximum number of elements. - pub fn new(plan: &TablePlan) -> Self { + pub fn new(plan: &TablePlan) -> Result { match plan.table.ty { Type::FuncRef => (), - ty => unimplemented!("tables of types other than anyfunc ({})", ty), + ty => return Err(format!("tables of types other than anyfunc ({})", ty)), }; match plan.style { - TableStyle::CallerChecksSignature => Self { + TableStyle::CallerChecksSignature => Ok(Self { vec: RefCell::new(vec![ VMCallerCheckedAnyfunc::default(); - usize::try_from(plan.table.minimum).unwrap() + usize::try_from(plan.table.minimum).map_err(|_| { + "Table minimum is bigger than usize".to_string() + })? ]), maximum: plan.table.maximum, plan: plan.clone(), - }, + }), } } From b7b8f22db35e918b798050647f4ee55996416c83 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 22:16:58 -0700 Subject: [PATCH 22/27] Renamed backends to compilers --- src/{backends => compilers}/llvm.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{backends => compilers}/llvm.rs (100%) diff --git a/src/backends/llvm.rs b/src/compilers/llvm.rs similarity index 100% rename from src/backends/llvm.rs rename to src/compilers/llvm.rs From 91c893c8874ce82e70a294a3032f0f6ebc60b155 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 22:24:48 -0700 Subject: [PATCH 23/27] Improved imports docs --- lib/api/src/import_object.rs | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/lib/api/src/import_object.rs b/lib/api/src/import_object.rs index 1c86af791..32a4ba7cb 100644 --- a/lib/api/src/import_object.rs +++ b/lib/api/src/import_object.rs @@ -194,13 +194,15 @@ impl Extend<((String, String), Export)> for ImportObject { /// /// /// # Usage: -/// ```ignore -/// use wasmer::{imports, func}; +/// ``` +/// # use wasmer::{Func, Store}; +/// # let store = Store::default(); +/// use wasmer::imports; /// /// let import_object = imports! { /// "env" => { -/// "foo" => func!(foo), -/// }, +/// "foo" => Func::new(&store, foo) +/// } /// }; /// /// fn foo(n: i32) -> i32 { @@ -224,24 +226,8 @@ macro_rules! imports { }}; } -/// Generate an [`Namespace`] easily with the `namespace!` macro. -/// -/// [`Namespace`]: struct.Namespace.html -/// -/// -/// # Usage: -/// ```ignore -/// use wasmer::{namespace, func}; -/// -/// let env = namespace! { -/// "foo" => func!(foo), -/// }; -/// -/// fn foo(n: i32) -> i32 { -/// n -/// } -/// ``` #[macro_export] +#[doc(hidden)] macro_rules! namespace { ($( $imp_name:expr => $import_item:expr ),* $(,)? ) => { $crate::import_namespace!({ $( $imp_name => $import_item, )* }) From 88253869a8e6d757d23d3030d61044962a835d6f Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 22:42:36 -0700 Subject: [PATCH 24/27] Added support for compiler-less engines --- Cargo.toml | 4 ++++ lib/api/Cargo.toml | 10 +++++++--- lib/jit/Cargo.toml | 5 +++++ lib/jit/src/engine.rs | 17 ++++++++++++++++- lib/jit/src/module.rs | 9 +++++++++ 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3646e5221..b6eeb24ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ default = ["wast", "wasi", "experimental-io-devices", "compiler-cranelift", "cac cache = ["wasmer-cache"] wast = ["wasmer-wast"] wasi = ["wasmer-wasi"] +compiler = ["wasmer-jit/compiler"] experimental-io-devices = [ "wasmer-wasi-experimental-io-devices" ] @@ -67,14 +68,17 @@ compiler-singlepass = [ "test-utils/compiler-singlepass", "wasmer/compiler-singlepass", "wasmer-compiler-singlepass", + "compiler", ] compiler-cranelift = [ "test-utils/compiler-cranelift", "wasmer/compiler-cranelift", "wasmer-compiler-cranelift", + "compiler", ] compiler-llvm = [ "test-utils/compiler-llvm", "wasmer/compiler-llvm", "wasmer-compiler-llvm", + "compiler", ] diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index cb5435081..061ab4e22 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -38,14 +38,18 @@ maintenance = { status = "actively-developed" } [features] default = ["wat", "default-compiler-cranelift"] +compiler = ["wasmer-jit/compiler"] compiler-singlepass = [ - "wasmer-compiler-singlepass" + "wasmer-compiler-singlepass", + "compiler", ] compiler-cranelift = [ - "wasmer-compiler-cranelift" + "wasmer-compiler-cranelift", + "compiler", ] compiler-llvm = [ - "wasmer-compiler-llvm" + "wasmer-compiler-llvm", + "compiler", ] default-compiler-singlepass = [ "compiler-singlepass" diff --git a/lib/jit/Cargo.toml b/lib/jit/Cargo.toml index 660bf6c63..0721981db 100644 --- a/lib/jit/Cargo.toml +++ b/lib/jit/Cargo.toml @@ -29,5 +29,10 @@ lazy_static = "1.4" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3.8", features = ["winnt", "impl-default"] } +[features] +# Enable the `compiler` feature if you want the engine to compile +# and not be only on headless mode. +compiler = [] + [badges] maintenance = { status = "actively-developed" } diff --git a/lib/jit/src/engine.rs b/lib/jit/src/engine.rs index 077e7f3fd..122d596f4 100644 --- a/lib/jit/src/engine.rs +++ b/lib/jit/src/engine.rs @@ -10,7 +10,9 @@ use std::collections::HashMap; use std::sync::Arc; use wasm_common::entity::PrimaryMap; use wasm_common::{FuncType, LocalFuncIndex, MemoryIndex, SignatureIndex, TableIndex}; -use wasmer_compiler::{Compilation, CompileError, Compiler, CompilerConfig, FunctionBody, Target}; +use wasmer_compiler::{Compilation, CompileError, FunctionBody, Target}; +#[cfg(feature = "compiler")] +use wasmer_compiler::{Compiler, CompilerConfig}; use wasmer_runtime::{ InstanceHandle, MemoryPlan, Module, SignatureRegistry, TablePlan, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline, @@ -27,6 +29,7 @@ impl JITEngine { const MAGIC_HEADER: &'static [u8] = b"\0wasmer-jit"; /// Create a new `JITEngine` with the given config + #[cfg(feature = "compiler")] pub fn new(config: &C, tunables: impl Tunables + 'static) -> Self where C: ?Sized, @@ -59,6 +62,7 @@ impl JITEngine { pub fn headless(tunables: impl Tunables + 'static) -> Self { Self { inner: Arc::new(RefCell::new(JITEngineInner { + #[cfg(feature = "compiler")] compiler: None, trampolines: HashMap::new(), code_memory: CodeMemory::new(), @@ -148,6 +152,7 @@ impl JITEngine { /// The inner contents of `JITEngine` pub struct JITEngineInner { /// The compiler + #[cfg(feature = "compiler")] compiler: Option>, /// Pointers to trampoline functions used to enter particular signatures trampolines: HashMap, @@ -161,6 +166,7 @@ pub struct JITEngineInner { impl JITEngineInner { /// Gets the compiler associated to this JIT + #[cfg(feature = "compiler")] pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> { if self.compiler.is_none() { return Err(CompileError::Codegen("The JITEngine is operating in headless mode, so it can only execute already compiled Modules.".to_string())); @@ -169,10 +175,19 @@ impl JITEngineInner { } /// Validate the module + #[cfg(feature = "compiler")] pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> { self.compiler()?.validate_module(data) } + /// Validate the module + #[cfg(not(feature = "compiler"))] + pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> { + Err(CompileError::Validate( + "Validation is only enabled with the compiler feature".to_string(), + )) + } + /// Compile the given function bodies. pub(crate) fn allocate<'data>( &mut self, diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index 00721582e..29cede6f4 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -41,6 +41,7 @@ pub struct CompiledModule { impl CompiledModule { /// Compile a data buffer into a `CompiledModule`, which may then be instantiated. + #[cfg(feature = "compiler")] pub fn new(jit: &JITEngine, data: &[u8]) -> Result { let environ = ModuleEnvironment::new(); let mut jit_compiler = jit.compiler_mut(); @@ -118,6 +119,14 @@ impl CompiledModule { Self::from_parts(&mut jit_compiler, serializable) } + /// Compile a data buffer into a `CompiledModule`, which may then be instantiated. + #[cfg(not(feature = "compiler"))] + pub fn new(jit: &JITEngine, data: &[u8]) -> Result { + Err(CompileError::Codegen( + "Compilation is not enabled in the engine".to_string(), + )) + } + /// Serialize a CompiledModule pub fn serialize(&self) -> Result, SerializeError> { // let mut s = flexbuffers::FlexbufferSerializer::new(); From 03c77b3cf1f10bae8c1351dfbb05872207be3932 Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 23:07:41 -0700 Subject: [PATCH 25/27] Improved compiler configuration --- Cargo.lock | 4 ++-- Cargo.toml | 28 +++++++++++++--------------- lib/api/src/lib.rs | 5 ++++- lib/api/src/store.rs | 1 + lib/jit/src/module.rs | 1 + src/store.rs | 15 ++++++++++++++- tests/lib/test-utils/Cargo.toml | 4 ++++ tests/lib/test-utils/src/lib.rs | 2 ++ tests/wast.rs | 2 ++ 9 files changed, 43 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c96d75a4..5df8d1ce9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1190,9 +1190,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05720e22615919e4734f6a99ceae50d00226c3c5aca406e102ebc33298214e0a" +checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" [[package]] name = "strsim" diff --git a/Cargo.toml b/Cargo.toml index b6eeb24ee..13b36360d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,16 +20,16 @@ publish = false autoexamples = false [dependencies] -wasmer = { path = "lib/api" } -wasmer-compiler = { path = "lib/compiler" } -wasmer-compiler-cranelift = { path = "lib/compiler-cranelift", optional = true } -wasmer-compiler-singlepass = { path = "lib/compiler-singlepass", optional = true } -wasmer-compiler-llvm = { path = "lib/compiler-llvm", optional = true } -wasmer-jit = { path = "lib/jit" } -wasmer-wasi = { path = "lib/wasi", optional = true } -wasmer-wasi-experimental-io-devices = { path = "lib/wasi-experimental-io-devices", optional = true } -wasmer-wast = { path = "tests/lib/wast", optional = true } -wasmer-cache = { path = "lib/cache", optional = true } +wasmer = { version = "0.16.2", path = "lib/api" } +wasmer-compiler = { version = "0.16.2", path = "lib/compiler" } +wasmer-compiler-cranelift = { version = "0.16.2", path = "lib/compiler-cranelift", optional = true } +wasmer-compiler-singlepass = { version = "0.16.2", path = "lib/compiler-singlepass", optional = true } +wasmer-compiler-llvm = { version = "0.16.2", path = "lib/compiler-llvm", optional = true } +wasmer-jit = { version = "0.16.2", path = "lib/jit" } +wasmer-wasi = { version = "0.16.2", path = "lib/wasi", optional = true } +wasmer-wasi-experimental-io-devices = { version = "0.16.2", path = "lib/wasi-experimental-io-devices", optional = true } +wasmer-wast = { version = "0.16.2", path = "tests/lib/wast", optional = true } +wasmer-cache = { version = "0.16.2", path = "lib/cache", optional = true } atty = "0.2" anyhow = "1.0.28" structopt = { version = "0.3", features = ["suggestions"] } @@ -47,15 +47,10 @@ rustc_version = "0.2" [dev-dependencies] anyhow = "1.0.28" test-utils = { path = "tests/lib/test-utils" } -wasmer = { path = "lib/api" } -wasmer-compiler = { path = "lib/compiler" } -wasmer-jit = { path = "lib/jit" } -wasmer-wast = { path = "tests/lib/wast" } [features] # Don't add the backend features in default, please add them on the Makefile # since we might want to autoconfigure them depending on the availability on the host. -# default = ["wasi"] default = ["wast", "wasi", "experimental-io-devices", "compiler-cranelift", "cache"] cache = ["wasmer-cache"] wast = ["wasmer-wast"] @@ -82,3 +77,6 @@ compiler-llvm = [ "wasmer-compiler-llvm", "compiler", ] + +# [profile.release] +# lto = "fat" diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 048e8913c..fc4b72c8b 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -27,7 +27,10 @@ pub use crate::types::{ }; pub use wasm_common::{ValueType, WasmExternType, WasmTypeList}; -pub use wasmer_compiler::{CompilerConfig, Features, Target}; +pub use wasmer_compiler::{Features, Target}; +#[cfg(feature = "compiler")] +pub use wasmer_compiler::CompilerConfig; + pub use wasmer_jit::{ DeserializeError, InstantiationError, LinkError, RuntimeError, SerializeError, }; diff --git a/lib/api/src/store.rs b/lib/api/src/store.rs index 949dadbd5..cd8d5a114 100644 --- a/lib/api/src/store.rs +++ b/lib/api/src/store.rs @@ -1,5 +1,6 @@ use crate::tunables::Tunables; use std::sync::Arc; +#[cfg(feature = "compiler")] use wasmer_compiler::CompilerConfig; use wasmer_jit::JITEngine; diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index 29cede6f4..c3aecfe0a 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -22,6 +22,7 @@ use wasm_common::{ MemoryIndex, OwnedDataInitializer, SignatureIndex, TableIndex, }; use wasmer_compiler::CompileError; +#[cfg(feature = "compiler")] use wasmer_compiler::ModuleEnvironment; use wasmer_runtime::{ InstanceHandle, LinearMemory, Module, SignatureRegistry, Table, VMFunctionBody, diff --git a/src/store.rs b/src/store.rs index 5cdd5674b..2d03d82f0 100644 --- a/src/store.rs +++ b/src/store.rs @@ -62,6 +62,7 @@ impl FromStr for Compiler { } } +#[cfg(feature="compiler")] impl StoreOptions { fn get_compiler(&self) -> Result { if self.cranelift { @@ -123,7 +124,7 @@ impl StoreOptions { } /// Get's the compiler config - pub fn get_compiler_config(&self) -> Result<(Box, String)> { + fn get_compiler_config(&self) -> Result<(Box, String)> { let compiler = self.get_compiler()?; let compiler_name = compiler.to_string(); let compiler_config = self.get_config(compiler)?; @@ -144,3 +145,15 @@ impl StoreOptions { Ok((store, compiler_name)) } } + +#[cfg(not(feature="compiler"))] +impl StoreOptions { + /// Get the store (headless engine) + pub fn get_store(&self) -> Result<(Store, String)> { + // Get the tunables for the current host + let tunables = Tunables::default(); + let engine = Engine::headless(tunables); + let store = Store::new(&engine); + Ok((store, "headless".to_string())) + } +} diff --git a/tests/lib/test-utils/Cargo.toml b/tests/lib/test-utils/Cargo.toml index a24083b22..4ddd80656 100644 --- a/tests/lib/test-utils/Cargo.toml +++ b/tests/lib/test-utils/Cargo.toml @@ -15,12 +15,16 @@ wasmer-compiler-cranelift = { path = "../../../lib/compiler-cranelift", version wasmer-compiler-llvm = { path = "../../../lib/compiler-llvm", version = "0.16.2", optional = true } [features] +compiler = [] compiler-singlepass = [ "wasmer-compiler-singlepass", + "compiler", ] compiler-cranelift = [ "wasmer-compiler-cranelift", + "compiler", ] compiler-llvm = [ "wasmer-compiler-llvm", + "compiler", ] diff --git a/tests/lib/test-utils/src/lib.rs b/tests/lib/test-utils/src/lib.rs index 18fa3c8cd..fb05b36fb 100644 --- a/tests/lib/test-utils/src/lib.rs +++ b/tests/lib/test-utils/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg(feature="compiler")] + use wasmer_compiler::{CompilerConfig, Features, Target}; pub fn get_compiler_config_from_str( diff --git a/tests/wast.rs b/tests/wast.rs index f5384aefe..4a3f6053e 100644 --- a/tests/wast.rs +++ b/tests/wast.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "compiler")] + use std::path::Path; use test_utils::get_compiler_config_from_str; use wasmer::{Engine, Features, Store, Tunables}; From 63760d78023f4b892719c2ea0ba045efa09aa16b Mon Sep 17 00:00:00 2001 From: Syrus Date: Sun, 3 May 2020 23:25:19 -0700 Subject: [PATCH 26/27] Fixed linting --- lib/api/src/lib.rs | 2 +- src/store.rs | 4 ++-- tests/lib/test-utils/src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index fc4b72c8b..d0f957b8a 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -27,9 +27,9 @@ pub use crate::types::{ }; pub use wasm_common::{ValueType, WasmExternType, WasmTypeList}; -pub use wasmer_compiler::{Features, Target}; #[cfg(feature = "compiler")] pub use wasmer_compiler::CompilerConfig; +pub use wasmer_compiler::{Features, Target}; pub use wasmer_jit::{ DeserializeError, InstantiationError, LinkError, RuntimeError, SerializeError, diff --git a/src/store.rs b/src/store.rs index 2d03d82f0..2cdd03b9c 100644 --- a/src/store.rs +++ b/src/store.rs @@ -62,7 +62,7 @@ impl FromStr for Compiler { } } -#[cfg(feature="compiler")] +#[cfg(feature = "compiler")] impl StoreOptions { fn get_compiler(&self) -> Result { if self.cranelift { @@ -146,7 +146,7 @@ impl StoreOptions { } } -#[cfg(not(feature="compiler"))] +#[cfg(not(feature = "compiler"))] impl StoreOptions { /// Get the store (headless engine) pub fn get_store(&self) -> Result<(Store, String)> { diff --git a/tests/lib/test-utils/src/lib.rs b/tests/lib/test-utils/src/lib.rs index fb05b36fb..93cad17ac 100644 --- a/tests/lib/test-utils/src/lib.rs +++ b/tests/lib/test-utils/src/lib.rs @@ -1,4 +1,4 @@ -#![cfg(feature="compiler")] +#![cfg(feature = "compiler")] use wasmer_compiler::{CompilerConfig, Features, Target}; From e197afe7c991737b871c3b890b7424a56f5bbc73 Mon Sep 17 00:00:00 2001 From: Syrus Date: Mon, 4 May 2020 00:31:35 -0700 Subject: [PATCH 27/27] Improved memory layout for Instance --- lib/api/src/module.rs | 12 ++++- lib/jit/src/engine.rs | 2 +- lib/jit/src/module.rs | 39 +++++++++++----- lib/jit/src/resolver.rs | 13 +----- lib/runtime/src/imports.rs | 7 --- lib/runtime/src/instance.rs | 90 +++++++++++++++++++------------------ 6 files changed, 87 insertions(+), 76 deletions(-) diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs index 402e06472..007895688 100644 --- a/lib/api/src/module.rs +++ b/lib/api/src/module.rs @@ -184,7 +184,17 @@ impl Module { &self, resolver: &dyn Resolver, ) -> Result { - self.store.engine().instantiate(&self.compiled, resolver) + unsafe { + let instance_handle = self.store.engine().instantiate(&self.compiled, resolver)?; + + // After the instance handle is created, we need to initialize + // the data, call the start function and so. However, if any + // of this steps traps, we still need to keep the instance alive + // as some of the Instance elements may have placed in other + // instance tables. + self.compiled.finish_instantiation(&instance_handle)?; + Ok(instance_handle) + } } /// Returns the name of the current module. diff --git a/lib/jit/src/engine.rs b/lib/jit/src/engine.rs index 122d596f4..db82091fa 100644 --- a/lib/jit/src/engine.rs +++ b/lib/jit/src/engine.rs @@ -119,7 +119,7 @@ impl JITEngine { } /// Instantiates a WebAssembly module - pub fn instantiate( + pub unsafe fn instantiate( &self, compiled_module: &CompiledModule, resolver: &dyn Resolver, diff --git a/lib/jit/src/module.rs b/lib/jit/src/module.rs index c3aecfe0a..18bbbb017 100644 --- a/lib/jit/src/module.rs +++ b/lib/jit/src/module.rs @@ -211,17 +211,7 @@ impl CompiledModule { ) -> Result { let jit_compiler = jit.compiler(); let tunables = jit.tunables(); - let is_bulk_memory: bool = self.serializable.features.bulk_memory; let sig_registry: &SignatureRegistry = jit_compiler.signatures(); - let data_initializers = self - .serializable - .data_initializers - .iter() - .map(|init| DataInitializer { - location: init.location.clone(), - data: &*init.data, - }) - .collect::>(); let imports = resolve_imports( &self.serializable.module, &sig_registry, @@ -254,14 +244,39 @@ impl CompiledModule { finished_tables, finished_globals, imports, - &data_initializers, self.signatures.clone(), - is_bulk_memory, host_state, ) .map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap))) } + /// Finish instantiation of a `InstanceHandle` + /// + /// # Unsafety + /// + /// See `InstanceHandle::finish_instantiation` + pub unsafe fn finish_instantiation( + &self, + handle: &InstanceHandle, + ) -> Result<(), InstantiationError> { + let is_bulk_memory: bool = self.serializable.features.bulk_memory; + handle + .finish_instantiation(is_bulk_memory, &self.data_initializers()) + .map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap))) + } + + /// Returns data initializers to pass to `InstanceHandle::initialize` + pub fn data_initializers(&self) -> Vec> { + self.serializable + .data_initializers + .iter() + .map(|init| DataInitializer { + location: init.location.clone(), + data: &*init.data, + }) + .collect::>() + } + /// Return a reference-counting pointer to a module. pub fn module(&self) -> &Arc { &self.serializable.module diff --git a/lib/jit/src/resolver.rs b/lib/jit/src/resolver.rs index 05efa2b5c..32d9fc08d 100644 --- a/lib/jit/src/resolver.rs +++ b/lib/jit/src/resolver.rs @@ -3,7 +3,6 @@ use crate::error::{ImportError, LinkError}; use more_asserts::assert_ge; -use std::collections::HashSet; use wasm_common::entity::PrimaryMap; use wasm_common::{ExternType, ImportIndex, MemoryIndex, TableIndex}; use wasmer_runtime::{ @@ -95,8 +94,6 @@ pub fn resolve_imports( memory_plans: &PrimaryMap, _table_plans: &PrimaryMap, ) -> Result { - let dependencies = HashSet::new(); - let mut function_imports = PrimaryMap::with_capacity(module.num_imported_funcs); let mut table_imports = PrimaryMap::with_capacity(module.num_imported_tables); let mut memory_imports = PrimaryMap::with_capacity(module.num_imported_memories); @@ -125,16 +122,12 @@ pub fn resolve_imports( } match resolved { Export::Function(ref f) => { - // TODO: Syrus - fix this - // dependencies.insert(unsafe { InstanceHandle::from_vmctx(f.vmctx) }); function_imports.push(VMFunctionImport { body: f.address, vmctx: f.vmctx, }); } Export::Table(ref t) => { - // TODO: Syrus - fix this - // dependencies.insert(unsafe { InstanceHandle::from_vmctx(t.vmctx) }); table_imports.push(VMTableImport { definition: t.definition, from: t.from, @@ -168,16 +161,13 @@ pub fn resolve_imports( } } - // TODO: Syrus - fix this - // dependencies.insert(unsafe { InstanceHandle::from_vmctx(m.vmctx) }); memory_imports.push(VMMemoryImport { definition: m.definition, from: m.from, }); } + Export::Global(ref g) => { - // TODO: Syrus - fix this - // dependencies.insert(unsafe { InstanceHandle::from_vmctx(g.vmctx) }); global_imports.push(VMGlobalImport { definition: g.definition, }); @@ -186,7 +176,6 @@ pub fn resolve_imports( } Ok(Imports::new( - dependencies, function_imports, table_imports, memory_imports, diff --git a/lib/runtime/src/imports.rs b/lib/runtime/src/imports.rs index 9b8c100d6..ff9c3359a 100644 --- a/lib/runtime/src/imports.rs +++ b/lib/runtime/src/imports.rs @@ -1,4 +1,3 @@ -use crate::instance::InstanceHandle; use crate::vmcontext::{VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport}; use std::collections::HashSet; use wasm_common::entity::{BoxedSlice, PrimaryMap}; @@ -7,9 +6,6 @@ use wasm_common::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex}; /// Resolved import pointers. #[derive(Clone)] pub struct Imports { - /// The set of instances that the imports depend on. - pub dependencies: HashSet, - /// Resolved addresses for imported functions. pub functions: BoxedSlice, @@ -26,14 +22,12 @@ pub struct Imports { impl Imports { /// Construct a new `Imports` instance. pub fn new( - dependencies: HashSet, function_imports: PrimaryMap, table_imports: PrimaryMap, memory_imports: PrimaryMap, global_imports: PrimaryMap, ) -> Self { Self { - dependencies, functions: function_imports.into_boxed_slice(), tables: table_imports.into_boxed_slice(), memories: memory_imports.into_boxed_slice(), @@ -44,7 +38,6 @@ impl Imports { /// Construct a new `Imports` instance with no imports. pub fn none() -> Self { Self { - dependencies: HashSet::new(), functions: PrimaryMap::new().into_boxed_slice(), tables: PrimaryMap::new().into_boxed_slice(), memories: PrimaryMap::new().into_boxed_slice(), diff --git a/lib/runtime/src/instance.rs b/lib/runtime/src/instance.rs index f430f8657..91a172ae4 100644 --- a/lib/runtime/src/instance.rs +++ b/lib/runtime/src/instance.rs @@ -35,7 +35,7 @@ cfg_if::cfg_if! { impl InstanceHandle { /// Set a custom signal handler - pub fn set_signal_handler(&mut self, handler: H) + pub fn set_signal_handler(&self, handler: H) where H: 'static + Fn(libc::c_int, *const libc::siginfo_t, *const libc::c_void) -> bool, { @@ -47,7 +47,7 @@ cfg_if::cfg_if! { impl InstanceHandle { /// Set a custom signal handler - pub fn set_signal_handler(&mut self, handler: H) + pub fn set_signal_handler(&self, handler: H) where H: 'static + Fn(winapi::um::winnt::PEXCEPTION_POINTERS) -> bool, { @@ -62,14 +62,6 @@ cfg_if::cfg_if! { /// This is repr(C) to ensure that the vmctx field is last. #[repr(C)] pub(crate) struct Instance { - /// The number of references to this `Instance`. - refcount: Cell, - - /// `Instance`s from which this `Instance` imports. These won't - /// create reference cycles because wasm instances can't cyclically - /// import from each other. - dependencies: HashSet, - /// The `Module` this `Instance` was instantiated from. module: Arc, @@ -788,9 +780,7 @@ impl InstanceHandle { finished_tables: BoxedSlice, finished_globals: BoxedSlice, imports: Imports, - data_initializers: &[DataInitializer<'_>], vmshared_signatures: BoxedSlice, - is_bulk_memory: bool, host_state: Box, ) -> Result { let vmctx_tables = finished_tables @@ -813,8 +803,6 @@ impl InstanceHandle { let handle = { let instance = Instance { - refcount: Cell::new(1), - dependencies: imports.dependencies, module, offsets, memories: finished_memories, @@ -883,29 +871,42 @@ impl InstanceHandle { VMBuiltinFunctionsArray::initialized(), ); + // Ensure that our signal handlers are ready for action. + init_traps(); + + // Perform infallible initialization in this constructor, while fallible + // initialization is deferred to the `initialize` method. + initialize_passive_elements(instance); + initialize_globals(instance); + + Ok(handle) + } + + /// Finishes the instantiation process started by `Instance::new`. + /// + /// Only safe to call immediately after instantiation. + pub unsafe fn finish_instantiation( + &self, + is_bulk_memory: bool, + data_initializers: &[DataInitializer<'_>], + ) -> Result<(), Trap> { // Check initializer bounds before initializing anything. Only do this // when bulk memory is disabled, since the bulk memory proposal changes // instantiation such that the intermediate results of failed // initializations are visible. if !is_bulk_memory { - check_table_init_bounds(instance)?; - check_memory_init_bounds(instance, data_initializers)?; + check_table_init_bounds(self.instance())?; + check_memory_init_bounds(self.instance(), data_initializers)?; } // Apply the initializers. - initialize_tables(instance)?; - initialize_passive_elements(instance); - initialize_memories(instance, data_initializers)?; - initialize_globals(instance); - - // Ensure that our signal handlers are ready for action. - init_traps(); + initialize_tables(self.instance())?; + initialize_memories(self.instance(), data_initializers)?; // The WebAssembly spec specifies that the start function is // invoked automatically at instantiation time. - instance.invoke_start_function()?; - - Ok(handle) + self.instance().invoke_start_function()?; + Ok(()) } /// Create a new `InstanceHandle` pointing at the instance @@ -916,7 +917,6 @@ impl InstanceHandle { /// be a `VMContext` allocated as part of an `Instance`. pub unsafe fn from_vmctx(vmctx: *mut VMContext) -> Self { let instance = (&mut *vmctx).instance(); - instance.refcount.set(instance.refcount.get() + 1); Self { instance: instance as *const Instance as *mut Instance, } @@ -1031,32 +1031,36 @@ impl InstanceHandle { pub(crate) fn instance(&self) -> &Instance { unsafe { &*(self.instance as *const Instance) } } + + /// Deallocates memory associated with this instance. + /// + /// Note that this is unsafe because there might be other handles to this + /// `InstanceHandle` elsewhere, and there's nothing preventing usage of + /// this handle after this function is called. + pub unsafe fn dealloc(&self) { + let instance = self.instance(); + let layout = instance.alloc_layout(); + ptr::drop_in_place(self.instance); + alloc::dealloc(self.instance.cast(), layout); + } } impl Clone for InstanceHandle { fn clone(&self) -> Self { - let instance = self.instance(); - instance.refcount.set(instance.refcount.get() + 1); Self { instance: self.instance, } } } -impl Drop for InstanceHandle { - fn drop(&mut self) { - let instance = self.instance(); - let count = instance.refcount.get(); - instance.refcount.set(count - 1); - if count == 1 { - let layout = instance.alloc_layout(); - unsafe { - ptr::drop_in_place(self.instance); - alloc::dealloc(self.instance.cast(), layout); - } - } - } -} +// TODO: uncomment this, as we need to store the handles +// in the store, and once the store is dropped, then the instances +// will too. +// impl Drop for InstanceHandle { +// fn drop(&mut self) { +// unsafe { self.dealloc() } +// } +// } fn check_table_init_bounds(instance: &Instance) -> Result<(), Trap> { let module = Arc::clone(&instance.module);