Title: [292778] trunk
Revision
292778
Author
[email protected]
Date
2022-04-12 10:54:56 -0700 (Tue, 12 Apr 2022)

Log Message

Implement Change Array by copy proposal
https://bugs.webkit.org/show_bug.cgi?id=234604

Patch by Aditi Singh <[email protected]> on 2022-04-12
Reviewed by Alexey Shvayka.

JSTests:

* stress/change-array-by-copy.js: Added.
(shouldBe):
(shouldThrow):
(shallowEqual):
(shouldThrow.Array.prototype.toSpliced.toReversed):
* stress/typed-array-change-by-copy.js: Added.
(shouldBe):
(shouldThrow):
(shallowEqual):
(sequence.new.Uint8Array):
* stress/unscopables.js:

Source/_javascript_Core:

This patch implements proposal Change Array By Copy. The proposal provides additional
methods on Array.prototype and TypedArray.prototype to enable changes on the array by
returning a new copy of it with the change.
Since, a call to intrinsic functions: Array.prototype.sort(comparefn) and
%TypedArray%.prototype.sort(comparefn) was needed, LinkTimeConstants have
been added for the same.
LinkTimeConstants were added instead of:
function sort(comparefn) { return @arraySort.@call(this, cmp); }
because this introduces an extra function call, which is slower.
%%TypedArray%%.prototype.sort(comparefn) and Array.prototype.sort(comparefn) are
implemented differently to avoid eager initialisation for TypedArrayPrototype
because it is quite large and not commonly used on the web.

The proposal details can be found here:
https://github.com/tc39/proposal-change-array-by-copy

* builtins/ArrayPrototype.js:
(toReversed):
(toSorted):
(toSpliced):
(with):
* builtins/BuiltinNames.h:
* builtins/TypedArrayPrototype.js:
(toReversed):
(toSorted):
(toSpliced):
(with):
(sort):
* bytecode/LinkTimeConstant.h:
* runtime/ArrayPrototype.cpp:
(JSC::ArrayPrototype::finishCreation):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildrenImpl):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::typedArrayProtoSort const):
* runtime/JSTypedArrayViewPrototype.cpp:
(JSC::JSTypedArrayViewPrototype::finishCreation):
* runtime/OptionsList.h:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (292777 => 292778)


--- trunk/JSTests/ChangeLog	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/JSTests/ChangeLog	2022-04-12 17:54:56 UTC (rev 292778)
@@ -1,3 +1,22 @@
+2022-04-12  Aditi Singh  <[email protected]>
+
+        Implement Change Array by copy proposal
+        https://bugs.webkit.org/show_bug.cgi?id=234604
+
+        Reviewed by Alexey Shvayka.
+
+        * stress/change-array-by-copy.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (shallowEqual):
+        (shouldThrow.Array.prototype.toSpliced.toReversed):
+        * stress/typed-array-change-by-copy.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (shallowEqual):
+        (sequence.new.Uint8Array):
+        * stress/unscopables.js:
+
 2022-04-12  Dmitry Bezhetskov  <[email protected]>
 
         [WASM-GC] Introduce structs types

Added: trunk/JSTests/stress/change-array-by-copy.js (0 => 292778)


