Remove some custom error types in Wasmtime (#5347)
* Remove some custom error types in Wasmtime These types are mostly cumbersome to work with nowadays that `anyhow` is used everywhere else. This commit removes `InstantiationError` and `SetupError` in favor of using `anyhow::Error` throughout. This can eventually culminate in creation of specific errors for embedders to downcast to but for now this should be general enough. * Fix Windows build
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -3643,7 +3643,6 @@ dependencies = [
|
|||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
"serde",
|
"serde",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"thiserror",
|
|
||||||
"wasmtime-environ",
|
"wasmtime-environ",
|
||||||
"wasmtime-jit-debug",
|
"wasmtime-jit-debug",
|
||||||
"wasmtime-jit-icache-coherence",
|
"wasmtime-jit-icache-coherence",
|
||||||
@@ -3687,7 +3686,6 @@ dependencies = [
|
|||||||
"paste",
|
"paste",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rustix",
|
"rustix",
|
||||||
"thiserror",
|
|
||||||
"wasmtime-asm-macros",
|
"wasmtime-asm-macros",
|
||||||
"wasmtime-environ",
|
"wasmtime-environ",
|
||||||
"wasmtime-fiber",
|
"wasmtime-fiber",
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ edition.workspace = true
|
|||||||
wasmtime-environ = { workspace = true }
|
wasmtime-environ = { workspace = true }
|
||||||
wasmtime-jit-debug = { workspace = true, features = ["perf_jitdump"], optional = true }
|
wasmtime-jit-debug = { workspace = true, features = ["perf_jitdump"], optional = true }
|
||||||
wasmtime-runtime = { workspace = true }
|
wasmtime-runtime = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
|
||||||
target-lexicon = { workspace = true }
|
target-lexicon = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
|
|||||||
@@ -14,39 +14,16 @@ use std::convert::TryFrom;
|
|||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
|
||||||
use wasmtime_environ::obj;
|
use wasmtime_environ::obj;
|
||||||
use wasmtime_environ::{
|
use wasmtime_environ::{
|
||||||
CompileError, DefinedFuncIndex, FuncIndex, FunctionLoc, MemoryInitialization, Module,
|
DefinedFuncIndex, FuncIndex, FunctionLoc, MemoryInitialization, Module, ModuleTranslation,
|
||||||
ModuleTranslation, PrimaryMap, SignatureIndex, StackMapInformation, Tunables, WasmFunctionInfo,
|
PrimaryMap, SignatureIndex, StackMapInformation, Tunables, WasmFunctionInfo,
|
||||||
};
|
};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
CompiledModuleId, CompiledModuleIdAllocator, GdbJitImageRegistration, InstantiationError,
|
CompiledModuleId, CompiledModuleIdAllocator, GdbJitImageRegistration, MmapVec, VMFunctionBody,
|
||||||
MmapVec, VMFunctionBody, VMTrampoline,
|
VMTrampoline,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An error condition while setting up a wasm instance, be it validation,
|
|
||||||
/// compilation, or instantiation.
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum SetupError {
|
|
||||||
/// The module did not pass validation.
|
|
||||||
#[error("Validation error: {0}")]
|
|
||||||
Validate(String),
|
|
||||||
|
|
||||||
/// A wasm translation error occurred.
|
|
||||||
#[error("WebAssembly failed to compile")]
|
|
||||||
Compile(#[from] CompileError),
|
|
||||||
|
|
||||||
/// Some runtime resource was unavailable or insufficient, or the start function
|
|
||||||
/// trapped.
|
|
||||||
#[error("Instantiation failed during setup")]
|
|
||||||
Instantiate(#[from] InstantiationError),
|
|
||||||
|
|
||||||
/// Debug information generation error occurred.
|
|
||||||
#[error("Debug information error")]
|
|
||||||
DebugInfo(#[from] anyhow::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Secondary in-memory results of compilation.
|
/// Secondary in-memory results of compilation.
|
||||||
///
|
///
|
||||||
/// This opaque structure can be optionally passed back to
|
/// This opaque structure can be optionally passed back to
|
||||||
@@ -446,7 +423,7 @@ impl CompiledModule {
|
|||||||
if self.meta.native_debug_info_present {
|
if self.meta.native_debug_info_present {
|
||||||
let text = self.text();
|
let text = self.text();
|
||||||
let bytes = create_gdbjit_image(self.mmap().to_vec(), (text.as_ptr(), text.len()))
|
let bytes = create_gdbjit_image(self.mmap().to_vec(), (text.as_ptr(), text.len()))
|
||||||
.map_err(SetupError::DebugInfo)?;
|
.context("failed to create jit image for gdb")?;
|
||||||
profiler.module_load(self, Some(&bytes));
|
profiler.module_load(self, Some(&bytes));
|
||||||
let reg = GdbJitImageRegistration::register(bytes);
|
let reg = GdbJitImageRegistration::register(bytes);
|
||||||
self.dbg_jit_registration = Some(reg);
|
self.dbg_jit_registration = Some(reg);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ mod unwind;
|
|||||||
|
|
||||||
pub use crate::code_memory::CodeMemory;
|
pub use crate::code_memory::CodeMemory;
|
||||||
pub use crate::instantiate::{
|
pub use crate::instantiate::{
|
||||||
subslice_range, CompiledModule, CompiledModuleInfo, ObjectBuilder, SetupError, SymbolizeContext,
|
subslice_range, CompiledModule, CompiledModuleInfo, ObjectBuilder, SymbolizeContext,
|
||||||
};
|
};
|
||||||
pub use demangling::*;
|
pub use demangling::*;
|
||||||
pub use profiling::*;
|
pub use profiling::*;
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ libc = { version = "0.2.112", default-features = false }
|
|||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
memoffset = "0.6.0"
|
memoffset = "0.6.0"
|
||||||
indexmap = "1.0.2"
|
indexmap = "1.0.2"
|
||||||
thiserror = { workspace = true }
|
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
rand = { version = "0.8.3", features = ['small_rng'] }
|
rand = { version = "0.8.3", features = ['small_rng'] }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#![cfg_attr(not(unix), allow(unused_imports, unused_variables))]
|
#![cfg_attr(not(unix), allow(unused_imports, unused_variables))]
|
||||||
|
|
||||||
use crate::InstantiationError;
|
|
||||||
use crate::MmapVec;
|
use crate::MmapVec;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
@@ -486,7 +485,7 @@ impl MemoryImageSlot {
|
|||||||
initial_size_bytes: usize,
|
initial_size_bytes: usize,
|
||||||
maybe_image: Option<&Arc<MemoryImage>>,
|
maybe_image: Option<&Arc<MemoryImage>>,
|
||||||
style: &MemoryStyle,
|
style: &MemoryStyle,
|
||||||
) -> Result<(), InstantiationError> {
|
) -> Result<()> {
|
||||||
assert!(!self.dirty);
|
assert!(!self.dirty);
|
||||||
assert!(initial_size_bytes <= self.static_size);
|
assert!(initial_size_bytes <= self.static_size);
|
||||||
|
|
||||||
@@ -499,16 +498,14 @@ impl MemoryImageSlot {
|
|||||||
// extent of the prior initialization image in order to preserve
|
// extent of the prior initialization image in order to preserve
|
||||||
// resident memory that might come before or after the image.
|
// resident memory that might come before or after the image.
|
||||||
if self.image.as_ref() != maybe_image {
|
if self.image.as_ref() != maybe_image {
|
||||||
self.remove_image()
|
self.remove_image()?;
|
||||||
.map_err(|e| InstantiationError::Resource(e.into()))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The next order of business is to ensure that `self.accessible` is
|
// The next order of business is to ensure that `self.accessible` is
|
||||||
// appropriate. First up is to grow the read/write portion of memory if
|
// appropriate. First up is to grow the read/write portion of memory if
|
||||||
// it's not large enough to accommodate `initial_size_bytes`.
|
// it's not large enough to accommodate `initial_size_bytes`.
|
||||||
if self.accessible < initial_size_bytes {
|
if self.accessible < initial_size_bytes {
|
||||||
self.set_protection(self.accessible..initial_size_bytes, true)
|
self.set_protection(self.accessible..initial_size_bytes, true)?;
|
||||||
.map_err(|e| InstantiationError::Resource(e.into()))?;
|
|
||||||
self.accessible = initial_size_bytes;
|
self.accessible = initial_size_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,8 +520,7 @@ impl MemoryImageSlot {
|
|||||||
if initial_size_bytes < self.accessible {
|
if initial_size_bytes < self.accessible {
|
||||||
match style {
|
match style {
|
||||||
MemoryStyle::Static { .. } => {
|
MemoryStyle::Static { .. } => {
|
||||||
self.set_protection(initial_size_bytes..self.accessible, false)
|
self.set_protection(initial_size_bytes..self.accessible, false)?;
|
||||||
.map_err(|e| InstantiationError::Resource(e.into()))?;
|
|
||||||
self.accessible = initial_size_bytes;
|
self.accessible = initial_size_bytes;
|
||||||
}
|
}
|
||||||
MemoryStyle::Dynamic { .. } => {}
|
MemoryStyle::Dynamic { .. } => {}
|
||||||
@@ -543,9 +539,7 @@ impl MemoryImageSlot {
|
|||||||
);
|
);
|
||||||
if image.len > 0 {
|
if image.len > 0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
image
|
image.map_at(self.base)?;
|
||||||
.map_at(self.base)
|
|
||||||
.map_err(|e| InstantiationError::Resource(e.into()))?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ use crate::instance::{Instance, InstanceHandle, RuntimeMemoryCreator};
|
|||||||
use crate::memory::{DefaultMemoryCreator, Memory};
|
use crate::memory::{DefaultMemoryCreator, Memory};
|
||||||
use crate::table::Table;
|
use crate::table::Table;
|
||||||
use crate::{CompiledModuleId, ModuleRuntimeInfo, Store};
|
use crate::{CompiledModuleId, ModuleRuntimeInfo, Store};
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, bail, Result};
|
||||||
use std::alloc;
|
use std::alloc;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
|
||||||
use wasmtime_environ::{
|
use wasmtime_environ::{
|
||||||
DefinedMemoryIndex, DefinedTableIndex, HostPtr, InitMemory, MemoryInitialization,
|
DefinedMemoryIndex, DefinedTableIndex, HostPtr, InitMemory, MemoryInitialization,
|
||||||
MemoryInitializer, Module, PrimaryMap, TableInitialization, TableInitializer, Trap, VMOffsets,
|
MemoryInitializer, Module, PrimaryMap, TableInitialization, TableInitializer, Trap, VMOffsets,
|
||||||
@@ -86,46 +85,6 @@ impl StorePtr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An link error while instantiating a module.
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
#[error("Link error: {0}")]
|
|
||||||
pub struct LinkError(pub String);
|
|
||||||
|
|
||||||
/// An error while instantiating a module.
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum InstantiationError {
|
|
||||||
/// Insufficient resources available for execution.
|
|
||||||
#[error("Insufficient resources: {0}")]
|
|
||||||
Resource(anyhow::Error),
|
|
||||||
|
|
||||||
/// A wasm link error occurred.
|
|
||||||
#[error("Failed to link module")]
|
|
||||||
Link(#[from] LinkError),
|
|
||||||
|
|
||||||
/// A trap ocurred during instantiation, after linking.
|
|
||||||
#[error("Trap occurred during instantiation")]
|
|
||||||
Trap(Trap),
|
|
||||||
|
|
||||||
/// A limit on how many instances are supported has been reached.
|
|
||||||
#[error("Limit of {0} concurrent instances has been reached")]
|
|
||||||
Limit(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An error while creating a fiber stack.
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum FiberStackError {
|
|
||||||
/// Insufficient resources available for the request.
|
|
||||||
#[error("Insufficient resources: {0}")]
|
|
||||||
Resource(anyhow::Error),
|
|
||||||
/// An error for when the allocator doesn't support fiber stacks.
|
|
||||||
#[error("fiber stacks are not supported by the allocator")]
|
|
||||||
NotSupported,
|
|
||||||
/// A limit on how many fibers are supported has been reached.
|
|
||||||
#[error("Limit of {0} concurrent fibers has been reached")]
|
|
||||||
Limit(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a runtime instance allocator.
|
/// Represents a runtime instance allocator.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@@ -151,10 +110,7 @@ pub unsafe trait InstanceAllocator: Send + Sync {
|
|||||||
///
|
///
|
||||||
/// This method is not inherently unsafe, but care must be made to ensure
|
/// This method is not inherently unsafe, but care must be made to ensure
|
||||||
/// pointers passed in the allocation request outlive the returned instance.
|
/// pointers passed in the allocation request outlive the returned instance.
|
||||||
unsafe fn allocate(
|
unsafe fn allocate(&self, req: InstanceAllocationRequest) -> Result<InstanceHandle>;
|
||||||
&self,
|
|
||||||
req: InstanceAllocationRequest,
|
|
||||||
) -> Result<InstanceHandle, InstantiationError>;
|
|
||||||
|
|
||||||
/// Finishes the instantiation process started by an instance allocator.
|
/// Finishes the instantiation process started by an instance allocator.
|
||||||
///
|
///
|
||||||
@@ -166,7 +122,7 @@ pub unsafe trait InstanceAllocator: Send + Sync {
|
|||||||
handle: &mut InstanceHandle,
|
handle: &mut InstanceHandle,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
is_bulk_memory: bool,
|
is_bulk_memory: bool,
|
||||||
) -> Result<(), InstantiationError>;
|
) -> Result<()>;
|
||||||
|
|
||||||
/// Deallocates a previously allocated instance.
|
/// Deallocates a previously allocated instance.
|
||||||
///
|
///
|
||||||
@@ -180,7 +136,7 @@ pub unsafe trait InstanceAllocator: Send + Sync {
|
|||||||
|
|
||||||
/// Allocates a fiber stack for calling async functions on.
|
/// Allocates a fiber stack for calling async functions on.
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack, FiberStackError>;
|
fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack>;
|
||||||
|
|
||||||
/// Deallocates a fiber stack that was previously allocated with `allocate_fiber_stack`.
|
/// Deallocates a fiber stack that was previously allocated with `allocate_fiber_stack`.
|
||||||
///
|
///
|
||||||
@@ -198,10 +154,7 @@ pub unsafe trait InstanceAllocator: Send + Sync {
|
|||||||
fn purge_module(&self, module: CompiledModuleId);
|
fn purge_module(&self, module: CompiledModuleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_table_init_start(
|
fn get_table_init_start(init: &TableInitializer, instance: &Instance) -> Result<u32> {
|
||||||
init: &TableInitializer,
|
|
||||||
instance: &Instance,
|
|
||||||
) -> Result<u32, InstantiationError> {
|
|
||||||
match init.base {
|
match init.base {
|
||||||
Some(base) => {
|
Some(base) => {
|
||||||
let val = unsafe {
|
let val = unsafe {
|
||||||
@@ -212,20 +165,15 @@ fn get_table_init_start(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
init.offset.checked_add(val).ok_or_else(|| {
|
init.offset
|
||||||
InstantiationError::Link(LinkError(
|
.checked_add(val)
|
||||||
"element segment global base overflows".to_owned(),
|
.ok_or_else(|| anyhow!("element segment global base overflows"))
|
||||||
))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
None => Ok(init.offset),
|
None => Ok(init.offset),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_table_init_bounds(
|
fn check_table_init_bounds(instance: &mut Instance, module: &Module) -> Result<()> {
|
||||||
instance: &mut Instance,
|
|
||||||
module: &Module,
|
|
||||||
) -> Result<(), InstantiationError> {
|
|
||||||
match &module.table_initialization {
|
match &module.table_initialization {
|
||||||
TableInitialization::FuncTable { segments, .. }
|
TableInitialization::FuncTable { segments, .. }
|
||||||
| TableInitialization::Segments { segments } => {
|
| TableInitialization::Segments { segments } => {
|
||||||
@@ -240,9 +188,7 @@ fn check_table_init_bounds(
|
|||||||
// Initializer is in bounds
|
// Initializer is in bounds
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(InstantiationError::Link(LinkError(
|
bail!("table out of bounds: elements segment does not fit")
|
||||||
"table out of bounds: elements segment does not fit".to_owned(),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,7 +198,7 @@ fn check_table_init_bounds(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_tables(instance: &mut Instance, module: &Module) -> Result<(), InstantiationError> {
|
fn initialize_tables(instance: &mut Instance, module: &Module) -> Result<()> {
|
||||||
// Note: if the module's table initializer state is in
|
// Note: if the module's table initializer state is in
|
||||||
// FuncTable mode, we will lazily initialize tables based on
|
// FuncTable mode, we will lazily initialize tables based on
|
||||||
// any statically-precomputed image of FuncIndexes, but there
|
// any statically-precomputed image of FuncIndexes, but there
|
||||||
@@ -264,15 +210,13 @@ fn initialize_tables(instance: &mut Instance, module: &Module) -> Result<(), Ins
|
|||||||
TableInitialization::FuncTable { segments, .. }
|
TableInitialization::FuncTable { segments, .. }
|
||||||
| TableInitialization::Segments { segments } => {
|
| TableInitialization::Segments { segments } => {
|
||||||
for segment in segments {
|
for segment in segments {
|
||||||
instance
|
instance.table_init_segment(
|
||||||
.table_init_segment(
|
segment.table_index,
|
||||||
segment.table_index,
|
&segment.elements,
|
||||||
&segment.elements,
|
get_table_init_start(segment, instance)?,
|
||||||
get_table_init_start(segment, instance)?,
|
0,
|
||||||
0,
|
segment.elements.len() as u32,
|
||||||
segment.elements.len() as u32,
|
)?;
|
||||||
)
|
|
||||||
.map_err(InstantiationError::Trap)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,10 +224,7 @@ fn initialize_tables(instance: &mut Instance, module: &Module) -> Result<(), Ins
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_memory_init_start(
|
fn get_memory_init_start(init: &MemoryInitializer, instance: &Instance) -> Result<u64> {
|
||||||
init: &MemoryInitializer,
|
|
||||||
instance: &Instance,
|
|
||||||
) -> Result<u64, InstantiationError> {
|
|
||||||
match init.base {
|
match init.base {
|
||||||
Some(base) => {
|
Some(base) => {
|
||||||
let mem64 = instance.module().memory_plans[init.memory_index]
|
let mem64 = instance.module().memory_plans[init.memory_index]
|
||||||
@@ -302,18 +243,15 @@ fn get_memory_init_start(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
init.offset.checked_add(val).ok_or_else(|| {
|
init.offset
|
||||||
InstantiationError::Link(LinkError("data segment global base overflows".to_owned()))
|
.checked_add(val)
|
||||||
})
|
.ok_or_else(|| anyhow!("data segment global base overflows"))
|
||||||
}
|
}
|
||||||
None => Ok(init.offset),
|
None => Ok(init.offset),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_memory_init_bounds(
|
fn check_memory_init_bounds(instance: &Instance, initializers: &[MemoryInitializer]) -> Result<()> {
|
||||||
instance: &Instance,
|
|
||||||
initializers: &[MemoryInitializer],
|
|
||||||
) -> Result<(), InstantiationError> {
|
|
||||||
for init in initializers {
|
for init in initializers {
|
||||||
let memory = instance.get_memory(init.memory_index);
|
let memory = instance.get_memory(init.memory_index);
|
||||||
let start = get_memory_init_start(init, instance)?;
|
let start = get_memory_init_start(init, instance)?;
|
||||||
@@ -326,9 +264,7 @@ fn check_memory_init_bounds(
|
|||||||
// Initializer is in bounds
|
// Initializer is in bounds
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(InstantiationError::Link(LinkError(
|
bail!("memory out of bounds: data segment does not fit")
|
||||||
"memory out of bounds: data segment does not fit".into(),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,7 +272,7 @@ fn check_memory_init_bounds(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_memories(instance: &mut Instance, module: &Module) -> Result<(), InstantiationError> {
|
fn initialize_memories(instance: &mut Instance, module: &Module) -> Result<()> {
|
||||||
let memory_size_in_pages =
|
let memory_size_in_pages =
|
||||||
&|memory| (instance.get_memory(memory).current_length() as u64) / u64::from(WASM_PAGE_SIZE);
|
&|memory| (instance.get_memory(memory).current_length() as u64) / u64::from(WASM_PAGE_SIZE);
|
||||||
|
|
||||||
@@ -392,13 +328,13 @@ fn initialize_memories(instance: &mut Instance, module: &Module) -> Result<(), I
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
if !ok {
|
if !ok {
|
||||||
return Err(InstantiationError::Trap(Trap::MemoryOutOfBounds));
|
return Err(Trap::MemoryOutOfBounds.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_init_bounds(instance: &mut Instance, module: &Module) -> Result<(), InstantiationError> {
|
fn check_init_bounds(instance: &mut Instance, module: &Module) -> Result<()> {
|
||||||
check_table_init_bounds(instance, module)?;
|
check_table_init_bounds(instance, module)?;
|
||||||
|
|
||||||
match &instance.module().memory_initialization {
|
match &instance.module().memory_initialization {
|
||||||
@@ -416,7 +352,7 @@ fn initialize_instance(
|
|||||||
instance: &mut Instance,
|
instance: &mut Instance,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
is_bulk_memory: bool,
|
is_bulk_memory: bool,
|
||||||
) -> Result<(), InstantiationError> {
|
) -> Result<()> {
|
||||||
// If bulk memory is not enabled, bounds check the data and element segments before
|
// If bulk memory is not enabled, bounds check the data and element segments before
|
||||||
// making any changes. With bulk memory enabled, initializers are processed
|
// making any changes. With bulk memory enabled, initializers are processed
|
||||||
// in-order and side effects are observed up to the point of an out-of-bounds
|
// in-order and side effects are observed up to the point of an out-of-bounds
|
||||||
@@ -456,20 +392,17 @@ impl OnDemandInstanceAllocator {
|
|||||||
fn create_tables(
|
fn create_tables(
|
||||||
store: &mut StorePtr,
|
store: &mut StorePtr,
|
||||||
runtime_info: &Arc<dyn ModuleRuntimeInfo>,
|
runtime_info: &Arc<dyn ModuleRuntimeInfo>,
|
||||||
) -> Result<PrimaryMap<DefinedTableIndex, Table>, InstantiationError> {
|
) -> Result<PrimaryMap<DefinedTableIndex, Table>> {
|
||||||
let module = runtime_info.module();
|
let module = runtime_info.module();
|
||||||
let num_imports = module.num_imported_tables;
|
let num_imports = module.num_imported_tables;
|
||||||
let mut tables: PrimaryMap<DefinedTableIndex, _> =
|
let mut tables: PrimaryMap<DefinedTableIndex, _> =
|
||||||
PrimaryMap::with_capacity(module.table_plans.len() - num_imports);
|
PrimaryMap::with_capacity(module.table_plans.len() - num_imports);
|
||||||
for (_, table) in module.table_plans.iter().skip(num_imports) {
|
for (_, table) in module.table_plans.iter().skip(num_imports) {
|
||||||
tables.push(
|
tables.push(Table::new_dynamic(table, unsafe {
|
||||||
Table::new_dynamic(table, unsafe {
|
store
|
||||||
store
|
.get()
|
||||||
.get()
|
.expect("if module has table plans, store is not empty")
|
||||||
.expect("if module has table plans, store is not empty")
|
})?);
|
||||||
})
|
|
||||||
.map_err(InstantiationError::Resource)?,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Ok(tables)
|
Ok(tables)
|
||||||
}
|
}
|
||||||
@@ -478,7 +411,7 @@ impl OnDemandInstanceAllocator {
|
|||||||
&self,
|
&self,
|
||||||
store: &mut StorePtr,
|
store: &mut StorePtr,
|
||||||
runtime_info: &Arc<dyn ModuleRuntimeInfo>,
|
runtime_info: &Arc<dyn ModuleRuntimeInfo>,
|
||||||
) -> Result<PrimaryMap<DefinedMemoryIndex, Memory>, InstantiationError> {
|
) -> Result<PrimaryMap<DefinedMemoryIndex, Memory>> {
|
||||||
let module = runtime_info.module();
|
let module = runtime_info.module();
|
||||||
let creator = self
|
let creator = self
|
||||||
.mem_creator
|
.mem_creator
|
||||||
@@ -491,23 +424,18 @@ impl OnDemandInstanceAllocator {
|
|||||||
let defined_memory_idx = module
|
let defined_memory_idx = module
|
||||||
.defined_memory_index(memory_idx)
|
.defined_memory_index(memory_idx)
|
||||||
.expect("Skipped imports, should never be None");
|
.expect("Skipped imports, should never be None");
|
||||||
let image = runtime_info
|
let image = runtime_info.memory_image(defined_memory_idx)?;
|
||||||
.memory_image(defined_memory_idx)
|
|
||||||
.map_err(|err| InstantiationError::Resource(err.into()))?;
|
|
||||||
|
|
||||||
memories.push(
|
memories.push(Memory::new_dynamic(
|
||||||
Memory::new_dynamic(
|
plan,
|
||||||
plan,
|
creator,
|
||||||
creator,
|
unsafe {
|
||||||
unsafe {
|
store
|
||||||
store
|
.get()
|
||||||
.get()
|
.expect("if module has memory plans, store is not empty")
|
||||||
.expect("if module has memory plans, store is not empty")
|
},
|
||||||
},
|
image,
|
||||||
image,
|
)?);
|
||||||
)
|
|
||||||
.map_err(InstantiationError::Resource)?,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Ok(memories)
|
Ok(memories)
|
||||||
}
|
}
|
||||||
@@ -532,7 +460,7 @@ impl Default for OnDemandInstanceAllocator {
|
|||||||
pub unsafe fn allocate_single_memory_instance(
|
pub unsafe fn allocate_single_memory_instance(
|
||||||
req: InstanceAllocationRequest,
|
req: InstanceAllocationRequest,
|
||||||
memory: Memory,
|
memory: Memory,
|
||||||
) -> Result<InstanceHandle, InstantiationError> {
|
) -> Result<InstanceHandle> {
|
||||||
let mut memories = PrimaryMap::default();
|
let mut memories = PrimaryMap::default();
|
||||||
memories.push(memory);
|
memories.push(memory);
|
||||||
let tables = PrimaryMap::default();
|
let tables = PrimaryMap::default();
|
||||||
@@ -554,10 +482,7 @@ pub unsafe fn deallocate(handle: &InstanceHandle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl InstanceAllocator for OnDemandInstanceAllocator {
|
unsafe impl InstanceAllocator for OnDemandInstanceAllocator {
|
||||||
unsafe fn allocate(
|
unsafe fn allocate(&self, mut req: InstanceAllocationRequest) -> Result<InstanceHandle> {
|
||||||
&self,
|
|
||||||
mut req: InstanceAllocationRequest,
|
|
||||||
) -> Result<InstanceHandle, InstantiationError> {
|
|
||||||
let memories = self.create_memories(&mut req.store, &req.runtime_info)?;
|
let memories = self.create_memories(&mut req.store, &req.runtime_info)?;
|
||||||
let tables = Self::create_tables(&mut req.store, &req.runtime_info)?;
|
let tables = Self::create_tables(&mut req.store, &req.runtime_info)?;
|
||||||
let module = req.runtime_info.module();
|
let module = req.runtime_info.module();
|
||||||
@@ -577,7 +502,7 @@ unsafe impl InstanceAllocator for OnDemandInstanceAllocator {
|
|||||||
handle: &mut InstanceHandle,
|
handle: &mut InstanceHandle,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
is_bulk_memory: bool,
|
is_bulk_memory: bool,
|
||||||
) -> Result<(), InstantiationError> {
|
) -> Result<()> {
|
||||||
initialize_instance(handle.instance_mut(), module, is_bulk_memory)
|
initialize_instance(handle.instance_mut(), module, is_bulk_memory)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,13 +511,13 @@ unsafe impl InstanceAllocator for OnDemandInstanceAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack, FiberStackError> {
|
fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack> {
|
||||||
if self.stack_size == 0 {
|
if self.stack_size == 0 {
|
||||||
return Err(FiberStackError::NotSupported);
|
bail!("fiber stacks are not supported by the allocator")
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmtime_fiber::FiberStack::new(self.stack_size)
|
let stack = wasmtime_fiber::FiberStack::new(self.stack_size)?;
|
||||||
.map_err(|e| FiberStackError::Resource(e.into()))
|
Ok(stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
|
|||||||
@@ -7,10 +7,7 @@
|
|||||||
//! Using the pooling instance allocator can speed up module instantiation
|
//! Using the pooling instance allocator can speed up module instantiation
|
||||||
//! when modules can be constrained based on configurable limits.
|
//! when modules can be constrained based on configurable limits.
|
||||||
|
|
||||||
use super::{
|
use super::{initialize_instance, InstanceAllocationRequest, InstanceAllocator, InstanceHandle};
|
||||||
initialize_instance, InstanceAllocationRequest, InstanceAllocator, InstanceHandle,
|
|
||||||
InstantiationError,
|
|
||||||
};
|
|
||||||
use crate::{instance::Instance, Memory, Mmap, Table};
|
use crate::{instance::Instance, Memory, Mmap, Table};
|
||||||
use crate::{CompiledModuleId, MemoryImageSlot, ModuleRuntimeInfo, Store};
|
use crate::{CompiledModuleId, MemoryImageSlot, ModuleRuntimeInfo, Store};
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
@@ -41,9 +38,6 @@ use imp::{commit_table_pages, decommit_table_pages};
|
|||||||
#[cfg(all(feature = "async", unix))]
|
#[cfg(all(feature = "async", unix))]
|
||||||
use imp::{commit_stack_pages, reset_stack_pages_to_zero};
|
use imp::{commit_stack_pages, reset_stack_pages_to_zero};
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
use super::FiberStackError;
|
|
||||||
|
|
||||||
fn round_up_to_pow2(n: usize, to: usize) -> usize {
|
fn round_up_to_pow2(n: usize, to: usize) -> usize {
|
||||||
debug_assert!(to > 0);
|
debug_assert!(to > 0);
|
||||||
debug_assert!(to.is_power_of_two());
|
debug_assert!(to.is_power_of_two());
|
||||||
@@ -167,7 +161,7 @@ impl InstancePool {
|
|||||||
&self,
|
&self,
|
||||||
instance_index: usize,
|
instance_index: usize,
|
||||||
req: InstanceAllocationRequest,
|
req: InstanceAllocationRequest,
|
||||||
) -> Result<InstanceHandle, InstantiationError> {
|
) -> Result<InstanceHandle> {
|
||||||
let module = req.runtime_info.module();
|
let module = req.runtime_info.module();
|
||||||
|
|
||||||
// Before doing anything else ensure that our instance slot is actually
|
// Before doing anything else ensure that our instance slot is actually
|
||||||
@@ -175,9 +169,7 @@ impl InstancePool {
|
|||||||
// If this fails then it's a configuration error at the `Engine` level
|
// If this fails then it's a configuration error at the `Engine` level
|
||||||
// from when this pooling allocator was created and that needs updating
|
// from when this pooling allocator was created and that needs updating
|
||||||
// if this is to succeed.
|
// if this is to succeed.
|
||||||
let offsets = self
|
let offsets = self.validate_instance_size(module)?;
|
||||||
.validate_instance_size(module)
|
|
||||||
.map_err(InstantiationError::Resource)?;
|
|
||||||
|
|
||||||
let mut memories =
|
let mut memories =
|
||||||
PrimaryMap::with_capacity(module.memory_plans.len() - module.num_imported_memories);
|
PrimaryMap::with_capacity(module.memory_plans.len() - module.num_imported_memories);
|
||||||
@@ -214,14 +206,16 @@ impl InstancePool {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate(
|
fn allocate(&self, req: InstanceAllocationRequest) -> Result<InstanceHandle> {
|
||||||
&self,
|
|
||||||
req: InstanceAllocationRequest,
|
|
||||||
) -> Result<InstanceHandle, InstantiationError> {
|
|
||||||
let id = self
|
let id = self
|
||||||
.index_allocator
|
.index_allocator
|
||||||
.alloc(req.runtime_info.unique_id())
|
.alloc(req.runtime_info.unique_id())
|
||||||
.ok_or_else(|| InstantiationError::Limit(self.max_instances as u32))?;
|
.ok_or_else(|| {
|
||||||
|
anyhow!(
|
||||||
|
"maximum concurrent instance limit of {} reached",
|
||||||
|
self.max_instances
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
match unsafe { self.initialize_instance(id.index(), req) } {
|
match unsafe { self.initialize_instance(id.index(), req) } {
|
||||||
Ok(handle) => Ok(handle),
|
Ok(handle) => Ok(handle),
|
||||||
@@ -271,7 +265,7 @@ impl InstancePool {
|
|||||||
store: Option<*mut dyn Store>,
|
store: Option<*mut dyn Store>,
|
||||||
memories: &mut PrimaryMap<DefinedMemoryIndex, Memory>,
|
memories: &mut PrimaryMap<DefinedMemoryIndex, Memory>,
|
||||||
tables: &mut PrimaryMap<DefinedTableIndex, Table>,
|
tables: &mut PrimaryMap<DefinedTableIndex, Table>,
|
||||||
) -> Result<(), InstantiationError> {
|
) -> Result<()> {
|
||||||
self.allocate_memories(instance_index, runtime_info, store, memories)?;
|
self.allocate_memories(instance_index, runtime_info, store, memories)?;
|
||||||
self.allocate_tables(instance_index, runtime_info, store, tables)?;
|
self.allocate_tables(instance_index, runtime_info, store, tables)?;
|
||||||
|
|
||||||
@@ -284,11 +278,10 @@ impl InstancePool {
|
|||||||
runtime_info: &dyn ModuleRuntimeInfo,
|
runtime_info: &dyn ModuleRuntimeInfo,
|
||||||
store: Option<*mut dyn Store>,
|
store: Option<*mut dyn Store>,
|
||||||
memories: &mut PrimaryMap<DefinedMemoryIndex, Memory>,
|
memories: &mut PrimaryMap<DefinedMemoryIndex, Memory>,
|
||||||
) -> Result<(), InstantiationError> {
|
) -> Result<()> {
|
||||||
let module = runtime_info.module();
|
let module = runtime_info.module();
|
||||||
|
|
||||||
self.validate_memory_plans(module)
|
self.validate_memory_plans(module)?;
|
||||||
.map_err(InstantiationError::Resource)?;
|
|
||||||
|
|
||||||
for (memory_index, plan) in module
|
for (memory_index, plan) in module
|
||||||
.memory_plans
|
.memory_plans
|
||||||
@@ -321,9 +314,7 @@ impl InstancePool {
|
|||||||
let mut slot = self
|
let mut slot = self
|
||||||
.memories
|
.memories
|
||||||
.take_memory_image_slot(instance_index, defined_index);
|
.take_memory_image_slot(instance_index, defined_index);
|
||||||
let image = runtime_info
|
let image = runtime_info.memory_image(defined_index)?;
|
||||||
.memory_image(defined_index)
|
|
||||||
.map_err(|err| InstantiationError::Resource(err.into()))?;
|
|
||||||
let initial_size = plan.memory.minimum * WASM_PAGE_SIZE as u64;
|
let initial_size = plan.memory.minimum * WASM_PAGE_SIZE as u64;
|
||||||
|
|
||||||
// If instantiation fails, we can propagate the error
|
// If instantiation fails, we can propagate the error
|
||||||
@@ -339,13 +330,11 @@ impl InstancePool {
|
|||||||
// the process to continue, because we never perform a
|
// the process to continue, because we never perform a
|
||||||
// mmap that would leave an open space for someone
|
// mmap that would leave an open space for someone
|
||||||
// else to come in and map something.
|
// else to come in and map something.
|
||||||
slot.instantiate(initial_size as usize, image, &plan.style)
|
slot.instantiate(initial_size as usize, image, &plan.style)?;
|
||||||
.map_err(|e| InstantiationError::Resource(e.into()))?;
|
|
||||||
|
|
||||||
memories.push(
|
memories.push(Memory::new_static(plan, memory, slot, unsafe {
|
||||||
Memory::new_static(plan, memory, slot, unsafe { &mut *store.unwrap() })
|
&mut *store.unwrap()
|
||||||
.map_err(InstantiationError::Resource)?,
|
})?);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -380,11 +369,10 @@ impl InstancePool {
|
|||||||
runtime_info: &dyn ModuleRuntimeInfo,
|
runtime_info: &dyn ModuleRuntimeInfo,
|
||||||
store: Option<*mut dyn Store>,
|
store: Option<*mut dyn Store>,
|
||||||
tables: &mut PrimaryMap<DefinedTableIndex, Table>,
|
tables: &mut PrimaryMap<DefinedTableIndex, Table>,
|
||||||
) -> Result<(), InstantiationError> {
|
) -> Result<()> {
|
||||||
let module = runtime_info.module();
|
let module = runtime_info.module();
|
||||||
|
|
||||||
self.validate_table_plans(module)
|
self.validate_table_plans(module)?;
|
||||||
.map_err(InstantiationError::Resource)?;
|
|
||||||
|
|
||||||
let mut bases = self.tables.get(instance_index);
|
let mut bases = self.tables.get(instance_index);
|
||||||
for (_, plan) in module.table_plans.iter().skip(module.num_imported_tables) {
|
for (_, plan) in module.table_plans.iter().skip(module.num_imported_tables) {
|
||||||
@@ -393,19 +381,13 @@ impl InstancePool {
|
|||||||
commit_table_pages(
|
commit_table_pages(
|
||||||
base as *mut u8,
|
base as *mut u8,
|
||||||
self.tables.max_elements as usize * mem::size_of::<*mut u8>(),
|
self.tables.max_elements as usize * mem::size_of::<*mut u8>(),
|
||||||
)
|
)?;
|
||||||
.map_err(InstantiationError::Resource)?;
|
|
||||||
|
|
||||||
tables.push(
|
tables.push(Table::new_static(
|
||||||
Table::new_static(
|
plan,
|
||||||
plan,
|
unsafe { std::slice::from_raw_parts_mut(base, self.tables.max_elements as usize) },
|
||||||
unsafe {
|
unsafe { &mut *store.unwrap() },
|
||||||
std::slice::from_raw_parts_mut(base, self.tables.max_elements as usize)
|
)?);
|
||||||
},
|
|
||||||
unsafe { &mut *store.unwrap() },
|
|
||||||
)
|
|
||||||
.map_err(InstantiationError::Resource)?,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -930,15 +912,20 @@ impl StackPool {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate(&self) -> Result<wasmtime_fiber::FiberStack, FiberStackError> {
|
fn allocate(&self) -> Result<wasmtime_fiber::FiberStack> {
|
||||||
if self.stack_size == 0 {
|
if self.stack_size == 0 {
|
||||||
return Err(FiberStackError::NotSupported);
|
bail!("pooling allocator not configured to enable fiber stack allocation");
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = self
|
let index = self
|
||||||
.index_allocator
|
.index_allocator
|
||||||
.alloc(None)
|
.alloc(None)
|
||||||
.ok_or(FiberStackError::Limit(self.max_instances as u32))?
|
.ok_or_else(|| {
|
||||||
|
anyhow!(
|
||||||
|
"maximum concurrent fiber limit of {} reached",
|
||||||
|
self.max_instances
|
||||||
|
)
|
||||||
|
})?
|
||||||
.index();
|
.index();
|
||||||
|
|
||||||
assert!(index < self.max_instances);
|
assert!(index < self.max_instances);
|
||||||
@@ -952,11 +939,11 @@ impl StackPool {
|
|||||||
.as_mut_ptr()
|
.as_mut_ptr()
|
||||||
.add((index * self.stack_size) + self.page_size);
|
.add((index * self.stack_size) + self.page_size);
|
||||||
|
|
||||||
commit_stack_pages(bottom_of_stack, size_without_guard)
|
commit_stack_pages(bottom_of_stack, size_without_guard)?;
|
||||||
.map_err(FiberStackError::Resource)?;
|
|
||||||
|
|
||||||
wasmtime_fiber::FiberStack::from_top_ptr(bottom_of_stack.add(size_without_guard))
|
let stack =
|
||||||
.map_err(|e| FiberStackError::Resource(e.into()))
|
wasmtime_fiber::FiberStack::from_top_ptr(bottom_of_stack.add(size_without_guard))?;
|
||||||
|
Ok(stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1106,10 +1093,7 @@ unsafe impl InstanceAllocator for PoolingInstanceAllocator {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn allocate(
|
unsafe fn allocate(&self, req: InstanceAllocationRequest) -> Result<InstanceHandle> {
|
||||||
&self,
|
|
||||||
req: InstanceAllocationRequest,
|
|
||||||
) -> Result<InstanceHandle, InstantiationError> {
|
|
||||||
self.instances.allocate(req)
|
self.instances.allocate(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1118,7 +1102,7 @@ unsafe impl InstanceAllocator for PoolingInstanceAllocator {
|
|||||||
handle: &mut InstanceHandle,
|
handle: &mut InstanceHandle,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
is_bulk_memory: bool,
|
is_bulk_memory: bool,
|
||||||
) -> Result<(), InstantiationError> {
|
) -> Result<()> {
|
||||||
let instance = handle.instance_mut();
|
let instance = handle.instance_mut();
|
||||||
initialize_instance(instance, module, is_bulk_memory)
|
initialize_instance(instance, module, is_bulk_memory)
|
||||||
}
|
}
|
||||||
@@ -1128,7 +1112,7 @@ unsafe impl InstanceAllocator for PoolingInstanceAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "async", unix))]
|
#[cfg(all(feature = "async", unix))]
|
||||||
fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack, FiberStackError> {
|
fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack> {
|
||||||
self.stacks.allocate()
|
self.stacks.allocate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1138,14 +1122,14 @@ unsafe impl InstanceAllocator for PoolingInstanceAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "async", windows))]
|
#[cfg(all(feature = "async", windows))]
|
||||||
fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack, FiberStackError> {
|
fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack> {
|
||||||
if self.stack_size == 0 {
|
if self.stack_size == 0 {
|
||||||
return Err(FiberStackError::NotSupported);
|
bail!("fiber stack allocation not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// On windows, we don't use a stack pool as we use the native fiber implementation
|
// On windows, we don't use a stack pool as we use the native fiber implementation
|
||||||
wasmtime_fiber::FiberStack::new(self.stack_size)
|
let stack = wasmtime_fiber::FiberStack::new(self.stack_size)?;
|
||||||
.map_err(|e| FiberStackError::Resource(e.into()))
|
Ok(stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "async", windows))]
|
#[cfg(all(feature = "async", windows))]
|
||||||
@@ -1269,7 +1253,7 @@ mod test {
|
|||||||
host_state: Box::new(()),
|
host_state: Box::new(()),
|
||||||
store: StorePtr::empty(),
|
store: StorePtr::empty(),
|
||||||
}) {
|
}) {
|
||||||
Err(InstantiationError::Limit(3)) => {}
|
Err(_) => {}
|
||||||
_ => panic!("unexpected error"),
|
_ => panic!("unexpected error"),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1414,10 +1398,7 @@ mod test {
|
|||||||
|
|
||||||
assert_eq!(pool.index_allocator.testing_freelist(), []);
|
assert_eq!(pool.index_allocator.testing_freelist(), []);
|
||||||
|
|
||||||
match pool.allocate().unwrap_err() {
|
pool.allocate().unwrap_err();
|
||||||
FiberStackError::Limit(10) => {}
|
|
||||||
_ => panic!("unexpected error"),
|
|
||||||
};
|
|
||||||
|
|
||||||
for stack in stacks {
|
for stack in stacks {
|
||||||
pool.deallocate(&stack);
|
pool.deallocate(&stack);
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ pub use crate::externref::*;
|
|||||||
pub use crate::imports::Imports;
|
pub use crate::imports::Imports;
|
||||||
pub use crate::instance::{
|
pub use crate::instance::{
|
||||||
allocate_single_memory_instance, InstanceAllocationRequest, InstanceAllocator, InstanceHandle,
|
allocate_single_memory_instance, InstanceAllocationRequest, InstanceAllocator, InstanceHandle,
|
||||||
InstantiationError, LinkError, OnDemandInstanceAllocator, StorePtr,
|
OnDemandInstanceAllocator, StorePtr,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "pooling-allocator")]
|
#[cfg(feature = "pooling-allocator")]
|
||||||
pub use crate::instance::{
|
pub use crate::instance::{
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ use crate::{
|
|||||||
AsContextMut, Engine, Export, Extern, Func, Global, Memory, Module, SharedMemory,
|
AsContextMut, Engine, Export, Extern, Func, Global, Memory, Module, SharedMemory,
|
||||||
StoreContextMut, Table, TypedFunc,
|
StoreContextMut, Table, TypedFunc,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, bail, Context, Error, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasmtime_environ::{EntityType, FuncIndex, GlobalIndex, MemoryIndex, PrimaryMap, TableIndex};
|
use wasmtime_environ::{EntityType, FuncIndex, GlobalIndex, MemoryIndex, PrimaryMap, TableIndex};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
Imports, InstanceAllocationRequest, InstantiationError, StorePtr, VMContext, VMFunctionBody,
|
Imports, InstanceAllocationRequest, StorePtr, VMContext, VMFunctionBody, VMFunctionImport,
|
||||||
VMFunctionImport, VMGlobalImport, VMMemoryImport, VMOpaqueContext, VMTableImport,
|
VMGlobalImport, VMMemoryImport, VMOpaqueContext, VMTableImport,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An instantiated WebAssembly module.
|
/// An instantiated WebAssembly module.
|
||||||
@@ -317,20 +317,11 @@ impl Instance {
|
|||||||
// items from this instance into other instances should be ok when
|
// items from this instance into other instances should be ok when
|
||||||
// those items are loaded and run we'll have all the metadata to
|
// those items are loaded and run we'll have all the metadata to
|
||||||
// look at them.
|
// look at them.
|
||||||
store
|
store.engine().allocator().initialize(
|
||||||
.engine()
|
&mut instance_handle,
|
||||||
.allocator()
|
compiled_module.module(),
|
||||||
.initialize(
|
store.engine().config().features.bulk_memory,
|
||||||
&mut instance_handle,
|
)?;
|
||||||
compiled_module.module(),
|
|
||||||
store.engine().config().features.bulk_memory,
|
|
||||||
)
|
|
||||||
.map_err(|e| -> Error {
|
|
||||||
match e {
|
|
||||||
InstantiationError::Trap(trap) => trap.into(),
|
|
||||||
other => other.into(),
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok((instance, compiled_module.module().start_func))
|
Ok((instance, compiled_module.module().start_func))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ use std::sync::Arc;
|
|||||||
use wasmtime_environ::{EntityIndex, MemoryPlan, MemoryStyle, Module, WASM_PAGE_SIZE};
|
use wasmtime_environ::{EntityIndex, MemoryPlan, MemoryStyle, Module, WASM_PAGE_SIZE};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
allocate_single_memory_instance, DefaultMemoryCreator, Imports, InstanceAllocationRequest,
|
allocate_single_memory_instance, DefaultMemoryCreator, Imports, InstanceAllocationRequest,
|
||||||
InstantiationError, Memory, MemoryImage, RuntimeLinearMemory, RuntimeMemoryCreator,
|
Memory, MemoryImage, RuntimeLinearMemory, RuntimeMemoryCreator, SharedMemory, StorePtr,
|
||||||
SharedMemory, StorePtr, VMMemoryDefinition,
|
VMMemoryDefinition,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Create a "frankenstein" instance with a single memory.
|
/// Create a "frankenstein" instance with a single memory.
|
||||||
@@ -48,8 +48,7 @@ pub fn create_memory(
|
|||||||
.as_mut()
|
.as_mut()
|
||||||
.expect("the store pointer cannot be null here")
|
.expect("the store pointer cannot be null here")
|
||||||
};
|
};
|
||||||
Memory::new_dynamic(&plan, creator, store, None)
|
Memory::new_dynamic(&plan, creator, store, None)?
|
||||||
.map_err(|err| InstantiationError::Resource(err.into()))?
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ fn test_initial_memory_limits_exceeded() -> Result<()> {
|
|||||||
Ok(_) => unreachable!(),
|
Ok(_) => unreachable!(),
|
||||||
Err(e) => assert_eq!(
|
Err(e) => assert_eq!(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
"Insufficient resources: memory minimum size of 11 pages exceeds memory limits"
|
"memory minimum size of 11 pages exceeds memory limits"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ fn test_initial_memory_limits_exceeded() -> Result<()> {
|
|||||||
Ok(_) => unreachable!(),
|
Ok(_) => unreachable!(),
|
||||||
Err(e) => assert_eq!(
|
Err(e) => assert_eq!(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
"Insufficient resources: memory minimum size of 25 pages exceeds memory limits"
|
"memory minimum size of 25 pages exceeds memory limits"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,7 +329,7 @@ fn test_initial_table_limits_exceeded() -> Result<()> {
|
|||||||
Ok(_) => unreachable!(),
|
Ok(_) => unreachable!(),
|
||||||
Err(e) => assert_eq!(
|
Err(e) => assert_eq!(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
"Insufficient resources: table minimum size of 23 elements exceeds table limits"
|
"table minimum size of 23 elements exceeds table limits"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,7 +341,7 @@ fn test_initial_table_limits_exceeded() -> Result<()> {
|
|||||||
Ok(_) => unreachable!(),
|
Ok(_) => unreachable!(),
|
||||||
Err(e) => assert_eq!(
|
Err(e) => assert_eq!(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
"Insufficient resources: table minimum size of 99 elements exceeds table limits"
|
"table minimum size of 99 elements exceeds table limits"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,7 +374,7 @@ fn test_pooling_allocator_initial_limits_exceeded() -> Result<()> {
|
|||||||
Ok(_) => unreachable!(),
|
Ok(_) => unreachable!(),
|
||||||
Err(e) => assert_eq!(
|
Err(e) => assert_eq!(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
"Insufficient resources: memory minimum size of 5 pages exceeds memory limits"
|
"memory minimum size of 5 pages exceeds memory limits"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ fn instantiation_limit() -> Result<()> {
|
|||||||
Err(e) => assert_eq!(
|
Err(e) => assert_eq!(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
format!(
|
format!(
|
||||||
"Limit of {} concurrent instances has been reached",
|
"maximum concurrent instance limit of {} reached",
|
||||||
INSTANCE_LIMIT
|
INSTANCE_LIMIT
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user