Furtuer optimize data structure sizes.

This commit is contained in:
Stephen Chung 2021-03-12 14:11:08 +08:00
parent 4e5d009386
commit 85fcb74be9
5 changed files with 109 additions and 151 deletions

View File

@ -658,7 +658,7 @@ impl AST {
pub(crate) fn iter_fn_def(&self) -> impl Iterator<Item = &ScriptFnDef> { pub(crate) fn iter_fn_def(&self) -> impl Iterator<Item = &ScriptFnDef> {
self.functions self.functions
.iter_script_fn() .iter_script_fn()
.map(|(_, _, _, _, fn_def)| fn_def) .map(|(_, _, _, _, fn_def)| fn_def.as_ref())
} }
/// Iterate through all function definitions. /// Iterate through all function definitions.
/// ///
@ -668,7 +668,7 @@ impl AST {
pub fn iter_functions<'a>(&'a self) -> impl Iterator<Item = ScriptFnMetadata> + 'a { pub fn iter_functions<'a>(&'a self) -> impl Iterator<Item = ScriptFnMetadata> + 'a {
self.functions self.functions
.iter_script_fn() .iter_script_fn()
.map(|(_, _, _, _, fn_def)| fn_def.into()) .map(|(_, _, _, _, fn_def)| fn_def.as_ref().into())
} }
/// Clear all function definitions in the [`AST`]. /// Clear all function definitions in the [`AST`].
/// ///

View File

@ -570,9 +570,9 @@ impl CallableFunction {
/// Panics if the [`CallableFunction`] is not [`Pure`][CallableFunction::Pure] or /// Panics if the [`CallableFunction`] is not [`Pure`][CallableFunction::Pure] or
/// [`Method`][CallableFunction::Method]. /// [`Method`][CallableFunction::Method].
#[inline(always)] #[inline(always)]
pub fn get_native_fn(&self) -> &FnAny { pub fn get_native_fn(&self) -> &Shared<FnAny> {
match self { match self {
Self::Pure(f) | Self::Method(f) => f.as_ref(), Self::Pure(f) | Self::Method(f) => f,
Self::Iterator(_) | Self::Plugin(_) => panic!("function should be native"), Self::Iterator(_) | Self::Plugin(_) => panic!("function should be native"),
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
@ -586,12 +586,12 @@ impl CallableFunction {
/// Panics if the [`CallableFunction`] is not [`Script`][CallableFunction::Script]. /// Panics if the [`CallableFunction`] is not [`Script`][CallableFunction::Script].
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[inline(always)] #[inline(always)]
pub fn get_fn_def(&self) -> &crate::ast::ScriptFnDef { pub fn get_fn_def(&self) -> &Shared<crate::ast::ScriptFnDef> {
match self { match self {
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => { Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => {
panic!("function should be scripted") panic!("function should be scripted")
} }
Self::Script(f) => f.as_ref(), Self::Script(f) => f,
} }
} }
/// Get a reference to an iterator function. /// Get a reference to an iterator function.
@ -617,9 +617,9 @@ impl CallableFunction {
/// ///
/// Panics if the [`CallableFunction`] is not [`Plugin`][CallableFunction::Plugin]. /// Panics if the [`CallableFunction`] is not [`Plugin`][CallableFunction::Plugin].
#[inline(always)] #[inline(always)]
pub fn get_plugin_fn<'s>(&'s self) -> &FnPlugin { pub fn get_plugin_fn<'s>(&'s self) -> &Shared<FnPlugin> {
match self { match self {
Self::Plugin(f) => f.as_ref(), Self::Plugin(f) => f,
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => { Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => {
panic!("function should a plugin") panic!("function should a plugin")
} }

View File

@ -136,7 +136,7 @@ pub struct Module {
/// Flattened collection of all [`Module`] variables, including those in sub-modules. /// Flattened collection of all [`Module`] variables, including those in sub-modules.
all_variables: HashMap<u64, Dynamic, StraightHasherBuilder>, all_variables: HashMap<u64, Dynamic, StraightHasherBuilder>,
/// External Rust functions. /// External Rust functions.
functions: HashMap<u64, FuncInfo, StraightHasherBuilder>, functions: HashMap<u64, Box<FuncInfo>, StraightHasherBuilder>,
/// Flattened collection of all external Rust functions, native or scripted. /// Flattened collection of all external Rust functions, native or scripted.
/// including those in sub-modules. /// including those in sub-modules.
all_functions: HashMap<u64, CallableFunction, StraightHasherBuilder>, all_functions: HashMap<u64, CallableFunction, StraightHasherBuilder>,
@ -207,7 +207,7 @@ impl fmt::Debug for Module {
" functions: {}\n", " functions: {}\n",
self.functions self.functions
.values() .values()
.map(|FuncInfo { func, .. }| func.to_string()) .map(|f| f.func.to_string())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(", ")
) )
@ -384,11 +384,11 @@ impl Module {
pub fn gen_fn_signatures(&self) -> impl Iterator<Item = String> + '_ { pub fn gen_fn_signatures(&self) -> impl Iterator<Item = String> + '_ {
self.functions self.functions
.values() .values()
.filter(|FuncInfo { access, .. }| match access { .filter(|f| match f.access {
FnAccess::Public => true, FnAccess::Public => true,
FnAccess::Private => false, FnAccess::Private => false,
}) })
.map(FuncInfo::gen_signature) .map(|f| f.gen_signature())
} }
/// Does a variable exist in the [`Module`]? /// Does a variable exist in the [`Module`]?
@ -490,7 +490,7 @@ impl Module {
param_names.push("Dynamic".into()); param_names.push("Dynamic".into());
self.functions.insert( self.functions.insert(
hash_script, hash_script,
FuncInfo { Box::new(FuncInfo {
name: fn_def.name.to_string(), name: fn_def.name.to_string(),
namespace: FnNamespace::Internal, namespace: FnNamespace::Internal,
access: fn_def.access, access: fn_def.access,
@ -498,14 +498,15 @@ impl Module {
param_types: Default::default(), param_types: Default::default(),
param_names, param_names,
func: fn_def.into(), func: fn_def.into(),
}, }),
); );
self.indexed = false; self.indexed = false;
self.contains_indexed_global_functions = false; self.contains_indexed_global_functions = false;
hash_script hash_script
} }
/// Get a script-defined function in the [`Module`] based on name and number of parameters. /// Get a shared reference to the script-defined function in the [`Module`] based on name
/// and number of parameters.
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[inline(always)] #[inline(always)]
pub fn get_script_fn( pub fn get_script_fn(
@ -513,22 +514,15 @@ impl Module {
name: &str, name: &str,
num_params: usize, num_params: usize,
public_only: bool, public_only: bool,
) -> Option<&crate::ast::ScriptFnDef> { ) -> Option<&Shared<crate::ast::ScriptFnDef>> {
self.functions self.functions
.values() .values()
.find( .find(|f| {
|FuncInfo { (!public_only || f.access == FnAccess::Public)
name: fn_name, && f.params == num_params
access, && f.name == name
params, })
.. .map(|f| f.func.get_fn_def())
}| {
(!public_only || *access == FnAccess::Public)
&& *params == num_params
&& fn_name == name
},
)
.map(|FuncInfo { func, .. }| func.get_fn_def())
} }
/// Get a mutable reference to the underlying [`HashMap`] of sub-modules. /// Get a mutable reference to the underlying [`HashMap`] of sub-modules.
@ -629,7 +623,7 @@ impl Module {
if public_only { if public_only {
self.functions self.functions
.get(&hash_fn) .get(&hash_fn)
.map_or(false, |FuncInfo { access, .. }| match access { .map_or(false, |f| match f.access {
FnAccess::Public => true, FnAccess::Public => true,
FnAccess::Private => false, FnAccess::Private => false,
}) })
@ -717,7 +711,7 @@ impl Module {
self.functions.insert( self.functions.insert(
hash_fn, hash_fn,
FuncInfo { Box::new(FuncInfo {
name, name,
namespace, namespace,
access, access,
@ -729,7 +723,7 @@ impl Module {
Default::default() Default::default()
}, },
func: func.into(), func: func.into(),
}, }),
); );
self.indexed = false; self.indexed = false;
@ -1478,13 +1472,11 @@ impl Module {
/// The [`u64`] hash is returned by the `set_fn_XXX` calls. /// The [`u64`] hash is returned by the `set_fn_XXX` calls.
#[inline(always)] #[inline(always)]
pub(crate) fn get_fn(&self, hash_fn: u64, public_only: bool) -> Option<&CallableFunction> { pub(crate) fn get_fn(&self, hash_fn: u64, public_only: bool) -> Option<&CallableFunction> {
self.functions self.functions.get(&hash_fn).and_then(|f| match f.access {
.get(&hash_fn) _ if !public_only => Some(&f.func),
.and_then(|FuncInfo { access, func, .. }| match access { FnAccess::Public => Some(&f.func),
_ if !public_only => Some(func), FnAccess::Private => None,
FnAccess::Public => Some(func), })
FnAccess::Private => None,
})
} }
/// Does the particular namespace-qualified function exist in the [`Module`]? /// Does the particular namespace-qualified function exist in the [`Module`]?
@ -1594,27 +1586,15 @@ impl Module {
other other
.functions .functions
.iter() .iter()
.filter( .filter(|(_, f)| {
|( _filter(
_, f.namespace,
FuncInfo { f.access,
namespace, f.func.is_script(),
access, f.name.as_str(),
name, f.params,
params, )
func, })
..
},
)| {
_filter(
*namespace,
*access,
func.is_script(),
name.as_str(),
*params,
)
},
)
.map(|(&k, v)| (k, v.clone())), .map(|(&k, v)| (k, v.clone())),
); );
@ -1634,23 +1614,13 @@ impl Module {
&mut self, &mut self,
filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool, filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool,
) -> &mut Self { ) -> &mut Self {
self.functions.retain( self.functions.retain(|_, f| {
|_, if f.func.is_script() {
FuncInfo { filter(f.namespace, f.access, f.name.as_str(), f.params)
namespace, } else {
access, false
name, }
params, });
func,
..
}| {
if func.is_script() {
filter(*namespace, *access, name.as_str(), *params)
} else {
false
}
},
);
self.all_functions.clear(); self.all_functions.clear();
self.all_variables.clear(); self.all_variables.clear();
@ -1686,7 +1656,7 @@ impl Module {
#[inline(always)] #[inline(always)]
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) fn iter_fn(&self) -> impl Iterator<Item = &FuncInfo> { pub(crate) fn iter_fn(&self) -> impl Iterator<Item = &FuncInfo> {
self.functions.values() self.functions.values().map(Box::as_ref)
} }
/// Get an iterator over all script-defined functions in the [`Module`]. /// Get an iterator over all script-defined functions in the [`Module`].
@ -1701,26 +1671,27 @@ impl Module {
#[inline(always)] #[inline(always)]
pub(crate) fn iter_script_fn( pub(crate) fn iter_script_fn(
&self, &self,
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, &crate::ast::ScriptFnDef)> + '_ ) -> impl Iterator<
{ Item = (
self.functions.values().filter(|f| f.func.is_script()).map( FnNamespace,
|FuncInfo { FnAccess,
namespace, &str,
access, usize,
name, &Shared<crate::ast::ScriptFnDef>,
params, ),
func, > + '_ {
.. self.functions
}| { .values()
.filter(|f| f.func.is_script())
.map(|f| {
( (
*namespace, f.namespace,
*access, f.access,
name.as_str(), f.name.as_str(),
*params, f.params,
func.get_fn_def(), f.func.get_fn_def(),
) )
}, })
)
} }
/// Get an iterator over all script-defined functions in the [`Module`]. /// Get an iterator over all script-defined functions in the [`Module`].
@ -1736,15 +1707,10 @@ impl Module {
pub fn iter_script_fn_info( pub fn iter_script_fn_info(
&self, &self,
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize)> { ) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize)> {
self.functions.values().filter(|f| f.func.is_script()).map( self.functions
|FuncInfo { .values()
name, .filter(|f| f.func.is_script())
namespace, .map(|f| (f.namespace, f.access, f.name.as_str(), f.params))
access,
params,
..
}| (*namespace, *access, name.as_str(), *params),
)
} }
/// _(INTERNALS)_ Get an iterator over all script-defined functions in the [`Module`]. /// _(INTERNALS)_ Get an iterator over all script-defined functions in the [`Module`].
@ -1825,14 +1791,14 @@ impl Module {
ast.lib() ast.lib()
.functions .functions
.values() .values()
.filter(|FuncInfo { access, .. }| match access { .filter(|f| match f.access {
FnAccess::Public => true, FnAccess::Public => true,
FnAccess::Private => false, FnAccess::Private => false,
}) })
.filter(|FuncInfo { func, .. }| func.is_script()) .filter(|f| f.func.is_script())
.for_each(|FuncInfo { func, .. }| { .for_each(|f| {
// Encapsulate AST environment // Encapsulate AST environment
let mut func = func.get_fn_def().clone(); let mut func = crate::fn_native::shared_take_or_clone(f.func.get_fn_def().clone());
func.lib = Some(ast.shared_lib()); func.lib = Some(ast.shared_lib());
func.mods = func_mods.clone(); func.mods = func_mods.clone();
module.set_script_fn(func); module.set_script_fn(func);
@ -1891,43 +1857,33 @@ impl Module {
}); });
// Index all Rust functions // Index all Rust functions
module.functions.iter().for_each( module.functions.iter().for_each(|(&hash, f)| {
|( match f.namespace {
&hash, FnNamespace::Global => {
FuncInfo { // Flatten all functions with global namespace
name, functions.insert(hash, f.func.clone());
namespace, contains_indexed_global_functions = true;
access,
params,
param_types,
func,
..
},
)| {
match namespace {
FnNamespace::Global => {
// Flatten all functions with global namespace
functions.insert(hash, func.clone());
contains_indexed_global_functions = true;
}
FnNamespace::Internal => (),
}
match access {
FnAccess::Public => (),
FnAccess::Private => return, // Do not index private functions
} }
FnNamespace::Internal => (),
}
match f.access {
FnAccess::Public => (),
FnAccess::Private => return, // Do not index private functions
}
if !func.is_script() { if !f.func.is_script() {
let hash_qualified_fn = let hash_qualified_fn = calc_native_fn_hash(
calc_native_fn_hash(qualifiers.iter().cloned(), name, param_types); qualifiers.iter().cloned(),
functions.insert(hash_qualified_fn, func.clone()); f.name.as_str(),
} else if cfg!(not(feature = "no_function")) { &f.param_types,
let hash_qualified_script = );
crate::calc_fn_hash(qualifiers.iter().cloned(), name, *params); functions.insert(hash_qualified_fn, f.func.clone());
functions.insert(hash_qualified_script, func.clone()); } else if cfg!(not(feature = "no_function")) {
} let hash_qualified_script =
}, crate::calc_fn_hash(qualifiers.iter().cloned(), f.name.as_str(), f.params);
); functions.insert(hash_qualified_script, f.func.clone());
}
});
contains_indexed_global_functions contains_indexed_global_functions
} }

View File

@ -849,7 +849,7 @@ pub fn optimize_into_ast(
engine: &Engine, engine: &Engine,
scope: &Scope, scope: &Scope,
mut statements: Vec<Stmt>, mut statements: Vec<Stmt>,
_functions: Vec<crate::ast::ScriptFnDef>, _functions: Vec<crate::Shared<crate::ast::ScriptFnDef>>,
optimization_level: OptimizationLevel, optimization_level: OptimizationLevel,
) -> AST { ) -> AST {
let level = if cfg!(feature = "no_optimize") { let level = if cfg!(feature = "no_optimize") {
@ -888,7 +888,9 @@ pub fn optimize_into_ast(
_functions _functions
.into_iter() .into_iter()
.map(|mut fn_def| { .map(|fn_def| {
let mut fn_def = crate::fn_native::shared_take_or_clone(fn_def);
let pos = fn_def.body.pos; let pos = fn_def.body.pos;
let mut body = fn_def.body.statements.into_vec(); let mut body = fn_def.body.statements.into_vec();

View File

@ -26,7 +26,7 @@ use crate::token::{is_keyword_function, is_valid_identifier, Token, TokenStream}
use crate::utils::{get_hasher, StraightHasherBuilder}; use crate::utils::{get_hasher, StraightHasherBuilder};
use crate::{ use crate::{
calc_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType, Position, calc_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType, Position,
Scope, StaticVec, AST, Scope, Shared, StaticVec, AST,
}; };
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
@ -37,7 +37,7 @@ use crate::FnAccess;
type PERR = ParseErrorType; type PERR = ParseErrorType;
type FunctionsLib = HashMap<u64, ScriptFnDef, StraightHasherBuilder>; type FunctionsLib = HashMap<u64, Shared<ScriptFnDef>, StraightHasherBuilder>;
/// A type that encapsulates the current state of the parser. /// A type that encapsulates the current state of the parser.
#[derive(Debug)] #[derive(Debug)]
@ -1008,7 +1008,7 @@ fn parse_primary(
}); });
let hash_script = calc_fn_hash(empty(), &func.name, func.params.len()); let hash_script = calc_fn_hash(empty(), &func.name, func.params.len());
lib.insert(hash_script, func); lib.insert(hash_script, func.into());
expr expr
} }
@ -2530,7 +2530,7 @@ fn parse_stmt(
.into_err(pos)); .into_err(pos));
} }
lib.insert(hash, func); lib.insert(hash, func.into());
Ok(Stmt::Noop(pos)) Ok(Stmt::Noop(pos))
} }
@ -2969,7 +2969,7 @@ impl Engine {
fn parse_global_level( fn parse_global_level(
&self, &self,
input: &mut TokenStream, input: &mut TokenStream,
) -> Result<(Vec<Stmt>, Vec<ScriptFnDef>), ParseError> { ) -> Result<(Vec<Stmt>, Vec<Shared<ScriptFnDef>>), ParseError> {
let mut statements = Vec::with_capacity(16); let mut statements = Vec::with_capacity(16);
let mut functions = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder); let mut functions = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder);
let mut state = ParseState::new( let mut state = ParseState::new(