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 mod_name = mod_all.ident.clone();
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 {
// Generate new module items.

View File

@ -16,10 +16,10 @@ use crate::FLOAT;
use crate::engine::Imports;
#[cfg(not(feature = "no_index"))]
use crate::engine::TYPICAL_ARRAY_SIZE;
use crate::{engine::TYPICAL_ARRAY_SIZE, Array};
#[cfg(not(feature = "no_object"))]
use crate::engine::TYPICAL_MAP_SIZE;
use crate::{engine::TYPICAL_MAP_SIZE, Map};
use crate::stdlib::{
borrow::Cow,
@ -129,7 +129,7 @@ impl fmt::Display for ScriptFnDef {
/// # Thread Safety
///
/// 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(
/// Global statements.
Vec<Stmt>,
@ -137,11 +137,17 @@ pub struct AST(
Module,
);
impl Default for AST {
fn default() -> Self {
Self(Vec::with_capacity(16), Default::default())
}
}
impl AST {
/// Create a new `AST`.
#[inline(always)]
pub fn new(statements: Vec<Stmt>, lib: Module) -> Self {
Self(statements, lib)
pub fn new(statements: impl IntoIterator<Item = Stmt>, lib: Module) -> Self {
Self(statements.into_iter().collect(), lib)
}
/// Get the statements.
#[cfg(not(feature = "internals"))]
@ -937,14 +943,14 @@ impl Expr {
#[cfg(not(feature = "no_index"))]
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()));
Dynamic(Union::Array(Box::new(arr)))
}
#[cfg(not(feature = "no_object"))]
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(
x.iter()
.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",))]
module_resolver: None,
type_names: HashMap::with_capacity(8),
disabled_symbols: HashSet::with_capacity(4),
custom_keywords: HashMap::with_capacity(4),
custom_syntax: HashMap::with_capacity(4),
type_names: Default::default(),
disabled_symbols: Default::default(),
custom_keywords: Default::default(),
custom_syntax: Default::default(),
// variable resolver
resolve_var: None,
@ -777,10 +777,10 @@ impl Engine {
#[cfg(not(feature = "no_module"))]
module_resolver: None,
type_names: HashMap::with_capacity(8),
disabled_symbols: HashSet::with_capacity(4),
custom_keywords: HashMap::with_capacity(4),
custom_syntax: HashMap::with_capacity(4),
type_names: Default::default(),
disabled_symbols: Default::default(),
custom_keywords: Default::default(),
custom_syntax: Default::default(),
resolve_var: None,
@ -1726,7 +1726,7 @@ impl Engine {
#[cfg(not(feature = "no_index"))]
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() {
arr.push(self.eval_expr(scope, mods, state, lib, this_ptr, item, level)?);
}
@ -1735,7 +1735,7 @@ impl Engine {
#[cfg(not(feature = "no_object"))]
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() {
map.insert(
key.clone(),

View File

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

View File

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

View File

@ -3,7 +3,7 @@
use crate::def_package;
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::plugin::*;
use crate::result::EvalAltResult;
@ -14,7 +14,7 @@ use crate::INT;
#[cfg(not(feature = "no_object"))]
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 = ();
@ -201,7 +201,7 @@ mod array_functions {
list: &mut Array,
mapper: FnPtr,
) -> 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() {
array.push(
@ -233,7 +233,7 @@ mod array_functions {
list: &mut Array,
filter: FnPtr,
) -> 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() {
if filter
@ -537,7 +537,7 @@ mod array_functions {
list: &mut Array,
filter: FnPtr,
) -> 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();
@ -596,7 +596,7 @@ mod array_functions {
list: &mut Array,
filter: FnPtr,
) -> 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();

View File

@ -130,7 +130,7 @@ macro_rules! def_package {
impl $package {
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(module.into())
}

View File

@ -41,9 +41,6 @@ use crate::stdlib::{
vec::Vec,
};
#[cfg(not(feature = "no_closure"))]
use crate::stdlib::collections::HashSet;
type PERR = ParseErrorType;
type FunctionsLib = HashMap<u64, ScriptFnDef, StraightHasherBuilder>;
@ -99,7 +96,7 @@ impl<'e> ParseState<'e> {
#[cfg(not(feature = "no_function"))]
max_function_expr_depth,
#[cfg(not(feature = "no_closure"))]
externals: HashMap::with_capacity(8),
externals: Default::default(),
#[cfg(not(feature = "no_closure"))]
allow_capture: true,
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 {
let (id, id_pos) = match input.next().unwrap() {
@ -2279,7 +2276,7 @@ fn parse_block(
#[cfg(not(feature = "unchecked"))]
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();
#[cfg(not(feature = "no_module"))]
@ -2584,7 +2581,7 @@ fn parse_fn(
(_, 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 {
let sep_err = format!("to separate the parameters of function '{}'", name);
@ -2716,7 +2713,7 @@ fn parse_anon_fn(
#[cfg(not(feature = "unchecked"))]
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 !match_token(input, Token::Pipe).0 {
@ -2800,7 +2797,7 @@ fn parse_anon_fn(
access: FnAccess::Public,
params,
#[cfg(not(feature = "no_closure"))]
externals: HashSet::with_capacity(4),
externals: Default::default(),
body,
lib: None,
#[cfg(not(feature = "no_module"))]
@ -2877,8 +2874,8 @@ impl Engine {
script_hash: u64,
input: &mut TokenStream,
) -> Result<(Vec<Stmt>, Vec<ScriptFnDef>), ParseError> {
let mut statements: Vec<Stmt> = Default::default();
let mut functions = Default::default();
let mut statements = Vec::with_capacity(16);
let mut functions = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder);
let mut state = ParseState::new(
self,
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.
// 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> {
/// Current value of the entry.
values: Vec<Dynamic>,
@ -75,6 +75,16 @@ pub struct Scope<'a> {
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> {
/// Create a new Scope.
///