[builtin] Fast paths for Array.concat

- Initial implementation of Array.concat on Torque.
- Adds fast paths for `[].concat()` and `x.concat()`, these are now
  as fast as `[...x]` and `x.slice()` for non-optimised code.

Bug: v8:7152
Change-Id: I86ca15e4e1e67f53424ef0c8bb7eea12d7e660b3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3026716
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75737}
This commit is contained in:
Victor Gomes 2021-07-15 11:53:20 +02:00 committed by V8 LUCI CQ
parent 5a4f8a08e8
commit 6ca1f677de
10 changed files with 78 additions and 2 deletions

View File

@ -610,6 +610,7 @@ filegroup(
srcs = [
"src/builtins/aggregate-error.tq",
"src/builtins/array-at.tq",
"src/builtins/array-concat.tq",
"src/builtins/array-copywithin.tq",
"src/builtins/array-every.tq",
"src/builtins/array-filter.tq",

View File

@ -1396,6 +1396,7 @@ action("postmortem-metadata") {
torque_files = [
"src/builtins/aggregate-error.tq",
"src/builtins/array-at.tq",
"src/builtins/array-concat.tq",
"src/builtins/array-copywithin.tq",
"src/builtins/array-every.tq",
"src/builtins/array-filter.tq",

View File

@ -0,0 +1,49 @@
// Copyright 2021 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.
namespace array {
extern builtin ArrayConcat(Context, JSFunction, JSAny, int32): JSAny;
transitioning javascript builtin
ArrayPrototypeConcat(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
// Fast path if we invoke as `x.concat()`.
if (arguments.length == 0) {
typeswitch (receiver) {
case (a: FastJSArrayForCopy): {
return CloneFastJSArray(context, a);
}
case (JSAny): {
// Fallthrough.
}
}
}
// Fast path if we invoke as `[].concat(x)`.
try {
const receiverAsArray: FastJSArrayForConcat =
Cast<FastJSArrayForConcat>(receiver)
otherwise ReceiverIsNotFastJSArrayForConcat;
if (receiverAsArray.IsEmpty() && arguments.length == 1) {
typeswitch (arguments[0]) {
case (a: FastJSArrayForCopy): {
return CloneFastJSArray(context, a);
}
case (JSAny): {
// Fallthrough.
}
}
}
} label ReceiverIsNotFastJSArrayForConcat {
// Fallthrough.
}
// TODO(victorgomes): Implement slow path ArrayConcat in Torque.
tail ArrayConcat(
context, LoadTargetFromFrame(), Undefined,
Convert<int32>(arguments.length));
}
} // namespace array

View File

@ -1198,6 +1198,7 @@ extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map):
extern macro IsNoElementsProtectorCellInvalid(): bool;
extern macro IsArrayIteratorProtectorCellInvalid(): bool;
extern macro IsArraySpeciesProtectorCellInvalid(): bool;
extern macro IsIsConcatSpreadableProtectorCellInvalid(): bool;
extern macro IsTypedArraySpeciesProtectorCellInvalid(): bool;
extern macro IsPromiseSpeciesProtectorCellInvalid(): bool;
extern macro IsMockArrayBufferAllocatorFlag(): bool;

View File

@ -551,6 +551,15 @@ Cast<FastJSArrayForCopy>(implicit context: Context)(o: HeapObject):
return %RawDownCast<FastJSArrayForCopy>(a);
}
Cast<FastJSArrayForConcat>(implicit context: Context)(o: HeapObject):
FastJSArrayForConcat
labels CastError {
if (IsArraySpeciesProtectorCellInvalid()) goto CastError;
if (IsIsConcatSpreadableProtectorCellInvalid()) goto CastError;
const a = Cast<FastJSArrayForRead>(o) otherwise CastError;
return %RawDownCast<FastJSArrayForConcat>(a);
}
Cast<FastJSArrayWithNoCustomIteration>(implicit context: Context)(
o: HeapObject): FastJSArrayWithNoCustomIteration
labels CastError {

View File

@ -6195,6 +6195,13 @@ TNode<BoolT> CodeStubAssembler::IsArraySpeciesProtectorCellInvalid() {
return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsIsConcatSpreadableProtectorCellInvalid() {
TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid);
TNode<PropertyCell> cell = IsConcatSpreadableProtectorConstant();
TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsTypedArraySpeciesProtectorCellInvalid() {
TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid);
TNode<PropertyCell> cell = TypedArraySpeciesProtectorConstant();

View File

@ -68,6 +68,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
AsyncGeneratorYieldResolveSharedFun) \
V(AsyncIteratorValueUnwrapSharedFun, async_iterator_value_unwrap_shared_fun, \
AsyncIteratorValueUnwrapSharedFun) \
V(IsConcatSpreadableProtector, is_concat_spreadable_protector, \
IsConcatSpreadableProtector) \
V(MapIteratorProtector, map_iterator_protector, MapIteratorProtector) \
V(NoElementsProtector, no_elements_protector, NoElementsProtector) \
V(MegaDOMProtector, mega_dom_protector, MegaDOMProtector) \
@ -2546,6 +2548,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsPromiseResolveProtectorCellInvalid();
TNode<BoolT> IsPromiseThenProtectorCellInvalid();
TNode<BoolT> IsArraySpeciesProtectorCellInvalid();
TNode<BoolT> IsIsConcatSpreadableProtectorCellInvalid();
TNode<BoolT> IsTypedArraySpeciesProtectorCellInvalid();
TNode<BoolT> IsRegExpSpeciesProtectorCellInvalid();
TNode<BoolT> IsPromiseSpeciesProtectorCellInvalid();

View File

@ -560,6 +560,7 @@ DebugInfo::SideEffectState BuiltinGetSideEffectState(Builtin id) {
case Builtin::kArrayPrototypeValues:
case Builtin::kArrayIncludes:
case Builtin::kArrayPrototypeAt:
case Builtin::kArrayPrototypeConcat:
case Builtin::kArrayPrototypeEntries:
case Builtin::kArrayPrototypeFill:
case Builtin::kArrayPrototypeFind:

View File

@ -1741,8 +1741,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
JSObject::AddProperty(isolate_, proto, factory->constructor_string(),
array_function, DONT_ENUM);
SimpleInstallFunction(isolate_, proto, "concat", Builtin::kArrayConcat, 1,
false);
SimpleInstallFunction(isolate_, proto, "concat",
Builtin::kArrayPrototypeConcat, 1, false);
SimpleInstallFunction(isolate_, proto, "copyWithin",
Builtin::kArrayPrototypeCopyWithin, 2, false);
SimpleInstallFunction(isolate_, proto, "fill", Builtin::kArrayPrototypeFill,

View File

@ -66,6 +66,10 @@ transient type FastJSArrayForRead extends JSArray;
// A FastJSArray when the global ArraySpeciesProtector is not invalidated.
transient type FastJSArrayForCopy extends FastJSArray;
// A FastJSArray when the global ArraySpeciesProtector and
// IsConcatSpreadableProtector are not invalidated.
transient type FastJSArrayForConcat extends FastJSArrayForRead;
// A FastJSArray when the global ArrayIteratorProtector is not invalidated.
transient type FastJSArrayWithNoCustomIteration extends FastJSArray;