Use SusLock to hold pre-calculated indexer hashes.

This commit is contained in:
Stephen Chung 2022-11-25 11:49:00 +08:00
parent 6600862c22
commit 0286a52084
3 changed files with 70 additions and 41 deletions

View File

@ -94,15 +94,25 @@ fn hokmalock(address: usize) -> &'static HokmaLock {
&RECORDS[address % LEN]
}
// Safety: lol, there is a reason its called `SusLock<T>`
/// # Safety
///
/// LOL, there is a reason its called `SusLock`
#[must_use]
struct SusLock<T: 'static> {
pub struct SusLock<T: 'static> {
initialized: AtomicBool,
data: UnsafeCell<MaybeUninit<T>>,
_marker: PhantomData<T>,
}
impl<T: 'static> Default for SusLock<T> {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl<T: 'static> SusLock<T> {
/// Create a new [`SusLock`].
#[inline]
pub const fn new() -> Self {
Self {
@ -112,12 +122,15 @@ impl<T: 'static> SusLock<T> {
}
}
/// Is the [`SusLock`] initialized?
#[inline(always)]
#[must_use]
pub fn is_initialized(&self) -> bool {
self.initialized.load(Ordering::SeqCst)
}
/// Return the value of the [`SusLock`] (if initialized).
#[inline]
#[must_use]
pub fn get(&self) -> Option<&'static T> {
if self.initialized.load(Ordering::SeqCst) {
@ -133,6 +146,8 @@ impl<T: 'static> SusLock<T> {
}
}
/// Return the value of the [`SusLock`], initializing it if not yet done.
#[inline]
#[must_use]
pub fn get_or_init(&self, f: impl FnOnce() -> T) -> &'static T {
if !self.initialized.load(Ordering::SeqCst) {
@ -147,7 +162,13 @@ impl<T: 'static> SusLock<T> {
self.get().unwrap()
}
pub fn set(&self, value: T) -> Result<(), T> {
/// Initialize the value of the [`SusLock`].
///
/// # Error
///
/// If the [`SusLock`] has already been initialized, the current value is returned as error.
#[inline]
pub fn init(&self, value: T) -> Result<(), T> {
if self.initialized.load(Ordering::SeqCst) {
Err(value)
} else {
@ -198,7 +219,7 @@ static AHASH_SEED: SusLock<Option<[u64; 4]>> = SusLock::new();
/// ```
#[inline(always)]
pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> {
AHASH_SEED.set(new_seed)
AHASH_SEED.init(new_seed)
}
/// Get the current hashing Seed.

View File

@ -3,13 +3,36 @@
use super::{Caches, GlobalRuntimeState, Target};
use crate::ast::{ASTFlags, Expr, OpAssignment};
use crate::config::hashing::SusLock;
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
use crate::types::dynamic::Union;
use crate::types::RestoreOnDrop;
use crate::{Dynamic, Engine, FnArgsVec, Position, RhaiResult, RhaiResultOf, Scope, ERR};
use crate::{
calc_fn_hash, Dynamic, Engine, FnArgsVec, Position, RhaiResult, RhaiResultOf, Scope, ERR,
};
use std::hash::Hash;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
/// Function call hashes to index getters and setters.
///
/// # Safety
///
/// Uses the extremely unsafe [`SusLock`]. Change to [`OnceCell`] when it is stabilized.
static INDEXER_HASHES: SusLock<(u64, u64)> = SusLock::new();
/// Get the pre-calculated index getter/setter hashes.
#[inline(always)]
#[must_use]
fn hash_idx() -> (u64, u64) {
*INDEXER_HASHES.get_or_init(|| {
(
calc_fn_hash(None, FN_IDX_GET, 2),
calc_fn_hash(None, FN_IDX_SET, 3),
)
})
}
/// Method of chaining.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum ChainType {
@ -45,16 +68,21 @@ impl Engine {
idx: &mut Dynamic,
pos: Position,
) -> RhaiResultOf<Dynamic> {
let args = &mut [target, idx];
let hash = global.hash_idx_get();
let fn_name = crate::engine::FN_IDX_GET;
let orig_level = global.level;
global.level += 1;
let global = &mut *RestoreOnDrop::lock(global, move |g| g.level = orig_level);
self.exec_native_fn_call(global, caches, fn_name, None, hash, args, true, pos)
.map(|(r, ..)| r)
self.exec_native_fn_call(
global,
caches,
FN_IDX_GET,
None,
hash_idx().0,
&mut [target, idx],
true,
pos,
)
.map(|(r, ..)| r)
}
/// Call a set indexer.
@ -69,15 +97,20 @@ impl Engine {
is_ref_mut: bool,
pos: Position,
) -> RhaiResultOf<(Dynamic, bool)> {
let hash = global.hash_idx_set();
let args = &mut [target, idx, new_val];
let fn_name = crate::engine::FN_IDX_SET;
let orig_level = global.level;
global.level += 1;
let global = &mut *RestoreOnDrop::lock(global, move |g| g.level = orig_level);
self.exec_native_fn_call(global, caches, fn_name, None, hash, args, is_ref_mut, pos)
self.exec_native_fn_call(
global,
caches,
FN_IDX_SET,
None,
hash_idx().1,
&mut [target, idx, new_val],
is_ref_mut,
pos,
)
}
/// Get the value at the indexed position of a base type.

View File

@ -58,9 +58,6 @@ pub struct GlobalRuntimeState {
///
/// When that happens, this flag is turned on.
pub always_search_scope: bool,
/// Function call hashes to index getters and setters.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn_hash_indexing: (u64, u64),
/// Embedded [module][crate::Module] resolver.
#[cfg(not(feature = "no_module"))]
pub embedded_module_resolver:
@ -99,11 +96,6 @@ impl GlobalRuntimeState {
always_search_scope: false,
#[cfg(not(feature = "no_module"))]
embedded_module_resolver: None,
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn_hash_indexing: (
crate::calc_fn_hash(None, crate::engine::FN_IDX_GET, 2),
crate::calc_fn_hash(None, crate::engine::FN_IDX_SET, 3),
),
#[cfg(not(feature = "no_module"))]
#[cfg(not(feature = "no_function"))]
constants: None,
@ -314,20 +306,6 @@ impl GlobalRuntimeState {
pub(crate) const fn source_raw(&self) -> Option<&ImmutableString> {
self.source.as_ref()
}
/// Get the pre-calculated index getter hash.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline(always)]
#[must_use]
pub(crate) fn hash_idx_get(&mut self) -> u64 {
self.fn_hash_indexing.0
}
/// Get the pre-calculated index setter hash.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline(always)]
#[must_use]
pub(crate) fn hash_idx_set(&mut self) -> u64 {
self.fn_hash_indexing.1
}
/// Return a reference to the debugging interface.
///
@ -387,9 +365,6 @@ impl fmt::Debug for GlobalRuntimeState {
.field("scope_level", &self.scope_level)
.field("always_search_scope", &self.always_search_scope);
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
f.field("fn_hash_indexing", &self.fn_hash_indexing);
#[cfg(not(feature = "no_module"))]
#[cfg(not(feature = "no_function"))]
f.field("constants", &self.constants);