Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option for host managed memory #1400

Merged
merged 12 commits into from Apr 6, 2020
1 change: 1 addition & 0 deletions crates/api/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ fn instantiate(
config.validating_config.operator_config.enable_bulk_memory,
&mut resolver,
sig_registry,
config.allocator.as_ref().map(|a| &**a),
)
.map_err(|e| -> Error {
match e {
Expand Down
14 changes: 14 additions & 0 deletions crates/api/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use wasmtime_environ::settings::{self, Configurable};
use wasmtime_environ::CacheConfig;
use wasmtime_jit::{native, CompilationStrategy, Compiler};
use wasmtime_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent};
use wasmtime_runtime::Allocator;

// Runtime Environment

Expand All @@ -27,6 +28,7 @@ pub struct Config {
pub(crate) strategy: CompilationStrategy,
pub(crate) cache_config: CacheConfig,
pub(crate) profiler: Arc<dyn ProfilingAgent>,
pub(crate) allocator: Option<Arc<dyn Allocator>>,
}

impl Config {
Expand Down Expand Up @@ -66,6 +68,7 @@ impl Config {
strategy: CompilationStrategy::Auto,
cache_config: CacheConfig::new_cache_disabled(),
profiler: Arc::new(NullProfilerAgent),
allocator: None,
}
}

Expand Down Expand Up @@ -309,6 +312,12 @@ impl Config {
self.cache_config = wasmtime_environ::CacheConfig::from_file(None)?;
Ok(self)
}

/// Sets a custom memory allocator
pub fn with_host_memory(&mut self, allocator: Arc<dyn Allocator>) -> &mut Self {
alexcrichton marked this conversation as resolved.
Show resolved Hide resolved
self.allocator = Some(allocator);
self
}
}

impl Default for Config {
Expand Down Expand Up @@ -486,6 +495,11 @@ impl Store {
&self.inner.engine
}

/// Returns an optional reference to a memory ['Allocator']
pub(crate) fn allocator(&self) -> Option<&dyn Allocator> {
self.engine().config.allocator.as_ref().map(|a| &**a)
}

pub(crate) fn compiler(&self) -> std::cell::Ref<'_, Compiler> {
self.inner.compiler.borrow()
}
Expand Down
1 change: 1 addition & 0 deletions crates/api/src/trampoline/create_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub(crate) fn create_handle(
finished_functions.into_boxed_slice(),
trampolines,
imports,
store.allocator(),
&data_initializers,
signatures.into_boxed_slice(),
None,
Expand Down
6 changes: 5 additions & 1 deletion crates/jit/src/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use wasmtime_environ::{
};
use wasmtime_profiling::ProfilingAgent;
use wasmtime_runtime::{
GdbJitImageRegistration, InstanceHandle, InstantiationError, SignatureRegistry,
Allocator, GdbJitImageRegistration, InstanceHandle, InstantiationError, SignatureRegistry,
TrapRegistration, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline,
};

Expand Down Expand Up @@ -203,6 +203,7 @@ impl CompiledModule {
is_bulk_memory: bool,
resolver: &mut dyn Resolver,
sig_registry: &SignatureRegistry,
allocator: Option<&dyn Allocator>,
) -> Result<InstanceHandle, InstantiationError> {
let data_initializers = self
.data_initializers
Expand All @@ -219,6 +220,7 @@ impl CompiledModule {
self.finished_functions.clone(),
self.trampolines.clone(),
imports,
allocator,
&data_initializers,
self.signatures.clone(),
self.dbg_jit_registration.as_ref().map(|r| Rc::clone(&r)),
Expand Down Expand Up @@ -283,11 +285,13 @@ pub unsafe fn instantiate(
debug_info: bool,
is_bulk_memory: bool,
profiler: &dyn ProfilingAgent,
allocator: Option<&dyn Allocator>,
) -> Result<InstanceHandle, SetupError> {
let instance = CompiledModule::new(compiler, data, debug_info, profiler)?.instantiate(
is_bulk_memory,
resolver,
compiler.signatures(),
allocator,
)?;
Ok(instance)
}
19 changes: 13 additions & 6 deletions crates/runtime/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use crate::export::Export;
use crate::imports::Imports;
use crate::jit_int::GdbJitImageRegistration;
use crate::memory::LinearMemory;
use crate::memory::{Allocator, DefaultAllocator, LinearMemory};
use crate::table::Table;
use crate::traphandlers;
use crate::traphandlers::{catch_traps, Trap};
Expand Down Expand Up @@ -82,7 +82,7 @@ pub(crate) struct Instance {
offsets: VMOffsets,

/// WebAssembly linear memory data.
memories: BoxedSlice<DefinedMemoryIndex, LinearMemory>,
memories: BoxedSlice<DefinedMemoryIndex, Box<dyn LinearMemory>>,

/// WebAssembly table data.
tables: BoxedSlice<DefinedTableIndex, Table>,
Expand Down Expand Up @@ -861,14 +861,16 @@ impl InstanceHandle {
finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
imports: Imports,
allocator: Option<&dyn Allocator>,
data_initializers: &[DataInitializer<'_>],
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
dbg_jit_registration: Option<Rc<GdbJitImageRegistration>>,
is_bulk_memory: bool,
host_state: Box<dyn Any>,
) -> Result<Self, InstantiationError> {
let tables = create_tables(&module);
let memories = create_memories(&module)?;

let memories = create_memories(&module, allocator.unwrap_or(&DefaultAllocator {}))?;

let vmctx_tables = tables
.values()
Expand All @@ -878,7 +880,7 @@ impl InstanceHandle {

let vmctx_memories = memories
.values()
.map(LinearMemory::vmmemory)
.map(|a| a.vmmemory())
.collect::<PrimaryMap<DefinedMemoryIndex, _>>()
.into_boxed_slice();

Expand Down Expand Up @@ -1300,12 +1302,17 @@ fn initialize_passive_elements(instance: &Instance) {
/// Allocate memory for just the memories of the current module.
fn create_memories(
module: &Module,
) -> Result<BoxedSlice<DefinedMemoryIndex, LinearMemory>, InstantiationError> {
allocator: &dyn Allocator,
) -> Result<BoxedSlice<DefinedMemoryIndex, Box<dyn LinearMemory>>, InstantiationError> {
let num_imports = module.imported_memories.len();
let mut memories: PrimaryMap<DefinedMemoryIndex, _> =
PrimaryMap::with_capacity(module.local.memory_plans.len() - num_imports);
for plan in &module.local.memory_plans.values().as_slice()[num_imports..] {
memories.push(LinearMemory::new(plan).map_err(InstantiationError::Resource)?);
memories.push(
allocator
.new_memory(plan)
.map_err(InstantiationError::Resource)?,
);
}
Ok(memories.into_boxed_slice())
}
Expand Down
1 change: 1 addition & 0 deletions crates/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub use crate::export::*;
pub use crate::imports::Imports;
pub use crate::instance::{InstanceHandle, InstantiationError, LinkError};
pub use crate::jit_int::GdbJitImageRegistration;
pub use crate::memory::{Allocator, LinearMemory};
pub use crate::mmap::Mmap;
pub use crate::sig_registry::SignatureRegistry;
pub use crate::table::Table;
Expand Down
41 changes: 36 additions & 5 deletions crates/runtime/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,38 @@ use std::cell::RefCell;
use std::convert::TryFrom;
use wasmtime_environ::{MemoryPlan, MemoryStyle, WASM_MAX_PAGES, WASM_PAGE_SIZE};

/// A memory allocator
pub trait Allocator: Send + Sync {
alexcrichton marked this conversation as resolved.
Show resolved Hide resolved
/// Create new LinearMemory
fn new_memory(&self, plan: &MemoryPlan) -> Result<Box<dyn LinearMemory>, String>;
}

/// A default memory allocator used by Wasmtime
pub struct DefaultAllocator;

impl Allocator for DefaultAllocator {
alexcrichton marked this conversation as resolved.
Show resolved Hide resolved
/// Create new MmapMemory
fn new_memory(&self, plan: &MemoryPlan) -> Result<Box<dyn LinearMemory>, String> {
Ok(Box::new(MmapMemory::new(plan)?) as Box<dyn LinearMemory>)
}
}

/// A linear memory
pub trait LinearMemory {
alexcrichton marked this conversation as resolved.
Show resolved Hide resolved
/// Returns the number of allocated wasm pages.
fn size(&self) -> u32;
/// Grow memory by the specified amount of wasm pages.
///
/// Returns `None` if memory can't be grown by the specified amount
/// of wasm pages.
fn grow(&self, delta: u32) -> Option<u32>;
/// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code.
fn vmmemory(&self) -> VMMemoryDefinition;
}

/// A linear memory instance.
#[derive(Debug)]
pub struct LinearMemory {
pub struct MmapMemory {
// The underlying allocation.
mmap: RefCell<WasmMmap>,

Expand All @@ -35,7 +64,7 @@ struct WasmMmap {
size: u32,
}

impl LinearMemory {
impl MmapMemory {
/// Create a new linear memory instance with specified minimum and maximum number of wasm pages.
pub fn new(plan: &MemoryPlan) -> Result<Self, String> {
// `maximum` cannot be set to more than `65536` pages.
Expand Down Expand Up @@ -77,17 +106,19 @@ impl LinearMemory {
needs_signal_handlers,
})
}
}

impl LinearMemory for MmapMemory {
/// Returns the number of allocated wasm pages.
pub fn size(&self) -> u32 {
fn size(&self) -> u32 {
self.mmap.borrow().size
}

/// Grow memory by the specified amount of wasm pages.
///
/// Returns `None` if memory can't be grown by the specified amount
/// of wasm pages.
pub fn grow(&self, delta: u32) -> Option<u32> {
fn grow(&self, delta: u32) -> Option<u32> {
// Optimization of memory.grow 0 calls.
let mut mmap = self.mmap.borrow_mut();
if delta == 0 {
Expand Down Expand Up @@ -143,7 +174,7 @@ impl LinearMemory {
}

/// Return a `VMMemoryDefinition` for exposing the memory to compiled wasm code.
pub fn vmmemory(&self) -> VMMemoryDefinition {
fn vmmemory(&self) -> VMMemoryDefinition {
let mut mmap = self.mmap.borrow_mut();
VMMemoryDefinition {
base: mmap.alloc.as_mut_ptr(),
Expand Down