More feedback changes.

* Don't reexport types from `wasmtime_runtime` from the `wasmtime` crate.
* Add more comments.
This commit is contained in:
Peter Huene
2021-03-04 22:27:27 -08:00
parent ff840b3d3b
commit a4084db096
3 changed files with 241 additions and 53 deletions

View File

@@ -381,7 +381,11 @@ impl Instance {
/// Returns `None` if memory can't be grown by the specified amount /// Returns `None` if memory can't be grown by the specified amount
/// of pages. /// of pages.
pub(crate) fn memory_grow(&self, memory_index: DefinedMemoryIndex, delta: u32) -> Option<u32> { pub(crate) fn memory_grow(&self, memory_index: DefinedMemoryIndex, delta: u32) -> Option<u32> {
// Reset all guard pages before growing any memory // Reset all guard pages before growing any memory when using the uffd feature.
// The uffd feature induces a trap when a fault on a linear memory page is determined to be out-of-bounds.
// It does this by temporarily setting the protection level to `NONE` to cause the kernel to signal SIGBUS.
// Because instances might still be used after a trap, this resets the page back to the expected protection
// level (READ_WRITE) for the uffd implementation.
#[cfg(all(feature = "uffd", target_os = "linux"))] #[cfg(all(feature = "uffd", target_os = "linux"))]
self.reset_guard_pages().ok()?; self.reset_guard_pages().ok()?;

View File

@@ -55,53 +55,37 @@ fn round_up_to_pow2(n: usize, to: usize) -> usize {
/// Represents the limits placed on a module for compiling with the pooling instance allocator. /// Represents the limits placed on a module for compiling with the pooling instance allocator.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct ModuleLimits { pub struct ModuleLimits {
/// The maximum number of imported functions for a module (default is 1000). /// The maximum number of imported functions for a module.
pub imported_functions: u32, pub imported_functions: u32,
/// The maximum number of imported tables for a module (default is 0). /// The maximum number of imported tables for a module.
pub imported_tables: u32, pub imported_tables: u32,
/// The maximum number of imported linear memories for a module (default is 0). /// The maximum number of imported linear memories for a module.
pub imported_memories: u32, pub imported_memories: u32,
/// The maximum number of imported globals for a module (default is 0). /// The maximum number of imported globals for a module.
pub imported_globals: u32, pub imported_globals: u32,
/// The maximum number of defined types for a module (default is 100). /// The maximum number of defined types for a module.
pub types: u32, pub types: u32,
/// The maximum number of defined functions for a module (default is 10000). /// The maximum number of defined functions for a module.
pub functions: u32, pub functions: u32,
/// The maximum number of defined tables for a module (default is 1). /// The maximum number of defined tables for a module.
pub tables: u32, pub tables: u32,
/// The maximum number of defined linear memories for a module (default is 1). /// The maximum number of defined linear memories for a module.
pub memories: u32, pub memories: u32,
/// The maximum number of defined globals for a module (default is 10). /// The maximum number of defined globals for a module.
pub globals: u32, pub globals: u32,
/// The maximum table elements for any table defined in a module (default is 10000). /// The maximum table elements for any table defined in a module.
///
/// If a table's minimum element limit is greater than this value, the module will
/// fail to compile.
///
/// If a table's maximum element limit is unbounded or greater than this value,
/// the maximum will be `table_elements` for the purpose of any `table.grow` instruction.
pub table_elements: u32, pub table_elements: u32,
/// The maximum number of pages for any linear memory defined in a module (default is 160). /// The maximum number of pages for any linear memory defined in a module.
///
/// The default of 160 means at most 10 MiB of host memory may be committed for each instance.
///
/// If a memory's minimum page limit is greater than this value, the module will
/// fail to compile.
///
/// If a memory's maximum page limit is unbounded or greater than this value,
/// the maximum will be `memory_pages` for the purpose of any `memory.grow` instruction.
///
/// This value cannot exceed any memory reservation size limits placed on instances.
pub memory_pages: u32, pub memory_pages: u32,
} }
@@ -224,7 +208,7 @@ impl ModuleLimits {
impl Default for ModuleLimits { impl Default for ModuleLimits {
fn default() -> Self { fn default() -> Self {
// See doc comments for `ModuleLimits` for these default values // See doc comments for `wasmtime::ModuleLimits` for these default values
Self { Self {
imported_functions: 1000, imported_functions: 1000,
imported_tables: 0, imported_tables: 0,
@@ -244,32 +228,16 @@ impl Default for ModuleLimits {
/// Represents the limits placed on instances by the pooling instance allocator. /// Represents the limits placed on instances by the pooling instance allocator.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct InstanceLimits { pub struct InstanceLimits {
/// The maximum number of concurrent instances supported (default is 1000). /// The maximum number of concurrent instances supported.
pub count: u32, pub count: u32,
/// The maximum size, in bytes, of host address space to reserve for each linear memory of an instance. /// The maximum size, in bytes, of host address space to reserve for each linear memory of an instance.
///
/// Note: this value has important performance ramifications.
///
/// On 64-bit platforms, the default for this value will be 6 GiB. A value of less than 4 GiB will
/// force runtime bounds checking for memory accesses and thus will negatively impact performance.
/// Any value above 4 GiB will start eliding bounds checks provided the `offset` of the memory access is
/// less than (`memory_reservation_size` - 4 GiB). A value of 8 GiB will completely elide *all* bounds
/// checks; consequently, 8 GiB will be the maximum supported value. The default of 6 GiB reserves
/// less host address space for each instance, but a memory access with an offet above 2 GiB will incur
/// runtime bounds checks.
///
/// On 32-bit platforms, the default for this value will be 10 MiB. A 32-bit host has very limited address
/// space to reserve for a lot of concurrent instances. As a result, runtime bounds checking will be used
/// for all memory accesses. For better runtime performance, a 64-bit host is recommended.
///
/// This value will be rounded up by the WebAssembly page size (64 KiB).
pub memory_reservation_size: u64, pub memory_reservation_size: u64,
} }
impl Default for InstanceLimits { impl Default for InstanceLimits {
fn default() -> Self { fn default() -> Self {
// See doc comments for `InstanceLimits` for these default values // See doc comments for `wasmtime::InstanceLimits` for these default values
Self { Self {
count: 1000, count: 1000,
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]

View File

@@ -16,8 +16,213 @@ use wasmtime_jit::{native, CompilationStrategy, Compiler};
use wasmtime_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent, VTuneAgent}; use wasmtime_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent, VTuneAgent};
use wasmtime_runtime::{InstanceAllocator, OnDemandInstanceAllocator, PoolingInstanceAllocator}; use wasmtime_runtime::{InstanceAllocator, OnDemandInstanceAllocator, PoolingInstanceAllocator};
// Re-export the limit structures for the pooling allocator /// Represents the limits placed on a module for compiling with the pooling instance allocation strategy.
pub use wasmtime_runtime::{InstanceLimits, ModuleLimits, PoolingAllocationStrategy}; #[derive(Debug, Copy, Clone)]
pub struct ModuleLimits {
/// The maximum number of imported functions for a module (default is 1000).
pub imported_functions: u32,
/// The maximum number of imported tables for a module (default is 0).
pub imported_tables: u32,
/// The maximum number of imported linear memories for a module (default is 0).
pub imported_memories: u32,
/// The maximum number of imported globals for a module (default is 0).
pub imported_globals: u32,
/// The maximum number of defined types for a module (default is 100).
pub types: u32,
/// The maximum number of defined functions for a module (default is 10000).
pub functions: u32,
/// The maximum number of defined tables for a module (default is 1).
pub tables: u32,
/// The maximum number of defined linear memories for a module (default is 1).
pub memories: u32,
/// The maximum number of defined globals for a module (default is 10).
pub globals: u32,
/// The maximum table elements for any table defined in a module (default is 10000).
///
/// If a table's minimum element limit is greater than this value, the module will
/// fail to compile.
///
/// If a table's maximum element limit is unbounded or greater than this value,
/// the maximum will be `table_elements` for the purpose of any `table.grow` instruction.
pub table_elements: u32,
/// The maximum number of pages for any linear memory defined in a module (default is 160).
///
/// The default of 160 means at most 10 MiB of host memory may be committed for each instance.
///
/// If a memory's minimum page limit is greater than this value, the module will
/// fail to compile.
///
/// If a memory's maximum page limit is unbounded or greater than this value,
/// the maximum will be `memory_pages` for the purpose of any `memory.grow` instruction.
///
/// This value cannot exceed any memory reservation size limits placed on instances.
pub memory_pages: u32,
}
impl Default for ModuleLimits {
fn default() -> Self {
// Use the defaults from the runtime
let wasmtime_runtime::ModuleLimits {
imported_functions,
imported_tables,
imported_memories,
imported_globals,
types,
functions,
tables,
memories,
globals,
table_elements,
memory_pages,
} = wasmtime_runtime::ModuleLimits::default();
Self {
imported_functions,
imported_tables,
imported_memories,
imported_globals,
types,
functions,
tables,
memories,
globals,
table_elements,
memory_pages,
}
}
}
// This exists so we can convert between the public Wasmtime API and the runtime representation
// without having to export runtime types from the Wasmtime API.
#[doc(hidden)]
impl Into<wasmtime_runtime::ModuleLimits> for ModuleLimits {
fn into(self) -> wasmtime_runtime::ModuleLimits {
let Self {
imported_functions,
imported_tables,
imported_memories,
imported_globals,
types,
functions,
tables,
memories,
globals,
table_elements,
memory_pages,
} = self;
wasmtime_runtime::ModuleLimits {
imported_functions,
imported_tables,
imported_memories,
imported_globals,
types,
functions,
tables,
memories,
globals,
table_elements,
memory_pages,
}
}
}
/// Represents the limits placed on instances by the pooling instance allocation strategy.
#[derive(Debug, Copy, Clone)]
pub struct InstanceLimits {
/// The maximum number of concurrent instances supported (default is 1000).
pub count: u32,
/// The maximum size, in bytes, of host address space to reserve for each linear memory of an instance.
///
/// Note: this value has important performance ramifications.
///
/// On 64-bit platforms, the default for this value will be 6 GiB. A value of less than 4 GiB will
/// force runtime bounds checking for memory accesses and thus will negatively impact performance.
/// Any value above 4 GiB will start eliding bounds checks provided the `offset` of the memory access is
/// less than (`memory_reservation_size` - 4 GiB). A value of 8 GiB will completely elide *all* bounds
/// checks; consequently, 8 GiB will be the maximum supported value. The default of 6 GiB reserves
/// less host address space for each instance, but a memory access with an offset above 2 GiB will incur
/// runtime bounds checks.
///
/// On 32-bit platforms, the default for this value will be 10 MiB. A 32-bit host has very limited address
/// space to reserve for a lot of concurrent instances. As a result, runtime bounds checking will be used
/// for all memory accesses. For better runtime performance, a 64-bit host is recommended.
///
/// This value will be rounded up by the WebAssembly page size (64 KiB).
pub memory_reservation_size: u64,
}
impl Default for InstanceLimits {
fn default() -> Self {
let wasmtime_runtime::InstanceLimits {
count,
memory_reservation_size,
} = wasmtime_runtime::InstanceLimits::default();
Self {
count,
memory_reservation_size,
}
}
}
// This exists so we can convert between the public Wasmtime API and the runtime representation
// without having to export runtime types from the Wasmtime API.
#[doc(hidden)]
impl Into<wasmtime_runtime::InstanceLimits> for InstanceLimits {
fn into(self) -> wasmtime_runtime::InstanceLimits {
let Self {
count,
memory_reservation_size,
} = self;
wasmtime_runtime::InstanceLimits {
count,
memory_reservation_size,
}
}
}
/// The allocation strategy to use for the pooling instance allocation strategy.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PoolingAllocationStrategy {
/// Allocate from the next available instance.
NextAvailable,
/// Allocate from a random available instance.
Random,
}
impl Default for PoolingAllocationStrategy {
fn default() -> Self {
match wasmtime_runtime::PoolingAllocationStrategy::default() {
wasmtime_runtime::PoolingAllocationStrategy::NextAvailable => Self::NextAvailable,
wasmtime_runtime::PoolingAllocationStrategy::Random => Self::Random,
}
}
}
// This exists so we can convert between the public Wasmtime API and the runtime representation
// without having to export runtime types from the Wasmtime API.
#[doc(hidden)]
impl Into<wasmtime_runtime::PoolingAllocationStrategy> for PoolingAllocationStrategy {
fn into(self) -> wasmtime_runtime::PoolingAllocationStrategy {
match self {
Self::NextAvailable => wasmtime_runtime::PoolingAllocationStrategy::NextAvailable,
Self::Random => wasmtime_runtime::PoolingAllocationStrategy::Random,
}
}
}
/// Represents the module instance allocation strategy to use. /// Represents the module instance allocation strategy to use.
#[derive(Clone)] #[derive(Clone)]
@@ -44,6 +249,17 @@ pub enum InstanceAllocationStrategy {
}, },
} }
impl InstanceAllocationStrategy {
/// The default pooling instance allocation strategy.
pub fn pooling() -> Self {
Self::Pooling {
strategy: PoolingAllocationStrategy::default(),
module_limits: ModuleLimits::default(),
instance_limits: InstanceLimits::default(),
}
}
}
impl Default for InstanceAllocationStrategy { impl Default for InstanceAllocationStrategy {
fn default() -> Self { fn default() -> Self {
Self::OnDemand Self::OnDemand
@@ -66,7 +282,7 @@ pub struct Config {
pub(crate) profiler: Arc<dyn ProfilingAgent>, pub(crate) profiler: Arc<dyn ProfilingAgent>,
pub(crate) instance_allocator: Option<Arc<dyn InstanceAllocator>>, pub(crate) instance_allocator: Option<Arc<dyn InstanceAllocator>>,
// The default instance allocator is used for instantiating host objects // The default instance allocator is used for instantiating host objects
// and for module instatiation when `instance_allocator` is None // and for module instantiation when `instance_allocator` is None
pub(crate) default_instance_allocator: OnDemandInstanceAllocator, pub(crate) default_instance_allocator: OnDemandInstanceAllocator,
pub(crate) max_wasm_stack: usize, pub(crate) max_wasm_stack: usize,
pub(crate) features: WasmFeatures, pub(crate) features: WasmFeatures,
@@ -628,9 +844,9 @@ impl Config {
let stack_size = 0; let stack_size = 0;
Some(Arc::new(PoolingInstanceAllocator::new( Some(Arc::new(PoolingInstanceAllocator::new(
strategy, strategy.into(),
module_limits, module_limits.into(),
instance_limits, instance_limits.into(),
stack_size, stack_size,
)?)) )?))
} }