Browse Source

Fix `TypedArray`s minus zero key (#2808)

It changes the following:

- Fix `-0` index in typed arrays
pull/2818/head
Haled Odat 2 years ago
parent
commit
bfa9815fe7
  1. 199
      boa_engine/src/object/internal_methods/integer_indexed.rs

199
boa_engine/src/object/internal_methods/integer_indexed.rs

@ -1,3 +1,5 @@
use boa_macros::utf16;
use crate::{ use crate::{
builtins::{array_buffer::SharedMemoryOrder, typed_array::integer_indexed_object::ContentType}, builtins::{array_buffer::SharedMemoryOrder, typed_array::integer_indexed_object::ContentType},
object::JsObject, object::JsObject,
@ -39,23 +41,29 @@ pub(crate) fn integer_indexed_exotic_get_own_property(
// 1. If Type(P) is String, then // 1. If Type(P) is String, then
// a. Let numericIndex be ! CanonicalNumericIndexString(P). // a. Let numericIndex be ! CanonicalNumericIndexString(P).
// b. If numericIndex is not undefined, then // b. If numericIndex is not undefined, then
if let PropertyKey::Index(index) = key { match key {
// i. Let value be ! IntegerIndexedElementGet(O, numericIndex). PropertyKey::Index(index) => {
// ii. If value is undefined, return undefined. // i. Let value be ! IntegerIndexedElementGet(O, numericIndex).
// iii. Return the PropertyDescriptor { [[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }. // ii. If value is undefined, return undefined.
Ok( // iii. Return the PropertyDescriptor { [[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }.
integer_indexed_element_get(obj, u64::from(*index)).map(|v| { Ok(
PropertyDescriptor::builder() integer_indexed_element_get(obj, u64::from(*index)).map(|v| {
.value(v) PropertyDescriptor::builder()
.writable(true) .value(v)
.enumerable(true) .writable(true)
.configurable(true) .enumerable(true)
.build() .configurable(true)
}), .build()
) }),
} else { )
// 2. Return OrdinaryGetOwnProperty(O, P). }
super::ordinary_get_own_property(obj, key, context) // The following step is taken from https://tc39.es/ecma262/#sec-isvalidintegerindex :
// Step 3. If index is -0𝔽, return false.
PropertyKey::String(string) if string == utf16!("-0") => Ok(None),
key => {
// 2. Return OrdinaryGetOwnProperty(O, P).
super::ordinary_get_own_property(obj, key, context)
}
} }
} }
@ -72,12 +80,18 @@ pub(crate) fn integer_indexed_exotic_has_property(
) -> JsResult<bool> { ) -> JsResult<bool> {
// 1. If Type(P) is String, then // 1. If Type(P) is String, then
// a. Let numericIndex be ! CanonicalNumericIndexString(P). // a. Let numericIndex be ! CanonicalNumericIndexString(P).
if let PropertyKey::Index(index) = key { match key {
// b. If numericIndex is not undefined, return ! IsValidIntegerIndex(O, numericIndex). PropertyKey::Index(index) => {
Ok(is_valid_integer_index(obj, u64::from(*index))) // b. If numericIndex is not undefined, return ! IsValidIntegerIndex(O, numericIndex).
} else { Ok(is_valid_integer_index(obj, u64::from(*index)))
// 2. Return ? OrdinaryHasProperty(O, P). }
super::ordinary_has_property(obj, key, context) // The following step is taken from https://tc39.es/ecma262/#sec-isvalidintegerindex :
// Step 3. If index is -0𝔽, return false.
PropertyKey::String(string) if string == utf16!("-0") => Ok(false),
key => {
// 2. Return ? OrdinaryHasProperty(O, P).
super::ordinary_has_property(obj, key, context)
}
} }
} }
@ -96,33 +110,37 @@ pub(crate) fn integer_indexed_exotic_define_own_property(
// 1. If Type(P) is String, then // 1. If Type(P) is String, then
// a. Let numericIndex be ! CanonicalNumericIndexString(P). // a. Let numericIndex be ! CanonicalNumericIndexString(P).
// b. If numericIndex is not undefined, then // b. If numericIndex is not undefined, then
if let &PropertyKey::Index(index) = key { match key {
// i. If ! IsValidIntegerIndex(O, numericIndex) is false, return false. &PropertyKey::Index(index) => {
// ii. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] is false, return false. // i. If ! IsValidIntegerIndex(O, numericIndex) is false, return false.
// iii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]] is false, return false. // ii. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] is false, return false.
// v. If Desc has a [[Writable]] field and if Desc.[[Writable]] is false, return false. // iii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]] is false, return false.
// iv. If ! IsAccessorDescriptor(Desc) is true, return false. // v. If Desc has a [[Writable]] field and if Desc.[[Writable]] is false, return false.
if !is_valid_integer_index(obj, u64::from(index)) // iv. If ! IsAccessorDescriptor(Desc) is true, return false.
|| !desc if !is_valid_integer_index(obj, u64::from(index))
.configurable() || !desc
.or_else(|| desc.enumerable()) .configurable()
.or_else(|| desc.writable()) .or_else(|| desc.enumerable())
.unwrap_or(true) .or_else(|| desc.writable())
|| desc.is_accessor_descriptor() .unwrap_or(true)
{ || desc.is_accessor_descriptor()
return Ok(false); {
return Ok(false);
}
// vi. If Desc has a [[Value]] field, perform ? IntegerIndexedElementSet(O, numericIndex, Desc.[[Value]]).
if let Some(value) = desc.value() {
integer_indexed_element_set(obj, index as usize, value, context)?;
}
// vii. Return true.
Ok(true)
} }
PropertyKey::String(string) if string == utf16!("-0") => Ok(false),
// vi. If Desc has a [[Value]] field, perform ? IntegerIndexedElementSet(O, numericIndex, Desc.[[Value]]). key => {
if let Some(value) = desc.value() { // 2. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
integer_indexed_element_set(obj, index as usize, value, context)?; super::ordinary_define_own_property(obj, key, desc, context)
} }
// vii. Return true.
Ok(true)
} else {
// 2. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
super::ordinary_define_own_property(obj, key, desc, context)
} }
} }
@ -141,12 +159,18 @@ pub(crate) fn integer_indexed_exotic_get(
// 1. If Type(P) is String, then // 1. If Type(P) is String, then
// a. Let numericIndex be ! CanonicalNumericIndexString(P). // a. Let numericIndex be ! CanonicalNumericIndexString(P).
// b. If numericIndex is not undefined, then // b. If numericIndex is not undefined, then
if let PropertyKey::Index(index) = key { match key {
// i. Return ! IntegerIndexedElementGet(O, numericIndex). PropertyKey::Index(index) => {
Ok(integer_indexed_element_get(obj, u64::from(*index)).unwrap_or_default()) // i. Return ! IntegerIndexedElementGet(O, numericIndex).
} else { Ok(integer_indexed_element_get(obj, u64::from(*index)).unwrap_or_default())
// 2. Return ? OrdinaryGet(O, P, Receiver). }
super::ordinary_get(obj, key, receiver, context) // The following step is taken from https://tc39.es/ecma262/#sec-isvalidintegerindex :
// Step 3. If index is -0𝔽, return false.
PropertyKey::String(string) if string == utf16!("-0") => Ok(JsValue::undefined()),
key => {
// 2. Return ? OrdinaryGet(O, P, Receiver).
super::ordinary_get(obj, key, receiver, context)
}
} }
} }
@ -166,15 +190,21 @@ pub(crate) fn integer_indexed_exotic_set(
// 1. If Type(P) is String, then // 1. If Type(P) is String, then
// a. Let numericIndex be ! CanonicalNumericIndexString(P). // a. Let numericIndex be ! CanonicalNumericIndexString(P).
// b. If numericIndex is not undefined, then // b. If numericIndex is not undefined, then
if let PropertyKey::Index(index) = key { match key {
// i. Perform ? IntegerIndexedElementSet(O, numericIndex, V). PropertyKey::Index(index) => {
integer_indexed_element_set(obj, index as usize, &value, context)?; // i. Perform ? IntegerIndexedElementSet(O, numericIndex, V).
integer_indexed_element_set(obj, index as usize, &value, context)?;
// ii. Return true. // ii. Return true.
Ok(true) Ok(true)
} else { }
// 2. Return ? OrdinarySet(O, P, V, Receiver). // The following step is taken from https://tc39.es/ecma262/#sec-isvalidintegerindex :
super::ordinary_set(obj, key, value, receiver, context) // Step 3. If index is -0𝔽, return false.
PropertyKey::String(string) if &string == utf16!("-0") => Ok(false),
key => {
// 2. Return ? OrdinarySet(O, P, V, Receiver).
super::ordinary_set(obj, key, value, receiver, context)
}
} }
} }
@ -192,12 +222,33 @@ pub(crate) fn integer_indexed_exotic_delete(
// 1. If Type(P) is String, then // 1. If Type(P) is String, then
// a. Let numericIndex be ! CanonicalNumericIndexString(P). // a. Let numericIndex be ! CanonicalNumericIndexString(P).
// b. If numericIndex is not undefined, then // b. If numericIndex is not undefined, then
if let PropertyKey::Index(index) = key { match key {
// i. If ! IsValidIntegerIndex(O, numericIndex) is false, return true; else return false. PropertyKey::Index(index) => {
Ok(!is_valid_integer_index(obj, u64::from(*index))) // i. If ! IsValidIntegerIndex(O, numericIndex) is false, return true; else return false.
} else { Ok(!is_valid_integer_index(obj, u64::from(*index)))
// 2. Return ? OrdinaryDelete(O, P). }
super::ordinary_delete(obj, key, context) // The following step is taken from https://tc39.es/ecma262/#sec-isvalidintegerindex :
// Step 3. If index is -0𝔽, return false.
PropertyKey::String(string) if string == utf16!("-0") => {
let obj = obj.borrow();
let inner = obj.as_typed_array().expect(
"integer indexed exotic method should only be callable from integer indexed objects",
);
// 1. If IsValidIntegerIndex(O, numericIndex) is false, return true; else return false.
// From IsValidIntegerIndex:
// 1. If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, return false.
// 3. If index is -0𝔽, return false.
//
// NOTE: They are negated, so it should return true.
if inner.is_detached() {
return Ok(true);
}
Ok(true)
}
key => {
// 2. Return ? OrdinaryDelete(O, P).
super::ordinary_delete(obj, key, context)
}
} }
} }
@ -263,10 +314,18 @@ pub(crate) fn is_valid_integer_index(obj: &JsObject, index: u64) -> bool {
"integer indexed exotic method should only be callable from integer indexed objects", "integer indexed exotic method should only be callable from integer indexed objects",
); );
// 1. If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, return false. // 1. If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, return false.
// 2. If ! IsIntegralNumber(index) is false, return false. //
// 3. If index is -0𝔽, return false. // SKIPPED: 2. If ! IsIntegralNumber(index) is false, return false.
// NOTE: This step has already been done when we construct a PropertyKey.
//
// MOVED: 3. If index is -0𝔽, return false.
// NOTE: This step has been moved into the callers of this functions,
// once we get the index it is already converted into unsigned integer
// index, it cannot be `-0`.
// 4. If ℝ(index) < 0 or ℝ(index) ≥ O.[[ArrayLength]], return false. // 4. If ℝ(index) < 0 or ℝ(index) ≥ O.[[ArrayLength]], return false.
// 5. Return true. // 5. Return true.
!inner.is_detached() && index < inner.array_length() !inner.is_detached() && index < inner.array_length()
} }

Loading…
Cancel
Save