This commit is contained in:
Stephen Chung 2022-09-06 17:41:47 +08:00
commit a6ce459b32
7 changed files with 71 additions and 78 deletions

View File

@ -6,7 +6,7 @@ use crate::engine::{KEYWORD_THIS, OP_CONCAT};
use crate::eval::FnResolutionCacheEntry; use crate::eval::FnResolutionCacheEntry;
use crate::func::{ use crate::func::{
calc_fn_params_hash, combine_hashes, gen_fn_call_signature, get_builtin_binary_op_fn, calc_fn_params_hash, combine_hashes, gen_fn_call_signature, get_builtin_binary_op_fn,
CallableFunction, FnAny, CallableFunction,
}; };
use crate::types::dynamic::AccessMode; use crate::types::dynamic::AccessMode;
use crate::{Dynamic, Engine, Module, Position, RhaiResult, RhaiResultOf, Scope, ERR}; use crate::{Dynamic, Engine, Module, Position, RhaiResult, RhaiResultOf, Scope, ERR};
@ -258,19 +258,23 @@ impl Engine {
let cache = caches.fn_resolution_cache_mut(); let cache = caches.fn_resolution_cache_mut();
let func = if let Entry::Vacant(entry) = cache.entry(hash) { let func = match cache.entry(hash) {
Entry::Vacant(entry) => {
let func = if args.len() == 2 { let func = if args.len() == 2 {
get_builtin_binary_op_fn(&name, operands[0], operands[1]) get_builtin_binary_op_fn(name, operands[0], operands[1])
} else { } else {
None None
}; };
if let Some(f) = func { if let Some(f) = func {
entry.insert(Some(FnResolutionCacheEntry { &entry
func: CallableFunction::from_method(Box::new(f) as Box<FnAny>), .insert(Some(FnResolutionCacheEntry {
func: CallableFunction::from_fn_builtin(f),
source: None, source: None,
})); }))
&cache.get(&hash).unwrap().as_ref().unwrap().func .as_ref()
.unwrap()
.func
} else { } else {
let result = self.exec_fn_call( let result = self.exec_fn_call(
None, global, caches, lib, name, *hashes, operands, false, false, pos, None, global, caches, lib, name, *hashes, operands, false, false, pos,
@ -278,11 +282,15 @@ impl Engine {
); );
return result.map(|(v, ..)| v); return result.map(|(v, ..)| v);
} }
} else if let Some(entry) = cache.get(&hash).unwrap() { }
Entry::Occupied(entry) => {
if let Some(entry) = entry.into_mut() {
&entry.func &entry.func
} else { } else {
let sig = gen_fn_call_signature(self, name, operands); let sig = gen_fn_call_signature(self, name, operands);
return Err(ERR::ErrorFunctionNotFound(sig, pos).into()); return Err(ERR::ErrorFunctionNotFound(sig, pos).into());
}
}
}; };
let context = (self, name, None, &*global, lib, pos, level).into(); let context = (self, name, None, &*global, lib, pos, level).into();

View File

@ -253,7 +253,7 @@ impl<'a> Target<'a> {
#[must_use] #[must_use]
pub fn source(&self) -> &Dynamic { pub fn source(&self) -> &Dynamic {
match self { match self {
Self::RefMut(r) => *r, Self::RefMut(r) => r,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Self::SharedValue { source, .. } => source, Self::SharedValue { source, .. } => source,
Self::TempValue(v) => v, Self::TempValue(v) => v,
@ -401,9 +401,9 @@ impl Deref for Target<'_> {
#[inline] #[inline]
fn deref(&self) -> &Dynamic { fn deref(&self) -> &Dynamic {
match self { match self {
Self::RefMut(r) => *r, Self::RefMut(r) => r,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Self::SharedValue { source, .. } => &**source, Self::SharedValue { source, .. } => source,
Self::TempValue(ref r) => r, Self::TempValue(ref r) => r,
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Self::Bit { ref value, .. } Self::Bit { ref value, .. }
@ -425,7 +425,7 @@ impl DerefMut for Target<'_> {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Dynamic { fn deref_mut(&mut self) -> &mut Dynamic {
match self { match self {
Self::RefMut(r) => *r, Self::RefMut(r) => r,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Self::SharedValue { source, .. } => &mut *source, Self::SharedValue { source, .. } => &mut *source,
Self::TempValue(ref mut r) => r, Self::TempValue(ref mut r) => r,

View File

@ -1,7 +1,6 @@
//! Implement function-calling mechanism for [`Engine`]. //! Implement function-calling mechanism for [`Engine`].
use super::callable_function::CallableFunction; use super::callable_function::CallableFunction;
use super::native::FnAny;
use super::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn}; use super::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn};
use crate::api::default_limits::MAX_DYNAMIC_PARAMETERS; use crate::api::default_limits::MAX_DYNAMIC_PARAMETERS;
use crate::ast::{Expr, FnCallHashes, Stmt}; use crate::ast::{Expr, FnCallHashes, Stmt};
@ -289,18 +288,14 @@ impl Engine {
get_builtin_op_assignment_fn(fn_name, *first_arg, rest_args[0]).map( get_builtin_op_assignment_fn(fn_name, *first_arg, rest_args[0]).map(
|f| FnResolutionCacheEntry { |f| FnResolutionCacheEntry {
func: CallableFunction::from_method( func: CallableFunction::from_fn_builtin(f),
Box::new(f) as Box<FnAny>
),
source: None, source: None,
}, },
) )
} else { } else {
get_builtin_binary_op_fn(fn_name, args[0], args[1]).map(|f| { get_builtin_binary_op_fn(fn_name, args[0], args[1]).map(|f| {
FnResolutionCacheEntry { FnResolutionCacheEntry {
func: CallableFunction::from_method( func: CallableFunction::from_fn_builtin(f),
Box::new(f) as Box<FnAny>
),
source: None, source: None,
} }
}) })

View File

@ -1,6 +1,6 @@
//! Module defining the standard Rhai function type. //! Module defining the standard Rhai function type.
use super::native::{FnAny, FnPlugin, IteratorFn, SendSync}; use super::native::{FnAny, FnBuiltin, FnPlugin, IteratorFn, SendSync};
use crate::ast::FnAccess; use crate::ast::FnAccess;
use crate::plugin::PluginFunction; use crate::plugin::PluginFunction;
use crate::Shared; use crate::Shared;
@ -197,23 +197,17 @@ impl CallableFunction {
Self::Script(..) => None, Self::Script(..) => None,
} }
} }
/// Create a new [`CallableFunction::Pure`]. /// Create a new [`CallableFunction::Method`] from `FnBuiltin`.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn from_pure(func: Box<FnAny>) -> Self { pub fn from_fn_builtin(func: FnBuiltin) -> Self {
Self::Pure(func.into()) Self::Method(Shared::new(func))
}
/// Create a new [`CallableFunction::Method`].
#[inline(always)]
#[must_use]
pub fn from_method(func: Box<FnAny>) -> Self {
Self::Method(func.into())
} }
/// Create a new [`CallableFunction::Plugin`]. /// Create a new [`CallableFunction::Plugin`].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn from_plugin(func: impl PluginFunction + 'static + SendSync) -> Self { pub fn from_plugin(func: impl PluginFunction + 'static + SendSync) -> Self {
Self::Plugin((Box::new(func) as Box<FnPlugin>).into()) Self::Plugin(Shared::new(func))
} }
} }

View File

@ -96,18 +96,15 @@ pub fn get_hasher() -> ahash::AHasher {
#[inline] #[inline]
#[must_use] #[must_use]
pub fn calc_qualified_var_hash<'a>( pub fn calc_qualified_var_hash<'a>(
modules: impl IntoIterator<Item = &'a str>, modules: impl IntoIterator<Item = &'a str, IntoIter = impl ExactSizeIterator<Item = &'a str>>,
var_name: &str, var_name: &str,
) -> u64 { ) -> u64 {
let s = &mut get_hasher(); let s = &mut get_hasher();
// We always skip the first module // We always skip the first module
let mut len = 0; let iter = modules.into_iter();
modules let len = iter.len();
.into_iter() iter.skip(1).for_each(|m| m.hash(s));
.inspect(|_| len += 1)
.skip(1)
.for_each(|m| m.hash(s));
len.hash(s); len.hash(s);
var_name.hash(s); var_name.hash(s);
@ -133,19 +130,16 @@ pub fn calc_qualified_var_hash<'a>(
#[inline] #[inline]
#[must_use] #[must_use]
pub fn calc_qualified_fn_hash<'a>( pub fn calc_qualified_fn_hash<'a>(
modules: impl IntoIterator<Item = &'a str>, modules: impl IntoIterator<Item = &'a str, IntoIter = impl ExactSizeIterator<Item = &'a str>>,
fn_name: &str, fn_name: &str,
num: usize, num: usize,
) -> u64 { ) -> u64 {
let s = &mut get_hasher(); let s = &mut get_hasher();
// We always skip the first module // We always skip the first module
let mut len = 0; let iter = modules.into_iter();
modules let len = iter.len();
.into_iter() iter.skip(1).for_each(|m| m.hash(s));
.inspect(|_| len += 1)
.skip(1)
.for_each(|m| m.hash(s));
len.hash(s); len.hash(s);
fn_name.hash(s); fn_name.hash(s);
num.hash(s); num.hash(s);
@ -179,11 +173,13 @@ pub fn calc_fn_hash(fn_name: &str, num: usize) -> u64 {
/// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`. /// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`.
#[inline] #[inline]
#[must_use] #[must_use]
pub fn calc_fn_params_hash(params: impl IntoIterator<Item = TypeId>) -> u64 { pub fn calc_fn_params_hash(
params: impl IntoIterator<Item = TypeId, IntoIter = impl ExactSizeIterator<Item = TypeId>>,
) -> u64 {
let s = &mut get_hasher(); let s = &mut get_hasher();
let mut len = 0; let iter = params.into_iter();
params.into_iter().for_each(|t| { let len = iter.len();
len += 1; iter.for_each(|t| {
t.hash(s); t.hash(s);
}); });
len.hash(s); len.hash(s);

View File

@ -4,7 +4,7 @@
use super::call::FnCallArgs; use super::call::FnCallArgs;
use super::callable_function::CallableFunction; use super::callable_function::CallableFunction;
use super::native::{FnAny, SendSync}; use super::native::{SendSync, Shared};
use crate::types::dynamic::{DynamicWriteLock, Variant}; use crate::types::dynamic::{DynamicWriteLock, Variant};
use crate::{reify, Dynamic, NativeCallContext, RhaiResultOf}; use crate::{reify, Dynamic, NativeCallContext, RhaiResultOf};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
@ -120,7 +120,7 @@ macro_rules! check_constant {
macro_rules! def_register { macro_rules! def_register {
() => { () => {
def_register!(imp from_pure :); def_register!(imp Pure :);
}; };
(imp $abi:ident : $($par:ident => $arg:expr => $mark:ty => $param:ty => $let:stmt => $clone:expr),*) => { (imp $abi:ident : $($par:ident => $arg:expr => $mark:ty => $param:ty => $let:stmt => $clone:expr),*) => {
// ^ function ABI type // ^ function ABI type
@ -140,7 +140,7 @@ macro_rules! def_register {
#[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RET>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RET>() }
#[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::<RET>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::<RET>() }
#[inline(always)] fn into_callable_function(self) -> CallableFunction { #[inline(always)] fn into_callable_function(self) -> CallableFunction {
CallableFunction::$abi(Box::new(move |_ctx: NativeCallContext, args: &mut FnCallArgs| { CallableFunction::$abi(Shared::new(move |_ctx: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types! // The arguments are assumed to be of the correct number and types!
check_constant!(_ctx, args); check_constant!(_ctx, args);
@ -152,7 +152,7 @@ macro_rules! def_register {
// Map the result // Map the result
Ok(Dynamic::from(r)) Ok(Dynamic::from(r))
}) as Box<FnAny>) }))
} }
} }
@ -166,7 +166,7 @@ macro_rules! def_register {
#[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RET>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RET>() }
#[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::<RET>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::<RET>() }
#[inline(always)] fn into_callable_function(self) -> CallableFunction { #[inline(always)] fn into_callable_function(self) -> CallableFunction {
CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| { CallableFunction::$abi(Shared::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types! // The arguments are assumed to be of the correct number and types!
check_constant!(ctx, args); check_constant!(ctx, args);
@ -178,7 +178,7 @@ macro_rules! def_register {
// Map the result // Map the result
Ok(Dynamic::from(r)) Ok(Dynamic::from(r))
}) as Box<FnAny>) }))
} }
} }
@ -192,7 +192,7 @@ macro_rules! def_register {
#[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RhaiResultOf<RET>>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RhaiResultOf<RET>>() }
#[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::<RhaiResultOf<RET>>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::<RhaiResultOf<RET>>() }
#[inline(always)] fn into_callable_function(self) -> CallableFunction { #[inline(always)] fn into_callable_function(self) -> CallableFunction {
CallableFunction::$abi(Box::new(move |_ctx: NativeCallContext, args: &mut FnCallArgs| { CallableFunction::$abi(Shared::new(move |_ctx: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types! // The arguments are assumed to be of the correct number and types!
check_constant!(_ctx, args); check_constant!(_ctx, args);
@ -201,7 +201,7 @@ macro_rules! def_register {
// Call the function with each argument value // Call the function with each argument value
self($($arg),*).map(Dynamic::from) self($($arg),*).map(Dynamic::from)
}) as Box<FnAny>) }))
} }
} }
@ -215,7 +215,7 @@ macro_rules! def_register {
#[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RhaiResultOf<RET>>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RhaiResultOf<RET>>() }
#[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::<RhaiResultOf<RET>>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::<RhaiResultOf<RET>>() }
#[inline(always)] fn into_callable_function(self) -> CallableFunction { #[inline(always)] fn into_callable_function(self) -> CallableFunction {
CallableFunction::$abi(Box::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| { CallableFunction::$abi(Shared::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types! // The arguments are assumed to be of the correct number and types!
check_constant!(ctx, args); check_constant!(ctx, args);
@ -224,15 +224,15 @@ macro_rules! def_register {
// Call the function with each argument value // Call the function with each argument value
self(ctx, $($arg),*).map(Dynamic::from) self(ctx, $($arg),*).map(Dynamic::from)
}) as Box<FnAny>) }))
} }
} }
//def_register!(imp_pop $($par => $mark => $param),*); //def_register!(imp_pop $($par => $mark => $param),*);
}; };
($p0:ident $(, $p:ident)*) => { ($p0:ident $(, $p:ident)*) => {
def_register!(imp from_pure : $p0 => $p0 => $p0 => $p0 => let $p0 => by_value $(, $p => $p => $p => $p => let $p => by_value)*); def_register!(imp Pure : $p0 => $p0 => $p0 => $p0 => let $p0 => by_value $(, $p => $p => $p => $p => let $p => by_value)*);
def_register!(imp from_method : $p0 => &mut $p0 => Mut<$p0> => &mut $p0 => let mut $p0 => by_ref $(, $p => $p => $p => $p => let $p => by_value)*); def_register!(imp Method : $p0 => &mut $p0 => Mut<$p0> => &mut $p0 => let mut $p0 => by_ref $(, $p => $p => $p => $p => let $p => by_value)*);
// ^ CallableFunction constructor // ^ CallableFunction constructor
// ^ first parameter passed through // ^ first parameter passed through
// ^ others passed by value (by_value) // ^ others passed by value (by_value)

View File

@ -239,7 +239,7 @@ impl FuncInfo {
/// The first module name is skipped. Hashing starts from the _second_ module in the chain. /// The first module name is skipped. Hashing starts from the _second_ module in the chain.
#[inline] #[inline]
pub fn calc_native_fn_hash<'a>( pub fn calc_native_fn_hash<'a>(
modules: impl IntoIterator<Item = &'a str>, modules: impl IntoIterator<Item = &'a str, IntoIter = impl ExactSizeIterator<Item = &'a str>>,
fn_name: &str, fn_name: &str,
params: &[TypeId], params: &[TypeId],
) -> u64 { ) -> u64 {
@ -1263,7 +1263,7 @@ impl Module {
access, access,
None, None,
arg_types, arg_types,
CallableFunction::from_method(Box::new(f)), CallableFunction::Method(Shared::new(f)),
) )
} }