Speed up method calls.

This commit is contained in:
Stephen Chung 2022-06-08 16:34:56 +08:00
parent f4ebaa7abf
commit bbaad8dfcb
4 changed files with 91 additions and 41 deletions

View File

@ -197,15 +197,17 @@ impl Engine {
name, hashes, args, .. name, hashes, args, ..
} = x.as_ref(); } = x.as_ref();
let call_args = &mut ( let offset = idx_values.len() - args.len();
idx_values.drain(idx_values.len() - args.len()..).collect(), let call_args = &mut idx_values[offset..];
args.get(0).map_or(Position::NONE, Expr::position), let pos1 = args.get(0).map_or(Position::NONE, Expr::position);
);
let result = self.make_method_call( let result = self.make_method_call(
global, caches, lib, name, *hashes, target, call_args, *pos, level, global, caches, lib, name, *hashes, target, call_args, pos1, *pos,
level,
); );
idx_values.truncate(offset);
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
global.debugger.reset_status(reset_debugger); global.debugger.reset_status(reset_debugger);
@ -372,16 +374,17 @@ impl Engine {
name, hashes, args, .. name, hashes, args, ..
} = x.as_ref(); } = x.as_ref();
let call_args = &mut ( let offset = idx_values.len() - args.len();
idx_values.drain(idx_values.len() - args.len()..).collect(), let call_args = &mut idx_values[offset..];
args.get(0).map_or(Position::NONE, Expr::position), let pos1 = args.get(0).map_or(Position::NONE, Expr::position);
);
let result = self.make_method_call( let result = self.make_method_call(
global, caches, lib, name, *hashes, target, call_args, pos, global, caches, lib, name, *hashes, target, call_args, pos1,
level, pos, level,
); );
idx_values.truncate(offset);
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
global.debugger.reset_status(reset_debugger); global.debugger.reset_status(reset_debugger);
@ -497,16 +500,17 @@ impl Engine {
} = f.as_ref(); } = f.as_ref();
let rhs_chain = rhs.into(); let rhs_chain = rhs.into();
let call_args = &mut ( let offset = idx_values.len() - args.len();
idx_values.drain(idx_values.len() - args.len()..).collect(), let call_args = &mut idx_values[offset..];
args.get(0).map_or(Position::NONE, Expr::position), let pos1 = args.get(0).map_or(Position::NONE, Expr::position);
);
let result = self.make_method_call( let result = self.make_method_call(
global, caches, lib, name, *hashes, target, call_args, pos, global, caches, lib, name, *hashes, target, call_args, pos1,
level, pos, level,
); );
idx_values.truncate(offset);
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
global.debugger.reset_status(reset_debugger); global.debugger.reset_status(reset_debugger);
@ -570,11 +574,14 @@ impl Engine {
Expr::FnCall(x, ..) Expr::FnCall(x, ..)
if chain_type == ChainType::Dotting && x.args.iter().all(Expr::is_constant) => if chain_type == ChainType::Dotting && x.args.iter().all(Expr::is_constant) =>
{ {
x.args idx_values.extend(x.args.iter().map(|expr| expr.get_literal_value().unwrap()))
.iter()
.map(|expr| expr.get_literal_value().unwrap())
.for_each(|v| idx_values.push(v))
} }
// Short-circuit for indexing with literal: {expr}[1]
#[cfg(not(feature = "no_index"))]
_ if chain_type == ChainType::Indexing && rhs.is_constant() => {
idx_values.push(rhs.get_literal_value().unwrap())
}
// All other patterns - evaluate the arguments chain
_ => { _ => {
self.eval_dot_index_chain_arguments( self.eval_dot_index_chain_arguments(
scope, global, caches, lib, this_ptr, rhs, options, chain_type, idx_values, 0, scope, global, caches, lib, this_ptr, rhs, options, chain_type, idx_values, 0,
@ -649,9 +656,11 @@ impl Engine {
if _parent_chain_type == ChainType::Dotting && !x.is_qualified() => if _parent_chain_type == ChainType::Dotting && !x.is_qualified() =>
{ {
for arg_expr in x.args.as_ref() { for arg_expr in x.args.as_ref() {
let (value, _) = idx_values.push(
self.get_arg_value(scope, global, caches, lib, this_ptr, arg_expr, level)?; self.get_arg_value(scope, global, caches, lib, this_ptr, arg_expr, level)?
idx_values.push(value.flatten()); .0
.flatten(),
);
} }
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -681,10 +690,13 @@ impl Engine {
if _parent_chain_type == ChainType::Dotting && !x.is_qualified() => if _parent_chain_type == ChainType::Dotting && !x.is_qualified() =>
{ {
for arg_expr in x.args.as_ref() { for arg_expr in x.args.as_ref() {
let (value, _) = self.get_arg_value( arg_values.push(
self.get_arg_value(
scope, global, caches, lib, this_ptr, arg_expr, level, scope, global, caches, lib, this_ptr, arg_expr, level,
)?; )?
arg_values.push(value.flatten()); .0
.flatten(),
);
} }
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]

View File

@ -315,7 +315,7 @@ impl Debugger {
/// Change the current status to [`CONTINUE`][DebuggerStatus::CONTINUE] and return the previous status. /// Change the current status to [`CONTINUE`][DebuggerStatus::CONTINUE] and return the previous status.
pub(crate) fn clear_status_if( pub(crate) fn clear_status_if(
&mut self, &mut self,
filter: impl Fn(&DebuggerStatus) -> bool, filter: impl FnOnce(&DebuggerStatus) -> bool,
) -> Option<DebuggerStatus> { ) -> Option<DebuggerStatus> {
if filter(&self.status) { if filter(&self.status) {
Some(mem::replace(&mut self.status, DebuggerStatus::CONTINUE)) Some(mem::replace(&mut self.status, DebuggerStatus::CONTINUE))

View File

@ -46,7 +46,7 @@ pub fn calc_index<E>(
length: usize, length: usize,
start: crate::INT, start: crate::INT,
negative_count_from_end: bool, negative_count_from_end: bool,
err: impl Fn() -> Result<usize, E>, err: impl FnOnce() -> Result<usize, E>,
) -> Result<usize, E> { ) -> Result<usize, E> {
if start < 0 { if start < 0 {
if negative_count_from_end { if negative_count_from_end {

View File

@ -782,8 +782,9 @@ impl Engine {
fn_name: &str, fn_name: &str,
mut hash: FnCallHashes, mut hash: FnCallHashes,
target: &mut crate::eval::Target, target: &mut crate::eval::Target,
(call_args, call_arg_pos): &mut (FnArgsVec<Dynamic>, Position), mut call_args: &mut [Dynamic],
pos: Position, first_arg_pos: Position,
fn_call_pos: Position,
level: usize, level: usize,
) -> RhaiResultOf<(Dynamic, bool)> { ) -> RhaiResultOf<(Dynamic, bool)> {
let is_ref_mut = target.is_ref(); let is_ref_mut = target.is_ref();
@ -806,7 +807,16 @@ impl Engine {
// Map it to name(args) in function-call style // Map it to name(args) in function-call style
self.exec_fn_call( self.exec_fn_call(
None, global, caches, lib, fn_name, new_hash, &mut args, false, false, pos, None,
global,
caches,
lib,
fn_name,
new_hash,
&mut args,
false,
false,
fn_call_pos,
level, level,
) )
} }
@ -814,15 +824,17 @@ impl Engine {
if !call_args.is_empty() { if !call_args.is_empty() {
if !call_args[0].is::<FnPtr>() { if !call_args[0].is::<FnPtr>() {
let typ = self.map_type_name(call_args[0].type_name()); let typ = self.map_type_name(call_args[0].type_name());
return Err(self.make_type_mismatch_err::<FnPtr>(typ, *call_arg_pos)); return Err(self.make_type_mismatch_err::<FnPtr>(typ, first_arg_pos));
} }
} else { } else {
let typ = self.map_type_name(target.type_name()); let typ = self.map_type_name(target.type_name());
return Err(self.make_type_mismatch_err::<FnPtr>(typ, pos)); return Err(self.make_type_mismatch_err::<FnPtr>(typ, fn_call_pos));
} }
// FnPtr call on object // FnPtr call on object
let fn_ptr = call_args.remove(0).cast::<FnPtr>(); let fn_ptr = mem::take(&mut call_args[0]).cast::<FnPtr>();
call_args = &mut call_args[1..];
// Redirect function name // Redirect function name
let fn_name = fn_ptr.fn_name(); let fn_name = fn_ptr.fn_name();
let args_len = call_args.len() + fn_ptr.curry().len(); let args_len = call_args.len() + fn_ptr.curry().len();
@ -842,14 +854,23 @@ impl Engine {
// Map it to name(args) in function-call style // Map it to name(args) in function-call style
self.exec_fn_call( self.exec_fn_call(
None, global, caches, lib, fn_name, new_hash, &mut args, is_ref_mut, true, pos, None,
global,
caches,
lib,
fn_name,
new_hash,
&mut args,
is_ref_mut,
true,
fn_call_pos,
level, level,
) )
} }
KEYWORD_FN_PTR_CURRY => { KEYWORD_FN_PTR_CURRY => {
if !target.is::<FnPtr>() { if !target.is::<FnPtr>() {
let typ = self.map_type_name(target.type_name()); let typ = self.map_type_name(target.type_name());
return Err(self.make_type_mismatch_err::<FnPtr>(typ, pos)); return Err(self.make_type_mismatch_err::<FnPtr>(typ, fn_call_pos));
} }
let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`"); let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`");
@ -883,6 +904,8 @@ impl Engine {
_ => { _ => {
let mut fn_name = fn_name; let mut fn_name = fn_name;
let _redirected; let _redirected;
let mut call_args = call_args;
let mut arg_values: FnArgsVec<_>;
// Check if it is a map method call in OOP style // Check if it is a map method call in OOP style
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -894,7 +917,13 @@ impl Engine {
fn_name = &_redirected; fn_name = &_redirected;
// Add curried arguments // Add curried arguments
if fn_ptr.is_curried() { if fn_ptr.is_curried() {
call_args.insert_many(0, fn_ptr.curry().iter().cloned()); arg_values = fn_ptr
.curry()
.iter()
.cloned()
.chain(call_args.iter_mut().map(mem::take))
.collect();
call_args = &mut arg_values;
} }
// Recalculate the hash based on the new function name and new arguments // Recalculate the hash based on the new function name and new arguments
hash = FnCallHashes::from_all( hash = FnCallHashes::from_all(
@ -912,7 +941,16 @@ impl Engine {
args.extend(call_args.iter_mut()); args.extend(call_args.iter_mut());
self.exec_fn_call( self.exec_fn_call(
None, global, caches, lib, fn_name, hash, &mut args, is_ref_mut, true, pos, None,
global,
caches,
lib,
fn_name,
hash,
&mut args,
is_ref_mut,
true,
fn_call_pos,
level, level,
) )
} }
@ -920,7 +958,7 @@ impl Engine {
// Propagate the changed value back to the source if necessary // Propagate the changed value back to the source if necessary
if updated { if updated {
target.propagate_changed_value(pos)?; target.propagate_changed_value(fn_call_pos)?;
} }
Ok((result, updated)) Ok((result, updated))