Fine tune hash map sizes.

This commit is contained in:
Stephen Chung 2020-11-15 13:49:54 +08:00
parent bde8917ed4
commit c919ee4e46
9 changed files with 69 additions and 54 deletions

View File

@ -259,7 +259,7 @@ impl Module {
let mut mod_all = mod_all.unwrap(); let mut mod_all = mod_all.unwrap();
let mod_name = mod_all.ident.clone(); let mod_name = mod_all.ident.clone();
let (_, orig_content) = mod_all.content.take().unwrap(); let (_, orig_content) = mod_all.content.take().unwrap();
let mod_attrs = mem::replace(&mut mod_all.attrs, Vec::with_capacity(0)); let mod_attrs = mem::take(&mut mod_all.attrs);
if !params.skip { if !params.skip {
// Generate new module items. // Generate new module items.

View File

@ -16,10 +16,10 @@ use crate::FLOAT;
use crate::engine::Imports; use crate::engine::Imports;
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::engine::TYPICAL_ARRAY_SIZE; use crate::{engine::TYPICAL_ARRAY_SIZE, Array};
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::engine::TYPICAL_MAP_SIZE; use crate::{engine::TYPICAL_MAP_SIZE, Map};
use crate::stdlib::{ use crate::stdlib::{
borrow::Cow, borrow::Cow,
@ -129,7 +129,7 @@ impl fmt::Display for ScriptFnDef {
/// # Thread Safety /// # Thread Safety
/// ///
/// Currently, `AST` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`. /// Currently, `AST` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone)]
pub struct AST( pub struct AST(
/// Global statements. /// Global statements.
Vec<Stmt>, Vec<Stmt>,
@ -137,11 +137,17 @@ pub struct AST(
Module, Module,
); );
impl Default for AST {
fn default() -> Self {
Self(Vec::with_capacity(16), Default::default())
}
}
impl AST { impl AST {
/// Create a new `AST`. /// Create a new `AST`.
#[inline(always)] #[inline(always)]
pub fn new(statements: Vec<Stmt>, lib: Module) -> Self { pub fn new(statements: impl IntoIterator<Item = Stmt>, lib: Module) -> Self {
Self(statements, lib) Self(statements.into_iter().collect(), lib)
} }
/// Get the statements. /// Get the statements.
#[cfg(not(feature = "internals"))] #[cfg(not(feature = "internals"))]
@ -937,14 +943,14 @@ impl Expr {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Self::Array(x, _) if self.is_constant() => { Self::Array(x, _) if self.is_constant() => {
let mut arr = Vec::with_capacity(max(TYPICAL_ARRAY_SIZE, x.len())); let mut arr = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, x.len()));
arr.extend(x.iter().map(|v| v.get_constant_value().unwrap())); arr.extend(x.iter().map(|v| v.get_constant_value().unwrap()));
Dynamic(Union::Array(Box::new(arr))) Dynamic(Union::Array(Box::new(arr)))
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Self::Map(x, _) if self.is_constant() => { Self::Map(x, _) if self.is_constant() => {
let mut map = HashMap::with_capacity(max(TYPICAL_MAP_SIZE, x.len())); let mut map = Map::with_capacity(max(TYPICAL_MAP_SIZE, x.len()));
map.extend( map.extend(
x.iter() x.iter()
.map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())), .map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())),

View File

@ -720,10 +720,10 @@ impl Engine {
#[cfg(any(feature = "no_std", target_arch = "wasm32",))] #[cfg(any(feature = "no_std", target_arch = "wasm32",))]
module_resolver: None, module_resolver: None,
type_names: HashMap::with_capacity(8), type_names: Default::default(),
disabled_symbols: HashSet::with_capacity(4), disabled_symbols: Default::default(),
custom_keywords: HashMap::with_capacity(4), custom_keywords: Default::default(),
custom_syntax: HashMap::with_capacity(4), custom_syntax: Default::default(),
// variable resolver // variable resolver
resolve_var: None, resolve_var: None,
@ -777,10 +777,10 @@ impl Engine {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
module_resolver: None, module_resolver: None,
type_names: HashMap::with_capacity(8), type_names: Default::default(),
disabled_symbols: HashSet::with_capacity(4), disabled_symbols: Default::default(),
custom_keywords: HashMap::with_capacity(4), custom_keywords: Default::default(),
custom_syntax: HashMap::with_capacity(4), custom_syntax: Default::default(),
resolve_var: None, resolve_var: None,
@ -1726,7 +1726,7 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Expr::Array(x, _) => { Expr::Array(x, _) => {
let mut arr = Vec::with_capacity(max(TYPICAL_ARRAY_SIZE, x.len())); let mut arr = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, x.len()));
for item in x.as_ref() { for item in x.as_ref() {
arr.push(self.eval_expr(scope, mods, state, lib, this_ptr, item, level)?); arr.push(self.eval_expr(scope, mods, state, lib, this_ptr, item, level)?);
} }
@ -1735,7 +1735,7 @@ impl Engine {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Map(x, _) => { Expr::Map(x, _) => {
let mut map = HashMap::with_capacity(max(TYPICAL_MAP_SIZE, x.len())); let mut map = Map::with_capacity(max(TYPICAL_MAP_SIZE, x.len()));
for (IdentX { name: key, .. }, expr) in x.as_ref() { for (IdentX { name: key, .. }, expr) in x.as_ref() {
map.insert( map.insert(
key.clone(), key.clone(),

View File

@ -81,12 +81,12 @@ pub struct Module {
impl Default for Module { impl Default for Module {
fn default() -> Self { fn default() -> Self {
Self { Self {
modules: HashMap::with_capacity(4), modules: Default::default(),
variables: HashMap::with_capacity(4), variables: Default::default(),
all_variables: HashMap::with_capacity_and_hasher(32, StraightHasherBuilder), all_variables: Default::default(),
functions: HashMap::with_capacity_and_hasher(64, StraightHasherBuilder), functions: HashMap::with_capacity_and_hasher(64, StraightHasherBuilder),
all_functions: HashMap::with_capacity_and_hasher(256, StraightHasherBuilder), all_functions: HashMap::with_capacity_and_hasher(256, StraightHasherBuilder),
type_iterators: HashMap::with_capacity(4), type_iterators: Default::default(),
indexed: false, indexed: false,
} }
} }
@ -1477,8 +1477,8 @@ impl Module {
if !self.indexed { if !self.indexed {
let mut qualifiers = Vec::with_capacity(4); let mut qualifiers = Vec::with_capacity(4);
let mut variables = Vec::with_capacity(8); let mut variables = Vec::with_capacity(16);
let mut functions = Vec::with_capacity(16); let mut functions = Vec::with_capacity(256);
qualifiers.push("root"); qualifiers.push("root");

View File

@ -753,7 +753,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
} }
fn optimize( fn optimize(
statements: Vec<Stmt>, mut statements: Vec<Stmt>,
engine: &Engine, engine: &Engine,
scope: &Scope, scope: &Scope,
lib: &[&Module], lib: &[&Module],
@ -761,6 +761,7 @@ fn optimize(
) -> Vec<Stmt> { ) -> Vec<Stmt> {
// If optimization level is None then skip optimizing // If optimization level is None then skip optimizing
if level == OptimizationLevel::None { if level == OptimizationLevel::None {
statements.shrink_to_fit();
return statements; return statements;
} }
@ -779,16 +780,14 @@ fn optimize(
let orig_constants_len = state.constants.len(); let orig_constants_len = state.constants.len();
let mut result = statements;
// Optimization loop // Optimization loop
loop { loop {
state.reset(); state.reset();
state.restore_constants(orig_constants_len); state.restore_constants(orig_constants_len);
let num_statements = result.len(); let num_statements = statements.len();
result.iter_mut().enumerate().for_each(|(i, stmt)| { statements.iter_mut().enumerate().for_each(|(i, stmt)| {
match stmt { match stmt {
Stmt::Const(var_def, expr, _, _) if expr.is_some() => { Stmt::Const(var_def, expr, _, _) if expr.is_some() => {
// Load constants // Load constants
@ -828,26 +827,27 @@ fn optimize(
} }
// Eliminate code that is pure but always keep the last statement // Eliminate code that is pure but always keep the last statement
let last_stmt = result.pop(); let last_stmt = statements.pop();
// Remove all pure statements at global level // Remove all pure statements at global level
result.retain(|stmt| !stmt.is_pure()); statements.retain(|stmt| !stmt.is_pure());
// Add back the last statement unless it is a lone No-op // Add back the last statement unless it is a lone No-op
if let Some(stmt) = last_stmt { if let Some(stmt) = last_stmt {
if !result.is_empty() || !stmt.is_noop() { if !statements.is_empty() || !stmt.is_noop() {
result.push(stmt); statements.push(stmt);
} }
} }
result statements.shrink_to_fit();
statements
} }
/// Optimize an AST. /// Optimize an AST.
pub fn optimize_into_ast( pub fn optimize_into_ast(
engine: &Engine, engine: &Engine,
scope: &Scope, scope: &Scope,
statements: Vec<Stmt>, mut statements: Vec<Stmt>,
_functions: Vec<ScriptFnDef>, _functions: Vec<ScriptFnDef>,
level: OptimizationLevel, level: OptimizationLevel,
) -> AST { ) -> AST {
@ -922,6 +922,8 @@ pub fn optimize_into_ast(
#[cfg(feature = "no_function")] #[cfg(feature = "no_function")]
let lib = Default::default(); let lib = Default::default();
statements.shrink_to_fit();
AST::new( AST::new(
match level { match level {
OptimizationLevel::None => statements, OptimizationLevel::None => statements,

View File

@ -3,7 +3,7 @@
use crate::def_package; use crate::def_package;
use crate::dynamic::Dynamic; use crate::dynamic::Dynamic;
use crate::engine::{Array, OP_EQUALS}; use crate::engine::{Array, OP_EQUALS, TYPICAL_ARRAY_SIZE};
use crate::fn_native::{FnPtr, NativeCallContext}; use crate::fn_native::{FnPtr, NativeCallContext};
use crate::plugin::*; use crate::plugin::*;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
@ -14,7 +14,7 @@ use crate::INT;
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::engine::Map; use crate::engine::Map;
use crate::stdlib::{any::TypeId, boxed::Box, cmp::Ordering, string::ToString}; use crate::stdlib::{any::TypeId, boxed::Box, cmp::max, cmp::Ordering, string::ToString};
pub type Unit = (); pub type Unit = ();
@ -201,7 +201,7 @@ mod array_functions {
list: &mut Array, list: &mut Array,
mapper: FnPtr, mapper: FnPtr,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let mut array = Array::with_capacity(list.len()); let mut array = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len()));
for (i, item) in list.iter().enumerate() { for (i, item) in list.iter().enumerate() {
array.push( array.push(
@ -233,7 +233,7 @@ mod array_functions {
list: &mut Array, list: &mut Array,
filter: FnPtr, filter: FnPtr,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let mut array = Array::with_capacity(list.len()); let mut array = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len()));
for (i, item) in list.iter().enumerate() { for (i, item) in list.iter().enumerate() {
if filter if filter
@ -537,7 +537,7 @@ mod array_functions {
list: &mut Array, list: &mut Array,
filter: FnPtr, filter: FnPtr,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let mut drained = Array::with_capacity(list.len()); let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len()));
let mut i = list.len(); let mut i = list.len();
@ -596,7 +596,7 @@ mod array_functions {
list: &mut Array, list: &mut Array,
filter: FnPtr, filter: FnPtr,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let mut drained = Array::with_capacity(list.len()); let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len()));
let mut i = list.len(); let mut i = list.len();

View File

@ -130,7 +130,7 @@ macro_rules! def_package {
impl $package { impl $package {
pub fn new() -> Self { pub fn new() -> Self {
let mut module = $root::Module::new_with_capacity(512); let mut module = $root::Module::new_with_capacity(1024);
<Self as $root::packages::Package>::init(&mut module); <Self as $root::packages::Package>::init(&mut module);
Self(module.into()) Self(module.into())
} }

View File

@ -41,9 +41,6 @@ use crate::stdlib::{
vec::Vec, vec::Vec,
}; };
#[cfg(not(feature = "no_closure"))]
use crate::stdlib::collections::HashSet;
type PERR = ParseErrorType; type PERR = ParseErrorType;
type FunctionsLib = HashMap<u64, ScriptFnDef, StraightHasherBuilder>; type FunctionsLib = HashMap<u64, ScriptFnDef, StraightHasherBuilder>;
@ -99,7 +96,7 @@ impl<'e> ParseState<'e> {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
max_function_expr_depth, max_function_expr_depth,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
externals: HashMap::with_capacity(8), externals: Default::default(),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
allow_capture: true, allow_capture: true,
strings: HashMap::with_capacity(64), strings: HashMap::with_capacity(64),
@ -2211,7 +2208,7 @@ fn parse_export(
_ => (), _ => (),
} }
let mut exports = Vec::new(); let mut exports = Vec::with_capacity(4);
loop { loop {
let (id, id_pos) = match input.next().unwrap() { let (id, id_pos) = match input.next().unwrap() {
@ -2279,7 +2276,7 @@ fn parse_block(
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let mut statements = Vec::new(); let mut statements = Vec::with_capacity(8);
let prev_stack_len = state.stack.len(); let prev_stack_len = state.stack.len();
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
@ -2584,7 +2581,7 @@ fn parse_fn(
(_, pos) => return Err(PERR::FnMissingParams(name).into_err(*pos)), (_, pos) => return Err(PERR::FnMissingParams(name).into_err(*pos)),
}; };
let mut params = Vec::new(); let mut params: StaticVec<_> = Default::default();
if !match_token(input, Token::RightParen).0 { if !match_token(input, Token::RightParen).0 {
let sep_err = format!("to separate the parameters of function '{}'", name); let sep_err = format!("to separate the parameters of function '{}'", name);
@ -2716,7 +2713,7 @@ fn parse_anon_fn(
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let mut params = Vec::new(); let mut params: StaticVec<_> = Default::default();
if input.next().unwrap().0 != Token::Or { if input.next().unwrap().0 != Token::Or {
if !match_token(input, Token::Pipe).0 { if !match_token(input, Token::Pipe).0 {
@ -2800,7 +2797,7 @@ fn parse_anon_fn(
access: FnAccess::Public, access: FnAccess::Public,
params, params,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
externals: HashSet::with_capacity(4), externals: Default::default(),
body, body,
lib: None, lib: None,
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
@ -2877,8 +2874,8 @@ impl Engine {
script_hash: u64, script_hash: u64,
input: &mut TokenStream, input: &mut TokenStream,
) -> Result<(Vec<Stmt>, Vec<ScriptFnDef>), ParseError> { ) -> Result<(Vec<Stmt>, Vec<ScriptFnDef>), ParseError> {
let mut statements: Vec<Stmt> = Default::default(); let mut statements = Vec::with_capacity(16);
let mut functions = Default::default(); let mut functions = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder);
let mut state = ParseState::new( let mut state = ParseState::new(
self, self,
script_hash, script_hash,

View File

@ -65,7 +65,7 @@ impl EntryType {
// //
// Since `Dynamic` is reasonably small, packing it tightly improves cache locality when variables are accessed. // Since `Dynamic` is reasonably small, packing it tightly improves cache locality when variables are accessed.
// The variable type is packed separately into another array because it is even smaller. // The variable type is packed separately into another array because it is even smaller.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone)]
pub struct Scope<'a> { pub struct Scope<'a> {
/// Current value of the entry. /// Current value of the entry.
values: Vec<Dynamic>, values: Vec<Dynamic>,
@ -75,6 +75,16 @@ pub struct Scope<'a> {
names: Vec<(Cow<'a, str>, Box<StaticVec<String>>)>, names: Vec<(Cow<'a, str>, Box<StaticVec<String>>)>,
} }
impl Default for Scope<'_> {
fn default() -> Self {
Self {
values: Vec::with_capacity(16),
types: Vec::with_capacity(16),
names: Vec::with_capacity(16),
}
}
}
impl<'a> Scope<'a> { impl<'a> Scope<'a> {
/// Create a new Scope. /// Create a new Scope.
/// ///