Skip to content

Commit

Permalink
Refactor module instantiation in the runtime.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
peterhuene committed Feb 4, 2021
1 parent 7f9a5ea commit 28a8416
Show file tree
Hide file tree
Showing 14 changed files with 829 additions and 686 deletions.
2 changes: 2 additions & 0 deletions cranelift/wasm/src/module_translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ pub fn translate_module<'data>(

Payload::DataCountSection { count, range } => {
validator.data_count_section(count, &range)?;

// NOTE: the count here is the total segment count, not the passive segment count
environ.reserve_passive_data(count)?;
}

Expand Down
2 changes: 1 addition & 1 deletion crates/environ/src/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
53 changes: 29 additions & 24 deletions crates/environ/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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)
}
}
39 changes: 33 additions & 6 deletions crates/environ/src/module_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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(),
}
}
}
Loading

0 comments on commit 28a8416

Please sign in to comment.