Skip to content
Permalink
Browse files
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]: Jarred-Sumner@b06577c

* JSTests/microbenchmarks/typed-array-fill.js: Added.
* JSTests/stress/typed-array-fill-complicated.js: Added.
(shouldBe):
(throw.new.Error):
* Source/JavaScriptCore/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
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@294047 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
Constellation committed May 11, 2022
1 parent 5562d2a commit 38f99b1251a27027b3eeea66ae7ae4a57b4144f2
@@ -1,3 +1,15 @@
2022-05-09 Yusuke Suzuki <ysuzuki@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.kirsling@sony.com>

Temporal round and total methods should accept string param
@@ -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);
}
@@ -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);
}
@@ -1,3 +1,33 @@
2022-05-09 Yusuke Suzuki <ysuzuki@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.lam@apple.com>

Add optional Integrity checks at JSC API boundaries.
@@ -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 @@ inline JSArrayBufferView* speciesConstruct(JSGlobalObject* globalObject, JSObjec
return nullptr;
}

if (!view->isDetached())
if (LIKELY(!view->isDetached()))
return view;

throwTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
@@ -156,7 +184,7 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncCopyWithin(VM& vm, JS

// 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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncCopyWithin(VM& vm, JS
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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncIncludes(VM& vm, JSGl
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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncIncludes(VM& vm, JSGl
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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncIndexOf(VM& vm, JSGlo

// 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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncIndexOf(VM& vm, JSGlo
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,14 +299,14 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncJoin(VM& vm, JSGlobal
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 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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncFill(VM& vm, JSGlobal
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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncLastIndexOf(VM& vm, J

// 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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncLastIndexOf(VM& vm, J
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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncReverse(VM& vm, JSGlo

// 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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewPrivateFuncSort(VM& vm, JSGlob

// 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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncSlice(VM& vm, JSGloba
// 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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncSlice(VM& vm, JSGloba
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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewProtoFuncSlice(VM& vm, JSGloba
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 @@ ALWAYS_INLINE EncodedJSValue genericTypedArrayViewPrivateFuncSubarrayCreate(VM&
// 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.

0 comments on commit 38f99b1

Please sign in to comment.