Commit d022b74c authored by Arno Renevier's avatar Arno Renevier Committed by Commit Bot

[builtins] Use fast path for JSArray source in TypedArray.from()

For TypedArray, a fast path is used when using the builtin iterator, and
next method has not been overriden. If we use that fast path for JSArray
too, the method will be about 200x times faster on a large array.

This patch also fixes a bug when a typed array is modified during the
mapper execution. In that case, the modification should not be taken
into account.

Bug: v8:10802

Change-Id: I74e2cbcd6a654def318585b4e08745037584669a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2358749
Commit-Queue: Arnaud Renevier <arenevier@fb.com>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69655}
parent 463ccd0e
......@@ -10,6 +10,8 @@ const kBuiltinNameFrom: constexpr string = '%TypedArray%.from';
type BuiltinsName extends int31 constexpr 'Builtins::Name';
const kTypedArrayPrototypeValues: constexpr BuiltinsName
generates 'Builtins::kTypedArrayPrototypeValues';
const kArrayPrototypeValues: constexpr BuiltinsName
generates 'Builtins::kArrayPrototypeValues';
extern builtin IterableToList(implicit context: Context)(JSAny, JSAny): JSArray;
......@@ -56,9 +58,9 @@ TypedArrayFrom(js-implicit context: NativeContext, receiver: JSAny)(
otherwise IteratorIsUndefined, IteratorNotCallable;
try {
// TypedArrays have iterators, so normally we would go through the
// IterableToList case below, which would convert the TypedArray to a
// JSArray (boxing the values if they won't fit in a Smi).
// TypedArrays and JSArrays have iterators, so normally we would go
// through the IterableToList case below, which would convert the
// source to a JSArray (boxing the values if they won't fit in a Smi).
//
// However, if we can guarantee that the source object has the
// built-in iterator and that the %ArrayIteratorPrototype%.next method
......@@ -73,29 +75,55 @@ TypedArrayFrom(js-implicit context: NativeContext, receiver: JSAny)(
//
// Drop through to the default check_iterator behavior if any of these
// checks fail.
const sourceTypedArray =
Cast<JSTypedArray>(source) otherwise UseUserProvidedIterator;
const sourceBuffer = sourceTypedArray.buffer;
if (IsDetachedBuffer(sourceBuffer)) goto UseUserProvidedIterator;
// Check that the iterator function is exactly
// Builtins::kTypedArrayPrototypeValues.
// If there is a mapping, we need to gather the values from the
// iterables before applying the mapping.
if (mapping) goto UseUserProvidedIterator;
const iteratorFn =
Cast<JSFunction>(usingIterator) otherwise UseUserProvidedIterator;
if (!TaggedEqual(
iteratorFn.shared_function_info.function_data,
SmiConstant(kTypedArrayPrototypeValues)))
goto UseUserProvidedIterator;
// Check that the ArrayIterator prototype's "next" method hasn't been
// overridden.
if (IsArrayIteratorProtectorCellInvalid()) goto UseUserProvidedIterator;
// Source is a TypedArray with unmodified iterator behavior. Use the
// source object directly, taking advantage of the special-case code
// in TypedArrayCopyElements
finalLength = sourceTypedArray.length;
finalSource = source;
typeswitch (source) {
case (sourceArray: JSArray): {
// Check that the iterator function is exactly
// Builtins::kArrayPrototypeValues.
if (!TaggedEqual(
iteratorFn.shared_function_info.function_data,
SmiConstant(kArrayPrototypeValues))) {
goto UseUserProvidedIterator;
}
// Source is a JSArray with unmodified iterator behavior. Use the
// source object directly, taking advantage of the special-case code
// in TypedArrayCopyElements
finalLength = Convert<uintptr>(sourceArray.length);
finalSource = source;
}
case (sourceTypedArray: JSTypedArray): {
const sourceBuffer = sourceTypedArray.buffer;
if (IsDetachedBuffer(sourceBuffer)) goto UseUserProvidedIterator;
// Check that the iterator function is exactly
// Builtins::kTypedArrayPrototypeValues.
if (!TaggedEqual(
iteratorFn.shared_function_info.function_data,
SmiConstant(kTypedArrayPrototypeValues)))
goto UseUserProvidedIterator;
// Source is a TypedArray with unmodified iterator behavior. Use the
// source object directly, taking advantage of the special-case code
// in TypedArrayCopyElements
finalLength = sourceTypedArray.length;
finalSource = source;
}
case (Object): {
goto UseUserProvidedIterator;
}
}
} label UseUserProvidedIterator {
// 6. If usingIterator is not undefined, then
// a. Let values be ? IterableToList(source, usingIterator).
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const arr = new Uint8Array([1, 2, 3]);
function mapper(x) {
arr[1] = 182;
return x + 1;
}
assertArrayEquals([2, 3, 4], Uint16Array.from(arr, mapper));
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