Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Direct array length access #2796

Merged
merged 1 commit into from
May 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 37 additions & 16 deletions boa_engine/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,28 @@ impl BuiltInConstructor for Array {
}

impl Array {
/// Optimized helper function, that sets the length of the array.
fn set_length(o: &JsObject, len: u64, context: &mut Context<'_>) -> JsResult<()> {
if o.is_array() && len < (2u64.pow(32) - 1) {
let mut borrowed_object = o.borrow_mut();
if borrowed_object.properties().shape.to_addr_usize()
== context
.intrinsics()
.templates()
.array()
.shape()
.to_addr_usize()
{
// NOTE: The "length" property is the first element.
borrowed_object.properties_mut().storage[0] = JsValue::new(len);
return Ok(());
}
}

o.set(utf16!("length"), len, true, context)?;
Ok(())
}

/// Utility for constructing `Array` objects.
///
/// More information:
Expand Down Expand Up @@ -655,7 +677,7 @@ impl Array {
}

// 8. Perform ? Set(A, "length", lenNumber, true).
a.set(utf16!("length"), len, true, context)?;
Self::set_length(&a, len as u64, context)?;

// 9. Return A.
Ok(a.into())
Expand Down Expand Up @@ -779,7 +801,7 @@ impl Array {
}
}
// 6. Perform ? Set(A, "length", 𝔽(n), true).
arr.set(utf16!("length"), n, true, context)?;
Self::set_length(&arr, n, context)?;

// 7. Return A.
Ok(JsValue::new(arr))
Expand Down Expand Up @@ -824,7 +846,8 @@ impl Array {
len += 1;
}
// 6. Perform ? Set(O, "length", 𝔽(len), true).
o.set(utf16!("length"), len, true, context)?;
Self::set_length(&o, len, context)?;

// 7. Return 𝔽(len).
Ok(len.into())
}
Expand All @@ -851,7 +874,8 @@ impl Array {
// 3. If len = 0, then
if len == 0 {
// a. Perform ? Set(O, "length", +0𝔽, true).
o.set(utf16!("length"), 0, true, context)?;
Self::set_length(&o, 0, context)?;

// b. Return undefined.
Ok(JsValue::undefined())
// 4. Else,
Expand All @@ -866,7 +890,7 @@ impl Array {
// e. Perform ? DeletePropertyOrThrow(O, index).
o.delete_property_or_throw(index, context)?;
// f. Perform ? Set(O, "length", newLen, true).
o.set(utf16!("length"), new_len, true, context)?;
Self::set_length(&o, new_len, context)?;
// g. Return element.
Ok(element)
}
Expand Down Expand Up @@ -1107,7 +1131,8 @@ impl Array {
// 3. If len = 0, then
if len == 0 {
// a. Perform ? Set(O, "length", +0𝔽, true).
o.set(utf16!("length"), 0, true, context)?;
Self::set_length(&o, 0, context)?;

// b. Return undefined.
return Ok(JsValue::undefined());
}
Expand Down Expand Up @@ -1139,7 +1164,7 @@ impl Array {
// 7. Perform ? DeletePropertyOrThrow(O, ! ToString(𝔽(len - 1))).
o.delete_property_or_throw(len - 1, context)?;
// 8. Perform ? Set(O, "length", 𝔽(len - 1), true).
o.set(utf16!("length"), len - 1, true, context)?;
Self::set_length(&o, len - 1, context)?;
// 9. Return first.
Ok(first)
}
Expand Down Expand Up @@ -1209,7 +1234,8 @@ impl Array {
}
}
// 5. Perform ? Set(O, "length", 𝔽(len + argCount), true).
o.set(utf16!("length"), len + arg_count, true, context)?;
Self::set_length(&o, len + arg_count, context)?;

// 6. Return 𝔽(len + argCount).
Ok((len + arg_count).into())
}
Expand Down Expand Up @@ -2088,7 +2114,7 @@ impl Array {
}

// 15. Perform ? Set(A, "length", 𝔽(n), true).
a.set(utf16!("length"), n, true, context)?;
Self::set_length(&a, n, context)?;

// 16. Return A.
Ok(a.into())
Expand Down Expand Up @@ -2243,7 +2269,7 @@ impl Array {
}

// 14. Perform ? Set(A, "length", 𝔽(actualDeleteCount), true).
arr.set(utf16!("length"), actual_delete_count, true, context)?;
Self::set_length(&arr, actual_delete_count, context)?;

// 15. Let itemCount be the number of elements in items.
let item_count = items.len() as u64;
Expand Down Expand Up @@ -2328,12 +2354,7 @@ impl Array {
}

// 20. Perform ? Set(O, "length", 𝔽(len - actualDeleteCount + itemCount), true).
o.set(
utf16!("length"),
len - actual_delete_count + item_count,
true,
context,
)?;
Self::set_length(&o, len - actual_delete_count + item_count, context)?;

// 21. Return A.
Ok(JsValue::from(arr))
Expand Down
12 changes: 12 additions & 0 deletions boa_engine/src/object/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,18 @@ impl JsObject {
/// [spec]: https://tc39.es/ecma262/#sec-lengthofarraylike
pub(crate) fn length_of_array_like(&self, context: &mut Context<'_>) -> JsResult<u64> {
// 1. Assert: Type(obj) is Object.

// NOTE: This is an optimization, most of the cases that `LengthOfArrayLike` will be called
// is for arrays. The "length" property of an array is stored in the first index.
if self.is_array() {
let borrowed_object = self.borrow();
// NOTE: using `to_u32` instead of `to_length` is an optimization,
// since arrays are limited to [0, 2^32 - 1] range.
return borrowed_object.properties().storage[0]
.to_u32(context)
.map(u64::from);
}

// 2. Return ℝ(? ToLength(? Get(obj, "length"))).
self.get(utf16!("length"), context)?.to_length(context)
}
Expand Down
7 changes: 5 additions & 2 deletions boa_engine/src/object/shape/shared_shape/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ impl ObjectTemplate {
self
}

/// Returns the inner shape of the [`ObjectTemplate`].
pub(crate) const fn shape(&self) -> &SharedShape {
&self.shape
}

/// Add a data property to the [`ObjectTemplate`].
///
/// This assumes that the property with the given key was not previously set
Expand All @@ -58,7 +63,6 @@ impl ObjectTemplate {
property_key: key,
attributes,
});

self
}

Expand Down Expand Up @@ -97,7 +101,6 @@ impl ObjectTemplate {
property_key: key,
attributes,
});

self
}

Expand Down