From dfb3378b28add4828582c9e53987c446c708c1db Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 27 Dec 2021 12:27:44 +0800 Subject: [PATCH] Expand function call arguments inline storage. --- src/engine.rs | 29 +++++++++++++---------------- src/func/call.rs | 28 ++++++++++++++-------------- src/lib.rs | 23 +++++++++++++++++++++++ 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index c26d54cc..39160104 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -2,19 +2,16 @@ use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, Stmt, AST_OPTION_FLAGS::*}; use crate::custom_syntax::CustomSyntax; -use crate::func::{ - get_hasher, - native::{OnDebugCallback, OnParseTokenCallback, OnPrintCallback, OnVarCallback}, - CallableFunction, IteratorFn, -}; +use crate::func::native::{OnDebugCallback, OnParseTokenCallback, OnPrintCallback, OnVarCallback}; +use crate::func::{get_hasher, CallableFunction, IteratorFn}; use crate::module::Namespace; use crate::packages::{Package, StandardPackage}; use crate::r#unsafe::unsafe_cast_var_name_to_lifetime; use crate::tokenizer::Token; use crate::types::dynamic::{map_std_type_name, AccessMode, Union, Variant}; use crate::{ - calc_fn_params_hash, combine_hashes, Dynamic, Identifier, ImmutableString, Module, Position, - RhaiError, RhaiResult, RhaiResultOf, Scope, Shared, StaticVec, ERR, INT, + calc_fn_params_hash, combine_hashes, Dynamic, FnArgsVec, Identifier, ImmutableString, Module, + Position, RhaiError, RhaiResult, RhaiResultOf, Scope, Shared, StaticVec, ERR, INT, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -372,7 +369,7 @@ enum ChainArgument { /// Arguments to a dot method call. /// Wrapped values are the arguments plus the [position][Position] of the first argument. #[cfg(not(feature = "no_object"))] - MethodCallArgs(StaticVec, Position), + MethodCallArgs(FnArgsVec, Position), /// Index value and [position][Position]. #[cfg(not(feature = "no_index"))] IndexValue(Dynamic, Position), @@ -395,7 +392,7 @@ impl ChainArgument { #[inline(always)] #[cfg(not(feature = "no_object"))] #[must_use] - pub fn into_fn_call_args(self) -> Option<(StaticVec, Position)> { + pub fn into_fn_call_args(self) -> Option<(FnArgsVec, Position)> { match self { Self::MethodCallArgs(values, pos) => Some((values, pos)), _ => None, @@ -418,9 +415,9 @@ impl ChainArgument { } #[cfg(not(feature = "no_object"))] -impl From<(StaticVec, Position)> for ChainArgument { +impl From<(FnArgsVec, Position)> for ChainArgument { #[inline(always)] - fn from((values, pos): (StaticVec, Position)) -> Self { + fn from((values, pos): (FnArgsVec, Position)) -> Self { Self::MethodCallArgs(values, pos) } } @@ -1325,7 +1322,7 @@ impl Engine { root: (&str, Position), rhs: &Expr, terminate_chaining: bool, - idx_values: &mut StaticVec, + idx_values: &mut FnArgsVec, chain_type: ChainType, level: usize, new_val: Option<((Dynamic, Position), (Option, Position))>, @@ -1790,7 +1787,7 @@ impl Engine { _ => unreachable!("index or dot chain expected, but gets {:?}", expr), }; - let idx_values = &mut StaticVec::new_const(); + let idx_values = &mut FnArgsVec::new_const(); self.eval_dot_index_chain_arguments( scope, mods, state, lib, this_ptr, rhs, term, chain_type, idx_values, 0, level, @@ -1846,7 +1843,7 @@ impl Engine { expr: &Expr, terminate_chaining: bool, parent_chain_type: ChainType, - idx_values: &mut StaticVec, + idx_values: &mut FnArgsVec, size: usize, level: usize, ) -> RhaiResultOf<()> { @@ -1863,7 +1860,7 @@ impl Engine { } = x.as_ref(); let (values, pos) = args.iter().try_fold( - (StaticVec::with_capacity(args.len()), Position::NONE), + (FnArgsVec::with_capacity(args.len()), Position::NONE), |(mut values, mut pos), expr| -> RhaiResultOf<_> { let (value, arg_pos) = self.get_arg_value( scope, mods, state, lib, this_ptr, level, expr, constants, @@ -1910,7 +1907,7 @@ impl Engine { args.iter() .try_fold( - (StaticVec::with_capacity(args.len()), Position::NONE), + (FnArgsVec::with_capacity(args.len()), Position::NONE), |(mut values, mut pos), expr| -> RhaiResultOf<_> { let (value, arg_pos) = self.get_arg_value( scope, mods, state, lib, this_ptr, level, expr, constants, diff --git a/src/func/call.rs b/src/func/call.rs index a6c44e42..3090a35b 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -12,8 +12,8 @@ use crate::engine::{ use crate::module::Namespace; use crate::tokenizer::Token; use crate::{ - calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, Identifier, - ImmutableString, Module, Position, RhaiResult, RhaiResultOf, Scope, StaticVec, ERR, + calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnArgsVec, FnPtr, + Identifier, ImmutableString, Module, Position, RhaiResult, RhaiResultOf, Scope, ERR, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -149,7 +149,7 @@ impl Engine { } else { self.map_type_name(a.type_name()) }) - .collect::>() + .collect::>() .join(", ") ) } @@ -727,7 +727,7 @@ impl Engine { fn_name: impl AsRef, mut hash: FnCallHashes, target: &mut crate::engine::Target, - (call_args, call_arg_pos): &mut (StaticVec, Position), + (call_args, call_arg_pos): &mut (FnArgsVec, Position), pos: Position, level: usize, ) -> RhaiResultOf<(Dynamic, bool)> { @@ -744,9 +744,9 @@ impl Engine { // Recalculate hashes let new_hash = calc_fn_hash(fn_name, args_len).into(); // Arguments are passed as-is, adding the curried arguments - let mut curry = StaticVec::with_capacity(fn_ptr.num_curried()); + let mut curry = FnArgsVec::with_capacity(fn_ptr.num_curried()); curry.extend(fn_ptr.curry().iter().cloned()); - let mut args = StaticVec::with_capacity(curry.len() + call_args.len()); + let mut args = FnArgsVec::with_capacity(curry.len() + call_args.len()); args.extend(curry.iter_mut()); args.extend(call_args.iter_mut()); @@ -782,9 +782,9 @@ impl Engine { calc_fn_hash(fn_name, args_len + 1), ); // Replace the first argument with the object pointer, adding the curried arguments - let mut curry = StaticVec::with_capacity(fn_ptr.num_curried()); + let mut curry = FnArgsVec::with_capacity(fn_ptr.num_curried()); curry.extend(fn_ptr.curry().iter().cloned()); - let mut args = StaticVec::with_capacity(curry.len() + call_args.len() + 1); + let mut args = FnArgsVec::with_capacity(curry.len() + call_args.len() + 1); args.push(target.as_mut()); args.extend(curry.iter_mut()); args.extend(call_args.iter_mut()); @@ -858,7 +858,7 @@ impl Engine { }; // Attached object pointer in front of the arguments - let mut args = StaticVec::with_capacity(call_args.len() + 1); + let mut args = FnArgsVec::with_capacity(call_args.len() + 1); args.push(target.as_mut()); args.extend(call_args.iter_mut()); @@ -918,7 +918,7 @@ impl Engine { let fn_name = fn_name.as_ref(); let mut a_expr = args_expr; let mut total_args = a_expr.len(); - let mut curry = StaticVec::new_const(); + let mut curry = FnArgsVec::new_const(); let mut name = fn_name; let mut hashes = hashes; let redirected; // Handle call() - Redirect function call @@ -1086,8 +1086,8 @@ impl Engine { } // Normal function call - except for Fn, curry, call and eval (handled above) - let mut arg_values = StaticVec::with_capacity(a_expr.len()); - let mut args = StaticVec::with_capacity(a_expr.len() + curry.len()); + let mut arg_values = FnArgsVec::with_capacity(a_expr.len()); + let mut args = FnArgsVec::with_capacity(a_expr.len() + curry.len()); let mut is_ref_mut = false; // Capture parent scope? @@ -1187,8 +1187,8 @@ impl Engine { level: usize, ) -> RhaiResult { let fn_name = fn_name.as_ref(); - let mut arg_values = StaticVec::with_capacity(args_expr.len()); - let mut args = StaticVec::with_capacity(args_expr.len()); + let mut arg_values = FnArgsVec::with_capacity(args_expr.len()); + let mut args = FnArgsVec::with_capacity(args_expr.len()); let mut first_arg_value = None; if args_expr.is_empty() { diff --git a/src/lib.rs b/src/lib.rs index bea085e1..d88dfc23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -313,6 +313,29 @@ type StaticVec = smallvec::SmallVec<[T; 3]>; #[cfg(feature = "internals")] pub type StaticVec = smallvec::SmallVec<[T; 3]>; +/// Inline arguments storage for function calls. +/// +/// # Notes +/// +/// Since most usage of this is during a function call to gather up arguments, this is mostly +/// allocated on the stack, so we can tolerate a larger number of values stored inline. +/// +/// Most functions have few parameters, but closures with a lot of captured variables can +/// potentially have many. Having a larger inline storage for arguments reduces allocations in +/// scripts with heavy closure usage. +/// +/// Under `no_closure`, this type aliases to [`StaticVec`][crate::StaticVec] instead. +#[cfg(not(feature = "no_closure"))] +type FnArgsVec = smallvec::SmallVec<[T; 8]>; + +/// Inline arguments storage for function calls. +/// +/// # Notes +/// +/// This type aliases to [`StaticVec`][crate::StaticVec] under `no_closure`. +#[cfg(feature = "no_closure")] +type FnArgsVec = crate::StaticVec; + pub(crate) type SmartString = smartstring::SmartString; // Compiler guards against mutually-exclusive feature flags