diff --git a/boa/src/builtins/array/array_iterator.rs b/boa/src/builtins/array/array_iterator.rs index 3934d5979a..f1ee54cce4 100644 --- a/boa/src/builtins/array/array_iterator.rs +++ b/boa/src/builtins/array/array_iterator.rs @@ -3,6 +3,7 @@ use crate::{ gc::{Finalize, Trace}, object::{GcObject, ObjectData}, property::{Attribute, DataDescriptor}, + symbol::WellKnownSymbols, BoaProfiler, Context, Result, }; @@ -126,7 +127,7 @@ impl ArrayIterator { make_builtin_fn(Self::next, "next", &array_iterator, 0, context); array_iterator.set_prototype_instance(iterator_prototype); - let to_string_tag = context.well_known_symbols().to_string_tag_symbol(); + let to_string_tag = WellKnownSymbols::to_string_tag(); let to_string_tag_property = DataDescriptor::new("Array Iterator", Attribute::CONFIGURABLE); array_iterator.insert(to_string_tag, to_string_tag_property); array_iterator diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 80ff6aaab2..bd5bb4923f 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -19,6 +19,7 @@ use crate::{ builtins::Number, object::{ConstructorBuilder, FunctionBuilder, GcObject, ObjectData, PROTOTYPE}, property::{Attribute, DataDescriptor}, + symbol::WellKnownSymbols, value::{same_value_zero, IntegerOrInfinity, Value}, BoaProfiler, Context, Result, }; @@ -42,7 +43,7 @@ impl BuiltIn for Array { fn init(context: &mut Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); - let symbol_iterator = context.well_known_symbols().iterator_symbol(); + let symbol_iterator = WellKnownSymbols::iterator(); let values_function = FunctionBuilder::new(context, Self::values) .name("values") diff --git a/boa/src/builtins/iterable/mod.rs b/boa/src/builtins/iterable/mod.rs index 9bd1218391..14f4cdb695 100644 --- a/boa/src/builtins/iterable/mod.rs +++ b/boa/src/builtins/iterable/mod.rs @@ -5,6 +5,7 @@ use crate::{ builtins::MapIterator, object::{GcObject, ObjectInitializer}, property::{Attribute, DataDescriptor}, + symbol::WellKnownSymbols, BoaProfiler, Context, Result, Value, }; @@ -79,8 +80,7 @@ pub fn create_iter_result_object(context: &mut Context, value: Value, done: bool /// Get an iterator record pub fn get_iterator(context: &mut Context, iterable: Value) -> Result { - let iterator_function = - iterable.get_field(context.well_known_symbols().iterator_symbol(), context)?; + let iterator_function = iterable.get_field(WellKnownSymbols::iterator(), context)?; if iterator_function.is_null_or_undefined() { return Err(context.construct_type_error("Not an iterable")); } @@ -101,7 +101,7 @@ pub fn get_iterator(context: &mut Context, iterable: Value) -> Result GcObject { let _timer = BoaProfiler::global().start_event("Iterator Prototype", "init"); - let symbol_iterator = context.well_known_symbols().iterator_symbol(); + let symbol_iterator = WellKnownSymbols::iterator(); let iterator_prototype = ObjectInitializer::new(context) .function( |v, _, _| Ok(v.clone()), diff --git a/boa/src/builtins/json/mod.rs b/boa/src/builtins/json/mod.rs index ab8f91984b..42c21adad4 100644 --- a/boa/src/builtins/json/mod.rs +++ b/boa/src/builtins/json/mod.rs @@ -13,7 +13,6 @@ //! [json]: https://www.json.org/json-en.html //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON -use crate::object::Object; use crate::{ builtins::BuiltIn, object::ObjectInitializer, @@ -21,6 +20,7 @@ use crate::{ value::IntegerOrInfinity, BoaProfiler, Context, Result, Value, }; +use crate::{object::Object, symbol::WellKnownSymbols}; use serde::Serialize; use serde_json::{self, ser::PrettyFormatter, Serializer, Value as JSONValue}; @@ -41,7 +41,7 @@ impl BuiltIn for Json { fn init(context: &mut Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); - let to_string_tag = context.well_known_symbols().to_string_tag_symbol(); + let to_string_tag = WellKnownSymbols::to_string_tag(); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; diff --git a/boa/src/builtins/map/map_iterator.rs b/boa/src/builtins/map/map_iterator.rs index 13766475a7..db289fd0a0 100644 --- a/boa/src/builtins/map/map_iterator.rs +++ b/boa/src/builtins/map/map_iterator.rs @@ -2,6 +2,7 @@ use crate::{ builtins::{function::make_builtin_fn, iterable::create_iter_result_object, Array, Value}, object::{GcObject, ObjectData}, property::{Attribute, DataDescriptor}, + symbol::WellKnownSymbols, BoaProfiler, Context, Result, }; use gc::{Finalize, Trace}; @@ -146,7 +147,7 @@ impl MapIterator { make_builtin_fn(Self::next, "next", &map_iterator, 0, context); map_iterator.set_prototype_instance(iterator_prototype); - let to_string_tag = context.well_known_symbols().to_string_tag_symbol(); + let to_string_tag = WellKnownSymbols::to_string_tag(); let to_string_tag_property = DataDescriptor::new("Map Iterator", Attribute::CONFIGURABLE); map_iterator.insert(to_string_tag, to_string_tag_property); map_iterator diff --git a/boa/src/builtins/map/mod.rs b/boa/src/builtins/map/mod.rs index 441694301a..eeb56d9b25 100644 --- a/boa/src/builtins/map/mod.rs +++ b/boa/src/builtins/map/mod.rs @@ -4,6 +4,7 @@ use crate::{ builtins::BuiltIn, object::{ConstructorBuilder, FunctionBuilder, ObjectData, PROTOTYPE}, property::{Attribute, DataDescriptor}, + symbol::WellKnownSymbols, BoaProfiler, Context, Result, Value, }; use ordered_map::OrderedMap; @@ -28,7 +29,7 @@ impl BuiltIn for Map { fn init(context: &mut Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); - let iterator_symbol = context.well_known_symbols().iterator_symbol(); + let iterator_symbol = WellKnownSymbols::iterator(); let entries_function = FunctionBuilder::new(context, Self::entries) .name("entries") diff --git a/boa/src/builtins/math/mod.rs b/boa/src/builtins/math/mod.rs index fee4911bee..130eb63f56 100644 --- a/boa/src/builtins/math/mod.rs +++ b/boa/src/builtins/math/mod.rs @@ -12,8 +12,8 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math use crate::{ - builtins::BuiltIn, object::ObjectInitializer, property::Attribute, BoaProfiler, Context, - Result, Value, + builtins::BuiltIn, object::ObjectInitializer, property::Attribute, symbol::WellKnownSymbols, + BoaProfiler, Context, Result, Value, }; #[cfg(test)] @@ -34,7 +34,7 @@ impl BuiltIn for Math { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); use std::f64; - let to_string_tag = context.well_known_symbols().to_string_tag_symbol(); + let to_string_tag = WellKnownSymbols::to_string_tag(); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; let object = ObjectInitializer::new(context) diff --git a/boa/src/builtins/object/for_in_iterator.rs b/boa/src/builtins/object/for_in_iterator.rs index deeb9c2284..fbe3a90615 100644 --- a/boa/src/builtins/object/for_in_iterator.rs +++ b/boa/src/builtins/object/for_in_iterator.rs @@ -1,4 +1,3 @@ -use crate::property::PropertyKey; use crate::value::RcString; use crate::{ builtins::{function::make_builtin_fn, iterable::create_iter_result_object}, @@ -7,6 +6,7 @@ use crate::{ property::{Attribute, DataDescriptor}, BoaProfiler, Context, Result, Value, }; +use crate::{property::PropertyKey, symbol::WellKnownSymbols}; use rustc_hash::FxHashSet; use std::collections::VecDeque; @@ -133,7 +133,7 @@ impl ForInIterator { make_builtin_fn(Self::next, "next", &for_in_iterator, 0, context); for_in_iterator.set_prototype_instance(iterator_prototype); - let to_string_tag = context.well_known_symbols().to_string_tag_symbol(); + let to_string_tag = WellKnownSymbols::to_string_tag(); let to_string_tag_property = DataDescriptor::new("For In Iterator", Attribute::CONFIGURABLE); for_in_iterator.insert(to_string_tag, to_string_tag_property); diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 8e386348e2..82f90e1523 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -21,6 +21,7 @@ use crate::{ property::Attribute, property::DataDescriptor, property::PropertyDescriptor, + symbol::WellKnownSymbols, value::{same_value, Type, Value}, BoaProfiler, Context, Result, }; @@ -433,7 +434,7 @@ impl Object { }; let tag = o.get( - &context.well_known_symbols().to_string_tag_symbol().into(), + &WellKnownSymbols::to_string_tag().into(), o.clone().into(), context, )?; diff --git a/boa/src/builtins/reflect/mod.rs b/boa/src/builtins/reflect/mod.rs index 9f44fcb2e6..160bd757a6 100644 --- a/boa/src/builtins/reflect/mod.rs +++ b/boa/src/builtins/reflect/mod.rs @@ -14,6 +14,7 @@ use crate::{ builtins::{self, BuiltIn}, object::{Object, ObjectData, ObjectInitializer}, property::{Attribute, DataDescriptor}, + symbol::WellKnownSymbols, BoaProfiler, Context, Result, Value, }; @@ -34,7 +35,7 @@ impl BuiltIn for Reflect { fn init(context: &mut Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); - let to_string_tag = context.well_known_symbols().to_string_tag_symbol(); + let to_string_tag = WellKnownSymbols::to_string_tag(); let object = ObjectInitializer::new(context) .function(Self::apply, "apply", 3) diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index af9fbcc75a..c206799d6e 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -20,6 +20,7 @@ use crate::{ builtins::{string::string_iterator::StringIterator, Array, BuiltIn, RegExp}, object::{ConstructorBuilder, Object, ObjectData}, property::Attribute, + symbol::WellKnownSymbols, value::{RcString, Value}, BoaProfiler, Context, Result, }; @@ -94,7 +95,7 @@ impl BuiltIn for String { fn init(context: &mut Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); - let symbol_iterator = context.well_known_symbols().iterator_symbol(); + let symbol_iterator = WellKnownSymbols::iterator(); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; let string_object = ConstructorBuilder::with_standard_object( @@ -1215,7 +1216,7 @@ impl String { if let Some(result) = separator .and_then(|separator| separator.as_object()) .and_then(|separator| { - let key = context.well_known_symbols().split_symbol(); + let key = WellKnownSymbols::split(); match separator.get_method(context, key) { Ok(splitter) => splitter.map(|splitter| { diff --git a/boa/src/builtins/string/string_iterator.rs b/boa/src/builtins/string/string_iterator.rs index cd76dafb65..3869008ff2 100644 --- a/boa/src/builtins/string/string_iterator.rs +++ b/boa/src/builtins/string/string_iterator.rs @@ -5,6 +5,7 @@ use crate::{ gc::{Finalize, Trace}, object::{GcObject, ObjectData}, property::{Attribute, DataDescriptor}, + symbol::WellKnownSymbols, BoaProfiler, Context, Result, Value, }; @@ -77,7 +78,7 @@ impl StringIterator { make_builtin_fn(Self::next, "next", &array_iterator, 0, context); array_iterator.set_prototype_instance(iterator_prototype); - let to_string_tag = context.well_known_symbols().to_string_tag_symbol(); + let to_string_tag = WellKnownSymbols::to_string_tag(); let to_string_tag_property = DataDescriptor::new("String Iterator", Attribute::CONFIGURABLE); array_iterator.insert(to_string_tag, to_string_tag_property); diff --git a/boa/src/builtins/symbol/mod.rs b/boa/src/builtins/symbol/mod.rs index d0d8a9f4fd..8bf69503bd 100644 --- a/boa/src/builtins/symbol/mod.rs +++ b/boa/src/builtins/symbol/mod.rs @@ -22,7 +22,7 @@ use crate::{ builtins::BuiltIn, object::{ConstructorBuilder, FunctionBuilder}, property::Attribute, - symbol::RcSymbol, + symbol::{RcSymbol, WellKnownSymbols}, value::Value, BoaProfiler, Context, Result, }; @@ -40,22 +40,19 @@ impl BuiltIn for Symbol { fn init(context: &mut Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); - // https://tc39.es/ecma262/#sec-well-known-symbols - let well_known_symbols = context.well_known_symbols(); - - let symbol_async_iterator = well_known_symbols.async_iterator_symbol(); - let symbol_has_instance = well_known_symbols.has_instance_symbol(); - let symbol_is_concat_spreadable = well_known_symbols.is_concat_spreadable_symbol(); - let symbol_iterator = well_known_symbols.iterator_symbol(); - let symbol_match = well_known_symbols.match_symbol(); - let symbol_match_all = well_known_symbols.match_all_symbol(); - let symbol_replace = well_known_symbols.replace_symbol(); - let symbol_search = well_known_symbols.search_symbol(); - let symbol_species = well_known_symbols.species_symbol(); - let symbol_split = well_known_symbols.split_symbol(); - let symbol_to_primitive = well_known_symbols.to_primitive_symbol(); - let symbol_to_string_tag = well_known_symbols.to_string_tag_symbol(); - let symbol_unscopables = well_known_symbols.unscopables_symbol(); + let symbol_async_iterator = WellKnownSymbols::async_iterator(); + let symbol_has_instance = WellKnownSymbols::has_instance(); + let symbol_is_concat_spreadable = WellKnownSymbols::is_concat_spreadable(); + let symbol_iterator = WellKnownSymbols::iterator(); + let symbol_match = WellKnownSymbols::match_(); + let symbol_match_all = WellKnownSymbols::match_all(); + let symbol_replace = WellKnownSymbols::replace(); + let symbol_search = WellKnownSymbols::search(); + let symbol_species = WellKnownSymbols::species(); + let symbol_split = WellKnownSymbols::split(); + let symbol_to_primitive = WellKnownSymbols::to_primitive(); + let symbol_to_string_tag = WellKnownSymbols::to_string_tag(); + let symbol_unscopables = WellKnownSymbols::unscopables(); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; diff --git a/boa/src/context.rs b/boa/src/context.rs index 4b537fc596..75fdb39ce4 100644 --- a/boa/src/context.rs +++ b/boa/src/context.rs @@ -11,7 +11,7 @@ use crate::{ object::{GcObject, Object, PROTOTYPE}, property::{Attribute, DataDescriptor, PropertyKey}, realm::Realm, - symbol::{RcSymbol, Symbol, WellKnownSymbols}, + symbol::{RcSymbol, Symbol}, syntax::{ ast::{ node::{ @@ -215,18 +215,10 @@ pub struct Context { /// The current executor. executor: Interpreter, - /// Symbol hash. - /// - /// For now this is an incremented u64 number. - symbol_count: u64, - /// console object state. #[cfg(feature = "console")] console: Console, - /// Cached well known symbols - well_known_symbols: WellKnownSymbols, - /// Cached iterator prototypes. iterator_prototypes: IteratorPrototypes, @@ -241,14 +233,11 @@ impl Default for Context { fn default() -> Self { let realm = Realm::create(); let executor = Interpreter::new(); - let (well_known_symbols, symbol_count) = WellKnownSymbols::new(); let mut context = Self { realm, executor, - symbol_count, #[cfg(feature = "console")] console: Console::default(), - well_known_symbols, iterator_prototypes: IteratorPrototypes::default(), standard_objects: Default::default(), trace: false, @@ -296,20 +285,10 @@ impl Context { builtins::init(self); } - /// Generates a new `Symbol` internal hash. - /// - /// This currently is an incremented value. - #[inline] - fn generate_hash(&mut self) -> u64 { - let hash = self.symbol_count; - self.symbol_count += 1; - hash - } - /// Construct a new `Symbol` with an optional description. #[inline] pub fn construct_symbol(&mut self, description: Option) -> RcSymbol { - RcSymbol::from(Symbol::new(self.generate_hash(), description)) + RcSymbol::from(Symbol::new(description)) } /// Construct an empty object. @@ -709,22 +688,6 @@ impl Context { result } - /// Returns a structure that contains the JavaScript well known symbols. - /// - /// # Examples - /// ``` - ///# use boa::Context; - /// let mut context = Context::new(); - /// - /// let iterator = context.well_known_symbols().iterator_symbol(); - /// assert_eq!(iterator.description(), Some("Symbol.iterator")); - /// ``` - /// This is equivalent to `let iterator = Symbol.iterator` in JavaScript. - #[inline] - pub fn well_known_symbols(&self) -> &WellKnownSymbols { - &self.well_known_symbols - } - /// Return the cached iterator prototypes. #[inline] pub fn iterator_prototypes(&self) -> &IteratorPrototypes { diff --git a/boa/src/symbol/mod.rs b/boa/src/symbol/mod.rs index 5ccdc33f87..a97e586d83 100644 --- a/boa/src/symbol/mod.rs +++ b/boa/src/symbol/mod.rs @@ -21,10 +21,23 @@ use crate::{ gc::{Finalize, Trace}, value::RcString, }; +use std::{ + cell::Cell, + hash::{Hash, Hasher}, +}; pub use rcsymbol::RcSymbol; /// A structure that contains the JavaScript well known symbols. +/// +/// # Examples +/// ``` +///# use boa::symbol::WellKnownSymbols; +/// +/// let iterator = WellKnownSymbols::iterator(); +/// assert_eq!(iterator.description(), Some("Symbol.iterator")); +/// ``` +/// This is equivalent to `let iterator = Symbol.iterator` in JavaScript. #[derive(Debug, Clone)] pub struct WellKnownSymbols { async_iterator: RcSymbol, @@ -42,56 +55,69 @@ pub struct WellKnownSymbols { unscopables: RcSymbol, } +/// Reserved number of symbols. +/// +/// This is where the well known symbol live +/// and internal engine symbols. +const RESERVED_SYMBOL_HASHES: u64 = 128; + +thread_local! { + /// Cached well known symbols + static WELL_KNOW_SYMBOLS: WellKnownSymbols = WellKnownSymbols::new(); + + /// Symbol hash. + /// + /// For now this is an incremented u64 number. + static SYMBOL_HASH_COUNT: Cell = Cell::new(RESERVED_SYMBOL_HASHES); +} + impl WellKnownSymbols { - pub(crate) fn new() -> (Self, u64) { + /// Create the well known symbols. + fn new() -> Self { let mut count = 0; - let async_iterator = Symbol::new(count, Some("Symbol.asyncIterator".into())).into(); + let async_iterator = Symbol::with_hash(count, Some("Symbol.asyncIterator".into())).into(); count += 1; - let has_instance = Symbol::new(count, Some("Symbol.hasInstance".into())).into(); + let has_instance = Symbol::with_hash(count, Some("Symbol.hasInstance".into())).into(); count += 1; let is_concat_spreadable = - Symbol::new(count, Some("Symbol.isConcatSpreadable".into())).into(); - count += 1; - let iterator = Symbol::new(count, Some("Symbol.iterator".into())).into(); + Symbol::with_hash(count, Some("Symbol.isConcatSpreadable".into())).into(); count += 1; - let match_ = Symbol::new(count, Some("Symbol.match".into())).into(); + let iterator = Symbol::with_hash(count, Some("Symbol.iterator".into())).into(); count += 1; - let match_all = Symbol::new(count, Some("Symbol.matchAll".into())).into(); + let match_ = Symbol::with_hash(count, Some("Symbol.match".into())).into(); count += 1; - let replace = Symbol::new(count, Some("Symbol.replace".into())).into(); + let match_all = Symbol::with_hash(count, Some("Symbol.matchAll".into())).into(); count += 1; - let search = Symbol::new(count, Some("Symbol.search".into())).into(); + let replace = Symbol::with_hash(count, Some("Symbol.replace".into())).into(); count += 1; - let species = Symbol::new(count, Some("Symbol.species".into())).into(); + let search = Symbol::with_hash(count, Some("Symbol.search".into())).into(); count += 1; - let split = Symbol::new(count, Some("Symbol.split".into())).into(); + let species = Symbol::with_hash(count, Some("Symbol.species".into())).into(); count += 1; - let to_primitive = Symbol::new(count, Some("Symbol.toPrimitive".into())).into(); + let split = Symbol::with_hash(count, Some("Symbol.split".into())).into(); count += 1; - let to_string_tag = Symbol::new(count, Some("Symbol.toStringTag".into())).into(); + let to_primitive = Symbol::with_hash(count, Some("Symbol.toPrimitive".into())).into(); count += 1; - let unscopables = Symbol::new(count, Some("Symbol.unscopables".into())).into(); + let to_string_tag = Symbol::with_hash(count, Some("Symbol.toStringTag".into())).into(); count += 1; + let unscopables = Symbol::with_hash(count, Some("Symbol.unscopables".into())).into(); - ( - Self { - async_iterator, - has_instance, - is_concat_spreadable, - iterator, - match_, - match_all, - replace, - search, - species, - split, - to_primitive, - to_string_tag, - unscopables, - }, - count, - ) + Self { + async_iterator, + has_instance, + is_concat_spreadable, + iterator, + match_, + match_all, + replace, + search, + species, + split, + to_primitive, + to_string_tag, + unscopables, + } } /// The `Symbol.asyncIterator` well known symbol. @@ -99,8 +125,8 @@ impl WellKnownSymbols { /// A method that returns the default AsyncIterator for an object. /// Called by the semantics of the `for-await-of` statement. #[inline] - pub fn async_iterator_symbol(&self) -> RcSymbol { - self.async_iterator.clone() + pub fn async_iterator() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.async_iterator.clone()) } /// The `Symbol.hasInstance` well known symbol. @@ -109,8 +135,8 @@ impl WellKnownSymbols { /// recognizes an object as one of the `constructor`'s instances. /// Called by the semantics of the instanceof operator. #[inline] - pub fn has_instance_symbol(&self) -> RcSymbol { - self.has_instance.clone() + pub fn has_instance() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.has_instance.clone()) } /// The `Symbol.isConcatSpreadable` well known symbol. @@ -119,8 +145,8 @@ impl WellKnownSymbols { /// an object should be flattened to its array elements /// by `Array.prototype.concat`. #[inline] - pub fn is_concat_spreadable_symbol(&self) -> RcSymbol { - self.is_concat_spreadable.clone() + pub fn is_concat_spreadable() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.is_concat_spreadable.clone()) } /// The `Symbol.iterator` well known symbol. @@ -128,8 +154,8 @@ impl WellKnownSymbols { /// A method that returns the default Iterator for an object. /// Called by the semantics of the `for-of` statement. #[inline] - pub fn iterator_symbol(&self) -> RcSymbol { - self.iterator.clone() + pub fn iterator() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.iterator.clone()) } /// The `Symbol.match` well known symbol. @@ -137,8 +163,8 @@ impl WellKnownSymbols { /// A regular expression method that matches the regular expression /// against a string. Called by the `String.prototype.match` method. #[inline] - pub fn match_symbol(&self) -> RcSymbol { - self.match_.clone() + pub fn match_() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.match_.clone()) } /// The `Symbol.matchAll` well known symbol. @@ -147,8 +173,8 @@ impl WellKnownSymbols { /// matches of the regular expression against a string. /// Called by the `String.prototype.matchAll` method. #[inline] - pub fn match_all_symbol(&self) -> RcSymbol { - self.match_all.clone() + pub fn match_all() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.match_all.clone()) } /// The `Symbol.replace` well known symbol. @@ -156,8 +182,8 @@ impl WellKnownSymbols { /// A regular expression method that replaces matched substrings /// of a string. Called by the `String.prototype.replace` method. #[inline] - pub fn replace_symbol(&self) -> RcSymbol { - self.replace.clone() + pub fn replace() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.replace.clone()) } /// The `Symbol.search` well known symbol. @@ -166,8 +192,8 @@ impl WellKnownSymbols { /// string that matches the regular expression. /// Called by the `String.prototype.search` method. #[inline] - pub fn search_symbol(&self) -> RcSymbol { - self.search.clone() + pub fn search() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.search.clone()) } /// The `Symbol.species` well known symbol. @@ -175,8 +201,8 @@ impl WellKnownSymbols { /// A function valued property that is the `constructor` function /// that is used to create derived objects. #[inline] - pub fn species_symbol(&self) -> RcSymbol { - self.species.clone() + pub fn species() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.species.clone()) } /// The `Symbol.split` well known symbol. @@ -185,8 +211,8 @@ impl WellKnownSymbols { /// that match the regular expression. /// Called by the `String.prototype.split` method. #[inline] - pub fn split_symbol(&self) -> RcSymbol { - self.split.clone() + pub fn split() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.split.clone()) } /// The `Symbol.toPrimitive` well known symbol. @@ -194,8 +220,8 @@ impl WellKnownSymbols { /// A method that converts an object to a corresponding primitive value. /// Called by the `ToPrimitive` (`Value::to_primitve`) abstract operation. #[inline] - pub fn to_primitive_symbol(&self) -> RcSymbol { - self.to_primitive.clone() + pub fn to_primitive() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.to_primitive.clone()) } /// The `Symbol.toStringTag` well known symbol. @@ -204,8 +230,8 @@ impl WellKnownSymbols { /// string description of an object. /// Accessed by the built-in method `Object.prototype.toString`. #[inline] - pub fn to_string_tag_symbol(&self) -> RcSymbol { - self.to_string_tag.clone() + pub fn to_string_tag() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.to_string_tag.clone()) } /// The `Symbol.unscopables` well known symbol. @@ -213,19 +239,31 @@ impl WellKnownSymbols { /// An object valued property whose own and inherited property names are property /// names that are excluded from the `with` environment bindings of the associated object. #[inline] - pub fn unscopables_symbol(&self) -> RcSymbol { - self.unscopables.clone() + pub fn unscopables() -> RcSymbol { + WELL_KNOW_SYMBOLS.with(|symbols| symbols.unscopables.clone()) } } -#[derive(Debug, Finalize, Trace, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Finalize, Trace, Clone, Eq, PartialOrd, Ord)] pub struct Symbol { pub(crate) hash: u64, pub(crate) description: Option, } impl Symbol { - pub(crate) fn new(hash: u64, description: Option) -> Self { + /// Create a new symbol with a specified hash and description. + fn with_hash(hash: u64, description: Option) -> Self { + Self { hash, description } + } + + /// Create a new symbol. + #[inline] + pub fn new(description: Option) -> Self { + let hash = SYMBOL_HASH_COUNT.with(|count| { + let hash = count.get(); + count.set(hash + 1); + hash + }); Self { hash, description } } @@ -236,8 +274,24 @@ impl Symbol { } /// Returns the `Symbol`s hash. + /// + /// The hash is guaranteed to be unique. #[inline] pub fn hash(&self) -> u64 { self.hash } } + +impl PartialEq for Symbol { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.hash == other.hash + } +} + +impl Hash for Symbol { + #[inline] + fn hash(&self, state: &mut H) { + self.hash.hash(state); + } +} diff --git a/boa/src/syntax/ast/node/operator/bin_op/mod.rs b/boa/src/syntax/ast/node/operator/bin_op/mod.rs index e20291353c..230a18e3cb 100644 --- a/boa/src/syntax/ast/node/operator/bin_op/mod.rs +++ b/boa/src/syntax/ast/node/operator/bin_op/mod.rs @@ -1,6 +1,7 @@ use crate::{ exec::Executable, gc::{Finalize, Trace}, + symbol::WellKnownSymbols, syntax::ast::{ node::Node, op::{self, AssignOp, BitOp, CompOp, LogOp, NumOp}, @@ -153,7 +154,7 @@ impl Executable for BinOp { } CompOp::InstanceOf => { if let Some(object) = y.as_object() { - let key = context.well_known_symbols().has_instance_symbol(); + let key = WellKnownSymbols::has_instance(); match object.get_method(context, key)? { Some(instance_of_handler) => { diff --git a/boa/src/value/mod.rs b/boa/src/value/mod.rs index c9b3eb6a75..5132567488 100644 --- a/boa/src/value/mod.rs +++ b/boa/src/value/mod.rs @@ -13,7 +13,7 @@ use crate::{ }, object::{GcObject, Object, ObjectData}, property::{Attribute, DataDescriptor, PropertyDescriptor, PropertyKey}, - symbol::RcSymbol, + symbol::{RcSymbol, WellKnownSymbols}, BoaProfiler, Context, Result, }; use gc::{Finalize, Trace}; @@ -520,7 +520,7 @@ impl Value { // 2. If Type(input) is Object, then if let Value::Object(obj) = self { if let Some(exotic_to_prim) = - obj.get_method(context, context.well_known_symbols().to_primitive_symbol())? + obj.get_method(context, WellKnownSymbols::to_primitive())? { let hint = match preferred_type { PreferredType::String => "string",