Browse Source

Cross realm symbols (#1243)

* Cross context symbols

* Remove redundant '_symbol' suffix for well known symbol getters

* Fix symbol equality and hashing

* Add documentation
pull/1250/head
Halid Odat 4 years ago committed by GitHub
parent
commit
087a857865
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      boa/src/builtins/array/array_iterator.rs
  2. 3
      boa/src/builtins/array/mod.rs
  3. 6
      boa/src/builtins/iterable/mod.rs
  4. 4
      boa/src/builtins/json/mod.rs
  5. 3
      boa/src/builtins/map/map_iterator.rs
  6. 3
      boa/src/builtins/map/mod.rs
  7. 6
      boa/src/builtins/math/mod.rs
  8. 4
      boa/src/builtins/object/for_in_iterator.rs
  9. 3
      boa/src/builtins/object/mod.rs
  10. 3
      boa/src/builtins/reflect/mod.rs
  11. 5
      boa/src/builtins/string/mod.rs
  12. 3
      boa/src/builtins/string/string_iterator.rs
  13. 31
      boa/src/builtins/symbol/mod.rs
  14. 41
      boa/src/context.rs
  15. 176
      boa/src/symbol/mod.rs
  16. 3
      boa/src/syntax/ast/node/operator/bin_op/mod.rs
  17. 4
      boa/src/value/mod.rs

3
boa/src/builtins/array/array_iterator.rs

@ -3,6 +3,7 @@ use crate::{
gc::{Finalize, Trace}, gc::{Finalize, Trace},
object::{GcObject, ObjectData}, object::{GcObject, ObjectData},
property::{Attribute, DataDescriptor}, property::{Attribute, DataDescriptor},
symbol::WellKnownSymbols,
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
}; };
@ -126,7 +127,7 @@ impl ArrayIterator {
make_builtin_fn(Self::next, "next", &array_iterator, 0, context); make_builtin_fn(Self::next, "next", &array_iterator, 0, context);
array_iterator.set_prototype_instance(iterator_prototype); 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); let to_string_tag_property = DataDescriptor::new("Array Iterator", Attribute::CONFIGURABLE);
array_iterator.insert(to_string_tag, to_string_tag_property); array_iterator.insert(to_string_tag, to_string_tag_property);
array_iterator array_iterator

3
boa/src/builtins/array/mod.rs

@ -19,6 +19,7 @@ use crate::{
builtins::Number, builtins::Number,
object::{ConstructorBuilder, FunctionBuilder, GcObject, ObjectData, PROTOTYPE}, object::{ConstructorBuilder, FunctionBuilder, GcObject, ObjectData, PROTOTYPE},
property::{Attribute, DataDescriptor}, property::{Attribute, DataDescriptor},
symbol::WellKnownSymbols,
value::{same_value_zero, IntegerOrInfinity, Value}, value::{same_value_zero, IntegerOrInfinity, Value},
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
}; };
@ -42,7 +43,7 @@ impl BuiltIn for Array {
fn init(context: &mut Context) -> (&'static str, Value, Attribute) { fn init(context: &mut Context) -> (&'static str, Value, Attribute) {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); 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) let values_function = FunctionBuilder::new(context, Self::values)
.name("values") .name("values")

6
boa/src/builtins/iterable/mod.rs

