Use caching for fast operators.

This commit is contained in:
Stephen Chung 2022-09-03 11:27:13 +08:00
parent 0516e8088c
commit fcdd2eb143
3 changed files with 64 additions and 24 deletions

View File

@ -242,17 +242,57 @@ impl Engine {
let arg_values = &mut [&mut lhs, &mut rhs]; let arg_values = &mut [&mut lhs, &mut rhs];
return if let Some(f) = let hash = crate::func::combine_hashes(
crate::func::get_builtin_binary_op_fn(&name, arg_values[0], arg_values[1]) hashes.native,
{ crate::func::calc_fn_params_hash(arg_values.iter().map(|a| a.type_id())),
let context = (self, name, None, &*global, lib, pos, level).into(); );
(f)(context, arg_values)
} else { let c = caches.fn_resolution_cache_mut();
self.exec_fn_call(
None, global, caches, lib, name, *hashes, arg_values, false, false, pos, level, let entry = if c.contains_key(&hash) {
match c.get(&hash).unwrap() {
Some(entry) => entry,
None => {
return Err(ERR::ErrorFunctionNotFound(
self.gen_fn_call_signature(
#[cfg(not(feature = "no_module"))]
&crate::ast::Namespace::NONE,
name,
arg_values,
),
pos,
) )
.map(|(v, ..)| v) .into())
}
}
} else {
match crate::func::get_builtin_binary_op_fn(&name, arg_values[0], arg_values[1]) {
Some(f) => {
let entry = crate::eval::FnResolutionCacheEntry {
func: crate::func::CallableFunction::from_method(
Box::new(f) as Box<crate::func::FnAny>
),
source: None,
}; };
c.insert(hash, Some(entry));
c.get(&hash).unwrap().as_ref().unwrap()
}
None => {
println!("Exec {name} with {:?}", arg_values);
return self
.exec_fn_call(
None, global, caches, lib, name, *hashes, arg_values, false, false,
pos, level,
)
.map(|(v, ..)| v);
}
}
};
let func = entry.func.get_native_fn().unwrap();
let context = (self, name, None, &*global, lib, pos, level).into();
let result = (func)(context, arg_values);
return self.check_return_value(result, pos);
} }
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]

View File

@ -131,7 +131,7 @@ impl Engine {
/// Generate the signature for a function call. /// Generate the signature for a function call.
#[inline] #[inline]
#[must_use] #[must_use]
fn gen_call_signature( pub(crate) fn gen_fn_call_signature(
&self, &self,
#[cfg(not(feature = "no_module"))] namespace: &crate::ast::Namespace, #[cfg(not(feature = "no_module"))] namespace: &crate::ast::Namespace,
fn_name: &str, fn_name: &str,
@ -174,26 +174,26 @@ impl Engine {
fn resolve_fn<'s>( fn resolve_fn<'s>(
&self, &self,
_global: &GlobalRuntimeState, _global: &GlobalRuntimeState,
state: &'s mut Caches, caches: &'s mut Caches,
lib: &[&Module], lib: &[&Module],
fn_name: &str, fn_name: &str,
hash_script: u64, hash_base: u64,
args: Option<&mut FnCallArgs>, args: Option<&mut FnCallArgs>,
allow_dynamic: bool, allow_dynamic: bool,
is_op_assignment: bool, is_op_assignment: bool,
) -> Option<&'s FnResolutionCacheEntry> { ) -> Option<&'s FnResolutionCacheEntry> {
if hash_script == 0 { if hash_base == 0 {
return None; return None;
} }
let mut hash = args.as_ref().map_or(hash_script, |args| { let mut hash = args.as_ref().map_or(hash_base, |args| {
combine_hashes( combine_hashes(
hash_script, hash_base,
calc_fn_params_hash(args.iter().map(|a| a.type_id())), calc_fn_params_hash(args.iter().map(|a| a.type_id())),
) )
}); });
let result = state let result = caches
.fn_resolution_cache_mut() .fn_resolution_cache_mut()
.entry(hash) .entry(hash)
.or_insert_with(|| { .or_insert_with(|| {
@ -248,21 +248,21 @@ impl Engine {
// Check `Dynamic` parameters for functions with parameters // Check `Dynamic` parameters for functions with parameters
if allow_dynamic && max_bitmask == 0 && num_args > 0 { if allow_dynamic && max_bitmask == 0 && num_args > 0 {
let is_dynamic = lib.iter().any(|&m| m.contains_dynamic_fn(hash_script)) let is_dynamic = lib.iter().any(|&m| m.contains_dynamic_fn(hash_base))
|| self || self
.global_modules .global_modules
.iter() .iter()
.any(|m| m.contains_dynamic_fn(hash_script)); .any(|m| m.contains_dynamic_fn(hash_base));
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
let is_dynamic = is_dynamic let is_dynamic = is_dynamic
|| _global || _global
.iter_imports_raw() .iter_imports_raw()
.any(|(_, m)| m.contains_dynamic_fn(hash_script)) .any(|(_, m)| m.contains_dynamic_fn(hash_base))
|| self || self
.global_sub_modules .global_sub_modules
.values() .values()
.any(|m| m.contains_dynamic_fn(hash_script)); .any(|m| m.contains_dynamic_fn(hash_base));
// Set maximum bitmask when there are dynamic versions of the function // Set maximum bitmask when there are dynamic versions of the function
if is_dynamic { if is_dynamic {
@ -317,7 +317,7 @@ impl Engine {
} }
}), }),
); );
hash = combine_hashes(hash_script, hash_params); hash = combine_hashes(hash_base, hash_params);
bitmask += 1; bitmask += 1;
} }
@ -542,7 +542,7 @@ impl Engine {
// Raise error // Raise error
_ => Err(ERR::ErrorFunctionNotFound( _ => Err(ERR::ErrorFunctionNotFound(
self.gen_call_signature( self.gen_fn_call_signature(
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
&crate::ast::Namespace::NONE, &crate::ast::Namespace::NONE,
name, name,
@ -1429,7 +1429,7 @@ impl Engine {
Some(f) => unreachable!("unknown function type: {:?}", f), Some(f) => unreachable!("unknown function type: {:?}", f),
None => Err(ERR::ErrorFunctionNotFound( None => Err(ERR::ErrorFunctionNotFound(
self.gen_call_signature(namespace, fn_name, &args), self.gen_fn_call_signature(namespace, fn_name, &args),
pos, pos,
) )
.into()), .into()),

View File

@ -123,7 +123,7 @@ pub mod array_functions {
/// let x = [1, 2, 3]; /// let x = [1, 2, 3];
/// let y = [true, 'x']; /// let y = [true, 'x'];
/// ///
/// x.push(y); /// x.append(y);
/// ///
/// print(x); // prints "[1, 2, 3, true, 'x']" /// print(x); // prints "[1, 2, 3, true, 'x']"
/// ``` /// ```