diff --git a/boa_builtins/build.rs b/boa_builtins/build.rs index c6b36a1d9c..71689e1e9c 100644 --- a/boa_builtins/build.rs +++ b/boa_builtins/build.rs @@ -1087,6 +1087,12 @@ fn main() -> io::Result<()> { .property(WellKnown::ToStringTag, Attribute::CONFIGURABLE) .build(file)?; + BuiltInBuilder::new(&context, "PROXY_CONSTRUCTOR") + .property(utf16!("length"), Attribute::CONFIGURABLE) + .property(utf16!("name"), Attribute::CONFIGURABLE) + .method(utf16!("revocable")) + .build(file)?; + #[cfg(feature = "intl")] { BuiltInBuilder::new(&context, "INTL_OBJECT") diff --git a/boa_engine/src/builtins/mod.rs b/boa_engine/src/builtins/mod.rs index 304796c0cd..098617f376 100644 --- a/boa_engine/src/builtins/mod.rs +++ b/boa_engine/src/builtins/mod.rs @@ -97,11 +97,8 @@ use crate::{ js_string, native_function::{NativeFunction, NativeFunctionPointer}, object::{ - shape::{ - property_table::PropertyTableInner, slot::SlotAttributes, static_shape::StaticShape, - }, - FunctionBinding, JsFunction, JsObject, JsPrototype, Object, ObjectData, ObjectKind, - CONSTRUCTOR, PROTOTYPE, + shape::static_shape::StaticShape, JsFunction, JsObject, JsPrototype, Object, ObjectData, + ObjectKind, CONSTRUCTOR, PROTOTYPE, }, property::{Attribute, PropertyDescriptor, PropertyKey}, realm::Realm, @@ -635,8 +632,6 @@ impl<'ctx> BuiltInBuilder { prototype_shape: &'static RawStaticShape, ) -> BuiltInBuilderConstructorStaticShape<'ctx> { let constructor = SC::STANDARD_CONSTRUCTOR(realm.intrinsics().constructors()); - // println!("{constructor_shape:#?}"); - // println!("{prototype_shape:#?}"); let mut this = BuiltInBuilderConstructorStaticShape { realm, function: SC::constructor, @@ -667,6 +662,35 @@ impl<'ctx> BuiltInBuilder { this } + + fn from_standard_constructor_static_shape_without_prototype( + realm: &'ctx Realm, + constructor_shape: &'static RawStaticShape, + ) -> BuiltInBuilderConstructorStaticShape<'ctx> { + let constructor = SC::STANDARD_CONSTRUCTOR(realm.intrinsics().constructors()); + let mut this = BuiltInBuilderConstructorStaticShape { + realm, + function: SC::constructor, + + constructor_property_index: 0, + constructor_shape, + constructor_storage: Vec::with_capacity(constructor_shape.storage_len), + constructor_object: constructor.constructor(), + + prototype_property_index: 0, + prototype_shape: &boa_builtins::EMPTY_OBJECT_STATIC_SHAPE, + prototype_storage: Vec::default(), + prototype_object: constructor.prototype(), + + __proto__: Some(realm.intrinsics().constructors().function().prototype()), + inherits: Some(realm.intrinsics().constructors().object().prototype()), + }; + + this.constructor_storage.push(SC::LENGTH.into()); + this.constructor_storage.push(js_string!(SC::NAME).into()); + + this + } } impl BuiltInBuilderConstructorStaticShape<'_> { @@ -822,6 +846,47 @@ impl BuiltInBuilderConstructorStaticShape<'_> { .push(self.inherits.map(JsValue::new).unwrap_or_default()); prototype.properties_mut().storage = self.prototype_storage; } + + fn build_without_prototype(mut self) { + debug_assert_eq!( + self.constructor_storage.len() + 1, + self.constructor_shape.storage_len + ); + debug_assert_eq!( + self.constructor_storage.capacity(), + self.constructor_shape.storage_len + ); + + let function = function::Function::new( + function::FunctionKind::Native { + function: NativeFunction::from_fn_ptr(self.function), + constructor: (true).then_some(function::ConstructorKind::Base), + }, + self.realm.clone(), + ); + + let mut object = self.constructor_object.borrow_mut(); + *object.kind_mut() = ObjectKind::Function(function); + object.properties_mut().shape = StaticShape::new(self.constructor_shape).into(); + self.constructor_storage.push( + self.__proto__ + .unwrap_or_else(|| { + self.realm + .intrinsics() + .constructors() + .function() + .prototype() + }) + .into(), + ); + object.properties_mut().storage = self.constructor_storage; + + debug_assert_eq!(self.prototype_storage.len(), 0); + debug_assert!(std::ptr::eq( + self.prototype_shape, + &boa_builtins::EMPTY_OBJECT_STATIC_SHAPE + )); + } } struct BuiltInBuilderStaticShape<'ctx> { @@ -909,94 +974,6 @@ impl<'ctx> BuiltInBuilder { } } -struct BuiltInConstructorWithPrototype<'ctx> { - realm: &'ctx Realm, - function: NativeFunctionPointer, - name: JsString, - length: usize, - - object_property_table: PropertyTableInner, - object_storage: Vec, - object: JsObject, - - __proto__: JsPrototype, -} - -impl BuiltInConstructorWithPrototype<'_> { - /// Adds a new static method to the builtin object. - fn static_method( - mut self, - function: NativeFunctionPointer, - binding: B, - length: usize, - ) -> Self - where - B: Into, - { - let binding = binding.into(); - let function = BuiltInBuilder::callable(self.realm, function) - .name(binding.name) - .length(length) - .build(); - - debug_assert!(self - .object_property_table - .map - .get(&binding.binding) - .is_none()); - self.object_property_table.insert( - binding.binding, - SlotAttributes::WRITABLE | SlotAttributes::CONFIGURABLE, - ); - self.object_storage.push(function.into()); - self - } - - /// Adds a new static data property to the builtin object. - fn static_property(mut self, key: K, value: V, attribute: Attribute) -> Self - where - K: Into, - V: Into, - { - let key = key.into(); - - debug_assert!(self.object_property_table.map.get(&key).is_none()); - self.object_property_table - .insert(key, SlotAttributes::from_bits_truncate(attribute.bits())); - self.object_storage.push(value.into()); - self - } - - fn build_without_prototype(mut self) { - let function = function::Function::new( - function::FunctionKind::Native { - function: NativeFunction::from_fn_ptr(self.function), - constructor: (true).then_some(function::ConstructorKind::Base), - }, - self.realm.clone(), - ); - - let length = self.length; - let name = self.name.clone(); - self = self.static_property("length", length, Attribute::CONFIGURABLE); - self = self.static_property("name", name, Attribute::CONFIGURABLE); - - let mut object = self.object.borrow_mut(); - *object.kind_mut() = ObjectKind::Function(function); - object - .properties_mut() - .shape - .as_unique() - .expect("The object should have a unique shape") - .override_internal(self.object_property_table, self.__proto__); - - let object_old_storage = - std::mem::replace(&mut object.properties_mut().storage, self.object_storage); - - debug_assert_eq!(object_old_storage.len(), 0); - } -} - struct BuiltInCallable<'ctx> { realm: &'ctx Realm, function: NativeFunctionPointer, @@ -1062,21 +1039,3 @@ impl<'ctx> BuiltInBuilder { } } } - -impl<'ctx> BuiltInBuilder { - fn from_standard_constructor( - realm: &'ctx Realm, - ) -> BuiltInConstructorWithPrototype<'ctx> { - let constructor = SC::STANDARD_CONSTRUCTOR(realm.intrinsics().constructors()); - BuiltInConstructorWithPrototype { - realm, - function: SC::constructor, - name: js_string!(SC::NAME), - length: SC::LENGTH, - object_property_table: PropertyTableInner::default(), - object_storage: Vec::default(), - object: constructor.constructor(), - __proto__: Some(realm.intrinsics().constructors().function().prototype()), - } - } -} diff --git a/boa_engine/src/builtins/proxy/mod.rs b/boa_engine/src/builtins/proxy/mod.rs index 8e754c589a..71ce4f6ff2 100644 --- a/boa_engine/src/builtins/proxy/mod.rs +++ b/boa_engine/src/builtins/proxy/mod.rs @@ -35,9 +35,12 @@ impl IntrinsicObject for Proxy { fn init(realm: &Realm) { let _timer = Profiler::global().start_event(Self::NAME, "init"); - BuiltInBuilder::from_standard_constructor::(realm) - .static_method(Self::revocable, "revocable", 2) - .build_without_prototype(); + BuiltInBuilder::from_standard_constructor_static_shape_without_prototype::( + realm, + &boa_builtins::PROXY_CONSTRUCTOR_STATIC_SHAPE, + ) + .static_method(Self::revocable, 2) + .build_without_prototype(); } fn get(intrinsics: &Intrinsics) -> JsObject { diff --git a/boa_engine/src/context/intrinsics.rs b/boa_engine/src/context/intrinsics.rs index 5304845198..23011e82ae 100644 --- a/boa_engine/src/context/intrinsics.rs +++ b/boa_engine/src/context/intrinsics.rs @@ -167,14 +167,14 @@ impl Default for StandardConstructors { object: StandardConstructor::with_prototype( JsObject::from_data_and_empty_static_shape(ObjectData::object_prototype()), ), - async_generator_function: StandardConstructor::default(), - proxy: StandardConstructor::default(), + async_generator_function: StandardConstructor::default_static_shape(), + proxy: StandardConstructor::default_static_shape(), date: StandardConstructor::default_static_shape(), function: StandardConstructor { constructor: JsFunction::empty_intrinsic_function_static_shape(true), prototype: JsFunction::empty_intrinsic_function_static_shape(false).into(), }, - async_function: StandardConstructor::default(), + async_function: StandardConstructor::default_static_shape(), generator_function: StandardConstructor::default_static_shape(), array: StandardConstructor::with_prototype(JsObject::from_data_and_empty_static_shape( ObjectData::array(), @@ -225,11 +225,11 @@ impl Default for StandardConstructors { #[cfg(feature = "intl")] collator: StandardConstructor::default_static_shape(), #[cfg(feature = "intl")] - list_format: StandardConstructor::default(), + list_format: StandardConstructor::default_static_shape(), #[cfg(feature = "intl")] - locale: StandardConstructor::default(), + locale: StandardConstructor::default_static_shape(), #[cfg(feature = "intl")] - segmenter: StandardConstructor::default(), + segmenter: StandardConstructor::default_static_shape(), } } } diff --git a/boa_engine/src/object/shape/mod.rs b/boa_engine/src/object/shape/mod.rs index afbb477c05..67ec66d39d 100644 --- a/boa_engine/src/object/shape/mod.rs +++ b/boa_engine/src/object/shape/mod.rs @@ -106,13 +106,6 @@ impl Shape { matches!(self.inner, Inner::Static(_)) } - pub(crate) const fn as_unique(&self) -> Option<&UniqueShape> { - if let Inner::Unique(shape) = &self.inner { - return Some(shape); - } - None - } - /// Create an insert property transitions returning the new transitioned [`Shape`]. /// /// NOTE: This assumes that there is no property with the given key! diff --git a/boa_engine/src/object/shape/unique_shape.rs b/boa_engine/src/object/shape/unique_shape.rs index 68872a96c8..6bb7ccdfa9 100644 --- a/boa_engine/src/object/shape/unique_shape.rs +++ b/boa_engine/src/object/shape/unique_shape.rs @@ -44,15 +44,6 @@ impl UniqueShape { } } - pub(crate) fn override_internal( - &self, - property_table: PropertyTableInner, - prototype: JsPrototype, - ) { - *self.inner.property_table.borrow_mut() = property_table; - *self.inner.prototype.borrow_mut() = prototype; - } - /// Get the prototype of the [`UniqueShape`]. pub(crate) fn prototype(&self) -> JsPrototype { self.inner.prototype.borrow().clone()