From b4ef89b5969ee1d5780e6ef26f70847105878e7d Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 24 Nov 2022 16:05:23 +0800 Subject: [PATCH] Fix sync build. --- src/api/compile.rs | 5 +++-- src/api/eval.rs | 3 ++- src/api/json.rs | 3 ++- src/api/run.rs | 3 ++- src/parser.rs | 2 +- src/types/interner.rs | 35 +++++++++++++++-------------------- 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/api/compile.rs b/src/api/compile.rs index 0eab7376..887d45ab 100644 --- a/src/api/compile.rs +++ b/src/api/compile.rs @@ -1,5 +1,6 @@ //! Module that defines the public compilation API of [`Engine`]. +use crate::func::native::locked_write; use crate::parser::{ParseResult, ParseState}; use crate::{Engine, OptimizationLevel, Scope, AST}; #[cfg(feature = "no_std")] @@ -221,7 +222,7 @@ impl Engine { scripts.as_ref(), self.token_mapper.as_ref().map(<_>::as_ref), ); - let interned_strings = &mut *self.interned_strings.borrow_mut(); + let interned_strings = &mut *locked_write(&self.interned_strings); let mut state = ParseState::new(self, scope, interned_strings, tokenizer_control); let mut _ast = self.parse(&mut stream.peekable(), &mut state, optimization_level)?; #[cfg(feature = "metadata")] @@ -295,7 +296,7 @@ impl Engine { self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref)); let mut peekable = stream.peekable(); - let interned_strings = &mut *self.interned_strings.borrow_mut(); + let interned_strings = &mut *locked_write(&self.interned_strings); let mut state = ParseState::new(self, scope, interned_strings, tokenizer_control); self.parse_global_expr(&mut peekable, &mut state, |_| {}, self.optimization_level) } diff --git a/src/api/eval.rs b/src/api/eval.rs index 10bb3138..cb855488 100644 --- a/src/api/eval.rs +++ b/src/api/eval.rs @@ -1,6 +1,7 @@ //! Module that defines the public evaluation API of [`Engine`]. use crate::eval::{Caches, GlobalRuntimeState}; +use crate::func::native::locked_write; use crate::parser::ParseState; use crate::types::dynamic::Variant; use crate::{ @@ -118,7 +119,7 @@ impl Engine { ) -> RhaiResultOf { let scripts = [script]; let ast = { - let interned_strings = &mut *self.interned_strings.borrow_mut(); + let interned_strings = &mut *locked_write(&self.interned_strings); let (stream, tokenizer_control) = self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref)); diff --git a/src/api/json.rs b/src/api/json.rs index cc0792ff..37c3a6c4 100644 --- a/src/api/json.rs +++ b/src/api/json.rs @@ -1,6 +1,7 @@ //! Module that defines JSON manipulation functions for [`Engine`]. #![cfg(not(feature = "no_object"))] +use crate::func::native::locked_write; use crate::parser::{ParseSettingFlags, ParseState}; use crate::tokenizer::Token; use crate::{Engine, LexError, Map, OptimizationLevel, RhaiResultOf, Scope}; @@ -118,7 +119,7 @@ impl Engine { let ast = { let scope = Scope::new(); - let interned_strings = &mut *self.interned_strings.borrow_mut(); + let interned_strings = &mut *locked_write(&self.interned_strings); let mut state = ParseState::new(self, &scope, interned_strings, tokenizer_control); self.parse_global_expr( diff --git a/src/api/run.rs b/src/api/run.rs index ca744900..264180b2 100644 --- a/src/api/run.rs +++ b/src/api/run.rs @@ -1,6 +1,7 @@ //! Module that defines the public evaluation API of [`Engine`]. use crate::eval::{Caches, GlobalRuntimeState}; +use crate::func::native::locked_write; use crate::parser::ParseState; use crate::{Engine, RhaiResultOf, Scope, AST}; #[cfg(feature = "no_std")] @@ -57,7 +58,7 @@ impl Engine { pub fn run_with_scope(&self, scope: &mut Scope, script: &str) -> RhaiResultOf<()> { let scripts = [script]; let ast = { - let interned_strings = &mut *self.interned_strings.borrow_mut(); + let interned_strings = &mut *locked_write(&self.interned_strings); let (stream, tokenizer_control) = self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref)); diff --git a/src/parser.rs b/src/parser.rs index 9eeba45e..aa7e940e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -51,7 +51,7 @@ pub struct ParseState<'e, 's> { pub tokenizer_control: TokenizerControl, /// Controls whether parsing of an expression should stop given the next token. pub expr_filter: fn(&Token) -> bool, - /// String interners. + /// Strings interner. interned_strings: &'s mut StringsInterner, /// External [scope][Scope] with constants. pub scope: &'e Scope<'e>, diff --git a/src/types/interner.rs b/src/types/interner.rs index 1127012f..8f2618ce 100644 --- a/src/types/interner.rs +++ b/src/types/interner.rs @@ -3,6 +3,7 @@ use super::BloomFilterU64; use crate::func::{hashing::get_hasher, StraightHashMap}; use crate::ImmutableString; +use ahash::HashMapExt; #[cfg(feature = "no_std")] use hashbrown::hash_map::Entry; #[cfg(not(feature = "no_std"))] @@ -26,14 +27,10 @@ pub const MAX_STRING_LEN: usize = 24; #[derive(Clone)] #[must_use] pub struct StringsInterner { - /// Maximum number of strings interned. - pub capacity: usize, - /// Maximum string length. - pub max_string_len: usize, /// Cached strings. cache: StraightHashMap, /// Bloom filter to avoid caching "one-hit wonders". - filter: BloomFilterU64, + bloom_filter: BloomFilterU64, } impl Default for StringsInterner { @@ -56,10 +53,8 @@ impl StringsInterner { #[inline(always)] pub fn new() -> Self { Self { - capacity: MAX_INTERNED_STRINGS, - max_string_len: MAX_STRING_LEN, - cache: StraightHashMap::default(), - filter: BloomFilterU64::new(), + cache: StraightHashMap::new(), + bloom_filter: BloomFilterU64::new(), } } @@ -87,10 +82,14 @@ impl StringsInterner { let hash = hasher.finish(); // Cache long strings only on the second try to avoid caching "one-hit wonders". - if key.len() > MAX_STRING_LEN && self.filter.is_absent_and_set(hash) { + if key.len() > MAX_STRING_LEN && self.bloom_filter.is_absent_and_set(hash) { return mapper(text); } + if self.cache.is_empty() { + self.cache.reserve(MAX_INTERNED_STRINGS); + } + let result = match self.cache.entry(hash) { Entry::Occupied(e) => return e.get().clone(), Entry::Vacant(e) => { @@ -110,26 +109,22 @@ impl StringsInterner { } /// If the interner is over capacity, remove the longest entry that has the lowest count - fn throttle_cache(&mut self, hash: u64) { - if self.cache.len() <= self.capacity { + #[inline] + fn throttle_cache(&mut self, skip_hash: u64) { + if self.cache.len() <= MAX_INTERNED_STRINGS { return; } // Leave some buffer to grow when shrinking the cache. // We leave at least two entries, one for the empty string, and one for the string // that has just been inserted. - let max = if self.capacity < 5 { - 2 - } else { - self.capacity - 3 - }; - - while self.cache.len() > max { + while self.cache.len() > MAX_INTERNED_STRINGS - 3 { let (_, _, n) = self .cache .iter() .fold((0, usize::MAX, 0), |(x, c, n), (&k, v)| { - if k != hash && (v.strong_count() < c || (v.strong_count() == c && v.len() > x)) + if k != skip_hash + && (v.strong_count() < c || (v.strong_count() == c && v.len() > x)) { (v.len(), v.strong_count(), k) } else {