diff --git a/lib/api/src/sys/mod.rs b/lib/api/src/sys/mod.rs index c8408b66219..3fd2461fc82 100644 --- a/lib/api/src/sys/mod.rs +++ b/lib/api/src/sys/mod.rs @@ -74,9 +74,9 @@ pub use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel}; #[cfg(feature = "llvm")] pub use wasmer_compiler_llvm::{LLVMOptLevel, LLVM}; -pub use wasmer_compiler::Engine; #[cfg(feature = "compiler")] pub use wasmer_compiler::{Artifact, EngineBuilder}; +pub use wasmer_compiler::{AsEngineRef, Engine, EngineRef}; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index 247530809e6..8eda10b2811 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -10,6 +10,7 @@ use std::sync::Arc; use thiserror::Error; use wasmer_compiler::Artifact; use wasmer_compiler::ArtifactCreate; +use wasmer_compiler::AsEngineRef; #[cfg(feature = "wat")] use wasmer_types::WasmError; use wasmer_types::{ @@ -158,8 +159,18 @@ impl Module { /// # Ok(()) /// # } /// ``` + /// # Example of loading a module using just an `Engine` and no `Store` + /// + /// ``` + /// # use wasmer::*; + /// # + /// # let compiler = Cranelift::default(); + /// # let engine = EngineBuilder::new(compiler).engine(); + /// + /// let module = Module::from_file(&engine, "path/to/foo.wasm"); + /// ``` #[allow(unreachable_code)] - pub fn new(store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result { + pub fn new(engine: &impl AsEngineRef, bytes: impl AsRef<[u8]>) -> Result { #[cfg(feature = "wat")] let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| { CompileError::Wasm(WasmError::Generic(format!( @@ -167,19 +178,19 @@ impl Module { e ))) })?; - Self::from_binary(store, bytes.as_ref()) + Self::from_binary(engine, bytes.as_ref()) } #[cfg(feature = "compiler")] /// Creates a new WebAssembly module from a file path. pub fn from_file( - store: &impl AsStoreRef, + engine: &impl AsEngineRef, file: impl AsRef, ) -> Result { let file_ref = file.as_ref(); let canonical = file_ref.canonicalize()?; let wasm_bytes = std::fs::read(file_ref)?; - let mut module = Self::new(store, &wasm_bytes)?; + let mut module = Self::new(engine, &wasm_bytes)?; // Set the module name to the absolute path of the filename. // This is useful for debugging the stack traces. let filename = canonical.as_path().to_str().unwrap(); @@ -193,9 +204,9 @@ impl Module { /// Opposed to [`Module::new`], this function is not compatible with /// the WebAssembly text format (if the "wat" feature is enabled for /// this crate). - pub fn from_binary(store: &impl AsStoreRef, binary: &[u8]) -> Result { - Self::validate(store, binary)?; - unsafe { Self::from_binary_unchecked(store, binary) } + pub fn from_binary(engine: &impl AsEngineRef, binary: &[u8]) -> Result { + Self::validate(engine, binary)?; + unsafe { Self::from_binary_unchecked(engine, binary) } } #[cfg(feature = "compiler")] @@ -207,10 +218,10 @@ impl Module { /// in environments where the WebAssembly modules are trusted and validated /// beforehand. pub unsafe fn from_binary_unchecked( - store: &impl AsStoreRef, + engine: &impl AsEngineRef, binary: &[u8], ) -> Result { - let module = Self::compile(store, binary)?; + let module = Self::compile(engine, binary)?; Ok(module) } @@ -221,16 +232,13 @@ impl Module { /// This validation is normally pretty fast and checks the enabled /// WebAssembly features in the Store Engine to assure deterministic /// validation of the Module. - pub fn validate(store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> { - store.as_store_ref().engine().validate(binary) + pub fn validate(engine: &impl AsEngineRef, binary: &[u8]) -> Result<(), CompileError> { + engine.as_engine_ref().engine().validate(binary) } #[cfg(feature = "compiler")] - fn compile(store: &impl AsStoreRef, binary: &[u8]) -> Result { - let artifact = store - .as_store_ref() - .engine() - .compile(binary, store.as_store_ref().tunables())?; + fn compile(engine: &impl AsEngineRef, binary: &[u8]) -> Result { + let artifact = engine.as_engine_ref().engine().compile(binary)?; Ok(Self::from_artifact(artifact)) } diff --git a/lib/api/src/sys/store.rs b/lib/api/src/sys/store.rs index e8d7ea44a37..65901c2dc82 100644 --- a/lib/api/src/sys/store.rs +++ b/lib/api/src/sys/store.rs @@ -2,7 +2,7 @@ use crate::sys::tunables::BaseTunables; use std::fmt; use std::sync::{Arc, RwLock}; #[cfg(feature = "compiler")] -use wasmer_compiler::{Engine, EngineBuilder, Tunables}; +use wasmer_compiler::{AsEngineRef, Engine, EngineBuilder, EngineRef, Tunables}; use wasmer_vm::{init_traps, TrapHandler, TrapHandlerFn}; use wasmer_vm::StoreObjects; @@ -14,8 +14,6 @@ pub(crate) struct StoreInner { pub(crate) objects: StoreObjects, #[cfg(feature = "compiler")] pub(crate) engine: Engine, - #[cfg(feature = "compiler")] - pub(crate) tunables: Box, pub(crate) trap_handler: Option>>, } @@ -25,10 +23,7 @@ pub(crate) struct StoreInner { /// have been allocated during the lifetime of the abstract machine. /// /// The `Store` holds the engine (that is —amongst many things— used to compile -/// the Wasm bytes into a valid module artifact), in addition to the -#[cfg_attr(feature = "compiler", doc = "[`Tunables`]")] -#[cfg_attr(not(feature = "compiler"), doc = "`Tunables`")] -/// (that are used to create the memories, tables and globals). +/// the Wasm bytes into a valid module artifact). /// /// Spec: pub struct Store { @@ -43,8 +38,20 @@ impl Store { /// Creates a new `Store` with a specific [`Engine`]. pub fn new(engine: impl Into) -> Self { let engine = engine.into(); - let target = engine.target().clone(); - Self::new_with_tunables(engine, BaseTunables::for_target(&target)) + + // Make sure the signal handlers are installed. + // This is required for handling traps. + init_traps(); + + Self { + inner: Box::new(StoreInner { + objects: Default::default(), + engine: engine.cloned(), + trap_handler: None, + }), + engine: engine.cloned(), + trap_handler: Arc::new(RwLock::new(None)), + } } #[cfg(feature = "compiler")] @@ -68,28 +75,16 @@ impl Store { engine: impl Into, tunables: impl Tunables + Send + Sync + 'static, ) -> Self { - let engine = engine.into(); + let mut engine = engine.into(); + engine.set_tunables(tunables); - // Make sure the signal handlers are installed. - // This is required for handling traps. - init_traps(); - - Self { - inner: Box::new(StoreInner { - objects: Default::default(), - engine: engine.cloned(), - tunables: Box::new(tunables), - trap_handler: None, - }), - engine: engine.cloned(), - trap_handler: Arc::new(RwLock::new(None)), - } + Self::new(engine) } #[cfg(feature = "compiler")] /// Returns the [`Tunables`]. pub fn tunables(&self) -> &dyn Tunables { - self.inner.tunables.as_ref() + self.engine.tunables() } #[cfg(feature = "compiler")] @@ -202,6 +197,30 @@ impl AsStoreMut for Store { } } +impl AsEngineRef for Store { + fn as_engine_ref(&self) -> EngineRef<'_> { + EngineRef::new(&self.engine) + } +} + +impl AsEngineRef for &Store { + fn as_engine_ref(&self) -> EngineRef<'_> { + EngineRef::new(&self.engine) + } +} + +impl AsEngineRef for StoreRef<'_> { + fn as_engine_ref(&self) -> EngineRef<'_> { + EngineRef::new(&self.inner.engine) + } +} + +impl AsEngineRef for StoreMut<'_> { + fn as_engine_ref(&self) -> EngineRef<'_> { + EngineRef::new(&self.inner.engine) + } +} + impl fmt::Debug for Store { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Store").finish() @@ -221,7 +240,7 @@ impl<'a> StoreRef<'a> { #[cfg(feature = "compiler")] /// Returns the [`Tunables`]. pub fn tunables(&self) -> &dyn Tunables { - self.inner.tunables.as_ref() + self.inner.engine.tunables() } #[cfg(feature = "compiler")] @@ -257,7 +276,7 @@ impl<'a> StoreMut<'a> { /// Returns the [`Tunables`]. #[cfg(feature = "compiler")] pub fn tunables(&self) -> &dyn Tunables { - self.inner.tunables.as_ref() + self.inner.engine.tunables() } /// Returns the [`Engine`]. @@ -276,7 +295,7 @@ impl<'a> StoreMut<'a> { #[cfg(feature = "compiler")] pub(crate) fn tunables_and_objects_mut(&mut self) -> (&dyn Tunables, &mut StoreObjects) { - (self.inner.tunables.as_ref(), &mut self.inner.objects) + (self.inner.engine.tunables(), &mut self.inner.objects) } pub(crate) fn as_raw(&self) -> *mut StoreInner { diff --git a/lib/api/src/sys/tunables.rs b/lib/api/src/sys/tunables.rs index 5bcebad7105..5274cc2a9cb 100644 --- a/lib/api/src/sys/tunables.rs +++ b/lib/api/src/sys/tunables.rs @@ -1,140 +1,20 @@ -use crate::sys::{MemoryType, Pages, TableType}; -use std::ptr::NonNull; -use wasmer_compiler::Tunables; -use wasmer_types::{PointerWidth, Target}; -use wasmer_vm::MemoryError; -use wasmer_vm::{ - MemoryStyle, TableStyle, VMMemory, VMMemoryDefinition, VMTable, VMTableDefinition, -}; +pub use wasmer_compiler::BaseTunables; -/// Tunable parameters for WebAssembly compilation. -/// This is the reference implementation of the `Tunables` trait, -/// used by default. -/// -/// You can use this as a template for creating a custom Tunables -/// implementation or use composition to wrap your Tunables around -/// this one. The later approach is demonstrated in the -/// tunables-limit-memory example. -#[derive(Clone)] -pub struct BaseTunables { - /// For static heaps, the size in wasm pages of the heap protected by bounds checking. - pub static_memory_bound: Pages, - - /// The size in bytes of the offset guard for static heaps. - pub static_memory_offset_guard_size: u64, - - /// The size in bytes of the offset guard for dynamic heaps. - pub dynamic_memory_offset_guard_size: u64, -} - -impl BaseTunables { - /// Get the `BaseTunables` for a specific Target - pub fn for_target(target: &Target) -> Self { - let triple = target.triple(); - let pointer_width: PointerWidth = triple.pointer_width().unwrap(); - let (static_memory_bound, static_memory_offset_guard_size): (Pages, u64) = - match pointer_width { - PointerWidth::U16 => (0x400.into(), 0x1000), - PointerWidth::U32 => (0x4000.into(), 0x1_0000), - // Static Memory Bound: - // Allocating 4 GiB of address space let us avoid the - // need for explicit bounds checks. - // Static Memory Guard size: - // Allocating 2 GiB of address space lets us translate wasm - // offsets into x86 offsets as aggressively as we can. - PointerWidth::U64 => (0x1_0000.into(), 0x8000_0000), - }; - - // Allocate a small guard to optimize common cases but without - // wasting too much memory. - // The Windows memory manager seems more laxed than the other ones - // And a guard of just 1 page may not be enough is some borderline cases - // So using 2 pages for guard on this platform - #[cfg(target_os = "windows")] - let dynamic_memory_offset_guard_size: u64 = 0x2_0000; - #[cfg(not(target_os = "windows"))] - let dynamic_memory_offset_guard_size: u64 = 0x1_0000; - - Self { - static_memory_bound, - static_memory_offset_guard_size, - dynamic_memory_offset_guard_size, - } - } -} - -impl Tunables for BaseTunables { - /// Get a `MemoryStyle` for the provided `MemoryType` - fn memory_style(&self, memory: &MemoryType) -> MemoryStyle { - // A heap with a maximum that doesn't exceed the static memory bound specified by the - // tunables make it static. - // - // If the module doesn't declare an explicit maximum treat it as 4GiB. - let maximum = memory.maximum.unwrap_or_else(Pages::max_value); - if maximum <= self.static_memory_bound { - MemoryStyle::Static { - // Bound can be larger than the maximum for performance reasons - bound: self.static_memory_bound, - offset_guard_size: self.static_memory_offset_guard_size, - } - } else { - MemoryStyle::Dynamic { - offset_guard_size: self.dynamic_memory_offset_guard_size, - } - } - } - - /// Get a [`TableStyle`] for the provided [`TableType`]. - fn table_style(&self, _table: &TableType) -> TableStyle { - TableStyle::CallerChecksSignature - } - - /// Create a memory owned by the host given a [`MemoryType`] and a [`MemoryStyle`]. - fn create_host_memory( - &self, - ty: &MemoryType, - style: &MemoryStyle, - ) -> Result { - VMMemory::new(ty, style) - } - - /// Create a memory owned by the VM given a [`MemoryType`] and a [`MemoryStyle`]. - /// - /// # Safety - /// - `vm_definition_location` must point to a valid, owned `VMMemoryDefinition`, - /// for example in `VMContext`. - unsafe fn create_vm_memory( - &self, - ty: &MemoryType, - style: &MemoryStyle, - vm_definition_location: NonNull, - ) -> Result { - VMMemory::from_definition(ty, style, vm_definition_location) - } - - /// Create a table owned by the host given a [`TableType`] and a [`TableStyle`]. - fn create_host_table(&self, ty: &TableType, style: &TableStyle) -> Result { - VMTable::new(ty, style) - } - - /// Create a table owned by the VM given a [`TableType`] and a [`TableStyle`]. - /// - /// # Safety - /// - `vm_definition_location` must point to a valid, owned `VMTableDefinition`, - /// for example in `VMContext`. - unsafe fn create_vm_table( - &self, - ty: &TableType, - style: &TableStyle, - vm_definition_location: NonNull, - ) -> Result { - VMTable::from_definition(ty, style, vm_definition_location) - } -} +// All BaseTunable definition now is in wasmer_compile crate +// Tests are still here #[cfg(test)] mod tests { use super::*; + use crate::sys::TableType; + use std::cell::UnsafeCell; + use std::ptr::NonNull; + use wasmer_compiler::Tunables; + use wasmer_types::{MemoryType, Pages, WASM_PAGE_SIZE}; + use wasmer_vm::{ + LinearMemory, MemoryError, MemoryStyle, TableStyle, VMMemory, VMMemoryDefinition, VMTable, + VMTableDefinition, + }; #[test] fn memory_style() { @@ -175,11 +55,6 @@ mod tests { } } - use std::cell::UnsafeCell; - use std::ptr::NonNull; - use wasmer_types::{MemoryError, MemoryStyle, MemoryType, Pages, WASM_PAGE_SIZE}; - use wasmer_vm::LinearMemory; - #[derive(Debug)] struct VMTinyMemory { mem: Vec, diff --git a/lib/compiler/src/engine/engineref.rs b/lib/compiler/src/engine/engineref.rs new file mode 100644 index 00000000000..107cd9b1153 --- /dev/null +++ b/lib/compiler/src/engine/engineref.rs @@ -0,0 +1,39 @@ +use super::Engine; +use crate::Tunables; + +/// A temporary handle to an [`Engine`] +/// EngineRef can be used to build a [`Module`][wasmer::Module] +/// It can be created directly with an [`Engine`] +/// Or from anything implementing [`AsEngineRef`] +/// like from [`Store`][wasmer::Store] typicaly +pub struct EngineRef<'a> { + /// The inner engine + pub(crate) inner: &'a Engine, +} + +impl<'a> EngineRef<'a> { + /// Get inner [`Engine`] + pub fn engine(&self) -> &Engine { + self.inner + } + /// Get the [`Tunables`] + pub fn tunables(&self) -> &dyn Tunables { + self.inner.tunables() + } + /// Create an EngineRef from an Engine and Tunables + pub fn new(engine: &'a Engine) -> Self { + EngineRef { inner: engine } + } +} + +/// Helper trait for a value that is convertible to a [`EngineRef`]. +pub trait AsEngineRef { + /// Returns a `EngineRef` pointing to the underlying context. + fn as_engine_ref(&self) -> EngineRef<'_>; +} + +impl AsEngineRef for EngineRef<'_> { + fn as_engine_ref(&self) -> EngineRef<'_> { + EngineRef { inner: self.inner } + } +} diff --git a/lib/compiler/src/engine/inner.rs b/lib/compiler/src/engine/inner.rs index 26c1e453db4..84e8774222f 100644 --- a/lib/compiler/src/engine/inner.rs +++ b/lib/compiler/src/engine/inner.rs @@ -4,7 +4,11 @@ use crate::engine::builder::EngineBuilder; #[cfg(not(target_arch = "wasm32"))] use crate::Artifact; #[cfg(not(target_arch = "wasm32"))] +use crate::BaseTunables; +#[cfg(not(target_arch = "wasm32"))] use crate::CodeMemory; +#[cfg(not(target_arch = "wasm32"))] +use crate::{AsEngineRef, EngineRef}; #[cfg(feature = "compiler")] use crate::{Compiler, CompilerConfig}; #[cfg(not(target_arch = "wasm32"))] @@ -36,6 +40,8 @@ pub struct Engine { /// The target for the compiler target: Arc, engine_id: EngineId, + #[cfg(not(target_arch = "wasm32"))] + tunables: Arc, } impl Engine { @@ -46,6 +52,8 @@ impl Engine { target: Target, features: Features, ) -> Self { + #[cfg(not(target_arch = "wasm32"))] + let tunables = BaseTunables::for_target(&target); Self { inner: Arc::new(Mutex::new(EngineInner { compiler: Some(compiler_config.compiler()), @@ -57,6 +65,8 @@ impl Engine { })), target: Arc::new(target), engine_id: EngineId::default(), + #[cfg(not(target_arch = "wasm32"))] + tunables: Arc::new(tunables), } } @@ -74,6 +84,9 @@ impl Engine { /// Headless engines can't compile or validate any modules, /// they just take already processed Modules (via `Module::serialize`). pub fn headless() -> Self { + let target = Target::default(); + #[cfg(not(target_arch = "wasm32"))] + let tunables = BaseTunables::for_target(&target); Self { inner: Arc::new(Mutex::new(EngineInner { #[cfg(feature = "compiler")] @@ -85,8 +98,10 @@ impl Engine { #[cfg(not(target_arch = "wasm32"))] signatures: SignatureRegistry::new(), })), - target: Arc::new(Target::default()), + target: Arc::new(target), engine_id: EngineId::default(), + #[cfg(not(target_arch = "wasm32"))] + tunables: Arc::new(tunables), } } @@ -128,12 +143,12 @@ impl Engine { /// Compile a WebAssembly binary #[cfg(feature = "compiler")] #[cfg(not(target_arch = "wasm32"))] - pub fn compile( - &self, - binary: &[u8], - tunables: &dyn Tunables, - ) -> Result, CompileError> { - Ok(Arc::new(Artifact::new(self, binary, tunables)?)) + pub fn compile(&self, binary: &[u8]) -> Result, CompileError> { + Ok(Arc::new(Artifact::new( + self, + binary, + self.tunables.as_ref(), + )?)) } /// Compile a WebAssembly binary @@ -187,6 +202,25 @@ impl Engine { pub fn cloned(&self) -> Self { self.clone() } + + /// Attach a Tunable to this engine + #[cfg(not(target_arch = "wasm32"))] + pub fn set_tunables(&mut self, tunables: impl Tunables + Send + Sync + 'static) { + self.tunables = Arc::new(tunables); + } + + /// Get a reference to attached Tunable of this engine + #[cfg(not(target_arch = "wasm32"))] + pub fn tunables(&self) -> &dyn Tunables { + self.tunables.as_ref() + } +} + +#[cfg(not(target_arch = "wasm32"))] +impl AsEngineRef for Engine { + fn as_engine_ref(&self) -> EngineRef { + EngineRef { inner: self } + } } /// The inner contents of `Engine` diff --git a/lib/compiler/src/engine/mod.rs b/lib/compiler/src/engine/mod.rs index c382be7959b..bf54a791311 100644 --- a/lib/compiler/src/engine/mod.rs +++ b/lib/compiler/src/engine/mod.rs @@ -1,5 +1,8 @@ //! The Wasmer Engine. +#[cfg(feature = "translator")] +#[cfg(not(target_arch = "wasm32"))] +mod engineref; mod error; #[cfg(not(target_arch = "wasm32"))] mod resolver; @@ -25,13 +28,16 @@ mod link; #[cfg(not(target_arch = "wasm32"))] mod unwind; +#[cfg(feature = "translator")] +#[cfg(not(target_arch = "wasm32"))] +pub use self::engineref::{AsEngineRef, EngineRef}; pub use self::error::{InstantiationError, LinkError}; #[cfg(not(target_arch = "wasm32"))] pub use self::resolver::resolve_imports; #[cfg(not(target_arch = "wasm32"))] pub use self::trap::*; #[cfg(not(target_arch = "wasm32"))] -pub use self::tunables::Tunables; +pub use self::tunables::{BaseTunables, Tunables}; #[cfg(feature = "translator")] #[cfg(not(target_arch = "wasm32"))] diff --git a/lib/compiler/src/engine/tunables.rs b/lib/compiler/src/engine/tunables.rs index 207ceec9dca..d67f15bee3a 100644 --- a/lib/compiler/src/engine/tunables.rs +++ b/lib/compiler/src/engine/tunables.rs @@ -3,7 +3,7 @@ use std::ptr::NonNull; use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::{ GlobalType, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, - ModuleInfo, TableIndex, TableType, + ModuleInfo, Pages, PointerWidth, TableIndex, TableType, Target, }; use wasmer_vm::{InternalStoreHandle, MemoryError, StoreObjects}; use wasmer_vm::{MemoryStyle, TableStyle}; @@ -142,3 +142,128 @@ pub trait Tunables { Ok(vmctx_globals) } } + +/// Tunable parameters for WebAssembly compilation. +/// This is the reference implementation of the `Tunables` trait, +/// used by default. +/// +/// You can use this as a template for creating a custom Tunables +/// implementation or use composition to wrap your Tunables around +/// this one. The later approach is demonstrated in the +/// tunables-limit-memory example. +#[derive(Clone)] +pub struct BaseTunables { + /// For static heaps, the size in wasm pages of the heap protected by bounds checking. + pub static_memory_bound: Pages, + + /// The size in bytes of the offset guard for static heaps. + pub static_memory_offset_guard_size: u64, + + /// The size in bytes of the offset guard for dynamic heaps. + pub dynamic_memory_offset_guard_size: u64, +} + +impl BaseTunables { + /// Get the `BaseTunables` for a specific Target + pub fn for_target(target: &Target) -> Self { + let triple = target.triple(); + let pointer_width: PointerWidth = triple.pointer_width().unwrap(); + let (static_memory_bound, static_memory_offset_guard_size): (Pages, u64) = + match pointer_width { + PointerWidth::U16 => (0x400.into(), 0x1000), + PointerWidth::U32 => (0x4000.into(), 0x1_0000), + // Static Memory Bound: + // Allocating 4 GiB of address space let us avoid the + // need for explicit bounds checks. + // Static Memory Guard size: + // Allocating 2 GiB of address space lets us translate wasm + // offsets into x86 offsets as aggressively as we can. + PointerWidth::U64 => (0x1_0000.into(), 0x8000_0000), + }; + + // Allocate a small guard to optimize common cases but without + // wasting too much memory. + // The Windows memory manager seems more laxed than the other ones + // And a guard of just 1 page may not be enough is some borderline cases + // So using 2 pages for guard on this platform + #[cfg(target_os = "windows")] + let dynamic_memory_offset_guard_size: u64 = 0x2_0000; + #[cfg(not(target_os = "windows"))] + let dynamic_memory_offset_guard_size: u64 = 0x1_0000; + + Self { + static_memory_bound, + static_memory_offset_guard_size, + dynamic_memory_offset_guard_size, + } + } +} + +impl Tunables for BaseTunables { + /// Get a `MemoryStyle` for the provided `MemoryType` + fn memory_style(&self, memory: &MemoryType) -> MemoryStyle { + // A heap with a maximum that doesn't exceed the static memory bound specified by the + // tunables make it static. + // + // If the module doesn't declare an explicit maximum treat it as 4GiB. + let maximum = memory.maximum.unwrap_or_else(Pages::max_value); + if maximum <= self.static_memory_bound { + MemoryStyle::Static { + // Bound can be larger than the maximum for performance reasons + bound: self.static_memory_bound, + offset_guard_size: self.static_memory_offset_guard_size, + } + } else { + MemoryStyle::Dynamic { + offset_guard_size: self.dynamic_memory_offset_guard_size, + } + } + } + + /// Get a [`TableStyle`] for the provided [`TableType`]. + fn table_style(&self, _table: &TableType) -> TableStyle { + TableStyle::CallerChecksSignature + } + + /// Create a memory owned by the host given a [`MemoryType`] and a [`MemoryStyle`]. + fn create_host_memory( + &self, + ty: &MemoryType, + style: &MemoryStyle, + ) -> Result { + VMMemory::new(ty, style) + } + + /// Create a memory owned by the VM given a [`MemoryType`] and a [`MemoryStyle`]. + /// + /// # Safety + /// - `vm_definition_location` must point to a valid, owned `VMMemoryDefinition`, + /// for example in `VMContext`. + unsafe fn create_vm_memory( + &self, + ty: &MemoryType, + style: &MemoryStyle, + vm_definition_location: NonNull, + ) -> Result { + VMMemory::from_definition(ty, style, vm_definition_location) + } + + /// Create a table owned by the host given a [`TableType`] and a [`TableStyle`]. + fn create_host_table(&self, ty: &TableType, style: &TableStyle) -> Result { + VMTable::new(ty, style) + } + + /// Create a table owned by the VM given a [`TableType`] and a [`TableStyle`]. + /// + /// # Safety + /// - `vm_definition_location` must point to a valid, owned `VMTableDefinition`, + /// for example in `VMContext`. + unsafe fn create_vm_table( + &self, + ty: &TableType, + style: &TableStyle, + vm_definition_location: NonNull, + ) -> Result { + VMTable::from_definition(ty, style, vm_definition_location) + } +}