mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 15:47:34 +00:00
LibJS: Allow TypedArrays to become detached while sorting
This is a normative change in the Change Array by Copy proposal. See:
17d8b54
This commit is contained in:
parent
4dfdca74e2
commit
34e328e580
4 changed files with 39 additions and 79 deletions
|
@ -358,10 +358,10 @@ ThrowCompletionOr<TypedArrayBase*> typed_array_create_same_type(VM& vm, TypedArr
|
|||
return result;
|
||||
}
|
||||
|
||||
// 1.2.2.1.2 CompareTypedArrayElements ( x, y, comparefn, buffer ), https://tc39.es/proposal-change-array-by-copy/#sec-comparetypedarrayelements
|
||||
ThrowCompletionOr<double> compare_typed_array_elements(VM& vm, Value x, Value y, FunctionObject* comparefn, ArrayBuffer& buffer)
|
||||
// 1.2.2.1.2 CompareTypedArrayElements ( x, y, comparefn ), https://tc39.es/proposal-change-array-by-copy/#sec-comparetypedarrayelements
|
||||
ThrowCompletionOr<double> compare_typed_array_elements(VM& vm, Value x, Value y, FunctionObject* comparefn)
|
||||
{
|
||||
// 1. Assert: Both Type(x) and Type(y) are Number or both are BigInt.
|
||||
// 1. Assert: x is a Number and y is a Number, or x is a BigInt and y is a BigInt.
|
||||
VERIFY(((x.is_number() && y.is_number()) || (x.is_bigint() && y.is_bigint())));
|
||||
|
||||
// 2. If comparefn is not undefined, then
|
||||
|
@ -370,15 +370,11 @@ ThrowCompletionOr<double> compare_typed_array_elements(VM& vm, Value x, Value y,
|
|||
auto value = TRY(call(vm, comparefn, js_undefined(), x, y));
|
||||
auto value_number = TRY(value.to_number(vm));
|
||||
|
||||
// b. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||
if (buffer.is_detached())
|
||||
return vm.throw_completion<TypeError>(ErrorType::DetachedArrayBuffer);
|
||||
|
||||
// c. If v is NaN, return +0𝔽.
|
||||
// b. If v is NaN, return +0𝔽.
|
||||
if (value_number.is_nan())
|
||||
return 0;
|
||||
|
||||
// d. Return v.
|
||||
// c. Return v.
|
||||
return value_number.as_double();
|
||||
}
|
||||
|
||||
|
|
|
@ -459,7 +459,7 @@ private:
|
|||
|
||||
ThrowCompletionOr<TypedArrayBase*> typed_array_create(VM&, FunctionObject& constructor, MarkedVector<Value> arguments);
|
||||
ThrowCompletionOr<TypedArrayBase*> typed_array_create_same_type(VM&, TypedArrayBase const& exemplar, MarkedVector<Value> arguments);
|
||||
ThrowCompletionOr<double> compare_typed_array_elements(VM&, Value x, Value y, FunctionObject* comparefn, ArrayBuffer&);
|
||||
ThrowCompletionOr<double> compare_typed_array_elements(VM&, Value x, Value y, FunctionObject* comparefn);
|
||||
|
||||
#define JS_DECLARE_TYPED_ARRAY(ClassName, snake_name, PrototypeName, ConstructorName, Type) \
|
||||
class ClassName : public TypedArray<Type> { \
|
||||
|
|
|
@ -1419,62 +1419,8 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::sort)
|
|||
// 5. NOTE: The following closure performs a numeric comparison rather than the string comparison used in 23.1.3.30.
|
||||
// 6. Let SortCompare be a new Abstract Closure with parameters (x, y) that captures comparefn and performs the following steps when called:
|
||||
Function<ThrowCompletionOr<double>(Value, Value)> sort_compare = [&](auto x, auto y) -> ThrowCompletionOr<double> {
|
||||
// FIXME: Replace the following steps with CompareTypedArrayElements when the change-array-by-copy proposal is
|
||||
// updated to no longer throw on detached array buffers. See: https://github.com/tc39/ecma262/commit/e0c74e1
|
||||
|
||||
// a. Assert: Both Type(x) and Type(y) are Number or both are BigInt.
|
||||
VERIFY((x.is_number() && y.is_number()) || (x.is_bigint() && y.is_bigint()));
|
||||
|
||||
// b. If comparefn is not undefined, then
|
||||
if (!compare_fn.is_undefined()) {
|
||||
// i. Let v be ? ToNumber(? Call(comparefn, undefined, « x, y »)).
|
||||
auto result = TRY(call(vm, compare_fn.as_function(), js_undefined(), x, y));
|
||||
auto value = TRY(result.to_number(vm));
|
||||
|
||||
// ii. If v is NaN, return +0𝔽.
|
||||
if (value.is_nan())
|
||||
return 0;
|
||||
|
||||
// iii. Return v.
|
||||
return value.as_double();
|
||||
}
|
||||
|
||||
// c. If x and y are both NaN, return +0𝔽.
|
||||
if (x.is_nan() && y.is_nan())
|
||||
return 0;
|
||||
|
||||
// d. If x is NaN, return 1𝔽.
|
||||
if (x.is_nan())
|
||||
return 1;
|
||||
|
||||
// e. If y is NaN, return -1𝔽.
|
||||
if (y.is_nan())
|
||||
return -1;
|
||||
|
||||
// f. If x < y, return -1𝔽.
|
||||
if (x.is_bigint()
|
||||
? (x.as_bigint().big_integer() < y.as_bigint().big_integer())
|
||||
: (x.as_double() < y.as_double())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// g. If x > y, return 1𝔽.
|
||||
if (x.is_bigint()
|
||||
? (x.as_bigint().big_integer() > y.as_bigint().big_integer())
|
||||
: (x.as_double() > y.as_double())) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// h. If x is -0𝔽 and y is +0𝔽, return -1𝔽.
|
||||
if (x.is_negative_zero() && y.is_positive_zero())
|
||||
return -1;
|
||||
|
||||
// i. If x is +0𝔽 and y is -0𝔽, return 1𝔽.
|
||||
if (x.is_positive_zero() && y.is_negative_zero())
|
||||
return 1;
|
||||
|
||||
// j. Return +0𝔽.
|
||||
return 0;
|
||||
// a. Return ? CompareTypedArrayElements(x, y, comparefn).
|
||||
return TRY(compare_typed_array_elements(vm, x, y, compare_fn.is_undefined() ? nullptr : &compare_fn.as_function()));
|
||||
};
|
||||
|
||||
// 7. Let sortedList be ? SortIndexedProperties(obj, len, SortCompare, false).
|
||||
|
@ -1673,30 +1619,26 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::to_sorted)
|
|||
// 3. Perform ? ValidateTypedArray(O).
|
||||
auto* typed_array = TRY(validate_typed_array_from_this(vm));
|
||||
|
||||
// 4. Let buffer be obj.[[ViewedArrayBuffer]].
|
||||
auto* array_buffer = typed_array->viewed_array_buffer();
|
||||
VERIFY(array_buffer);
|
||||
|
||||
// 5. Let len be O.[[ArrayLength]].
|
||||
// 4. Let len be O.[[ArrayLength]].
|
||||
auto length = typed_array->array_length();
|
||||
|
||||
// 6. Let A be ? TypedArrayCreateSameType(O, « 𝔽(len) »).
|
||||
// 5. Let A be ? TypedArrayCreateSameType(O, « 𝔽(len) »).
|
||||
MarkedVector<Value> arguments(vm.heap());
|
||||
arguments.empend(length);
|
||||
auto* return_array = TRY(typed_array_create_same_type(vm, *typed_array, move(arguments)));
|
||||
|
||||
// 7. NOTE: The following closure performs a numeric comparison rather than the string comparison used in Array.prototype.toSorted
|
||||
// 8. Let SortCompare be a new Abstract Closure with parameters (x, y) that captures comparefn and buffer and performs the following steps when called:
|
||||
// 6. NOTE: The following closure performs a numeric comparison rather than the string comparison used in Array.prototype.toSorted
|
||||
// 7. Let SortCompare be a new Abstract Closure with parameters (x, y) that captures comparefn and performs the following steps when called:
|
||||
Function<ThrowCompletionOr<double>(Value, Value)> sort_compare = [&](auto x, auto y) -> ThrowCompletionOr<double> {
|
||||
// a. Return ? CompareTypedArrayElements(x, y, comparefn, buffer).
|
||||
return TRY(compare_typed_array_elements(vm, x, y, comparefn.is_undefined() ? nullptr : &comparefn.as_function(), *return_array->viewed_array_buffer()));
|
||||
// a. Return ? CompareTypedArrayElements(x, y, comparefn).
|
||||
return TRY(compare_typed_array_elements(vm, x, y, comparefn.is_undefined() ? nullptr : &comparefn.as_function()));
|
||||
};
|
||||
|
||||
// 9. Let sortedList be ? SortIndexedProperties(obj, len, SortCompare, false).
|
||||
// 8. Let sortedList be ? SortIndexedProperties(obj, len, SortCompare, false).
|
||||
auto sorted_list = TRY(sort_indexed_properties(vm, *object, length, sort_compare, false));
|
||||
|
||||
// 10. Let j be 0.
|
||||
// 11. Repeat, while j < len,
|
||||
// 9. Let j be 0.
|
||||
// 10. Repeat, while j < len,
|
||||
for (size_t j = 0; j < length; j++) {
|
||||
// Perform ! Set(A, ! ToString(𝔽(j)), sortedList[j], true).
|
||||
MUST(return_array->create_data_property_or_throw(j, sorted_list[j]));
|
||||
|
|
|
@ -49,6 +49,28 @@ test("basic functionality", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test("detached buffer", () => {
|
||||
TYPED_ARRAYS.forEach(T => {
|
||||
const typedArray = new T(3);
|
||||
typedArray[0] = 3;
|
||||
typedArray[1] = 1;
|
||||
typedArray[2] = 2;
|
||||
|
||||
const sortedTypedArray = typedArray.toSorted((a, b) => {
|
||||
detachArrayBuffer(typedArray.buffer);
|
||||
return a - b;
|
||||
});
|
||||
|
||||
expect(typedArray[0]).toBeUndefined();
|
||||
expect(typedArray[1]).toBeUndefined();
|
||||
expect(typedArray[2]).toBeUndefined();
|
||||
|
||||
expect(sortedTypedArray[0]).toBe(1);
|
||||
expect(sortedTypedArray[1]).toBe(2);
|
||||
expect(sortedTypedArray[2]).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("null or undefined this value", () => {
|
||||
TYPED_ARRAYS.forEach(T => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue