Title: [294047] trunk
Revision
294047
Author
ysuz...@apple.com
Date
2022-05-10 18:00:50 -0700 (Tue, 10 May 2022)

Log Message

Upstream TypedArray.prototype.fill speedup from bun
https://bugs.webkit.org/show_bug.cgi?id=239891

Reviewed by Saam Barati.

This patch imports bun's improvement in TypedArray#fill[1], bun is MIT licensed.
We use memset and its variant to fill TypedArray if possible.
Microbenchmarks show 5x improvement.

                                 ToT                     Patched

    typed-array-fill     1092.0348+-6.2496     ^    221.3430+-9.1261        ^ definitely 4.9337x faster

[1]: https://github.com/Jarred-Sumner/WebKit/commit/b06577c1f1de19d2ef3d4a87d14ea41909ddf5fc

* JSTests/microbenchmarks/typed-array-fill.js: Added.
* JSTests/stress/typed-array-fill-complicated.js: Added.
(shouldBe):
(throw.new.Error):
* Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
(JSC::speciesConstruct):
(JSC::genericTypedArrayViewProtoFuncCopyWithin):
(JSC::genericTypedArrayViewProtoFuncIncludes):
(JSC::genericTypedArrayViewProtoFuncIndexOf):
(JSC::genericTypedArrayViewProtoFuncJoin):
(JSC::genericTypedArrayViewProtoFuncFill):
(JSC::genericTypedArrayViewProtoFuncLastIndexOf):
(JSC::genericTypedArrayViewProtoFuncReverse):
(JSC::genericTypedArrayViewPrivateFuncSort):
(JSC::genericTypedArrayViewProtoFuncSlice):
(JSC::genericTypedArrayViewPrivateFuncSubarrayCreate):

Canonical link: https://commits.webkit.org/250455@main

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (294046 => 294047)


--- trunk/JSTests/ChangeLog	2022-05-11 00:53:30 UTC (rev 294046)
+++ trunk/JSTests/ChangeLog	2022-05-11 01:00:50 UTC (rev 294047)
@@ -1,3 +1,15 @@
+2022-05-09  Yusuke Suzuki  <ysuz...@apple.com>
+
+        Upstream TypedArray.prototype.fill speedup from bun
+        https://bugs.webkit.org/show_bug.cgi?id=239891
+
+        Reviewed by Saam Barati.
+
+        * microbenchmarks/typed-array-fill.js: Added.
+        * stress/typed-array-fill-complicated.js: Added.
+        (shouldBe):
+        (throw.new.Error):
+
 2022-05-09  Ross Kirsling  <ross.kirsl...@sony.com>
 
         Temporal round and total methods should accept string param

Added: trunk/JSTests/microbenchmarks/typed-array-fill.js (0 => 294047)


--- trunk/JSTests/microbenchmarks/typed-array-fill.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/typed-array-fill.js	2022-05-11 01:00:50 UTC (rev 294047)
@@ -0,0 +1,11 @@
+var a1 = new Uint8Array(1024 * 1024 * 1);
+var a2 = new Uint16Array(1024 * 1024 * 1);
+var a3 = new Uint32Array(1024 * 1024 * 1);
+var a4 = new Float64Array(1024 * 1024 * 1);
+
+for (var i = 0; i < 3e2; ++i) {
+    a1.fill(99);
+    a2.fill(99);
+    a3.fill(99);
+    a4.fill(99);
+}

Added: trunk/JSTests/stress/typed-array-fill-complicated.js (0 => 294047)


