Refactor module instantiation in the runtime.
This commit refactors module instantiation in the runtime to allow for different instance allocation strategy implementations. It adds an `InstanceAllocator` trait with the current implementation put behind the `OnDemandInstanceAllocator` struct. The Wasmtime API has been updated to allow a `Config` to have an instance allocation strategy set which will determine how instances get allocated. This change is in preparation for an alternative *pooling* instance allocator that can reserve all needed host process address space in advance. This commit also makes changes to the `wasmtime_environ` crate to represent compiled modules in a way that reduces copying at instantiation time.
This commit is contained in:
@@ -20,7 +20,7 @@ pub mod isa {
|
||||
}
|
||||
|
||||
pub mod entity {
|
||||
pub use cranelift_entity::{packed_option, BoxedSlice, EntityRef, PrimaryMap};
|
||||
pub use cranelift_entity::{packed_option, BoxedSlice, EntityRef, EntitySet, PrimaryMap};
|
||||
}
|
||||
|
||||
pub mod wasm {
|
||||
|
||||
@@ -158,13 +158,19 @@ pub struct Module {
|
||||
pub table_elements: Vec<TableElements>,
|
||||
|
||||
/// WebAssembly passive elements.
|
||||
pub passive_elements: HashMap<ElemIndex, Box<[FuncIndex]>>,
|
||||
pub passive_elements: Vec<Box<[FuncIndex]>>,
|
||||
|
||||
/// The map from passive element index (element segment index space) to index in `passive_elements`.
|
||||
pub passive_elements_map: HashMap<ElemIndex, usize>,
|
||||
|
||||
/// WebAssembly passive data segments.
|
||||
#[serde(with = "passive_data_serde")]
|
||||
pub passive_data: HashMap<DataIndex, Arc<[u8]>>,
|
||||
pub passive_data: Vec<Arc<[u8]>>,
|
||||
|
||||
/// WebAssembly table initializers.
|
||||
/// The map from passive data index (data segment index space) to index in `passive_data`.
|
||||
pub passive_data_map: HashMap<DataIndex, usize>,
|
||||
|
||||
/// WebAssembly function names.
|
||||
pub func_names: HashMap<FuncIndex, String>,
|
||||
|
||||
/// Types declared in the wasm module.
|
||||
@@ -272,7 +278,8 @@ impl Module {
|
||||
|
||||
/// Get the given passive element, if it exists.
|
||||
pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FuncIndex]> {
|
||||
self.passive_elements.get(&index).map(|es| &**es)
|
||||
let index = *self.passive_elements_map.get(&index)?;
|
||||
Some(self.passive_elements[index].as_ref())
|
||||
}
|
||||
|
||||
/// Convert a `DefinedFuncIndex` into a `FuncIndex`.
|
||||
@@ -419,47 +426,45 @@ pub struct InstanceSignature {
|
||||
}
|
||||
|
||||
mod passive_data_serde {
|
||||
use super::{Arc, DataIndex, HashMap};
|
||||
use serde::{de::MapAccess, de::Visitor, ser::SerializeMap, Deserializer, Serializer};
|
||||
use super::Arc;
|
||||
use serde::{de::SeqAccess, de::Visitor, ser::SerializeSeq, Deserializer, Serializer};
|
||||
use std::fmt;
|
||||
|
||||
pub(super) fn serialize<S>(
|
||||
data: &HashMap<DataIndex, Arc<[u8]>>,
|
||||
ser: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
pub(super) fn serialize<S>(data: &Vec<Arc<[u8]>>, ser: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut map = ser.serialize_map(Some(data.len()))?;
|
||||
for (k, v) in data {
|
||||
map.serialize_entry(k, v.as_ref())?;
|
||||
let mut seq = ser.serialize_seq(Some(data.len()))?;
|
||||
for v in data {
|
||||
seq.serialize_element(v.as_ref())?;
|
||||
}
|
||||
map.end()
|
||||
seq.end()
|
||||
}
|
||||
|
||||
struct PassiveDataVisitor;
|
||||
impl<'de> Visitor<'de> for PassiveDataVisitor {
|
||||
type Value = HashMap<DataIndex, Arc<[u8]>>;
|
||||
type Value = Vec<Arc<[u8]>>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a passive_data map")
|
||||
formatter.write_str("a passive data sequence")
|
||||
}
|
||||
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
|
||||
|
||||
fn visit_seq<M>(self, mut access: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
M: SeqAccess<'de>,
|
||||
{
|
||||
let mut map = HashMap::with_capacity(access.size_hint().unwrap_or(0));
|
||||
while let Some((key, value)) = access.next_entry::<_, Vec<u8>>()? {
|
||||
map.insert(key, value.into());
|
||||
let mut data = Vec::with_capacity(access.size_hint().unwrap_or(0));
|
||||
while let Some(value) = access.next_element::<Vec<u8>>()? {
|
||||
data.push(value.into());
|
||||
}
|
||||
Ok(map)
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn deserialize<'de, D>(de: D) -> Result<HashMap<DataIndex, Arc<[u8]>>, D::Error>
|
||||
pub(super) fn deserialize<'de, D>(de: D) -> Result<Vec<Arc<[u8]>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
de.deserialize_map(PassiveDataVisitor)
|
||||
de.deserialize_seq(PassiveDataVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -710,11 +710,13 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
||||
elem_index: ElemIndex,
|
||||
segments: Box<[FuncIndex]>,
|
||||
) -> WasmResult<()> {
|
||||
let index = self.result.module.passive_elements.len();
|
||||
self.result.module.passive_elements.push(segments);
|
||||
let old = self
|
||||
.result
|
||||
.module
|
||||
.passive_elements
|
||||
.insert(elem_index, segments);
|
||||
.passive_elements_map
|
||||
.insert(elem_index, index);
|
||||
debug_assert!(
|
||||
old.is_none(),
|
||||
"should never get duplicate element indices, that would be a bug in `cranelift_wasm`'s \
|
||||
@@ -782,17 +784,21 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reserve_passive_data(&mut self, count: u32) -> WasmResult<()> {
|
||||
self.result.module.passive_data.reserve(count as usize);
|
||||
fn reserve_passive_data(&mut self, _count: u32) -> WasmResult<()> {
|
||||
// Note: the count passed in here is the *total* segment count
|
||||
// There is no way to reserve for just the passive segments as they are discovered when iterating the data section entries
|
||||
// Given that the total segment count might be much larger than the passive count, do not reserve
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn declare_passive_data(&mut self, data_index: DataIndex, data: &'data [u8]) -> WasmResult<()> {
|
||||
let index = self.result.module.passive_data.len();
|
||||
self.result.module.passive_data.push(Arc::from(data));
|
||||
let old = self
|
||||
.result
|
||||
.module
|
||||
.passive_data
|
||||
.insert(data_index, Arc::from(data));
|
||||
.passive_data_map
|
||||
.insert(data_index, index);
|
||||
debug_assert!(
|
||||
old.is_none(),
|
||||
"a module can't have duplicate indices, this would be a cranelift-wasm bug"
|
||||
@@ -1088,3 +1094,24 @@ pub struct DataInitializer<'data> {
|
||||
/// The initialization data.
|
||||
pub data: &'data [u8],
|
||||
}
|
||||
|
||||
/// Similar to `DataInitializer`, but owns its own copy of the data rather
|
||||
/// than holding a slice of the original module.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct OwnedDataInitializer {
|
||||
/// The location where the initialization is to be performed.
|
||||
pub location: DataInitializerLocation,
|
||||
|
||||
/// The initialization data.
|
||||
pub data: Box<[u8]>,
|
||||
}
|
||||
|
||||
impl OwnedDataInitializer {
|
||||
/// Creates a new owned data initializer from a borrowed data initializer.
|
||||
pub fn new(borrowed: DataInitializer<'_>) -> Self {
|
||||
Self {
|
||||
location: borrowed.location.clone(),
|
||||
data: borrowed.data.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user