Shrink the size of the anyfunc table in VMContext (#3850)
* Shrink the size of the anyfunc table in `VMContext` This commit shrinks the size of the `VMCallerCheckedAnyfunc` table allocated into a `VMContext` to be the size of the number of "escaped" functions in a module rather than the number of functions in a module. Escaped functions include exports, table elements, etc, and are typically an order of magnitude smaller than the number of functions in general. This should greatly shrink the `VMContext` for some modules which while we aren't necessarily having any problems with that today shouldn't cause any problems in the future. The original motivation for this was that this came up during the recent lazy-table-initialization work and while it no longer has a direct performance benefit since tables aren't initialized at all on instantiation it should still improve long-running instances theoretically with smaller `VMContext` allocations as well as better locality between anyfuncs. * Fix some tests * Remove redundant hash set * Use a helper for pushing function type information * Use a more descriptive `is_escaping` method * Clarify a comment * Fix condition
This commit is contained in:
@@ -897,8 +897,15 @@ pub struct Module {
|
||||
/// Number of imported or aliased globals in the module.
|
||||
pub num_imported_globals: usize,
|
||||
|
||||
/// Number of functions that "escape" from this module may need to have a
|
||||
/// `VMCallerCheckedAnyfunc` constructed for them.
|
||||
///
|
||||
/// This is also the number of functions in the `functions` array below with
|
||||
/// an `anyfunc` index (and is the maximum anyfunc index).
|
||||
pub num_escaped_funcs: usize,
|
||||
|
||||
/// Types of functions, imported and local.
|
||||
pub functions: PrimaryMap<FuncIndex, SignatureIndex>,
|
||||
pub functions: PrimaryMap<FuncIndex, FunctionType>,
|
||||
|
||||
/// WebAssembly tables.
|
||||
pub table_plans: PrimaryMap<TableIndex, TablePlan>,
|
||||
@@ -1108,11 +1115,30 @@ impl Module {
|
||||
EntityIndex::Global(i) => EntityType::Global(self.globals[i]),
|
||||
EntityIndex::Table(i) => EntityType::Table(self.table_plans[i].table),
|
||||
EntityIndex::Memory(i) => EntityType::Memory(self.memory_plans[i].memory),
|
||||
EntityIndex::Function(i) => EntityType::Function(self.functions[i]),
|
||||
EntityIndex::Function(i) => EntityType::Function(self.functions[i].signature),
|
||||
EntityIndex::Instance(i) => EntityType::Instance(self.instances[i]),
|
||||
EntityIndex::Module(i) => EntityType::Module(self.modules[i]),
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends a new function to this module with the given type information,
|
||||
/// used for functions that either don't escape or aren't certain whether
|
||||
/// they escape yet.
|
||||
pub fn push_function(&mut self, signature: SignatureIndex) -> FuncIndex {
|
||||
self.functions.push(FunctionType {
|
||||
signature,
|
||||
anyfunc: AnyfuncIndex::reserved_value(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Appends a new function to this module with the given type information.
|
||||
pub fn push_escaped_function(
|
||||
&mut self,
|
||||
signature: SignatureIndex,
|
||||
anyfunc: AnyfuncIndex,
|
||||
) -> FuncIndex {
|
||||
self.functions.push(FunctionType { signature, anyfunc })
|
||||
}
|
||||
}
|
||||
|
||||
/// All types which are recorded for the entirety of a translation.
|
||||
@@ -1144,3 +1170,28 @@ pub struct InstanceSignature {
|
||||
/// The name of what's being exported as well as its type signature.
|
||||
pub exports: IndexMap<String, EntityType>,
|
||||
}
|
||||
|
||||
/// Type information about functions in a wasm module.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FunctionType {
|
||||
/// The type of this function, indexed into the module-wide type tables for
|
||||
/// a module compilation.
|
||||
pub signature: SignatureIndex,
|
||||
/// The index into the anyfunc table, if present. Note that this is
|
||||
/// `reserved_value()` if the function does not escape from a module.
|
||||
pub anyfunc: AnyfuncIndex,
|
||||
}
|
||||
|
||||
impl FunctionType {
|
||||
/// Returns whether this function's type is one that "escapes" the current
|
||||
/// module, meaning that the function is exported, used in `ref.func`, used
|
||||
/// in a table, etc.
|
||||
pub fn is_escaping(&self) -> bool {
|
||||
!self.anyfunc.is_reserved_value()
|
||||
}
|
||||
}
|
||||
|
||||
/// Index into the anyfunc table within a VMContext for a function.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
|
||||
pub struct AnyfuncIndex(u32);
|
||||
cranelift_entity::entity_impl!(AnyfuncIndex);
|
||||
|
||||
Reference in New Issue
Block a user