--- trunk/JSTests/stress/typed-array-fill-complicated.js	                        (rev 0)
+++ trunk/JSTests/stress/typed-array-fill-complicated.js	2022-05-11 01:00:50 UTC (rev 294047)
@@ -0,0 +1,22 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+{
+    let a0 = new Uint8Array(100);
+    shouldBe(a0[3], 0);
+    shouldBe(a0[4], 0);
+    a0.fill(42, 3, 4);
+    shouldBe(a0[3], 42);
+    shouldBe(a0[4], 0);
+}
+{
+    let a0 = new Uint8Array(4);
+    shouldBe(a0[0], 0);
+    a0.fill(42, 0, 0);
+    shouldBe(a0[0], 0);
+    a0.fill(42, 3, 0);
+    for (let i = 0; i < 4; ++i)
+        shouldBe(a0[i], 0);
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (294046 => 294047)


--- trunk/Source/_javascript_Core/ChangeLog	2022-05-11 00:53:30 UTC (rev 294046)
+++ trunk/Source/_javascript_Core/ChangeLog	2022-05-11 01:00:50 UTC (rev 294047)
@@ -1,3 +1,33 @@
+2022-05-09  Yusuke Suzuki  <ysuz...@apple.com>
+
+        Upstream TypedArray.prototype.fill speedup from bun
+        https://bugs.webkit.org/show_bug.cgi?id=239891
+
+        Reviewed by Saam Barati.
+
+        This patch imports bun's improvement in TypedArray#fill[1], bun is MIT licensed.
+        We use memset and its variant to fill TypedArray if possible.
+        Microbenchmarks show 5x improvement.
+
+                                         ToT                     Patched
+
+            typed-array-fill     1092.0348+-6.2496     ^    221.3430+-9.1261        ^ definitely 4.9337x faster
+
+        [1]: https://github.com/Jarred-Sumner/WebKit/commit/b06577c1f1de19d2ef3d4a87d14ea41909ddf5fc
+
+        * runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
+        (JSC::speciesConstruct):
+        (JSC::genericTypedArrayViewProtoFuncCopyWithin):
+        (JSC::genericTypedArrayViewProtoFuncIncludes):
+        (JSC::genericTypedArrayViewProtoFuncIndexOf):
+        (JSC::genericTypedArrayViewProtoFuncJoin):
+        (JSC::genericTypedArrayViewProtoFuncFill):
+        (JSC::genericTypedArrayViewProtoFuncLastIndexOf):
+        (JSC::genericTypedArrayViewProtoFuncReverse):
+        (JSC::genericTypedArrayViewPrivateFuncSort):
+        (JSC::genericTypedArrayViewProtoFuncSlice):
+        (JSC::genericTypedArrayViewPrivateFuncSubarrayCreate):
+
 2022-05-10  Mark Lam  <mark....@apple.com>
 
         Add optional Integrity checks at JSC API boundaries.

Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h (294046 => 294047)


--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h	2022-05-11 00:53:30 UTC (rev 294046)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h	2022-05-11 01:00:50 UTC (rev 294047)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2021 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -22,6 +22,30 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+/*
+ * Part of TypedArray#fill code derived from bun, MIT licensed.
+ * https://github.com/Jarred-Sumner/bun-releases-for-updater
+ *
+ * Copyright (C) 2022 Jarred Sumner. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+*/
 
 #pragma once
 
@@ -38,6 +62,10 @@
 #include "TypedArrayController.h"
 #include <wtf/StdLibExtras.h>
 
+#if OS(DARWIN)
+#include <strings.h>
+#endif
+
 namespace JSC {
 
 // This implements 22.2.4.7 TypedArraySpeciesCreate
@@ -75,7 +103,7 @@
             return nullptr;
         }
 
-        if (!view->isDetached())
+        if (LIKELY(!view->isDetached()))
             return view;
 
         throwTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
@@ -156,7 +184,7 @@
 
     // 22.2.3.5
     ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     size_t length = thisObject->length();
@@ -174,7 +202,7 @@
     ASSERT(from <= length);
     size_t count = std::min(length - std::max(to, from), final - from);
 
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     typename ViewClass::ElementType* array = thisObject->typedVector();
@@ -189,7 +217,7 @@
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     size_t length = thisObject->length();
@@ -202,7 +230,7 @@
     size_t index = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(1), length);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return JSValue::encode(jsBoolean(valueToFind.isUndefined()));
 
     typename ViewClass::ElementType* array = thisObject->typedVector();
@@ -235,7 +263,7 @@
 
     // 22.2.3.13
     ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     size_t length = thisObject->length();
@@ -247,7 +275,7 @@
     size_t index = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(1), length);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return JSValue::encode(jsNumber(-1));
 
     typename ViewClass::ElementType* array = thisObject->typedVector();