--- trunk/JSTests/stress/change-array-by-copy.js	                        (rev 0)
+++ trunk/JSTests/stress/change-array-by-copy.js	2022-04-12 17:54:56 UTC (rev 292778)
@@ -0,0 +1,117 @@
+//@ requireOptions("--useChangeArrayByCopyMethods=1")
+
+function shouldBe(actual, expected) {
+    if (!shallowEqual(actual, expected)){
+        throw new Error(`expected ${expected} but got ${actual}`);
+    }
+}
+
+function shouldThrow(func, errorType, message) {
+    let error;
+    try {
+        func();
+    } catch (e) {
+        error = e;
+    }
+
+    if (!(error instanceof errorType))
+        throw new Error(`Expected ${errorType.name}!`);
+    if (message !== undefined) {
+        if (Object.prototype.toString.call(message) === '[object RegExp]') {
+            if (!message.test(String(error)))
+                throw new Error(`expected '${String(error)}' to match ${message}!`);
+        } else {
+            if (String(error) !== message)
+                throw new Error(`expected ${String(error)} but got ${message}`);
+        }
+    }
+}
+
+function shallowEqual(a, b) {
+    if (a.length !== b.length)
+        return false;
+    for (let i = 0; i < a.length; i++) {
+        if (a[i] !== b[i])
+            return false;
+    }
+    return true;
+}
+
+var sequence = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+// Array.prototype.toReversed()
+{
+    let reversedSequence = sequence.toReversed();
+    shouldBe(reversedSequence, [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
+
+    // |this| = null.
+    shouldThrow(() => Array.prototype.toSpliced.toReversed(null, 0, 5), TypeError);
+}
+
+// Array.prototype.toSorted()
+{
+    var unsortedSequence = [9, 2, 3, 4, 56, 12, 0];
+    var sortedSequence = unsortedSequence.toSorted();
+    shouldBe(sortedSequence, [0, 12, 2, 3, 4, 56, 9]);
+
+    // |this| = null.
+    shouldThrow(() => Array.prototype.toSorted.call(null), TypeError);
+
+    // Non callable comparator.
+    var nonCallableComparator = "a";
+    shouldThrow(() => unsortedSequence.toSorted(nonCallableComparator), TypeError);
+}
+
+// Array.prototype.toSpliced()
+{
+    var splicedSequence = sequence.toSpliced(3, 5);
+    shouldBe(splicedSequence, [1, 2, 3, 9, 10]);
+
+    // Start missing.
+    splicedSequence = sequence.toSpliced();
+    shouldBe(splicedSequence, sequence);
+
+    // Delete count missing.
+    splicedSequence = sequence.toSpliced(3);
+    shouldBe(splicedSequence, [1, 2, 3]);
+
+    // Start undefined.
+    splicedSequence = sequence.toSpliced(undefined);
+    shouldBe(splicedSequence, []);
+
+    // Delete count undefined.
+    splicedSequence = sequence.toSpliced(1, undefined);
+    shouldBe(splicedSequence, sequence);
+
+    // Insertion
+    splicedSequence = sequence.toSpliced(3, 5, 11, 12, 13);
+    shouldBe(splicedSequence, [1, 2, 3, 11, 12, 13, 9, 10]);
+
+    // |this| = null.
+    shouldThrow(() => Array.prototype.toSpliced.call(null, 0, 5), TypeError);
+
+    // Length >= 2^53 - 1.
+    var arrayLike = {};
+    arrayLike.length = 2 ** 53 - 1;
+    shouldThrow(() => Array.prototype.toSpliced.call(arrayLike, 0, 0, null), TypeError);
+}
+
+//Array.prototype.with()
+{
+    var withSequence = sequence.with(3, "a");
+    shouldBe(withSequence, [1, 2, 3, "a", 5, 6, 7, 8, 9, 10]);
+
+    // Index missing.
+    withSequence = sequence.with();
+    shouldBe(withSequence, [undefined, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+
+    // Index undefined.
+    withSequence = sequence.with(undefined, "a");
+    shouldBe(withSequence, ["a", 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+
+    // Invalid index.
+    shouldThrow(() => sequence.with(-11, "a"), RangeError);
+
+    // |this| = null.
+    shouldThrow(() => Array.prototype.toReversed.with(null, 5, "a"), TypeError);
+}

Added: trunk/JSTests/stress/typed-array-change-by-copy.js (0 => 292778)


--- trunk/JSTests/stress/typed-array-change-by-copy.js	                        (rev 0)
+++ trunk/JSTests/stress/typed-array-change-by-copy.js	2022-04-12 17:54:56 UTC (rev 292778)
@@ -0,0 +1,107 @@
+//@ requireOptions("--useChangeArrayByCopyMethods=1")
+
+function shouldBe(actual, expected) {
+    if (!shallowEqual(actual, expected)){
+        throw new Error(`expected ${expected} but got ${actual}`);
+    }
+}
+
+function shouldThrow(func, errorType, message) {
+    let error;
+    try {
+        func();
+    } catch (e) {
+        error = e;
+    }
+
+    if (!(error instanceof errorType))
+        throw new Error(`Expected ${errorType.name}!`);
+    if (message !== undefined) {
+        if (Object.prototype.toString.call(message) === '[object RegExp]') {
+            if (!message.test(String(error)))
+                throw new Error(`expected '${String(error)}' to match ${message}!`);
+        } else {
+            if (String(error) !== message)
+                throw new Error(`expected ${String(error)} but got ${message}`);
+        }
+    }
+}
+
+function shallowEqual(a, b) {
+    if (a.length !== b.length)
+        return false;
+    for (let i = 0; i < a.length; i++) {
+        if (a[i] !== b[i])
+            return false;
+    }
+    return true;
+}
+
+var sequence = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+
+// TypedArray.prototype.toReversed()
+{
+    var reversedTypedArray = sequence.toReversed();
+    shouldBe(reversedTypedArray, [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
+}
+
+// TypedArray.prototype.toSorted()
+{
+    var unsortedTypedArray = new Uint8Array([9, 2, 3, 4, 56, 12, 0]);
+    let sortedTypedArray = unsortedTypedArray.toSorted();
+    shouldBe(sortedTypedArray, [0, 2, 3, 4, 9, 12, 56]);
+
+    // Non callable comparator.
+    var nonCallableComparator = "a";
+    shouldThrow(() => unsortedTypedArray.toSorted(nonCallableComparator), TypeError);
+}
+
+
+// TypedArray.prototype.toSpliced()
+{
+    var splicedTypedArray = sequence.toSpliced(3, 5);
+    shouldBe(splicedTypedArray, [1, 2, 3, 9, 10]);
+
+    // Start missing
+    splicedTypedArray = sequence.toSpliced();
+    shouldBe(splicedTypedArray, sequence);
+
+    // Delete count missing.
+    splicedTypedArray = sequence.toSpliced(3);
+    shouldBe(splicedTypedArray, [1, 2, 3]);
+
+    // Start undefined.
+    splicedTypedArray = sequence.toSpliced(undefined);
+    shouldBe(splicedTypedArray, []);
+
+    // Delete count undefined
+    splicedTypedArray = sequence.toSpliced(3, undefined);
+    shouldBe(splicedTypedArray, sequence);
+
+    // Insertion.
+    splicedTypedArray = sequence.toSpliced(3, 5, 11, 12, 13);
+    shouldBe(splicedTypedArray, [1, 2, 3, 11, 12, 13, 9, 10]);
+}
+
+// TypedArray.prototype.with()
+{
+    var withTypedArray = sequence.with(3, 0);
+    shouldBe(withTypedArray, [1, 2, 3, 0, 5, 6, 7, 8, 9, 10]);
+
+    // Index missing
+    withTypedArray = sequence.with();
+    shouldBe(withTypedArray, [0, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+
+    // Index undefined
+    withTypedArray = sequence.with(undefined, 0);
+    shouldBe(withTypedArray, [0, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+
+    // Invalid index.
+    shouldThrow(() => sequence.with(-11, 0), RangeError);
+
+    // Detached buffer.
+    transferArrayBuffer(sequence.buffer);
+    shouldThrow(() => sequence.with(0, 0), TypeError);
+}
+
+

Modified: trunk/JSTests/stress/unscopables.js (292777 => 292778)


--- trunk/JSTests/stress/unscopables.js	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/JSTests/stress/unscopables.js	2022-04-12 17:54:56 UTC (rev 292778)
@@ -1,4 +1,4 @@
-//@ requireOptions("--useAtMethod=1")
+//@ requireOptions("--useAtMethod=1", "--useChangeArrayByCopyMethods=1")
 
 function test(actual, expected) {
     if (actual !== expected)
@@ -11,7 +11,7 @@
 
     test(typeof unscopables, "object");
     test(unscopables.__proto__, undefined);
-    test(String(Object.keys(unscopables).sort()), "at,copyWithin,entries,fill,find,findIndex,findLast,findLastIndex,flat,flatMap,includes,keys,values");
+    test(String(Object.keys(unscopables).sort()), "at,copyWithin,entries,fill,find,findIndex,findLast,findLastIndex,flat,flatMap,includes,keys,toReversed,toSorted,toSpliced,values");
 }());
 
 (function () {

Modified: trunk/Source/_javascript_Core/ChangeLog (292777 => 292778)


--- trunk/Source/_javascript_Core/ChangeLog	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/Source/_javascript_Core/ChangeLog	2022-04-12 17:54:56 UTC (rev 292778)
@@ -1,3 +1,50 @@
+2022-04-12  Aditi Singh  <[email protected]>
+
+        Implement Change Array by copy proposal
+        https://bugs.webkit.org/show_bug.cgi?id=234604
+
+        Reviewed by Alexey Shvayka.
+
+        This patch implements proposal Change Array By Copy. The proposal provides additional 
+        methods on Array.prototype and TypedArray.prototype to enable changes on the array by 
+        returning a new copy of it with the change.
+        Since, a call to intrinsic functions: Array.prototype.sort(comparefn) and 
+        %TypedArray%.prototype.sort(comparefn) was needed, LinkTimeConstants have
+        been added for the same.
+        LinkTimeConstants were added instead of:
+        function sort(comparefn) { return @arraySort.@call(this, cmp); }
+        because this introduces an extra function call, which is slower.
+        %%TypedArray%%.prototype.sort(comparefn) and Array.prototype.sort(comparefn) are
+        implemented differently to avoid eager initialisation for TypedArrayPrototype
+        because it is quite large and not commonly used on the web. 
+        
+        The proposal details can be found here:
+        https://github.com/tc39/proposal-change-array-by-copy
+
+        * builtins/ArrayPrototype.js:
+        (toReversed):
+        (toSorted):
+        (toSpliced):
+        (with):
+        * builtins/BuiltinNames.h:
+        * builtins/TypedArrayPrototype.js:
+        (toReversed):
+        (toSorted):
+        (toSpliced):
+        (with):
+        (sort):
+        * bytecode/LinkTimeConstant.h:
+        * runtime/ArrayPrototype.cpp:
+        (JSC::ArrayPrototype::finishCreation):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildrenImpl):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::typedArrayProtoSort const):
+        * runtime/JSTypedArrayViewPrototype.cpp:
+        (JSC::JSTypedArrayViewPrototype::finishCreation):
+        * runtime/OptionsList.h:
+
 2022-04-12  Dmitry Bezhetskov  <[email protected]>
 
         [WASM-GC] Introduce structs types

Modified: trunk/Source/_javascript_Core/builtins/ArrayPrototype.js (292777 => 292778)


--- trunk/Source/_javascript_Core/builtins/ArrayPrototype.js	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/Source/_javascript_Core/builtins/ArrayPrototype.js	2022-04-12 17:54:56 UTC (rev 292778)
@@ -795,3 +795,159 @@
 
     return (k >= 0 && k < length) ? array[k] : @undefined;
 }
+
+function toReversed()
+{
+    "use strict";
+
+    // Step 1.
+    var array = @toObject(this, "Array.prototype.toReversed requires that |this| not be null or undefined");
+
+    // Step 2.
+    var length = @toLength(array.length);
+
+    // Step 3.
+    var result = @newArrayWithSize(length);
+
+    // Step 4-5.
+    for (var k = 0; k < length; k++) {
+        var fromValue = array[length - k - 1];
+        @putByValDirect(result, k, fromValue);
+    }
+
+    return result;
+}
+
+function toSorted(comparefn)
+{
+    "use strict";
+
+    // Step 1.
+    if (comparefn !== @undefined && !@isCallable(comparefn))
+        @throwTypeError("Array.prototype.toSorted requires the comparator argument to be a function or undefined");
+
+    // Step 2.
+    var array = @toObject(this, "Array.prototype.toSorted requires that |this| not be null or undefined");
+
+    // Step 3.
+    var length = @toLength(array.length);
+
+    // Step 4.
+    var result = @newArrayWithSize(length);
+
+    // Step 8.
+    for (var k = 0; k < length; k++)
+        @putByValDirect(result, k, array[k]);
+
+    // Step 6.
+    @arraySort.@call(result, comparefn);
+
+    return result;
+}
+
+function toSpliced(start, deleteCount /*, ...items */)
+{
+    "use strict"
+
+    // Step 1.
+    var array = @toObject(this, "Array.prototype.toSpliced requires that |this| not be null or undefined");
+
+    // Step 2.
+    var length = @toLength(array.length);
+
+    // Step 3.
+    var relativeStart = @toIntegerOrInfinity(start);
+
+    var actualStart;
+    // Step 4-6.
+    if (relativeStart === -@Infinity)
+        actualStart = 0;
+    else if (relativeStart < 0)
+        actualStart = length + relativeStart > 0 ? length + relativeStart : 0;
+    else
+        actualStart = @min(relativeStart, length);
+
+    // Step 7.
+    var insertCount = 0;
+    var actualDeleteCount;
+
+    // Step 8-10.
+    if (arguments.length === 0)
+        actualDeleteCount = 0;
+    else if (arguments.length === 1)
+        actualDeleteCount = length - actualStart;
+    else {
+        insertCount = arguments.length - 2;
+        var tempDeleteCount = @toIntegerOrInfinity(deleteCount);
+        tempDeleteCount = tempDeleteCount > 0 ? tempDeleteCount : 0;
+        actualDeleteCount = @min(tempDeleteCount, length - actualStart);
+    }
+
+    // Step 11.
+    var newLen = length + insertCount - actualDeleteCount;
+
+    // Step 12.
+    if (newLen >= @MAX_SAFE_INTEGER)
+        @throwTypeError("Array length exceeds 2**53 - 1");
+
+    // Step 13.
+    var result = @newArrayWithSize(newLen);
+
+    // Step 14.
+    var k = 0;
+
+    // Step 16.
+    for (; k < actualStart; k++)
+        @putByValDirect(result, k, array[k]);
+
+    // Step 17.
+    for (var i = 0; i < insertCount; i++, k++)
+        @putByValDirect(result, k, arguments[i + 2]);
+
+    // Step 18.
+    for (; k < newLen; k++) {
+        var from = k + actualDeleteCount - insertCount;
+        @putByValDirect(result, k, array[from]);
+    }
+
+    return result;
+
+}
+
+function with(index, value)
+{
+    "use strict";
+
+    // Step 1.
+    var array = @toObject(this, "Array.prototype.with requires that |this| not be null or undefined");
+
+    // Step 2.
+    var length = @toLength(array.length);
+
+    // Step 3.
+    var relativeIndex = @toIntegerOrInfinity(index);
+
+    // Step 4-5.
+    var actualIndex;
+    if (relativeIndex >= 0)
+        actualIndex = relativeIndex;
+    else
+        actualIndex = length + relativeIndex;
+
+    // Step 6.
+    if (actualIndex >= length || actualIndex < 0)
+        @throwRangeError("Array index out of Range");
+
+    // Step 7.
+    var result = @newArrayWithSize(length);
+
+    // Step 8-9
+    for (var k = 0; k < length; k++) {
+        if (k === actualIndex)
+            @putByValDirect(result, k, value);
+        else
+            @putByValDirect(result, k, array[k]);
+    }
+
+    return result;
+}

Modified: trunk/Source/_javascript_Core/builtins/BuiltinNames.h (292777 => 292778)


--- trunk/Source/_javascript_Core/builtins/BuiltinNames.h	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/Source/_javascript_Core/builtins/BuiltinNames.h	2022-04-12 17:54:56 UTC (rev 292778)
@@ -191,6 +191,7 @@
     macro(sentinelString) \
     macro(createRemoteFunction) \
     macro(isRemoteFunction) \
+    macro(arraySort) \
 
 
 namespace Symbols {

Modified: trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js (292777 => 292778)


--- trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js	2022-04-12 17:54:56 UTC (rev 292778)
@@ -226,6 +226,7 @@
     }
 }
 
+@globalPrivate
 function sort(comparator)
 {
     "use strict";
@@ -404,3 +405,150 @@
 
     return (k >= 0 && k < length) ? this[k] : @undefined;
 }
+
+function toReversed()
+{
+    "use strict";
+
+    // Step 2-3.
+    var length = @typedArrayLength(this);
+
+    // Step 4.
+    var constructor = @typedArrayGetOriginalConstructor(this);
+    var result = new constructor(length);
+
+    // Step 5-6.
+    for (var k = 0; k < length; k++) {
+        var fromValue = this[length - k - 1];
+        result[k] = fromValue;
+    }
+
+    return result;
+}
+
+function toSorted(comparefn)
+{
+    "use strict";
+
+    // Step 1.
+    if (comparefn !== @undefined && !@isCallable(comparefn))
+        @throwTypeError("TypedArray.prototype.toSorted requires the comparefn argument to be a function or undefined");
+
+    // Step 5.
+    var length = @typedArrayLength(this);
+
+    // Step 6.
+    var constructor = @typedArrayGetOriginalConstructor(this);
+    var result = new constructor(length);
+
+    // Step 11.
+    for (var k = 0; k < length; k++)
+        result[k] = this[k];
+
+    // Step 9.
+    @sort.@call(result, comparefn);
+
+    return result;
+}
+
+function toSpliced(start, deleteCount /*, ...items */)
+{
+    "use strict";
+
+    // Step 2-3.
+    var length = @typedArrayLength(this);
+
+    // Step 4.
+    var relativeStart = @toIntegerOrInfinity(start);
+
+    // Step 5-7.
+    var actualStart;
+    if (relativeStart === -@Infinity)
+        actualStart = 0;
+    else if (relativeStart < 0)
+        actualStart = length + relativeStart > 0 ? length + relativeStart : 0;
+    else
+        actualStart = @min(relativeStart, length);
+
+    // Step 8-11.
+    var insertCount = 0;
+    var actualDeleteCount;
+
+    if (arguments.length === 0)
+        actualDeleteCount = 0;
+    else if (arguments.length === 1)
+        actualDeleteCount = length - actualStart;
+    else {
+        insertCount = arguments.length - 2;
+        var tempDeleteCount = @toIntegerOrInfinity(deleteCount);
+        tempDeleteCount = tempDeleteCount > 0 ? tempDeleteCount : 0;
+        actualDeleteCount = @min(tempDeleteCount, length - actualStart);
+    }
+
+    // Step 12.
+    var newLen = length + insertCount - actualDeleteCount;
+
+    // Step 13.
+    var constructor = @typedArrayGetOriginalConstructor(this);
+    var result = new constructor(newLen);
+
+    // Step 14.
+    var k = 0;
+
+    // Step 16.
+    for (; k < actualStart; k++) {
+        result[k] = this[k];
+    }
+
+    // Step 17.
+    for (var i = 0; i < insertCount; i++) {
+        result[k] = arguments[i + 2];
+        k++;
+    }
+
+    // Step 18.
+    for (; k < newLen; k++) {
+        var from = k + actualDeleteCount - insertCount;
+        result[k] = this[from];
+    }
+
+    return result;
+}
+
+function with(index, value)
+{
+    "use strict";
+
+    // Step 2-3.
+    var length = @typedArrayLength(this);
+
+    // Step 4.
+    var relativeIndex = @toIntegerOrInfinity(index);
+    var actualIndex;
+
+    // Step 5-6.
+    if (relativeIndex >= 0)
+        actualIndex = relativeIndex;
+    else
+        actualIndex = length + relativeIndex;
+
+    // Step 7.
+    if (@isDetached(this))
+        @throwRangeError("TypedArray.prototype.with called on an detached array");
+    if (actualIndex < 0 || actualIndex >= length)
+        @throwRangeError("Array index out of range")
+
+    // Step 8.
+    var constructor = @typedArrayGetOriginalConstructor(this);
+    var result = new constructor(length);
+
+    // Step 9-10.
+    for (var k = 0; k < length; k++) {
+        if (k == actualIndex)
+            result[k] = value;
+        else
+            result[k] = this[k];
+    }
+
+    return result;
+}

Modified: trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h (292777 => 292778)


--- trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h	2022-04-12 17:54:56 UTC (rev 292778)
@@ -119,6 +119,7 @@
     v(sentinelString, nullptr) \
     v(createRemoteFunction, nullptr) \
     v(isRemoteFunction, nullptr) \
+    v(arraySort, nullptr) \
 
 
 #define DECLARE_LINK_TIME_CONSTANT(name, code) name,

Modified: trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp (292777 => 292778)


--- trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2022-04-12 17:54:56 UTC (rev 292778)
@@ -122,7 +122,12 @@
 
     if (Options::useAtMethod())
         JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().atPublicName(), arrayPrototypeAtCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
-
+    if (Options::useChangeArrayByCopyMethods()) {
+        JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().toReversedPublicName(), arrayPrototypeToReversedCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
+        JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().toSortedPublicName(), arrayPrototypeToSortedCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
+        JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().toSplicedPublicName(), arrayPrototypeToSplicedCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
+        JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().withPublicName(), arrayPrototypeWithCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
+    }
     putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().entriesPrivateName(), getDirect(vm, vm.propertyNames->builtinNames().entriesPublicName()), static_cast<unsigned>(PropertyAttribute::ReadOnly));
     putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().forEachPrivateName(), getDirect(vm, vm.propertyNames->builtinNames().forEachPublicName()), static_cast<unsigned>(PropertyAttribute::ReadOnly));
     putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().keysPrivateName(), getDirect(vm, vm.propertyNames->builtinNames().keysPublicName()), static_cast<unsigned>(PropertyAttribute::ReadOnly));
@@ -145,6 +150,9 @@
         Options::useArrayGroupByMethod() ? &vm.propertyNames->builtinNames().groupByToMapPublicName() : nullptr,
         &vm.propertyNames->builtinNames().includesPublicName(),
         &vm.propertyNames->builtinNames().keysPublicName(),
+        Options::useChangeArrayByCopyMethods() ? &vm.propertyNames->builtinNames().toReversedPublicName() : nullptr,
+        Options::useChangeArrayByCopyMethods() ? &vm.propertyNames->builtinNames().toSortedPublicName() : nullptr,
+        Options::useChangeArrayByCopyMethods() ? &vm.propertyNames->builtinNames().toSplicedPublicName() : nullptr,
         &vm.propertyNames->builtinNames().valuesPublicName()
     };
     for (const auto* unscopableName : unscopableNames) {

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (292777 => 292778)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2022-04-12 17:54:56 UTC (rev 292778)
@@ -809,6 +809,11 @@
             init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 1, init.vm.propertyNames->toString.string(), numberProtoFuncToString, NumberPrototypeToStringIntrinsic));
         });
 
+    m_typedArrayProtoSort.initLater(
+        [] (const Initializer<JSFunction>& init) {
+            init.set(JSFunction::create(init.vm, typedArrayPrototypeSortCodeGenerator(init.vm), init.owner));
+        });
+
     m_functionProtoHasInstanceSymbolFunction.set(vm, this, hasInstanceSymbolFunction);
 
     m_nullGetterFunction.set(vm, this, NullGetterFunction::create(vm, NullGetterFunction::createStructure(vm, this, m_functionPrototype.get())));
@@ -1344,6 +1349,10 @@
         RELEASE_ASSERT(!!jsDynamicCast<JSFunction*>(vm, hasOwnPropertyFunction));
         m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::hasOwnPropertyFunction)].set(vm, this, jsCast<JSFunction*>(hasOwnPropertyFunction));
     }
