diff --git a/include/hermes/VM/NativeFunctions.def b/include/hermes/VM/NativeFunctions.def index 3e605b6a5df..3fe807582ad 100644 --- a/include/hermes/VM/NativeFunctions.def +++ b/include/hermes/VM/NativeFunctions.def @@ -392,6 +392,7 @@ NATIVE_FUNCTION(typedArrayPrototypeSort) NATIVE_FUNCTION(typedArrayPrototypeSubarray) NATIVE_FUNCTION(typedArrayPrototypeSymbolToStringTag) NATIVE_FUNCTION(typedArrayPrototypeToLocaleString) +NATIVE_FUNCTION(typedArrayPrototypeToSorted) NATIVE_FUNCTION(unescape) NATIVE_FUNCTION(weakMapConstructor) NATIVE_FUNCTION(weakMapPrototypeDelete) diff --git a/include/hermes/VM/PredefinedStrings.def b/include/hermes/VM/PredefinedStrings.def index 6242697af14..b73bc8381b1 100644 --- a/include/hermes/VM/PredefinedStrings.def +++ b/include/hermes/VM/PredefinedStrings.def @@ -202,6 +202,7 @@ STR(flat, "flat") STR(flatMap, "flatMap") STR(toReversed, "toReversed") STR(toSpliced, "toSpliced") +STR(toSorted, "toSorted") STR(with, "with") STR(ArrayBuffer, "ArrayBuffer") diff --git a/lib/VM/JSLib/TypedArray.cpp b/lib/VM/JSLib/TypedArray.cpp index f491f5bf2b7..c7bd8643a7c 100644 --- a/lib/VM/JSLib/TypedArray.cpp +++ b/lib/VM/JSLib/TypedArray.cpp @@ -1746,6 +1746,60 @@ typedArrayPrototypeToLocaleString(void *, Runtime &runtime, NativeArgs args) { return HermesValue::encodeStringValue(*builder->getStringPrimitive()); } +/// ES14.0 23.2.3.33 +CallResult +typedArrayPrototypeToSorted(void *, Runtime &runtime, NativeArgs args) { + GCScope gcScope{runtime}; + + // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw + // a TypeError exception. + auto compareFn = Handle::dyn_vmcast(args.getArgHandle(0)); + if (!args.getArg(0).isUndefined() && !compareFn) { + return runtime.raiseTypeError( + "TypedArray toSorted argument must be callable"); + } + + // 3. Perform ? ValidateTypedArray(O). + if (JSTypedArrayBase::validateTypedArray(runtime, args.getThisHandle()) == + ExecutionStatus::EXCEPTION) { + return ExecutionStatus::EXCEPTION; + } + + // 2. Let O be this value + auto self = args.vmcastThis(); + + // 4. Let len be O.[[ArrayLength]]. + double len = self->getLength(); + + // 5. Let A be ? TypedArrayCreateSameType(O, « 𝔽(len) »). + auto aRes = JSTypedArrayBase::allocateSpecies(runtime, self, len); + if (LLVM_UNLIKELY(aRes == ExecutionStatus::EXCEPTION)) { + return ExecutionStatus::EXCEPTION; + } + auto A = aRes.getValue(); + + if (LLVM_UNLIKELY( + JSTypedArrayBase::setToCopyOfTypedArray( + runtime, A, 0, self, 0, len) == ExecutionStatus::EXCEPTION)) { + return ExecutionStatus::EXCEPTION; + } + + // Use our custom sort routine. We can't use std::sort because it performs + // optimizations that allow it to bypass calls to std::swap, but our swap + // function is special, since it needs to use the internal Object functions. + if (compareFn) { + TypedArraySortModel sm(runtime, A, compareFn); + if (LLVM_UNLIKELY(quickSort(&sm, 0, len) == ExecutionStatus::EXCEPTION)) + return ExecutionStatus::EXCEPTION; + } else { + TypedArraySortModel sm(runtime, A, compareFn); + if (LLVM_UNLIKELY(quickSort(&sm, 0, len) == ExecutionStatus::EXCEPTION)) + return ExecutionStatus::EXCEPTION; + } + + return A.getHermesValue(); +} + Handle createTypedArrayBaseConstructor(Runtime &runtime) { auto proto = Handle::vmcast(&runtime.typedArrayBasePrototype); @@ -2044,6 +2098,14 @@ Handle createTypedArrayBaseConstructor(Runtime &runtime) { typedArrayPrototypeToLocaleString, 0); + defineMethod( + runtime, + proto, + Predefined::getSymbolID(Predefined::toSorted), + nullptr, + typedArrayPrototypeToSorted, + 0); + // TypedArrayBase.xxx defineMethod( runtime, diff --git a/test/hermes/TypedArray.js b/test/hermes/TypedArray.js index 4955e420cad..bc55056bcad 100644 --- a/test/hermes/TypedArray.js +++ b/test/hermes/TypedArray.js @@ -1438,6 +1438,34 @@ cons.forEach(function(TypedArray) { }); /// @} +/// @name TypedArray.prototype.toSorted +/// @{ +cons.forEach(function(TypedArray) { + var arr = new TypedArray([ 5, 1, 2, 4, 0, 3 ]); + + assert.arrayEqual(arr.toSorted(), [ 0, 1, 2, 3, 4, 5 ]); + assert.arrayEqual( + arr.toSorted( + (a, b) => a < b ? -1 + : a > b ? 1 + : 0), + [ 0, 1, 2, 3, 4, 5 ]); + assert.arrayEqual( + arr.toSorted( + (a, b) => a < b ? 1 + : a > b ? -1 + : 0), + [ 5, 4, 3, 2, 1, 0 ]); + + assert.throws(function() { + arr.toSorted(1); + }, TypeError); + assert.throws(function() { + arr.toSorted("test"); + }, TypeError); +}); +/// @} + /// @name Exception cases /// @{