Browse Source

Direct length access on arrays (#2796)

pull/2905/head
Haled Odat 2 years ago committed by GitHub
parent
commit
31a60cb448
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 53
      boa_engine/src/builtins/array/mod.rs
  2. 12
      boa_engine/src/object/operations.rs
  3. 7
      boa_engine/src/object/shape/shared_shape/template.rs

53
boa_engine/src/builtins/array/mod.rs

@ -236,6 +236,28 @@ impl BuiltInConstructor for Array {
} }
impl 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. /// Utility for constructing `Array` objects.
/// ///
/// More information: /// More information:
@ -655,7 +677,7 @@ impl Array {
} }
// 8. Perform ? Set(A, "length", lenNumber, true). // 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. // 9. Return A.
Ok(a.into()) Ok(a.into())
@ -779,7 +801,7 @@ impl Array {
} }
} }
// 6. Perform ? Set(A, "length", 𝔽(n), true). // 6. Perform ? Set(A, "length", 𝔽(n), true).
arr.set(utf16!("length"), n, true, context)?; Self::set_length(&arr, n, context)?;
// 7. Return A. // 7. Return A.
Ok(JsValue::new(arr)) Ok(JsValue::new(arr))
@ -824,7 +846,8 @@ impl Array {
len += 1; len += 1;
} }
// 6. Perform ? Set(O, "length", 𝔽(len), true). // 6. Perform ? Set(O, "length", 𝔽(len), true).
o.set(utf16!("length"), len, true, context)?; Self::set_length(&o, len, context)?;
// 7. Return 𝔽(len). // 7. Return 𝔽(len).
Ok(len.into()) Ok(len.into())
} }
@ -851,7 +874,8 @@ impl Array {
// 3. If len = 0, then // 3. If len = 0, then
if len == 0 { if len == 0 {
// a. Perform ? Set(O, "length", +0𝔽, true). // a. Perform ? Set(O, "length", +0𝔽, true).
o.set(utf16!("length"), 0, true, context)?; Self::set_length(&o, 0, context)?;
// b. Return undefined. // b. Return undefined.
Ok(JsValue::undefined()) Ok(JsValue::undefined())
// 4. Else, // 4. Else,
@ -866,7 +890,7 @@ impl Array {
// e. Perform ? DeletePropertyOrThrow(O, index). // e. Perform ? DeletePropertyOrThrow(O, index).
o.delete_property_or_throw(index, context)?; o.delete_property_or_throw(index, context)?;
// f. Perform ? Set(O, "length", newLen, true). // 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. // g. Return element.
Ok(element) Ok(element)
} }
@ -1107,7 +1131,8 @@ impl Array {
// 3. If len = 0, then // 3. If len = 0, then
if len == 0 { if len == 0 {
// a. Perform ? Set(O, "length", +0𝔽, true). // a. Perform ? Set(O, "length", +0𝔽, true).
o.set(utf16!("length"), 0, true, context)?; Self::set_length(&o, 0, context)?;
// b. Return undefined. // b. Return undefined.
return Ok(JsValue::undefined()); return Ok(JsValue::undefined());
} }
@ -1139,7 +1164,7 @@ impl Array {
// 7. Perform ? DeletePropertyOrThrow(O, ! ToString(𝔽(len - 1))). // 7. Perform ? DeletePropertyOrThrow(O, ! ToString(𝔽(len - 1))).
o.delete_property_or_throw(len - 1, context)?; o.delete_property_or_throw(len - 1, context)?;
// 8. Perform ? Set(O, "length", 𝔽(len - 1), true). // 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. // 9. Return first.
Ok(first) Ok(first)
} }
@ -1209,7 +1234,8 @@ impl Array {
} }
} }
// 5. Perform ? Set(O, "length", 𝔽(len + argCount), true). // 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). // 6. Return 𝔽(len + argCount).
Ok((len + arg_count).into()) Ok((len + arg_count).into())
} }
@ -2088,7 +2114,7 @@ impl Array {
} }
// 15. Perform ? Set(A, "length", 𝔽(n), true). // 15. Perform ? Set(A, "length", 𝔽(n), true).
a.set(utf16!("length"), n, true, context)?; Self::set_length(&a, n, context)?;
// 16. Return A. // 16. Return A.
Ok(a.into()) Ok(a.into())
@ -2243,7 +2269,7 @@ impl Array {
} }
// 14. Perform ? Set(A, "length", 𝔽(actualDeleteCount), true). // 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. // 15. Let itemCount be the number of elements in items.
let item_count = items.len() as u64; let item_count = items.len() as u64;
@ -2328,12 +2354,7 @@ impl Array {
} }
// 20. Perform ? Set(O, "length", 𝔽(len - actualDeleteCount + itemCount), true). // 20. Perform ? Set(O, "length", 𝔽(len - actualDeleteCount + itemCount), true).
o.set( Self::set_length(&o, len - actual_delete_count + item_count, context)?;
utf16!("length"),
len - actual_delete_count + item_count,
true,
context,
)?;
// 21. Return A. // 21. Return A.
Ok(JsValue::from(arr)) Ok(JsValue::from(arr))

12
boa_engine/src/object/operations.rs

@ -480,6 +480,18 @@ impl JsObject {
/// [spec]: https://tc39.es/ecma262/#sec-lengthofarraylike /// [spec]: https://tc39.es/ecma262/#sec-lengthofarraylike
pub(crate) fn length_of_array_like(&self, context: &mut Context<'_>) -> JsResult<u64> { pub(crate) fn length_of_array_like(&self, context: &mut Context<'_>) -> JsResult<u64> {
// 1. Assert: Type(obj) is Object. // 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"))). // 2. Return ℝ(? ToLength(? Get(obj, "length"))).
self.get(utf16!("length"), context)?.to_length(context) self.get(utf16!("length"), context)?.to_length(context)
} }

7
boa_engine/src/object/shape/shared_shape/template.rs

@ -46,6 +46,11 @@ impl ObjectTemplate {
self self
} }
/// Returns the inner shape of the [`ObjectTemplate`].
pub(crate) const fn shape(&self) -> &SharedShape {
&self.shape
}
/// Add a data property to the [`ObjectTemplate`]. /// Add a data property to the [`ObjectTemplate`].
/// ///
/// This assumes that the property with the given key was not previously set /// This assumes that the property with the given key was not previously set
@ -58,7 +63,6 @@ impl ObjectTemplate {
property_key: key, property_key: key,
attributes, attributes,
}); });
self self
} }
@ -97,7 +101,6 @@ impl ObjectTemplate {
property_key: key, property_key: key,
attributes, attributes,
}); });
self self
} }

Loading…
Cancel
Save