Skip to content

Commit

Permalink
Merge 75af983 into 65f9105
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat authored Apr 20, 2023
2 parents 65f9105 + 75af983 commit cef443f
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 7 deletions.
2 changes: 2 additions & 0 deletions boa_engine/src/object/internal_methods/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]]`
///
Expand Down
9 changes: 3 additions & 6 deletions boa_engine/src/object/jsobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
//! The `JsObject` is a garbage collected Object.
use super::{
internal_methods::InternalObjectMethods, JsPrototype, NativeObject, Object, PropertyMap,
internal_methods::{InternalObjectMethods, ARRAY_EXOTIC_INTERNAL_METHODS},
JsPrototype, NativeObject, Object, PropertyMap,
};
use crate::{
context::intrinsics::Intrinsics,
Expand Down Expand Up @@ -338,14 +339,10 @@ impl JsObject {
}

/// Checks if it's an `Array` object.
///
/// # Panics
///
/// Panics if the object is currently mutably borrowed.
#[inline]
#[track_caller]
pub fn is_array(&self) -> bool {
self.borrow().is_array()
std::ptr::eq(self.vtable(), &ARRAY_EXOTIC_INTERNAL_METHODS)
}

/// Checks if it's a `DataView` object.
Expand Down
9 changes: 9 additions & 0 deletions boa_engine/src/object/property_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<JsValue>> {
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.
Expand Down
35 changes: 35 additions & 0 deletions boa_engine/src/vm/opcode/get/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@ impl Operation for GetPropertyByValue {
};

let key = key.to_property_key(context)?;

// Fast Path
if object.is_array() {
if let PropertyKey::Index(index) = &key {
let object_borrowed = object.borrow();
if let Some(element) = object_borrowed
.properties()
.dense_indexed_properties()
.and_then(|vec| vec.get(*index as usize))
{
context.vm.push(element.clone());
return Ok(CompletionType::Normal);
}
}
}

// Slow path:
let result = object.__get__(&key, value, context)?;

context.vm.push(result);
Expand Down Expand Up @@ -110,6 +127,24 @@ impl Operation for GetPropertyByValuePush {
};

let key = key.to_property_key(context)?;

// Fast path:
if object.is_array() {
if let PropertyKey::Index(index) = &key {
let object_borrowed = object.borrow();
if let Some(element) = object_borrowed
.properties()
.dense_indexed_properties()
.and_then(|vec| vec.get(*index as usize))
{
context.vm.push(key);
context.vm.push(element.clone());
return Ok(CompletionType::Normal);
}
}
}

// Slow path:
let result = object.__get__(&key, value, context)?;

context.vm.push(key);
Expand Down
47 changes: 46 additions & 1 deletion boa_engine/src/vm/opcode/set/property.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use boa_macros::utf16;

use crate::{
builtins::function::set_function_name,
property::{PropertyDescriptor, PropertyKey},
Expand Down Expand Up @@ -31,7 +33,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()
Expand Down Expand Up @@ -65,6 +66,50 @@ impl Operation for SetPropertyByValue {
};

let key = key.to_property_key(context)?;

// Fast Path:
if object.is_array() {
if let PropertyKey::Index(index) = &key {
let mut object_borrowed = object.borrow_mut();
if let Some(dense_elements) = object_borrowed
.properties_mut()
.dense_indexed_properties_mut()
{
let index = *index as usize;
if let Some(element) = dense_elements.get_mut(index) {
*element = value;
context.vm.push(element.clone());
return Ok(CompletionType::Normal);
} else if dense_elements.len() == index {
dense_elements.push(value.clone());
context.vm.push(value);

let len = dense_elements.len();
let length_key = PropertyKey::from(utf16!("length"));
let length = object_borrowed
.properties_mut()
.get(&length_key)
.expect("Arrays must have length property");
if length.expect_writable() {
object_borrowed.insert(
length_key,
PropertyDescriptor::builder()
.value(len)
.writable(true)
.enumerable(length.expect_enumerable())
.configurable(false)
.build(),
);
} else if context.vm.frame().code_block.strict {
return Err(JsNativeError::typ().with_message("TypeError: Cannot assign to read only property 'length' of array object").into());
}
return Ok(CompletionType::Normal);
}
}
}
}

// Slow path:
object.set(
key,
value.clone(),
Expand Down

0 comments on commit cef443f

Please sign in to comment.