diff --git a/Userland/Libraries/LibJS/Runtime/TypedArray.cpp b/Userland/Libraries/LibJS/Runtime/TypedArray.cpp index 5652ccdc02..976dec4180 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArray.cpp +++ b/Userland/Libraries/LibJS/Runtime/TypedArray.cpp @@ -358,10 +358,10 @@ ThrowCompletionOr 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 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 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 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(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(); } diff --git a/Userland/Libraries/LibJS/Runtime/TypedArray.h b/Userland/Libraries/LibJS/Runtime/TypedArray.h index d1d0361bcc..5b48d7b0c2 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArray.h +++ b/Userland/Libraries/LibJS/Runtime/TypedArray.h @@ -459,7 +459,7 @@ private: ThrowCompletionOr typed_array_create(VM&, FunctionObject& constructor, MarkedVector arguments); ThrowCompletionOr typed_array_create_same_type(VM&, TypedArrayBase const& exemplar, MarkedVector arguments); -ThrowCompletionOr compare_typed_array_elements(VM&, Value x, Value y, FunctionObject* comparefn, ArrayBuffer&); +ThrowCompletionOr 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 { \ diff --git a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp index 1a8f5766cf..cc90c3883a 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp @@ -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(Value, Value)> sort_compare = [&](auto x, auto y) -> ThrowCompletionOr { - // 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 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(Value, Value)> sort_compare = [&](auto x, auto y) -> ThrowCompletionOr { - // 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])); diff --git a/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.toSorted.js b/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.toSorted.js index 461acb1ca7..410c4aa082 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.toSorted.js +++ b/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.toSorted.js @@ -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 => {