diff --git a/src/engine.rs b/src/engine.rs index 44cd129a..5c39140f 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -24,7 +24,7 @@ use crate::stdlib::{ string::{String, ToString}, }; use crate::syntax::CustomSyntax; -use crate::utils::get_hasher; +use crate::utils::{get_hasher, StraightHasherBuilder}; use crate::{ calc_native_fn_hash, Dynamic, EvalAltResult, FnPtr, ImmutableString, Module, Position, Scope, Shared, StaticVec, @@ -476,7 +476,7 @@ impl> From for Target<'_> { /// ## WARNING /// /// This type is volatile and may change. -#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)] +#[derive(Debug, Clone, Default)] pub struct State { /// Normally, access to variables are parsed with a relative offset into the scope to avoid a lookup. /// In some situation, e.g. after running an `eval` statement, subsequent offsets become mis-aligned. @@ -489,6 +489,8 @@ pub struct State { pub operations: u64, /// Number of modules loaded. pub modules: usize, + /// Cached lookup values for function hashes. + pub functions_cache: HashMap, StraightHasherBuilder>, } impl State { @@ -1886,6 +1888,10 @@ impl Engine { }); scope.rewind(prev_scope_len); + if mods.len() != prev_mods_len { + // If imports list is modified, clear the functions lookup cache + state.functions_cache.clear(); + } mods.truncate(prev_mods_len); state.scope_level -= 1; @@ -2365,6 +2371,8 @@ impl Engine { } else { mods.push(name_def.name.clone(), module); } + // When imports list is modified, clear the functions lookup cache + state.functions_cache.clear(); } state.modules += 1; diff --git a/src/fn_call.rs b/src/fn_call.rs index bb8720cb..9b1500ef 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -170,14 +170,25 @@ impl Engine { ) -> Result<(Dynamic, bool), Box> { self.inc_operations(state)?; - // Search for the native function - // First search registered functions (can override packages) - // Then search packages - let func = //lib.get_fn(hash_fn, pub_only) - self.global_namespace.get_fn(hash_fn, pub_only) + let func = state.functions_cache.get(&hash_fn).cloned(); + + let func = if let Some(ref f) = func { + f.as_ref() + } else { + // Search for the native function + // First search registered functions (can override packages) + // Then search packages + // lib.get_fn(hash_fn, pub_only) + let f = self + .global_namespace + .get_fn(hash_fn, pub_only) .or_else(|| self.packages.get_fn(hash_fn)) .or_else(|| mods.get_fn(hash_fn)); + state.functions_cache.insert(hash_fn, f.cloned()); + f + }; + if let Some(func) = func { assert!(func.is_native()); @@ -370,6 +381,9 @@ impl Engine { let mut lib_merged: StaticVec<_>; let unified_lib = if let Some(ref env_lib) = fn_def.lib { + // If the library is modified, clear the functions lookup cache + state.functions_cache.clear(); + lib_merged = Default::default(); lib_merged.push(env_lib.as_ref()); lib_merged.extend(lib.iter().cloned());