Add FnResolutionCacheEntry.
This commit is contained in:
parent
61b0c7b2b3
commit
558ffeaf3e
@ -488,6 +488,18 @@ impl<T: Into<Dynamic>> From<T> for Target<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// An entry in a function resolution cache.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FnResolutionCacheEntry {
|
||||
/// Function.
|
||||
pub func: CallableFunction,
|
||||
/// Optional source.
|
||||
pub source: Option<ImmutableString>,
|
||||
}
|
||||
|
||||
/// A function resolution cache.
|
||||
pub type FnResolutionCache = HashMap<u64, Option<FnResolutionCacheEntry>, StraightHasherBuilder>;
|
||||
|
||||
/// _(INTERNALS)_ A type that holds all the current states of the [`Engine`].
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
@ -512,10 +524,10 @@ pub struct State {
|
||||
/// Embedded module resolver.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
|
||||
/// Functions resolution cache.
|
||||
fn_resolution_caches: StaticVec<
|
||||
HashMap<u64, Option<(CallableFunction, Option<ImmutableString>)>, StraightHasherBuilder>,
|
||||
>,
|
||||
/// function resolution cache.
|
||||
fn_resolution_caches: StaticVec<FnResolutionCache>,
|
||||
/// Free resolution caches.
|
||||
fn_resolution_caches_free_list: Vec<FnResolutionCache>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
@ -524,25 +536,32 @@ impl State {
|
||||
pub fn is_global(&self) -> bool {
|
||||
self.scope_level == 0
|
||||
}
|
||||
/// Get a mutable reference to the current functions resolution cache.
|
||||
pub fn fn_resolution_cache_mut(
|
||||
&mut self,
|
||||
) -> &mut HashMap<u64, Option<(CallableFunction, Option<ImmutableString>)>, StraightHasherBuilder>
|
||||
{
|
||||
/// Get a mutable reference to the current function resolution cache.
|
||||
pub fn fn_resolution_cache_mut(&mut self) -> &mut FnResolutionCache {
|
||||
if self.fn_resolution_caches.is_empty() {
|
||||
self.fn_resolution_caches
|
||||
.push(HashMap::with_capacity_and_hasher(16, StraightHasherBuilder));
|
||||
}
|
||||
self.fn_resolution_caches.last_mut().unwrap()
|
||||
}
|
||||
/// Push an empty functions resolution cache onto the stack and make it current.
|
||||
/// Push an empty function resolution cache onto the stack and make it current.
|
||||
#[allow(dead_code)]
|
||||
pub fn push_fn_resolution_cache(&mut self) {
|
||||
self.fn_resolution_caches.push(Default::default());
|
||||
self.fn_resolution_caches.push(
|
||||
self.fn_resolution_caches_free_list
|
||||
.pop()
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
}
|
||||
/// Remove the current functions resolution cache and make the last one current.
|
||||
/// Remove the current function resolution cache from the stack and make the last one current.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if there are no more function resolution cache in the stack.
|
||||
pub fn pop_fn_resolution_cache(&mut self) {
|
||||
self.fn_resolution_caches.pop();
|
||||
let mut cache = self.fn_resolution_caches.pop().unwrap();
|
||||
cache.clear();
|
||||
self.fn_resolution_caches_free_list.push(cache);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
use crate::ast::FnHash;
|
||||
use crate::engine::{
|
||||
Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL,
|
||||
KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||
FnResolutionCacheEntry, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
||||
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||
MAX_DYNAMIC_PARAMETERS,
|
||||
};
|
||||
use crate::fn_builtin::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn};
|
||||
@ -186,7 +186,7 @@ impl Engine {
|
||||
args: Option<&mut FnCallArgs>,
|
||||
allow_dynamic: bool,
|
||||
is_op_assignment: bool,
|
||||
) -> &'s Option<(CallableFunction, Option<ImmutableString>)> {
|
||||
) -> &'s Option<FnResolutionCacheEntry> {
|
||||
let mut hash = if let Some(ref args) = args {
|
||||
let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id()));
|
||||
combine_hashes(hash_script, hash_params)
|
||||
@ -211,28 +211,43 @@ impl Engine {
|
||||
.iter()
|
||||
.find_map(|m| {
|
||||
m.get_fn(hash, false)
|
||||
.map(|f| (f.clone(), m.id_raw().cloned()))
|
||||
.cloned()
|
||||
.map(|func| FnResolutionCacheEntry {
|
||||
func,
|
||||
source: m.id_raw().cloned(),
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
self.global_namespace
|
||||
.get_fn(hash, false)
|
||||
.cloned()
|
||||
.map(|f| (f, None))
|
||||
.map(|func| FnResolutionCacheEntry { func, source: None })
|
||||
})
|
||||
.or_else(|| {
|
||||
self.global_modules.iter().find_map(|m| {
|
||||
m.get_fn(hash, false)
|
||||
.map(|f| (f.clone(), m.id_raw().cloned()))
|
||||
.cloned()
|
||||
.map(|func| FnResolutionCacheEntry {
|
||||
func,
|
||||
source: m.id_raw().cloned(),
|
||||
})
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
mods.get_fn(hash)
|
||||
.map(|(f, source)| (f.clone(), source.cloned()))
|
||||
.map(|(func, source)| FnResolutionCacheEntry {
|
||||
func: func.clone(),
|
||||
source: source.cloned(),
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
self.global_sub_modules.values().find_map(|m| {
|
||||
m.get_qualified_fn(hash)
|
||||
.map(|f| (f.clone(), m.id_raw().cloned()))
|
||||
m.get_qualified_fn(hash).cloned().map(|func| {
|
||||
FnResolutionCacheEntry {
|
||||
func,
|
||||
source: m.id_raw().cloned(),
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
@ -249,10 +264,12 @@ impl Engine {
|
||||
if let Some(f) =
|
||||
get_builtin_binary_op_fn(fn_name, &args[0], &args[1])
|
||||
{
|
||||
Some((
|
||||
CallableFunction::from_method(Box::new(f) as Box<FnAny>),
|
||||
None,
|
||||
))
|
||||
Some(FnResolutionCacheEntry {
|
||||
func: CallableFunction::from_method(
|
||||
Box::new(f) as Box<FnAny>
|
||||
),
|
||||
source: None,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -262,10 +279,12 @@ impl Engine {
|
||||
if let Some(f) =
|
||||
get_builtin_op_assignment_fn(fn_name, *first, second[0])
|
||||
{
|
||||
Some((
|
||||
CallableFunction::from_method(Box::new(f) as Box<FnAny>),
|
||||
None,
|
||||
))
|
||||
Some(FnResolutionCacheEntry {
|
||||
func: CallableFunction::from_method(
|
||||
Box::new(f) as Box<FnAny>
|
||||
),
|
||||
source: None,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -318,7 +337,7 @@ impl Engine {
|
||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||
self.inc_operations(state, pos)?;
|
||||
|
||||
let source = state.source.clone();
|
||||
let state_source = state.source.clone();
|
||||
|
||||
// Check if function access already in the cache
|
||||
let func = self.resolve_function(
|
||||
@ -332,7 +351,7 @@ impl Engine {
|
||||
is_op_assignment,
|
||||
);
|
||||
|
||||
if let Some((func, src)) = func {
|
||||
if let Some(FnResolutionCacheEntry { func, source }) = func {
|
||||
assert!(func.is_native());
|
||||
|
||||
// Calling pure function but the first argument is a reference?
|
||||
@ -343,7 +362,10 @@ impl Engine {
|
||||
}
|
||||
|
||||
// Run external function
|
||||
let source = src.as_ref().or_else(|| source.as_ref()).map(|s| s.as_str());
|
||||
let source = source
|
||||
.as_ref()
|
||||
.or_else(|| state_source.as_ref())
|
||||
.map(|s| s.as_str());
|
||||
let result = if func.is_plugin_fn() {
|
||||
func.get_plugin_fn()
|
||||
.call((self, fn_name, source, mods, lib).into(), args)
|
||||
@ -719,10 +741,9 @@ impl Engine {
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
if let Some((func, source)) = hash_script.and_then(|hash| {
|
||||
if let Some(FnResolutionCacheEntry { func, source }) = hash_script.and_then(|hash| {
|
||||
self.resolve_function(mods, state, lib, fn_name, hash, None, false, false)
|
||||
.as_ref()
|
||||
.map(|(f, s)| (f.clone(), s.clone()))
|
||||
.clone()
|
||||
}) {
|
||||
// Script function call
|
||||
assert!(func.is_script());
|
||||
|
Loading…
Reference in New Issue
Block a user