Commit 11a1ac4b authored by Jakob Kummerow's avatar Jakob Kummerow Committed by V8 LUCI CQ

Faster TypedArray.fill(0) and .fill(-1)

Calling memset directly is faster than std::fill for multi-byte element
types.

Change-Id: I83b997740146688f87b86901825e31d6644bc25b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3687700
Auto-Submit: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80945}
parent 90804935
......@@ -3306,22 +3306,32 @@ class TypedElementsAccessor
DisallowGarbageCollection no_gc;
ElementType scalar = FromHandle(value);
ElementType* data = static_cast<ElementType*>(typed_array->DataPtr());
ElementType* first = data + start;
ElementType* last = data + end;
if (typed_array->buffer().is_shared()) {
// TypedArrays backed by shared buffers need to be filled using atomic
// operations. Since 8-byte data are not currently always 8-byte aligned,
// manually fill using SetImpl, which abstracts over alignment and atomic
// complexities.
ElementType* first = data + start;
ElementType* last = data + end;
for (; first != last; ++first) {
AccessorClass::SetImpl(first, scalar, kShared);
}
} else if ((scalar == 0 && !(std::is_floating_point_v<ElementType> &&
IsMinusZero(scalar))) ||
(std::is_integral_v<ElementType> &&
scalar == static_cast<ElementType>(-1))) {
// As of 2022-06, this is faster than {std::fill}.
// We could extend this to any {scalar} that's a pattern of repeating
// bytes, but patterns other than 0 and -1 are probably rare.
size_t num_bytes = static_cast<size_t>(reinterpret_cast<int8_t*>(last) -
reinterpret_cast<int8_t*>(first));
memset(first, static_cast<int8_t>(scalar), num_bytes);
} else if (COMPRESS_POINTERS_BOOL && alignof(ElementType) > kTaggedSize) {
// TODO(ishell, v8:8875): See UnalignedSlot<T> for details.
std::fill(UnalignedSlot<ElementType>(data + start),
UnalignedSlot<ElementType>(data + end), scalar);
std::fill(UnalignedSlot<ElementType>(first),
UnalignedSlot<ElementType>(last), scalar);
} else {
std::fill(data + start, data + end, scalar);
std::fill(first, last, scalar);
}
return MaybeHandle<Object>(typed_array);
}
......
......@@ -81,7 +81,18 @@ for (var constructor of typedArrayConstructors) {
var array = new constructor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
%ArrayBufferDetach(array.buffer);
assertThrows(() => array.fill(tmp), TypeError);
// Exercise fast paths.
assertArrayEquals([0, 0, 0, 0], new constructor(4).fill(0));
}
var signed = [Int8Array, Int16Array, Int32Array, Float32Array, Float64Array];
for (var constructor of signed) {
assertArrayEquals([-1, -1, -1, -1], new constructor(4).fill(-1));
}
assertArrayEquals([0xFF, 0xFF, 0xFF], new Uint8Array(3).fill(-1));
assertArrayEquals([0xFFFF, 0xFFFF, 0xFFFF], new Uint16Array(3).fill(-1));
assertArrayEquals([0xFFFF_FFFF, 0xFFFF_FFFF], new Uint32Array(2).fill(-1));
for (var constructor of intArrayConstructors) {
assertArrayEquals([0, 0, 0, 0, 0], new constructor([0, 0, 0, 0, 0]).fill(undefined));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment