diff --git a/boa_engine/benches/full.rs b/boa_engine/benches/full.rs index 5317bbdb650..f59a92dca57 100644 --- a/boa_engine/benches/full.rs +++ b/boa_engine/benches/full.rs @@ -1,7 +1,7 @@ //! Benchmarks of the whole execution engine in Boa. use boa_engine::{ - context::DefaultHooks, object::shape::SharedShape, optimizer::OptimizerOptions, realm::Realm, + context::DefaultHooks, object::shape::RootShape, optimizer::OptimizerOptions, realm::Realm, Context, Source, }; use criterion::{criterion_group, criterion_main, Criterion}; @@ -16,7 +16,7 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; fn create_realm(c: &mut Criterion) { c.bench_function("Create Realm", move |b| { - let root_shape = SharedShape::root(); + let root_shape = RootShape::default(); b.iter(|| Realm::create(&DefaultHooks, &root_shape)) }); } diff --git a/boa_engine/src/builtins/weak/weak_ref.rs b/boa_engine/src/builtins/weak/weak_ref.rs index a12ef32d32d..4ec3bbe1cee 100644 --- a/boa_engine/src/builtins/weak/weak_ref.rs +++ b/boa_engine/src/builtins/weak/weak_ref.rs @@ -80,9 +80,11 @@ impl BuiltInConstructor for WeakRef { // 3. Let weakRef be ? OrdinaryCreateFromConstructor(NewTarget, "%WeakRef.prototype%", « [[WeakRefTarget]] »). // 5. Set weakRef.[[WeakRefTarget]] to target. + let prototype = + get_prototype_from_constructor(new_target, StandardConstructors::weak_ref, context)?; let weak_ref = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), - get_prototype_from_constructor(new_target, StandardConstructors::weak_ref, context)?, + prototype, ObjectData::weak_ref(WeakGc::new(target.inner())), ); diff --git a/boa_engine/src/builtins/weak_map/mod.rs b/boa_engine/src/builtins/weak_map/mod.rs index 788cef1ea3c..66f5e5aed42 100644 --- a/boa_engine/src/builtins/weak_map/mod.rs +++ b/boa_engine/src/builtins/weak_map/mod.rs @@ -82,9 +82,11 @@ impl BuiltInConstructor for WeakMap { // 2. Let map be ? OrdinaryCreateFromConstructor(NewTarget, "%WeakMap.prototype%", « [[WeakMapData]] »). // 3. Set map.[[WeakMapData]] to a new empty List. + let prototype = + get_prototype_from_constructor(new_target, StandardConstructors::weak_map, context)?; let map = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), - get_prototype_from_constructor(new_target, StandardConstructors::weak_map, context)?, + prototype, ObjectData::weak_map(boa_gc::WeakMap::new()), ); diff --git a/boa_engine/src/builtins/weak_set/mod.rs b/boa_engine/src/builtins/weak_set/mod.rs index 68f2bb4aeee..13304a39f8e 100644 --- a/boa_engine/src/builtins/weak_set/mod.rs +++ b/boa_engine/src/builtins/weak_set/mod.rs @@ -78,9 +78,11 @@ impl BuiltInConstructor for WeakSet { // 2. Let set be ? OrdinaryCreateFromConstructor(NewTarget, "%WeakSet.prototype%", « [[WeakSetData]] »). // 3. Set set.[[WeakSetData]] to a new empty List. + let prototype = + get_prototype_from_constructor(new_target, StandardConstructors::weak_set, context)?; let weak_set = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), - get_prototype_from_constructor(new_target, StandardConstructors::weak_set, context)?, + prototype, ObjectData::weak_set(WeakMap::new()), ); diff --git a/boa_engine/src/context/intrinsics.rs b/boa_engine/src/context/intrinsics.rs index 9d2ff4e0b1c..92d3c825d5c 100644 --- a/boa_engine/src/context/intrinsics.rs +++ b/boa_engine/src/context/intrinsics.rs @@ -5,7 +5,7 @@ use boa_gc::{Finalize, Trace}; use crate::{ builtins::{iterable::IteratorPrototypes, uri::UriFunctions}, object::{ - shape::shared_shape::{template::ObjectTemplate, SharedShape}, + shape::{shared_shape::template::ObjectTemplate, RootShape}, JsFunction, JsObject, ObjectData, CONSTRUCTOR, PROTOTYPE, }, property::{Attribute, PropertyKey}, @@ -27,7 +27,7 @@ pub struct Intrinsics { } impl Intrinsics { - pub(crate) fn new(root_shape: &SharedShape) -> Self { + pub(crate) fn new(root_shape: &RootShape) -> Self { let constructors = StandardConstructors::default(); let templates = ObjectTemplates::new(root_shape, &constructors); @@ -1004,7 +1004,9 @@ pub(crate) struct ObjectTemplates { } impl ObjectTemplates { - pub(crate) fn new(root_shape: &SharedShape, constructors: &StandardConstructors) -> Self { + pub(crate) fn new(root_shape: &RootShape, constructors: &StandardConstructors) -> Self { + let root_shape = root_shape.shape(); + // pre-initialize used shapes. let ordinary_object = ObjectTemplate::with_prototype(root_shape, constructors.object().prototype()); diff --git a/boa_engine/src/context/mod.rs b/boa_engine/src/context/mod.rs index 8bedb552058..5d8551a8202 100644 --- a/boa_engine/src/context/mod.rs +++ b/boa_engine/src/context/mod.rs @@ -23,7 +23,7 @@ use crate::{ job::{JobQueue, NativeJob, SimpleJobQueue}, module::{ModuleLoader, SimpleModuleLoader}, native_function::NativeFunction, - object::{shape::SharedShape, FunctionObjectBuilder, JsObject}, + object::{shape::RootShape, FunctionObjectBuilder, JsObject}, optimizer::{Optimizer, OptimizerOptions, OptimizerStatistics}, property::{Attribute, PropertyDescriptor, PropertyKey}, realm::Realm, @@ -109,7 +109,7 @@ pub struct Context<'host> { module_loader: MaybeShared<'host, dyn ModuleLoader>, optimizer_options: OptimizerOptions, - root_shape: SharedShape, + root_shape: RootShape, /// Unique identifier for each parser instance used during the context lifetime. parser_identifier: u32, @@ -496,8 +496,10 @@ impl<'host> Context<'host> { std::mem::replace(&mut self.realm, realm) } - pub(crate) fn root_shape(&self) -> SharedShape { - self.root_shape.clone() + /// Get the [`RootShape`]. + #[inline] + pub const fn root_shape(&self) -> &RootShape { + &self.root_shape } /// Gets the host hooks. @@ -916,7 +918,7 @@ impl<'icu, 'hooks, 'queue, 'module> ContextBuilder<'icu, 'hooks, 'queue, 'module 'queue: 'host, 'module: 'host, { - let root_shape = SharedShape::root(); + let root_shape = RootShape::default(); let host_hooks = self.host_hooks.unwrap_or_else(|| { let hooks: &dyn HostHooks = &DefaultHooks; diff --git a/boa_engine/src/object/jsobject.rs b/boa_engine/src/object/jsobject.rs index df62ce1b068..94607b61eb1 100644 --- a/boa_engine/src/object/jsobject.rs +++ b/boa_engine/src/object/jsobject.rs @@ -4,7 +4,7 @@ use super::{ internal_methods::{InternalObjectMethods, ARRAY_EXOTIC_INTERNAL_METHODS}, - shape::{shared_shape::SharedShape, Shape}, + shape::RootShape, JsPrototype, NativeObject, Object, PropertyMap, }; use crate::{ @@ -127,7 +127,7 @@ impl JsObject { /// /// [`OrdinaryObjectCreate`]: https://tc39.es/ecma262/#sec-ordinaryobjectcreate pub(crate) fn from_proto_and_data_with_shared_shape>>( - root_shape: SharedShape, + root_shape: &RootShape, prototype: O, data: ObjectData, ) -> Self { @@ -136,7 +136,7 @@ impl JsObject { object: GcRefCell::new(Object { kind: data.kind, properties: PropertyMap::from_prototype_with_shared_shape( - Shape::shared(root_shape), + root_shape, prototype.into(), ), extensible: true, diff --git a/boa_engine/src/object/property_map.rs b/boa_engine/src/object/property_map.rs index 90ffb50989b..ed1cea1d66c 100644 --- a/boa_engine/src/object/property_map.rs +++ b/boa_engine/src/object/property_map.rs @@ -3,7 +3,7 @@ use super::{ property_table::PropertyTableInner, shared_shape::TransitionKey, slot::{Slot, SlotAttributes}, - ChangeTransitionAction, Shape, UniqueShape, + ChangeTransitionAction, RootShape, Shape, UniqueShape, }, JsPrototype, ObjectStorage, PropertyDescriptor, PropertyKey, }; @@ -252,11 +252,14 @@ impl PropertyMap { /// Construct a [`PropertyMap`] from with the given prototype with a shared shape [`Shape`]. #[must_use] #[inline] - pub fn from_prototype_with_shared_shape(mut root_shape: Shape, prototype: JsPrototype) -> Self { - root_shape = root_shape.change_prototype_transition(prototype); + pub fn from_prototype_with_shared_shape( + root_shape: &RootShape, + prototype: JsPrototype, + ) -> Self { + let shape = root_shape.shape().change_prototype_transition(prototype); Self { indexed_properties: IndexedProperties::default(), - shape: root_shape, + shape: Shape::shared(shape), storage: Vec::default(), } } diff --git a/boa_engine/src/object/shape/mod.rs b/boa_engine/src/object/shape/mod.rs index 0d7f6e8c13e..3527be4b247 100644 --- a/boa_engine/src/object/shape/mod.rs +++ b/boa_engine/src/object/shape/mod.rs @@ -1,10 +1,12 @@ //! Implements object shapes. pub(crate) mod property_table; +mod root_shape; pub(crate) mod shared_shape; pub(crate) mod slot; pub(crate) mod unique_shape; +pub use root_shape::RootShape; pub use shared_shape::SharedShape; pub(crate) use unique_shape::UniqueShape; diff --git a/boa_engine/src/object/shape/root_shape.rs b/boa_engine/src/object/shape/root_shape.rs new file mode 100644 index 00000000000..e025ff9da2f --- /dev/null +++ b/boa_engine/src/object/shape/root_shape.rs @@ -0,0 +1,26 @@ +use boa_macros::{Finalize, Trace}; + +use super::SharedShape; + +/// Represent the root shape that [`SharedShape`] transitions start from. +/// +/// This is a wrapper around [`SharedShape`] that ensures that the shape the root shape. +#[derive(Debug, Clone, Trace, Finalize)] +pub struct RootShape { + shape: SharedShape, +} + +impl Default for RootShape { + fn default() -> Self { + Self { + shape: SharedShape::root(), + } + } +} + +impl RootShape { + /// Gets the inner [`SharedShape`]. + pub(crate) const fn shape(&self) -> &SharedShape { + &self.shape + } +} diff --git a/boa_engine/src/object/shape/shared_shape/mod.rs b/boa_engine/src/object/shape/shared_shape/mod.rs index 0908bc1235f..128438467db 100644 --- a/boa_engine/src/object/shape/shared_shape/mod.rs +++ b/boa_engine/src/object/shape/shared_shape/mod.rs @@ -174,7 +174,7 @@ impl SharedShape { /// Create a root [`SharedShape`]. #[must_use] - pub fn root() -> Self { + pub(crate) fn root() -> Self { Self::new(Inner { forward_transitions: ForwardTransition::default(), prototype: None, diff --git a/boa_engine/src/realm.rs b/boa_engine/src/realm.rs index f7772899721..95ff5941f38 100644 --- a/boa_engine/src/realm.rs +++ b/boa_engine/src/realm.rs @@ -10,7 +10,7 @@ use crate::{ context::{intrinsics::Intrinsics, HostHooks}, environments::DeclarativeEnvironment, module::Module, - object::{shape::shared_shape::SharedShape, JsObject}, + object::{shape::RootShape, JsObject}, JsString, }; use boa_gc::{Finalize, Gc, GcRefCell, Trace}; @@ -57,7 +57,7 @@ struct Inner { impl Realm { /// Create a new Realm. #[inline] - pub fn create(hooks: &dyn HostHooks, root_shape: &SharedShape) -> Self { + pub fn create(hooks: &dyn HostHooks, root_shape: &RootShape) -> Self { let _timer = Profiler::global().start_event("Realm::create", "realm"); let intrinsics = Intrinsics::new(root_shape);