From aaf2b923e47b3efe98606a7723a3458cb3184b4f Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Fri, 31 Jul 2020 02:04:07 +0200 Subject: [PATCH 1/6] Added [[IsExtensible]] --- boa/src/builtins/object/internal_methods.rs | 33 ++++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/boa/src/builtins/object/internal_methods.rs b/boa/src/builtins/object/internal_methods.rs index c86aa6f7353..e671983d303 100644 --- a/boa/src/builtins/object/internal_methods.rs +++ b/boa/src/builtins/object/internal_methods.rs @@ -13,6 +13,28 @@ use crate::builtins::{ use crate::BoaProfiler; impl Object { + /// Check if the ordinary object is extensible. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-isextensible + #[inline] + fn ordinary_is_extensible(&self) -> bool { + self.extensible + } + + /// Check if the object is extensible. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#table-5 + #[inline] + pub fn is_extensible(&self) -> bool { + self.ordinary_is_extensible() + } + /// Check if object has property. /// /// More information: @@ -37,17 +59,6 @@ impl Object { true } - /// Check if it is extensible. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-isextensible - #[inline] - pub fn is_extensible(&self) -> bool { - self.extensible - } - /// Disable extensibility. /// /// More information: From eea9fb38725af6b27e497b7ae89607d5a03c24ae Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Fri, 31 Jul 2020 02:06:20 +0200 Subject: [PATCH 2/6] Added [[PreventExtensions]] --- boa/src/builtins/object/internal_methods.rs | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/boa/src/builtins/object/internal_methods.rs b/boa/src/builtins/object/internal_methods.rs index e671983d303..e4281e4ac19 100644 --- a/boa/src/builtins/object/internal_methods.rs +++ b/boa/src/builtins/object/internal_methods.rs @@ -35,6 +35,29 @@ impl Object { self.ordinary_is_extensible() } + /// Prevent further extensions to ordinary object. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinaryisextensible + #[inline] + fn ordinary_prevent_extensions(&self) -> bool { + self.extensible = false; + true + } + + /// Prevent further extensions to object. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#table-5 + #[inline] + pub fn prevent_extensions(&self) -> bool { + self.ordinary_is_extensible() + } + /// Check if object has property. /// /// More information: From 81e755efefb235fb3289f86ac0a12bb7b506938b Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Fri, 31 Jul 2020 02:08:10 +0200 Subject: [PATCH 3/6] better doc --- boa/src/builtins/object/internal_methods.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/boa/src/builtins/object/internal_methods.rs b/boa/src/builtins/object/internal_methods.rs index e4281e4ac19..aab4a358704 100644 --- a/boa/src/builtins/object/internal_methods.rs +++ b/boa/src/builtins/object/internal_methods.rs @@ -24,7 +24,7 @@ impl Object { self.extensible } - /// Check if the object is extensible. + /// Determine whether it is permitted to add additional properties to this object. /// /// More information: /// - [ECMAScript reference][spec] @@ -47,7 +47,9 @@ impl Object { true } - /// Prevent further extensions to object. + /// Control whether new properties may be added to this object. + /// Returns `true` if the operation was successful or `false` + /// if the operation was unsuccessful. /// /// More information: /// - [ECMAScript reference][spec] From 493b56badf78a1b74d32543716c785df33f5a05e Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Fri, 31 Jul 2020 02:25:56 +0200 Subject: [PATCH 4/6] Remove double prevent_extensionsfunctions --- boa/src/builtins/object/internal_methods.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/boa/src/builtins/object/internal_methods.rs b/boa/src/builtins/object/internal_methods.rs index aab4a358704..36e60b73b07 100644 --- a/boa/src/builtins/object/internal_methods.rs +++ b/boa/src/builtins/object/internal_methods.rs @@ -42,7 +42,7 @@ impl Object { /// /// [spec]: https://tc39.es/ecma262/#sec-ordinaryisextensible #[inline] - fn ordinary_prevent_extensions(&self) -> bool { + fn ordinary_prevent_extensions(&mut self) -> bool { self.extensible = false; true } @@ -56,8 +56,8 @@ impl Object { /// /// [spec]: https://tc39.es/ecma262/#table-5 #[inline] - pub fn prevent_extensions(&self) -> bool { - self.ordinary_is_extensible() + pub fn prevent_extensions(&mut self) -> bool { + self.ordinary_prevent_extensions() } /// Check if object has property. @@ -84,18 +84,6 @@ impl Object { true } - /// Disable extensibility. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-preventextensions - #[inline] - pub fn prevent_extensions(&mut self) -> bool { - self.extensible = false; - true - } - /// Delete property. pub fn delete(&mut self, property_key: &PropertyKey) -> bool { let desc = self.get_own_property(property_key); From 2383211681170062b4d1345b8999ab7a250a2246 Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Sat, 1 Aug 2020 15:38:13 +0200 Subject: [PATCH 5/6] Made get_own_property retrun an Option --- boa/src/builtins/object/internal_methods.rs | 120 +++++++++----------- boa/src/builtins/object/mod.rs | 20 ++-- 2 files changed, 61 insertions(+), 79 deletions(-) diff --git a/boa/src/builtins/object/internal_methods.rs b/boa/src/builtins/object/internal_methods.rs index 36e60b73b07..a5778883579 100644 --- a/boa/src/builtins/object/internal_methods.rs +++ b/boa/src/builtins/object/internal_methods.rs @@ -66,37 +66,29 @@ impl Object { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p - pub fn has_property(&self, property_key: &PropertyKey) -> bool { - let prop = self.get_own_property(property_key); - if prop.value.is_none() { - let parent: Value = self.get_prototype_of(); - if !parent.is_null() { - // the parent value variant should be an object - // In the unlikely event it isn't return false - return match parent { - Value::Object(ref obj) => obj.borrow().has_property(property_key), - _ => false, - }; - } - return false; + pub fn has_property(&self, key: &PropertyKey) -> bool { + if self.get_own_property(key).is_some() { + return true; } - true + if let Value::Object(ref object) = self.get_prototype_of() { + let object = object.borrow(); + object.has_property(key) + } else { + false + } } /// Delete property. - pub fn delete(&mut self, property_key: &PropertyKey) -> bool { - let desc = self.get_own_property(property_key); - if desc - .value - .clone() - .expect("unable to get value") - .is_undefined() - { + pub fn delete(&mut self, key: &PropertyKey) -> bool { + let desc = if let Some(desc) = self.get_own_property(key) { + desc + } else { return true; - } + }; + if desc.configurable_or(false) { - self.remove_property(&property_key.to_string()); + self.remove_property(&key.to_string()); return true; } @@ -105,26 +97,17 @@ impl Object { /// [[Get]] /// https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-get-p-receiver - pub fn get(&self, property_key: &PropertyKey) -> Value { - let desc = self.get_own_property(property_key); - if desc.value.clone().is_none() - || desc - .value - .clone() - .expect("Failed to get object") - .is_undefined() - { - // parent will either be null or an Object - let parent = self.get_prototype_of(); - if parent.is_null() { - return Value::undefined(); - } - - let parent_obj = Object::from(&parent).expect("Failed to get object"); - - return parent_obj.get(property_key); + pub fn get(&self, key: &PropertyKey) -> Value { + let desc = self.get_own_property(key); + if desc.is_none() { + return if let Some(object) = self.get_prototype_of().as_object() { + object.get(key) + } else { + Value::undefined() + }; } + let desc = desc.unwrap(); if desc.is_data_descriptor() { return desc.value.clone().expect("failed to extract value"); } @@ -140,22 +123,22 @@ impl Object { /// [[Set]] /// - pub fn set(&mut self, property_key: &PropertyKey, val: Value) -> bool { + pub fn set(&mut self, key: &PropertyKey, val: Value) -> bool { let _timer = BoaProfiler::global().start_event("Object::set", "object"); // Fetch property key - let mut own_desc = self.get_own_property(property_key); - // [2] - if own_desc.is_none() { + let mut own_desc = if let Some(desc) = self.get_own_property(key) { + desc + } else { let parent = self.get_prototype_of(); if !parent.is_null() { // TODO: come back to this } - own_desc = Property::data_descriptor( + Property::data_descriptor( Value::undefined(), Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::CONFIGURABLE, - ); - } + ) + }; // [3] if own_desc.is_data_descriptor() { if !own_desc.writable() { @@ -164,7 +147,7 @@ impl Object { // Change value on the current descriptor own_desc = own_desc.value(val); - return self.define_own_property(property_key, own_desc); + return self.define_own_property(key, own_desc); } // [4] debug_assert!(own_desc.is_accessor_descriptor()); @@ -185,7 +168,9 @@ impl Object { pub fn define_own_property(&mut self, property_key: &PropertyKey, desc: Property) -> bool { let _timer = BoaProfiler::global().start_event("Object::define_own_property", "object"); - let mut current = self.get_own_property(property_key); + let mut current = self + .get_own_property(property_key) + .unwrap_or_else(Property::empty); let extensible = self.is_extensible(); // https://tc39.es/ecma262/#sec-validateandapplypropertydescriptor @@ -285,13 +270,25 @@ impl Object { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-getownproperty-p - pub fn get_own_property(&self, property_key: &PropertyKey) -> Property { + pub fn get_own_property(&self, property_key: &PropertyKey) -> Option { let _timer = BoaProfiler::global().start_event("Object::get_own_property", "object"); // Prop could either be a String or Symbol match property_key { - PropertyKey::String(ref st) => { - self.properties().get(st).map_or_else(Property::empty, |v| { + PropertyKey::String(ref st) => self.properties().get(st).map(|v| { + let mut d = Property::empty(); + if v.is_data_descriptor() { + d.value = v.value.clone(); + } else { + debug_assert!(v.is_accessor_descriptor()); + d.get = v.get.clone(); + d.set = v.set.clone(); + } + d.attribute = v.attribute; + d + }), + PropertyKey::Symbol(ref symbol) => { + self.symbol_properties().get(&symbol.hash()).map(|v| { let mut d = Property::empty(); if v.is_data_descriptor() { d.value = v.value.clone(); @@ -304,21 +301,6 @@ impl Object { d }) } - PropertyKey::Symbol(ref symbol) => self - .symbol_properties() - .get(&symbol.hash()) - .map_or_else(Property::empty, |v| { - let mut d = Property::empty(); - if v.is_data_descriptor() { - d.value = v.value.clone(); - } else { - debug_assert!(v.is_accessor_descriptor()); - d.get = v.get.clone(); - d.set = v.set.clone(); - } - d.attribute = v.attribute; - d - }), } } diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 77ac66274db..1bf5f4a4353 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -561,16 +561,16 @@ pub fn property_is_enumerable(this: &Value, args: &[Value], ctx: &mut Interprete Some(key) => key, }; - let property_key = ctx.to_property_key(key)?; - let own_property = ctx.to_object(this).map(|obj| { - obj.as_object() - .expect("Unable to deref object") - .get_own_property(&property_key) - }); - - Ok(own_property.map_or(Value::from(false), |own_prop| { - Value::from(own_prop.enumerable_or(false)) - })) + let key = ctx.to_property_key(key)?; + let property = ctx + .to_object(this)? + .as_object() + .expect("Unable to deref object") + .get_own_property(&key); + + Ok(property + .map_or(false, |own_prop| own_prop.enumerable_or(false)) + .into()) } /// Initialise the `Object` object on the global object. From a39c471f3a7d20cf1c26527dcf6e32290931f482 Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Sun, 2 Aug 2020 03:44:09 +0200 Subject: [PATCH 6/6] Added ordinary_has_property --- boa/src/builtins/object/internal_methods.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/boa/src/builtins/object/internal_methods.rs b/boa/src/builtins/object/internal_methods.rs index a5778883579..84cc4b069c4 100644 --- a/boa/src/builtins/object/internal_methods.rs +++ b/boa/src/builtins/object/internal_methods.rs @@ -60,13 +60,14 @@ impl Object { self.ordinary_prevent_extensions() } - /// Check if object has property. + /// Return a bool value indicating whether this ordinay object already has either an own + /// or inherited property with the specified key. /// /// More information: /// - [ECMAScript reference][spec] /// - /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p - pub fn has_property(&self, key: &PropertyKey) -> bool { + /// [spec]: https://tc39.es/ecma262/#table-5 + fn ordinary_has_property(&self, key: &PropertyKey) -> bool { if self.get_own_property(key).is_some() { return true; } @@ -79,6 +80,17 @@ impl Object { } } + /// Return a bool value indicating whether this ordinay object already has either an own + /// or inherited property with the specified key. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p + pub fn has_property(&self, key: &PropertyKey) -> bool { + self.ordinary_has_property(key) + } + /// Delete property. pub fn delete(&mut self, key: &PropertyKey) -> bool { let desc = if let Some(desc) = self.get_own_property(key) {