@@ -271,7 +299,7 @@
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     size_t length = thisObject->length();
@@ -278,7 +306,7 @@
     auto joinWithSeparator = [&] (StringView separator) -> EncodedJSValue {
         JSStringJoiner joiner(globalObject, separator, length);
         RETURN_IF_EXCEPTION(scope, { });
-        if (!thisObject->isDetached()) {
+        if (LIKELY(!thisObject->isDetached())) {
             for (size_t i = 0; i < length; i++) {
                 JSValue value;
                 if constexpr (ViewClass::Adaptor::canConvertToJSQuickly)
@@ -319,24 +347,52 @@
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     size_t length = thisObject->length();
-    auto nativeValue = ViewClass::toAdaptorNativeFromValue(globalObject, callFrame->argument(0));
+    typename ViewClass::ElementType nativeValue = ViewClass::toAdaptorNativeFromValue(globalObject, callFrame->argument(0));
     RETURN_IF_EXCEPTION(scope, { });
 
     size_t start = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(1), length, 0);
     RETURN_IF_EXCEPTION(scope, { });
+    ASSERT(start <= length);
+
     size_t end = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(2), length, length);
     RETURN_IF_EXCEPTION(scope, { });
+    ASSERT(end <= length);
 
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
-    for (size_t index = start; index < end; ++index)
-        thisObject->setIndexQuicklyToNativeValue(index, nativeValue);
+    if (!(start < end))
+        return JSValue::encode(thisObject);
 
+    size_t count = end - start;
+    typename ViewClass::ElementType* underlyingVector = thisObject->typedVector();
+    ASSERT(count <= length);
+
+#if OS(DARWIN)
+    if constexpr (ViewClass::elementSize == 8) {
+        static_assert(sizeof(decltype(nativeValue)) == 8);
+        memset_pattern8(underlyingVector + start, &nativeValue, count * ViewClass::elementSize);
+        return JSValue::encode(thisObject);
+    }
+
+    if constexpr (ViewClass::elementSize == 4) {
+        static_assert(sizeof(decltype(nativeValue)) == 4);
+        memset_pattern4(underlyingVector + start, &nativeValue, count * ViewClass::elementSize);
+        return JSValue::encode(thisObject);
+    }
+#endif
+
+    if constexpr (ViewClass::elementSize == 1) {
+        static_assert(sizeof(decltype(nativeValue)) == 1);
+        memset(underlyingVector + start, nativeValue, count * ViewClass::elementSize);
+        return JSValue::encode(thisObject);
+    }
+
+    std::fill(underlyingVector + start, underlyingVector + end, nativeValue);
     return JSValue::encode(thisObject);
 }
 
@@ -347,7 +403,7 @@
 
     // 22.2.3.16
     ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     size_t length = thisObject->length();
@@ -371,7 +427,7 @@
             index = static_cast<size_t>(fromDouble);
     }
 
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return JSValue::encode(jsNumber(-1));
 
     auto targetOption = ViewClass::toAdaptorNativeFromValueWithoutCoercion(valueToFind);
@@ -437,7 +493,7 @@
 
     // 22.2.3.21
     ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     typename ViewClass::ElementType* array = thisObject->typedVector();
@@ -453,7 +509,7 @@
 
     // 22.2.3.25
     ViewClass* thisObject = jsCast<ViewClass*>(callFrame->argument(0));
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     thisObject->sort();
@@ -469,7 +525,7 @@
     // 22.2.3.26
 
     ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     size_t thisLength = thisObject->length();
@@ -479,7 +535,7 @@
     size_t end = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(1), thisLength, thisLength);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     // Clamp end to begin.
@@ -508,7 +564,7 @@
     if (!length)
         return JSValue::encode(result);
 
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     // The species constructor may return an array with any arbitrary length.
@@ -574,7 +630,7 @@
     // 22.2.3.23
 
     ViewClass* thisObject = jsCast<ViewClass*>(callFrame->thisValue());
-    if (thisObject->isDetached())
+    if (UNLIKELY(thisObject->isDetached()))
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
     // Get the length here; later assert that the length didn't change.
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to