+    {
+        JSFunction* arraySort = jsCast<JSFunction*>(arrayPrototype()->getDirect(vm, vm.propertyNames->builtinNames().sortPublicName()));
+        m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::arraySort)].set(vm, this, jsCast<JSFunction*>(arraySort));
+    }
 
 #define INIT_PRIVATE_GLOBAL(funcName, code) \
     m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::funcName)].initLater([] (const Initializer<JSCell>& init) { \
@@ -2227,6 +2236,7 @@
     visitor.append(thisObject->m_regExpProtoSymbolReplace);
     thisObject->m_throwTypeErrorArgumentsCalleeGetterSetter.visit(visitor);
     thisObject->m_moduleLoader.visit(visitor);
+    thisObject->m_typedArrayProtoSort.visit(visitor);
 
     visitor.append(thisObject->m_objectPrototype);
     visitor.append(thisObject->m_functionPrototype);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (292777 => 292778)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2022-04-12 17:54:56 UTC (rev 292778)
@@ -356,6 +356,7 @@
     LazyProperty<JSGlobalObject, JSFunction> m_iteratorProtocolFunction;
     LazyProperty<JSGlobalObject, JSFunction> m_promiseResolveFunction;
     LazyProperty<JSGlobalObject, JSFunction> m_numberProtoToStringFunction;
+    LazyProperty<JSGlobalObject, JSFunction> m_typedArrayProtoSort;
     WriteBarrier<JSFunction> m_objectProtoValueOfFunction;
     WriteBarrier<JSFunction> m_functionProtoHasInstanceSymbolFunction;
     WriteBarrier<JSObject> m_regExpProtoSymbolReplace;
@@ -725,6 +726,7 @@
     JSFunction* numberProtoToStringFunction() const { return m_numberProtoToStringFunction.getInitializedOnMainThread(this); }
     JSFunction* functionProtoHasInstanceSymbolFunction() const { return m_functionProtoHasInstanceSymbolFunction.get(); }
     JSFunction* regExpProtoExecFunction() const;
+    JSFunction* typedArrayProtoSort() const { return m_typedArrayProtoSort.get(this); }
     JSObject* regExpProtoSymbolReplaceFunction() const { return m_regExpProtoSymbolReplace.get(); }
     GetterSetter* regExpProtoGlobalGetter() const;
     GetterSetter* regExpProtoUnicodeGetter() const;

Modified: trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.cpp (292777 => 292778)


--- trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.cpp	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.cpp	2022-04-12 17:54:56 UTC (rev 292778)
@@ -441,6 +441,7 @@
     ASSERT(inherits(vm, info()));
 
     putDirectWithoutTransition(vm, vm.propertyNames->toString, globalObject->arrayProtoToStringFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum));
+    putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().sortPublicName(), globalObject->typedArrayProtoSort(), static_cast<unsigned>(PropertyAttribute::DontEnum));
 
     JSC_NATIVE_GETTER_WITHOUT_TRANSITION("buffer"_s, typedArrayViewProtoGetterFuncBuffer, PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
     JSC_NATIVE_INTRINSIC_GETTER_WITHOUT_TRANSITION(vm.propertyNames->byteLength, typedArrayViewProtoGetterFuncByteLength, PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly, TypedArrayByteLengthIntrinsic);
@@ -448,7 +449,6 @@
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("copyWithin"_s, typedArrayViewProtoFuncCopyWithin, static_cast<unsigned>(PropertyAttribute::DontEnum), 2);
     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("every"_s, typedArrayPrototypeEveryCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("filter"_s, typedArrayPrototypeFilterCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
-    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("sort"_s, typedArrayPrototypeSortCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().entriesPublicName(), typedArrayProtoViewFuncEntries, static_cast<unsigned>(PropertyAttribute::DontEnum), 0, TypedArrayEntriesIntrinsic);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("includes"_s, typedArrayViewProtoFuncIncludes, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().fillPublicName(), typedArrayViewProtoFuncFill, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
@@ -474,6 +474,12 @@
     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->subarray, typedArrayPrototypeSubarrayCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, typedArrayPrototypeToLocaleStringCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
 
+    if (Options::useChangeArrayByCopyMethods()) {
+        JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toReversed"_s, typedArrayPrototypeToReversedCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
+        JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toSorted"_s, typedArrayPrototypeToSortedCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
+        JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toSpliced"_s, typedArrayPrototypeToSplicedCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
+        JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("with"_s, typedArrayPrototypeWithCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
+    }
     if (Options::useAtMethod())
         JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().atPublicName(), typedArrayPrototypeAtCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
 

Modified: trunk/Source/_javascript_Core/runtime/OptionsList.h (292777 => 292778)


--- trunk/Source/_javascript_Core/runtime/OptionsList.h	2022-04-12 17:44:42 UTC (rev 292777)
+++ trunk/Source/_javascript_Core/runtime/OptionsList.h	2022-04-12 17:54:56 UTC (rev 292778)
@@ -540,6 +540,7 @@
     v(Bool, useArrayFindLastMethod, true, Normal, "Expose the findLast() and findLastIndex() methods on Array and %TypedArray%.") \
     v(Bool, useArrayGroupByMethod, false, Normal, "Expose the groupBy() and groupByToMap() methods on Array.") \
     v(Bool, useAtMethod, true, Normal, "Expose the at() method on Array, %TypedArray%, and String.") \
+    v(Bool, useChangeArrayByCopyMethods, false, Normal, "Expose the withAt(), withReversed(), withSorted() and withSpliced() methods on Array and %TypedArray%.") \
     v(Bool, useHasOwn, true, Normal, "Expose the Object.hasOwn method") \
     v(Bool, useImportAssertion, false, Normal, "Enable import assertion.") \
     v(Bool, useIntlEnumeration, true, Normal, "Expose the Intl enumeration APIs.") \
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to