@ -5,6 +5,7 @@ use crate::{
builtins::MapIterator, builtins::MapIterator,
object::{GcObject, ObjectInitializer}, object::{GcObject, ObjectInitializer},
property::{Attribute, DataDescriptor}, property::{Attribute, DataDescriptor},
symbol::WellKnownSymbols,
BoaProfiler, Context, Result, Value, 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 /// Get an iterator record
pub fn get_iterator(context: &mut Context, iterable: Value) -> Result<IteratorRecord> { pub fn get_iterator(context: &mut Context, iterable: Value) -> Result<IteratorRecord> {
let iterator_function = let iterator_function = iterable.get_field(WellKnownSymbols::iterator(), context)?;
iterable.get_field(context.well_known_symbols().iterator_symbol(), context)?;
if iterator_function.is_null_or_undefined() { if iterator_function.is_null_or_undefined() {
return Err(context.construct_type_error("Not an iterable")); return Err(context.construct_type_error("Not an iterable"));
} }
@ -101,7 +101,7 @@ pub fn get_iterator(context: &mut Context, iterable: Value) -> Result<IteratorRe
fn create_iterator_prototype(context: &mut Context) -> GcObject { fn create_iterator_prototype(context: &mut Context) -> GcObject {
let _timer = BoaProfiler::global().start_event("Iterator Prototype", "init"); 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) let iterator_prototype = ObjectInitializer::new(context)
.function( .function(
|v, _, _| Ok(v.clone()), |v, _, _| Ok(v.clone()),

4
boa/src/builtins/json/mod.rs

@ -13,7 +13,6 @@
//! [json]: https://www.json.org/json-en.html //! [json]: https://www.json.org/json-en.html
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON
use crate::object::Object;
use crate::{ use crate::{
builtins::BuiltIn, builtins::BuiltIn,
object::ObjectInitializer, object::ObjectInitializer,
@ -21,6 +20,7 @@ use crate::{
value::IntegerOrInfinity, value::IntegerOrInfinity,
BoaProfiler, Context, Result, Value, BoaProfiler, Context, Result, Value,
}; };
use crate::{object::Object, symbol::WellKnownSymbols};
use serde::Serialize; use serde::Serialize;
use serde_json::{self, ser::PrettyFormatter, Serializer, Value as JSONValue}; 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) { fn init(context: &mut Context) -> (&'static str, Value, Attribute) {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); 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; let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;

3
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}, builtins::{function::make_builtin_fn, iterable::create_iter_result_object, Array, Value},
object::{GcObject, ObjectData}, object::{GcObject, ObjectData},
property::{Attribute, DataDescriptor}, property::{Attribute, DataDescriptor},
symbol::WellKnownSymbols,
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
}; };
use gc::{Finalize, Trace}; use gc::{Finalize, Trace};
@ -146,7 +147,7 @@ impl MapIterator {
make_builtin_fn(Self::next, "next", &map_iterator, 0, context); make_builtin_fn(Self::next, "next", &map_iterator, 0, context);
map_iterator.set_prototype_instance(iterator_prototype); 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); let to_string_tag_property = DataDescriptor::new("Map Iterator", Attribute::CONFIGURABLE);
map_iterator.insert(to_string_tag, to_string_tag_property); map_iterator.insert(to_string_tag, to_string_tag_property);
map_iterator map_iterator

3
boa/src/builtins/map/mod.rs

@ -4,6 +4,7 @@ use crate::{
builtins::BuiltIn, builtins::BuiltIn,
object::{ConstructorBuilder, FunctionBuilder, ObjectData, PROTOTYPE}, object::{ConstructorBuilder, FunctionBuilder, ObjectData, PROTOTYPE},
property::{Attribute, DataDescriptor}, property::{Attribute, DataDescriptor},
symbol::WellKnownSymbols,
BoaProfiler, Context, Result, Value, BoaProfiler, Context, Result, Value,
}; };
use ordered_map::OrderedMap; use ordered_map::OrderedMap;
@ -28,7 +29,7 @@ impl BuiltIn for Map {
fn init(context: &mut Context) -> (&'static str, Value, Attribute) { fn init(context: &mut Context) -> (&'static str, Value, Attribute) {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); 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) let entries_function = FunctionBuilder::new(context, Self::entries)
.name("entries") .name("entries")

6
boa/src/builtins/math/mod.rs

@ -12,8 +12,8 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math
use crate::{ use crate::{
builtins::BuiltIn, object::ObjectInitializer, property::Attribute, BoaProfiler, Context, builtins::BuiltIn, object::ObjectInitializer, property::Attribute, symbol::WellKnownSymbols,
Result, Value, BoaProfiler, Context, Result, Value,
}; };
#[cfg(test)] #[cfg(test)]
@ -34,7 +34,7 @@ impl BuiltIn for Math {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let _timer = BoaProfiler::global().start_event(Self::NAME, "init");
use std::f64; 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 attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;
let object = ObjectInitializer::new(context) let object = ObjectInitializer::new(context)

4
boa/src/builtins/object/for_in_iterator.rs

@ -1,4 +1,3 @@
use crate::property::PropertyKey;
use crate::value::RcString; use crate::value::RcString;
use crate::{ use crate::{
builtins::{function::make_builtin_fn, iterable::create_iter_result_object}, builtins::{function::make_builtin_fn, iterable::create_iter_result_object},
@ -7,6 +6,7 @@ use crate::{
property::{Attribute, DataDescriptor}, property::{Attribute, DataDescriptor},
BoaProfiler, Context, Result, Value, BoaProfiler, Context, Result, Value,
}; };
use crate::{property::PropertyKey, symbol::WellKnownSymbols};
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use std::collections::VecDeque; use std::collections::VecDeque;
@ -133,7 +133,7 @@ impl ForInIterator {
make_builtin_fn(Self::next, "next", &for_in_iterator, 0, context); make_builtin_fn(Self::next, "next", &for_in_iterator, 0, context);
for_in_iterator.set_prototype_instance(iterator_prototype); 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 = let to_string_tag_property =
DataDescriptor::new("For In Iterator", Attribute::CONFIGURABLE); DataDescriptor::new("For In Iterator", Attribute::CONFIGURABLE);
for_in_iterator.insert(to_string_tag, to_string_tag_property); for_in_iterator.insert(to_string_tag, to_string_tag_property);

3
boa/src/builtins/object/mod.rs

@ -21,6 +21,7 @@ use crate::{
property::Attribute, property::Attribute,
property::DataDescriptor, property::DataDescriptor,
property::PropertyDescriptor, property::PropertyDescriptor,
symbol::WellKnownSymbols,
value::{same_value, Type, Value}, value::{same_value, Type, Value},
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
}; };
@ -433,7 +434,7 @@ impl Object {
}; };
let tag = o.get( let tag = o.get(
&context.well_known_symbols().to_string_tag_symbol().into(), &WellKnownSymbols::to_string_tag().into(),
o.clone().into(), o.clone().into(),
context, context,
)?; )?;

3
boa/src/builtins/reflect/mod.rs

@ -14,6 +14,7 @@ use crate::{
builtins::{self, BuiltIn}, builtins::{self, BuiltIn},
object::{Object, ObjectData, ObjectInitializer}, object::{Object, ObjectData, ObjectInitializer},
property::{Attribute, DataDescriptor}, property::{Attribute, DataDescriptor},
symbol::WellKnownSymbols,
BoaProfiler, Context, Result, Value, BoaProfiler, Context, Result, Value,
}; };
@ -34,7 +35,7 @@ impl BuiltIn for Reflect {
fn init(context: &mut Context) -> (&'static str, Value, Attribute) { fn init(context: &mut Context) -> (&'static str, Value, Attribute) {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); 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) let object = ObjectInitializer::new(context)
.function(Self::apply, "apply", 3) .function(Self::apply, "apply", 3)

5
boa/src/builtins/string/mod.rs

@ -20,6 +20,7 @@ use crate::{
builtins::{string::string_iterator::StringIterator, Array, BuiltIn, RegExp}, builtins::{string::string_iterator::StringIterator, Array, BuiltIn, RegExp},
object::{ConstructorBuilder, Object, ObjectData}, object::{ConstructorBuilder, Object, ObjectData},
property::Attribute, property::Attribute,
symbol::WellKnownSymbols,
value::{RcString, Value}, value::{RcString, Value},
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
}; };
@ -94,7 +95,7 @@ impl BuiltIn for String {
fn init(context: &mut Context) -> (&'static str, Value, Attribute) { fn init(context: &mut Context) -> (&'static str, Value, Attribute) {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); 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 attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;
let string_object = ConstructorBuilder::with_standard_object( let string_object = ConstructorBuilder::with_standard_object(
@ -1215,7 +1216,7 @@ impl String {
if let Some(result) = separator if let Some(result) = separator
.and_then(|separator| separator.as_object()) .and_then(|separator| separator.as_object())
.and_then(|separator| { .and_then(|separator| {
let key = context.well_known_symbols().split_symbol(); let key = WellKnownSymbols::split();
match separator.get_method(context, key) { match separator.get_method(context, key) {
Ok(splitter) => splitter.map(|splitter| { Ok(splitter) => splitter.map(|splitter| {

3
boa/src/builtins/string/string_iterator.rs

@ -5,6 +5,7 @@ use crate::{
gc::{Finalize, Trace}, gc::{Finalize, Trace},
object::{GcObject, ObjectData}, object::{GcObject, ObjectData},
property::{Attribute, DataDescriptor}, property::{Attribute, DataDescriptor},
symbol::WellKnownSymbols,
BoaProfiler, Context, Result, Value, BoaProfiler, Context, Result, Value,
}; };
@ -77,7 +78,7 @@ impl StringIterator {
make_builtin_fn(Self::next, "next", &array_iterator, 0, context); make_builtin_fn(Self::next, "next", &array_iterator, 0, context);
array_iterator.set_prototype_instance(iterator_prototype); 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 = let to_string_tag_property =
DataDescriptor::new("String Iterator", Attribute::CONFIGURABLE); DataDescriptor::new("String Iterator", Attribute::CONFIGURABLE);
array_iterator.insert(to_string_tag, to_string_tag_property); array_iterator.insert(to_string_tag, to_string_tag_property);

31
boa/src/builtins/symbol/mod.rs

@ -22,7 +22,7 @@ use crate::{
builtins::BuiltIn, builtins::BuiltIn,
object::{ConstructorBuilder, FunctionBuilder}, object::{ConstructorBuilder, FunctionBuilder},
property::Attribute, property::Attribute,
symbol::RcSymbol, symbol::{RcSymbol, WellKnownSymbols},
value::Value, value::Value,
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
}; };
@ -40,22 +40,19 @@ impl BuiltIn for Symbol {
fn init(context: &mut Context) -> (&'static str, Value, Attribute) { fn init(context: &mut Context) -> (&'static str, Value, Attribute) {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let _timer = BoaProfiler::global().start_event(Self::NAME, "init");
// https://tc39.es/ecma262/#sec-well-known-symbols let symbol_async_iterator = WellKnownSymbols::async_iterator();
let well_known_symbols = context.well_known_symbols(); let symbol_has_instance = WellKnownSymbols::has_instance();
let symbol_is_concat_spreadable = WellKnownSymbols::is_concat_spreadable();
let symbol_async_iterator = well_known_symbols.async_iterator_symbol(); let symbol_iterator = WellKnownSymbols::iterator();
let symbol_has_instance = well_known_symbols.has_instance_symbol(); let symbol_match = WellKnownSymbols::match_();
let symbol_is_concat_spreadable = well_known_symbols.is_concat_spreadable_symbol(); let symbol_match_all = WellKnownSymbols::match_all();
let symbol_iterator = well_known_symbols.iterator_symbol(); let symbol_replace = WellKnownSymbols::replace();
let symbol_match = well_known_symbols.match_symbol(); let symbol_search = WellKnownSymbols::search();
let symbol_match_all = well_known_symbols.match_all_symbol(); let symbol_species = WellKnownSymbols::species();
let symbol_replace = well_known_symbols.replace_symbol(); let symbol_split = WellKnownSymbols::split();
let symbol_search = well_known_symbols.search_symbol(); let symbol_to_primitive = WellKnownSymbols::to_primitive();
let symbol_species = well_known_symbols.species_symbol(); let symbol_to_string_tag = WellKnownSymbols::to_string_tag();
let symbol_split = well_known_symbols.split_symbol(); let symbol_unscopables = WellKnownSymbols::unscopables();
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 attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;

41
boa/src/context.rs

@ -11,7 +11,7 @@ use crate::{
object::{GcObject, Object, PROTOTYPE}, object::{GcObject, Object, PROTOTYPE},
property::{Attribute, DataDescriptor, PropertyKey}, property::{Attribute, DataDescriptor, PropertyKey},
realm::Realm, realm::Realm,
symbol::{RcSymbol, Symbol, WellKnownSymbols}, symbol::{RcSymbol, Symbol},
syntax::{ syntax::{
ast::{ ast::{
node::{ node::{
@ -215,18 +215,10 @@ pub struct Context {
/// The current executor. /// The current executor.
executor: Interpreter, executor: Interpreter,
/// Symbol hash.
///
/// For now this is an incremented u64 number.
symbol_count: u64,
/// console object state. /// console object state.
#[cfg(feature = "console")] #[cfg(feature = "console")]
console: Console, console: Console,
/// Cached well known symbols
well_known_symbols: WellKnownSymbols,
/// Cached iterator prototypes. /// Cached iterator prototypes.
iterator_prototypes: IteratorPrototypes, iterator_prototypes: IteratorPrototypes,
@ -241,14 +233,11 @@ impl Default for Context {
fn default() -> Self { fn default() -> Self {
let realm = Realm::create(); let realm = Realm::create();
let executor = Interpreter::new(); let executor = Interpreter::new();
let (well_known_symbols, symbol_count) = WellKnownSymbols::new();
let mut context = Self { let mut context = Self {
realm, realm,
executor, executor,
symbol_count,
#[cfg(feature = "console")] #[cfg(feature = "console")]
console: Console::default(), console: Console::default(),
well_known_symbols,
iterator_prototypes: IteratorPrototypes::default(), iterator_prototypes: IteratorPrototypes::default(),
standard_objects: Default::default(), standard_objects: Default::default(),
trace: false, trace: false,
@ -296,20 +285,10 @@ impl Context {
builtins::init(self); 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. /// Construct a new `Symbol` with an optional description.
#[inline] #[inline]
pub fn construct_symbol(&mut self, description: Option<RcString>) -> RcSymbol { pub fn construct_symbol(&mut self, description: Option<RcString>) -> RcSymbol {
RcSymbol::from(Symbol::new(self.generate_hash(), description)) RcSymbol::from(Symbol::new(description))
} }
/// Construct an empty object. /// Construct an empty object.
@ -709,22 +688,6 @@ impl Context {
result 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. /// Return the cached iterator prototypes.
#[inline] #[inline]
pub fn iterator_prototypes(&self) -> &IteratorPrototypes { pub fn iterator_prototypes(&self) -> &IteratorPrototypes {

176
boa/src/symbol/mod.rs

@ -21,10 +21,23 @@ use crate::{
gc::{Finalize, Trace}, gc::{Finalize, Trace},
value::RcString, value::RcString,
}; };
use std::{
cell::Cell,
hash::{Hash, Hasher},
};
pub use rcsymbol::RcSymbol; pub use rcsymbol::RcSymbol;
/// A structure that contains the JavaScript well known symbols. /// 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)] #[derive(Debug, Clone)]
pub struct WellKnownSymbols { pub struct WellKnownSymbols {
async_iterator: RcSymbol, async_iterator: RcSymbol,
@ -42,56 +55,69 @@ pub struct WellKnownSymbols {
unscopables: RcSymbol, 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<u64> = Cell::new(RESERVED_SYMBOL_HASHES);
}
impl WellKnownSymbols { impl WellKnownSymbols {
pub(crate) fn new() -> (Self, u64) { /// Create the well known symbols.
fn new() -> Self {
let mut count = 0; 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; 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; count += 1;
let is_concat_spreadable = let is_concat_spreadable =
Symbol::new(count, Some("Symbol.isConcatSpreadable".into())).into(); Symbol::with_hash(count, Some("Symbol.isConcatSpreadable".into())).into();
count += 1;
let iterator = Symbol::new(count, Some("Symbol.iterator".into())).into();
count += 1; 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; 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; 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; 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; 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; 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; 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; 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; 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; count += 1;
let unscopables = Symbol::with_hash(count, Some("Symbol.unscopables".into())).into();
( Self {
Self { async_iterator,
async_iterator, has_instance,
has_instance, is_concat_spreadable,
is_concat_spreadable, iterator,
iterator, match_,
match_, match_all,
match_all, replace,
replace, search,
search, species,
species, split,
split, to_primitive,
to_primitive, to_string_tag,
to_string_tag, unscopables,
unscopables, }
},
count,
)
} }
/// The `Symbol.asyncIterator` well known symbol. /// The `Symbol.asyncIterator` well known symbol.
@ -99,8 +125,8 @@ impl WellKnownSymbols {
/// A method that returns the default AsyncIterator for an object. /// A method that returns the default AsyncIterator for an object.
/// Called by the semantics of the `for-await-of` statement. /// Called by the semantics of the `for-await-of` statement.
#[inline] #[inline]
pub fn async_iterator_symbol(&self) -> RcSymbol { pub fn async_iterator() -> RcSymbol {
self.async_iterator.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.async_iterator.clone())
} }
/// The `Symbol.hasInstance` well known symbol. /// The `Symbol.hasInstance` well known symbol.
@ -109,8 +135,8 @@ impl WellKnownSymbols {
/// recognizes an object as one of the `constructor`'s instances. /// recognizes an object as one of the `constructor`'s instances.
/// Called by the semantics of the instanceof operator. /// Called by the semantics of the instanceof operator.
#[inline] #[inline]
pub fn has_instance_symbol(&self) -> RcSymbol { pub fn has_instance() -> RcSymbol {
self.has_instance.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.has_instance.clone())
} }
/// The `Symbol.isConcatSpreadable` well known symbol. /// The `Symbol.isConcatSpreadable` well known symbol.
@ -119,8 +145,8 @@ impl WellKnownSymbols {
/// an object should be flattened to its array elements /// an object should be flattened to its array elements
/// by `Array.prototype.concat`. /// by `Array.prototype.concat`.
#[inline] #[inline]
pub fn is_concat_spreadable_symbol(&self) -> RcSymbol { pub fn is_concat_spreadable() -> RcSymbol {
self.is_concat_spreadable.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.is_concat_spreadable.clone())
} }
/// The `Symbol.iterator` well known symbol. /// The `Symbol.iterator` well known symbol.
@ -128,8 +154,8 @@ impl WellKnownSymbols {
/// A method that returns the default Iterator for an object. /// A method that returns the default Iterator for an object.
/// Called by the semantics of the `for-of` statement. /// Called by the semantics of the `for-of` statement.
#[inline] #[inline]
pub fn iterator_symbol(&self) -> RcSymbol { pub fn iterator() -> RcSymbol {
self.iterator.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.iterator.clone())
} }
/// The `Symbol.match` well known symbol. /// The `Symbol.match` well known symbol.
@ -137,8 +163,8 @@ impl WellKnownSymbols {
/// A regular expression method that matches the regular expression /// A regular expression method that matches the regular expression
/// against a string. Called by the `String.prototype.match` method. /// against a string. Called by the `String.prototype.match` method.
#[inline] #[inline]
pub fn match_symbol(&self) -> RcSymbol { pub fn match_() -> RcSymbol {
self.match_.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.match_.clone())
} }
/// The `Symbol.matchAll` well known symbol. /// The `Symbol.matchAll` well known symbol.
@ -147,8 +173,8 @@ impl WellKnownSymbols {
/// matches of the regular expression against a string. /// matches of the regular expression against a string.
/// Called by the `String.prototype.matchAll` method. /// Called by the `String.prototype.matchAll` method.
#[inline] #[inline]
pub fn match_all_symbol(&self) -> RcSymbol { pub fn match_all() -> RcSymbol {
self.match_all.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.match_all.clone())
} }
/// The `Symbol.replace` well known symbol. /// The `Symbol.replace` well known symbol.
@ -156,8 +182,8 @@ impl WellKnownSymbols {
/// A regular expression method that replaces matched substrings /// A regular expression method that replaces matched substrings
/// of a string. Called by the `String.prototype.replace` method. /// of a string. Called by the `String.prototype.replace` method.
#[inline] #[inline]
pub fn replace_symbol(&self) -> RcSymbol { pub fn replace() -> RcSymbol {
self.replace.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.replace.clone())
} }
/// The `Symbol.search` well known symbol. /// The `Symbol.search` well known symbol.
@ -166,8 +192,8 @@ impl WellKnownSymbols {
/// string that matches the regular expression. /// string that matches the regular expression.
/// Called by the `String.prototype.search` method. /// Called by the `String.prototype.search` method.
#[inline] #[inline]
pub fn search_symbol(&self) -> RcSymbol { pub fn search() -> RcSymbol {
self.search.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.search.clone())
} }
/// The `Symbol.species` well known symbol. /// The `Symbol.species` well known symbol.
@ -175,8 +201,8 @@ impl WellKnownSymbols {
/// A function valued property that is the `constructor` function /// A function valued property that is the `constructor` function
/// that is used to create derived objects. /// that is used to create derived objects.
#[inline] #[inline]
pub fn species_symbol(&self) -> RcSymbol { pub fn species() -> RcSymbol {
self.species.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.species.clone())
} }
/// The `Symbol.split` well known symbol. /// The `Symbol.split` well known symbol.
@ -185,8 +211,8 @@ impl WellKnownSymbols {
/// that match the regular expression. /// that match the regular expression.
/// Called by the `String.prototype.split` method. /// Called by the `String.prototype.split` method.
#[inline] #[inline]
pub fn split_symbol(&self) -> RcSymbol { pub fn split() -> RcSymbol {
self.split.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.split.clone())
} }
/// The `Symbol.toPrimitive` well known symbol. /// The `Symbol.toPrimitive` well known symbol.
@ -194,8 +220,8 @@ impl WellKnownSymbols {
/// A method that converts an object to a corresponding primitive value. /// A method that converts an object to a corresponding primitive value.
/// Called by the `ToPrimitive` (`Value::to_primitve`) abstract operation. /// Called by the `ToPrimitive` (`Value::to_primitve`) abstract operation.
#[inline] #[inline]
pub fn to_primitive_symbol(&self) -> RcSymbol { pub fn to_primitive() -> RcSymbol {
self.to_primitive.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.to_primitive.clone())
} }
/// The `Symbol.toStringTag` well known symbol. /// The `Symbol.toStringTag` well known symbol.
@ -204,8 +230,8 @@ impl WellKnownSymbols {
/// string description of an object. /// string description of an object.
/// Accessed by the built-in method `Object.prototype.toString`. /// Accessed by the built-in method `Object.prototype.toString`.
#[inline] #[inline]
pub fn to_string_tag_symbol(&self) -> RcSymbol { pub fn to_string_tag() -> RcSymbol {
self.to_string_tag.clone() WELL_KNOW_SYMBOLS.with(|symbols| symbols.to_string_tag.clone())
} }
/// The `Symbol.unscopables` well known symbol. /// The `Symbol.unscopables` well known symbol.
@ -213,19 +239,31 @@ impl WellKnownSymbols {
/// An object valued property whose own and inherited property names are property /// 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. /// names that are excluded from the `with` environment bindings of the associated object.
#[inline] #[inline]
pub fn unscopables_symbol(&self) -> RcSymbol { pub fn unscopables() -> RcSymbol {
self.unscopables.clone() 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 struct Symbol {
pub(crate) hash: u64, pub(crate) hash: u64,
pub(crate) description: Option<RcString>, pub(crate) description: Option<RcString>,
} }
impl Symbol { impl Symbol {
pub(crate) fn new(hash: u64, description: Option<RcString>) -> Self { /// Create a new symbol with a specified hash and description.
fn with_hash(hash: u64, description: Option<RcString>) -> Self {
Self { hash, description }
}
/// Create a new symbol.
#[inline]
pub fn new(description: Option<RcString>) -> Self {
let hash = SYMBOL_HASH_COUNT.with(|count| {
let hash = count.get();
count.set(hash + 1);
hash
});
Self { hash, description } Self { hash, description }
} }
@ -236,8 +274,24 @@ impl Symbol {
} }
/// Returns the `Symbol`s hash. /// Returns the `Symbol`s hash.
///
/// The hash is guaranteed to be unique.
#[inline] #[inline]
pub fn hash(&self) -> u64 { pub fn hash(&self) -> u64 {
self.hash self.hash
} }
} }
impl PartialEq for Symbol {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
}
}
impl Hash for Symbol {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.hash.hash(state);
}
}

3
boa/src/syntax/ast/node/operator/bin_op/mod.rs

@ -1,6 +1,7 @@
use crate::{ use crate::{
exec::Executable, exec::Executable,
gc::{Finalize, Trace}, gc::{Finalize, Trace},
symbol::WellKnownSymbols,
syntax::ast::{ syntax::ast::{
node::Node, node::Node,
op::{self, AssignOp, BitOp, CompOp, LogOp, NumOp}, op::{self, AssignOp, BitOp, CompOp, LogOp, NumOp},
@ -153,7 +154,7 @@ impl Executable for BinOp {
} }
CompOp::InstanceOf => { CompOp::InstanceOf => {
if let Some(object) = y.as_object() { 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)? { match object.get_method(context, key)? {
Some(instance_of_handler) => { Some(instance_of_handler) => {

4
boa/src/value/mod.rs

@ -13,7 +13,7 @@ use crate::{
}, },
object::{GcObject, Object, ObjectData}, object::{GcObject, Object, ObjectData},
property::{Attribute, DataDescriptor, PropertyDescriptor, PropertyKey}, property::{Attribute, DataDescriptor, PropertyDescriptor, PropertyKey},
symbol::RcSymbol, symbol::{RcSymbol, WellKnownSymbols},
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
}; };
use gc::{Finalize, Trace}; use gc::{Finalize, Trace};
@ -520,7 +520,7 @@ impl Value {
// 2. If Type(input) is Object, then // 2. If Type(input) is Object, then
if let Value::Object(obj) = self { if let Value::Object(obj) = self {
if let Some(exotic_to_prim) = 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 { let hint = match preferred_type {
PreferredType::String => "string", PreferredType::String => "string",

Loading…
Cancel
Save