From 74e2830c6ed65508f3f7c42744c01e2056c1bf69 Mon Sep 17 00:00:00 2001 From: Haled Odat Date: Sat, 15 Apr 2023 23:28:25 +0200 Subject: [PATCH] Direct array element access on `ByValue` instructions --- boa_engine/src/object/internal_methods/mod.rs | 2 + boa_engine/src/object/property_map.rs | 9 +++++ boa_engine/src/vm/opcode/get/property.rs | 37 +++++++++++++++++++ boa_engine/src/vm/opcode/set/property.rs | 20 +++++++++- 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/boa_engine/src/object/internal_methods/mod.rs b/boa_engine/src/object/internal_methods/mod.rs index 9511173c079..9079630a009 100644 --- a/boa_engine/src/object/internal_methods/mod.rs +++ b/boa_engine/src/object/internal_methods/mod.rs @@ -23,6 +23,8 @@ pub(super) mod integer_indexed; pub(super) mod proxy; pub(super) mod string; +pub(crate) use array::ARRAY_EXOTIC_INTERNAL_METHODS; + impl JsObject { /// Internal method `[[GetPrototypeOf]]` /// diff --git a/boa_engine/src/object/property_map.rs b/boa_engine/src/object/property_map.rs index 228f07a3ab1..374bd7e221f 100644 --- a/boa_engine/src/object/property_map.rs +++ b/boa_engine/src/object/property_map.rs @@ -287,6 +287,15 @@ impl PropertyMap { } } + /// Returns the vec of dense indexed properties if they exist. + pub(crate) fn dense_indexed_properties_mut(&mut self) -> Option<&mut ThinVec> { + if let IndexedProperties::Dense(properties) = &mut self.indexed_properties { + Some(properties) + } else { + None + } + } + /// An iterator visiting all key-value pairs in arbitrary order. The iterator element type is `(PropertyKey, &'a Property)`. /// /// This iterator does not recurse down the prototype chain. diff --git a/boa_engine/src/vm/opcode/get/property.rs b/boa_engine/src/vm/opcode/get/property.rs index b5de8900fbd..561177b6f7f 100644 --- a/boa_engine/src/vm/opcode/get/property.rs +++ b/boa_engine/src/vm/opcode/get/property.rs @@ -1,5 +1,6 @@ use crate::{ js_string, + object::internal_methods::ARRAY_EXOTIC_INTERNAL_METHODS, property::PropertyKey, vm::{opcode::Operation, CompletionType}, Context, JsResult, JsValue, @@ -56,6 +57,23 @@ impl Operation for GetPropertyByValue { }; let key = key.to_property_key(context)?; + + // Fast Path + if std::ptr::eq(object.vtable(), &ARRAY_EXOTIC_INTERNAL_METHODS) { + if let PropertyKey::Index(index) = &key { + let object_borrowed = object.borrow(); + if let Some(dense_elements) = + object_borrowed.properties().dense_indexed_properties() + { + let index = *index as usize; + context + .vm + .push(dense_elements.get(index).cloned().unwrap_or_default()); + return Ok(CompletionType::Normal); + } + } + } + let result = object.__get__(&key, value, context)?; context.vm.push(result); @@ -110,6 +128,25 @@ impl Operation for GetPropertyByValuePush { }; let key = key.to_property_key(context)?; + + // Fast path: + if std::ptr::eq(object.vtable(), &ARRAY_EXOTIC_INTERNAL_METHODS) { + if let PropertyKey::Index(index) = &key { + let object_borrowed = object.borrow(); + if let Some(dense_elements) = + object_borrowed.properties().dense_indexed_properties() + { + let index = *index as usize; + context.vm.push(key); + context + .vm + .push(dense_elements.get(index).cloned().unwrap_or_default()); + return Ok(CompletionType::Normal); + } + } + } + + // Slow path: let result = object.__get__(&key, value, context)?; context.vm.push(key); diff --git a/boa_engine/src/vm/opcode/set/property.rs b/boa_engine/src/vm/opcode/set/property.rs index 948e79c7c90..5a479bc56bc 100644 --- a/boa_engine/src/vm/opcode/set/property.rs +++ b/boa_engine/src/vm/opcode/set/property.rs @@ -1,5 +1,6 @@ use crate::{ builtins::function::set_function_name, + object::internal_methods::ARRAY_EXOTIC_INTERNAL_METHODS, property::{PropertyDescriptor, PropertyKey}, vm::{opcode::Operation, CompletionType}, Context, JsNativeError, JsResult, JsString, JsValue, @@ -31,7 +32,6 @@ impl Operation for SetPropertyByName { let name = context.vm.frame().code_block.names[index as usize]; let name: PropertyKey = context.interner().resolve_expect(name.sym()).utf16().into(); - //object.set(name, value.clone(), context.vm.frame().code.strict, context)?; let succeeded = object.__set__(name.clone(), value.clone(), receiver, context)?; if !succeeded && context.vm.frame().code_block.strict { return Err(JsNativeError::typ() @@ -65,6 +65,24 @@ impl Operation for SetPropertyByValue { }; let key = key.to_property_key(context)?; + + // Fast Path: + if std::ptr::eq(object.vtable(), &ARRAY_EXOTIC_INTERNAL_METHODS) { + if let PropertyKey::Index(index) = &key { + let mut object_borrowed = object.borrow_mut(); + if let Some(element) = object_borrowed + .properties_mut() + .dense_indexed_properties_mut() + .and_then(|vec| vec.get_mut(*index as usize)) + { + *element = value; + context.vm.push(element.clone()); + return Ok(CompletionType::Normal); + } + } + } + + // Slow path: object.set( key, value.clone(),