Streamline ref object backup.

This commit is contained in:
Stephen Chung 2021-03-02 14:44:21 +08:00
parent b76e8da5ee
commit 521c8fad27
2 changed files with 19 additions and 13 deletions

View File

@ -25,6 +25,7 @@ Breaking changes
Enhancements Enhancements
------------ ------------
* Function calls are more optimized and should now run faster.
* `range` function now supports negative step and decreasing streams (i.e. to < from). * `range` function now supports negative step and decreasing streams (i.e. to < from).
* More information is provided to the error variable captured by the `catch` statement in an _object map_. * More information is provided to the error variable captured by the `catch` statement in an _object map_.
* Previously, `private` functions in an `AST` cannot be called with `call_fn` etc. This is inconvenient when trying to call a function inside a script which also serves as a loadable module exporting part (but not all) of the functions. Now, all functions (`private` or not) can be called in an `AST`. The `private` keyword is relegated to preventing a function from being exported. * Previously, `private` functions in an `AST` cannot be called with `call_fn` etc. This is inconvenient when trying to call a function inside a script which also serves as a loadable module exporting part (but not all) of the functions. Now, all functions (`private` or not) can be called in an `AST`. The `private` keyword is relegated to preventing a function from being exported.

View File

@ -75,12 +75,7 @@ impl<'a> ArgBackup<'a> {
/// ///
/// If `restore_first_arg` is called before the end of the scope, the shorter lifetime will not leak. /// If `restore_first_arg` is called before the end of the scope, the shorter lifetime will not leak.
#[inline(always)] #[inline(always)]
fn change_first_arg_to_copy(&mut self, normalize: bool, args: &mut FnCallArgs<'a>) { fn change_first_arg_to_copy(&mut self, args: &mut FnCallArgs<'a>) {
// Only do it for method calls with arguments.
if !normalize || args.is_empty() {
return;
}
// Clone the original value. // Clone the original value.
self.value_copy = args[0].clone(); self.value_copy = args[0].clone();
@ -105,7 +100,7 @@ impl<'a> ArgBackup<'a> {
/// If `change_first_arg_to_copy` has been called, this function **MUST** be called _BEFORE_ exiting /// If `change_first_arg_to_copy` has been called, this function **MUST** be called _BEFORE_ exiting
/// the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak. /// the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak.
#[inline(always)] #[inline(always)]
fn restore_first_arg(&mut self, args: &mut FnCallArgs<'a>) { fn restore_first_arg(mut self, args: &mut FnCallArgs<'a>) {
if let Some(this_pointer) = self.orig_mut.take() { if let Some(this_pointer) = self.orig_mut.take() {
args[0] = this_pointer; args[0] = this_pointer;
} }
@ -340,8 +335,11 @@ impl Engine {
assert!(func.is_native()); assert!(func.is_native());
// Calling pure function but the first argument is a reference? // Calling pure function but the first argument is a reference?
let mut backup: ArgBackup = Default::default(); let mut backup: Option<ArgBackup> = None;
backup.change_first_arg_to_copy(is_ref && func.is_pure(), args); if is_ref && func.is_pure() && !args.is_empty() {
backup = Some(Default::default());
backup.as_mut().unwrap().change_first_arg_to_copy(args);
}
// Run external function // Run external function
let source = src.as_ref().or_else(|| source.as_ref()).map(|s| s.as_str()); let source = src.as_ref().or_else(|| source.as_ref()).map(|s| s.as_str());
@ -353,7 +351,9 @@ impl Engine {
}; };
// Restore the original reference // Restore the original reference
if let Some(backup) = backup {
backup.restore_first_arg(args); backup.restore_first_arg(args);
}
let result = result.map_err(|err| err.fill_position(pos))?; let result = result.map_err(|err| err.fill_position(pos))?;
@ -772,8 +772,11 @@ impl Engine {
} else { } else {
// Normal call of script function // Normal call of script function
// The first argument is a reference? // The first argument is a reference?
let mut backup: ArgBackup = Default::default(); let mut backup: Option<ArgBackup> = None;
backup.change_first_arg_to_copy(is_ref, args); if is_ref && !args.is_empty() {
backup = Some(Default::default());
backup.as_mut().unwrap().change_first_arg_to_copy(args);
}
let orig_source = mem::take(&mut state.source); let orig_source = mem::take(&mut state.source);
state.source = source; state.source = source;
@ -787,7 +790,9 @@ impl Engine {
state.source = orig_source; state.source = orig_source;
// Restore the original reference // Restore the original reference
if let Some(backup) = backup {
backup.restore_first_arg(args); backup.restore_first_arg(args);
}
result? result?
}; };