Commit 40c9cce4 authored by Mike Stanton's avatar Mike Stanton Committed by Commit Bot

[Torque] Move some TypedArray builtins to Torque

This CL moves the following builtins from CSA to Torque:

TypedArray.prototype.forEach
TypedArray.prototype.reduce
TypedArray.prototype.reduceRight

A space-saving decision was made in the design -- instead of emitting
versions of the central loop for each ElementsKind, a function
pointer which knows how to read from the appropriate TypedArray
ElementsKind is constructed at the outset, and passed into the
loop. This enormously reduces codesize for the TypedArray builtins.
We'll have to see if the overhead of the builtin call affects
performance too adversely.

BUG: v8:8906
Change-Id: I808cd70f58ddbde18f85e5b2a9be0b883a3f6647
Reviewed-on: https://chromium-review.googlesource.com/c/1484292Reviewed-by: 's avatarSimon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59970}
parent 7eae3a63
...@@ -925,6 +925,9 @@ torque_files = [ ...@@ -925,6 +925,9 @@ torque_files = [
"src/builtins/string-startswith.tq", "src/builtins/string-startswith.tq",
"src/builtins/typed-array.tq", "src/builtins/typed-array.tq",
"src/builtins/typed-array-createtypedarray.tq", "src/builtins/typed-array-createtypedarray.tq",
"src/builtins/typed-array-foreach.tq",
"src/builtins/typed-array-reduce.tq",
"src/builtins/typed-array-reduceright.tq",
"src/builtins/typed-array-subarray.tq", "src/builtins/typed-array-subarray.tq",
"test/torque/test-torque.tq", "test/torque/test-torque.tq",
"third_party/v8/builtins/array-sort.tq", "third_party/v8/builtins/array-sort.tq",
...@@ -956,6 +959,9 @@ torque_namespaces = [ ...@@ -956,6 +959,9 @@ torque_namespaces = [
"test", "test",
"typed-array", "typed-array",
"typed-array-createtypedarray", "typed-array-createtypedarray",
"typed-array-foreach",
"typed-array-reduce",
"typed-array-reduceright",
"typed-array-subarray", "typed-array-subarray",
] ]
......
...@@ -779,8 +779,6 @@ extern macro HeapObjectToJSDataView(HeapObject): JSDataView ...@@ -779,8 +779,6 @@ extern macro HeapObjectToJSDataView(HeapObject): JSDataView
labels CastError; labels CastError;
extern macro HeapObjectToJSArrayBuffer(HeapObject): JSArrayBuffer extern macro HeapObjectToJSArrayBuffer(HeapObject): JSArrayBuffer
labels CastError; labels CastError;
extern macro HeapObjectToJSTypedArray(HeapObject): JSTypedArray
labels CastError;
extern macro TaggedToHeapObject(Object): HeapObject extern macro TaggedToHeapObject(Object): HeapObject
labels CastError; labels CastError;
extern macro TaggedToSmi(Object): Smi extern macro TaggedToSmi(Object): Smi
...@@ -864,6 +862,12 @@ Cast<JSTypedArray>(o: HeapObject): JSTypedArray ...@@ -864,6 +862,12 @@ Cast<JSTypedArray>(o: HeapObject): JSTypedArray
goto CastError; goto CastError;
} }
Cast<JSTypedArray>(implicit context: Context)(o: Object): JSTypedArray
labels CastError {
const heapObject = Cast<HeapObject>(o) otherwise CastError;
return Cast<JSTypedArray>(heapObject) otherwise CastError;
}
Cast<Callable>(o: HeapObject): Callable Cast<Callable>(o: HeapObject): Callable
labels CastError { labels CastError {
return HeapObjectToCallable(o) otherwise CastError; return HeapObjectToCallable(o) otherwise CastError;
......
...@@ -60,16 +60,6 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) { ...@@ -60,16 +60,6 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
return a(); return a();
} }
void ArrayBuiltinsAssembler::ForEachResultGenerator() {
a_.Bind(UndefinedConstant());
}
Node* ArrayBuiltinsAssembler::ForEachProcessor(Node* k_value, Node* k) {
CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(),
k_value, k, o());
return a();
}
void ArrayBuiltinsAssembler::SomeResultGenerator() { void ArrayBuiltinsAssembler::SomeResultGenerator() {
a_.Bind(FalseConstant()); a_.Bind(FalseConstant());
} }
...@@ -100,33 +90,6 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) { ...@@ -100,33 +90,6 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
return a(); return a();
} }
void ArrayBuiltinsAssembler::ReduceResultGenerator() {
return a_.Bind(this_arg());
}
Node* ArrayBuiltinsAssembler::ReduceProcessor(Node* k_value, Node* k) {
VARIABLE(result, MachineRepresentation::kTagged);
Label done(this, {&result}), initial(this);
GotoIf(WordEqual(a(), TheHoleConstant()), &initial);
result.Bind(CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
UndefinedConstant(), a(), k_value, k, o()));
Goto(&done);
BIND(&initial);
result.Bind(k_value);
Goto(&done);
BIND(&done);
return result.value();
}
void ArrayBuiltinsAssembler::ReducePostLoopAction() {
Label ok(this);
GotoIf(WordNotEqual(a(), TheHoleConstant()), &ok);
ThrowTypeError(context(), MessageTemplate::kReduceNoInitial);
BIND(&ok);
}
void ArrayBuiltinsAssembler::TypedArrayMapResultGenerator() { void ArrayBuiltinsAssembler::TypedArrayMapResultGenerator() {
// 6. Let A be ? TypedArraySpeciesCreate(O, len). // 6. Let A be ? TypedArraySpeciesCreate(O, len).
TNode<JSTypedArray> original_array = CAST(o()); TNode<JSTypedArray> original_array = CAST(o());
...@@ -1121,23 +1084,6 @@ TF_BUILTIN(TypedArrayPrototypeFindIndex, ArrayBuiltinsAssembler) { ...@@ -1121,23 +1084,6 @@ TF_BUILTIN(TypedArrayPrototypeFindIndex, ArrayBuiltinsAssembler) {
&ArrayBuiltinsAssembler::NullPostLoopAction); &ArrayBuiltinsAssembler::NullPostLoopAction);
} }
TF_BUILTIN(TypedArrayPrototypeForEach, ArrayBuiltinsAssembler) {
TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> receiver = args.GetReceiver();
Node* callbackfn = args.GetOptionalArgumentValue(0);
Node* this_arg = args.GetOptionalArgumentValue(1);
InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
GenerateIteratingTypedArrayBuiltinBody(
"%TypedArray%.prototype.forEach",
&ArrayBuiltinsAssembler::ForEachResultGenerator,
&ArrayBuiltinsAssembler::ForEachProcessor,
&ArrayBuiltinsAssembler::NullPostLoopAction);
}
TF_BUILTIN(TypedArrayPrototypeSome, ArrayBuiltinsAssembler) { TF_BUILTIN(TypedArrayPrototypeSome, ArrayBuiltinsAssembler) {
TNode<IntPtrT> argc = TNode<IntPtrT> argc =
...@@ -1175,46 +1121,6 @@ TF_BUILTIN(TypedArrayPrototypeEvery, ArrayBuiltinsAssembler) { ...@@ -1175,46 +1121,6 @@ TF_BUILTIN(TypedArrayPrototypeEvery, ArrayBuiltinsAssembler) {
&ArrayBuiltinsAssembler::NullPostLoopAction); &ArrayBuiltinsAssembler::NullPostLoopAction);
} }
TF_BUILTIN(TypedArrayPrototypeReduce, ArrayBuiltinsAssembler) {
TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> receiver = args.GetReceiver();
Node* callbackfn = args.GetOptionalArgumentValue(0);
Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
argc);
GenerateIteratingTypedArrayBuiltinBody(
"%TypedArray%.prototype.reduce",
&ArrayBuiltinsAssembler::ReduceResultGenerator,
&ArrayBuiltinsAssembler::ReduceProcessor,
&ArrayBuiltinsAssembler::ReducePostLoopAction);
}
TF_BUILTIN(TypedArrayPrototypeReduceRight, ArrayBuiltinsAssembler) {
TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> receiver = args.GetReceiver();
Node* callbackfn = args.GetOptionalArgumentValue(0);
Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
argc);
GenerateIteratingTypedArrayBuiltinBody(
"%TypedArray%.prototype.reduceRight",
&ArrayBuiltinsAssembler::ReduceResultGenerator,
&ArrayBuiltinsAssembler::ReduceProcessor,
&ArrayBuiltinsAssembler::ReducePostLoopAction,
ForEachDirection::kReverse);
}
TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinsAssembler) { TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinsAssembler) {
TNode<IntPtrT> argc = TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)); ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
......
...@@ -1152,17 +1152,8 @@ namespace internal { ...@@ -1152,17 +1152,8 @@ namespace internal {
/* ES6 %TypedArray%.prototype.some */ \ /* ES6 %TypedArray%.prototype.some */ \
TFJ(TypedArrayPrototypeSome, \ TFJ(TypedArrayPrototypeSome, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \ SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 %TypedArray%.prototype.reduce */ \
TFJ(TypedArrayPrototypeReduce, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 %TypedArray%.prototype.reduceRight */ \
TFJ(TypedArrayPrototypeReduceRight, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 %TypedArray%.prototype.map */ \ /* ES6 %TypedArray%.prototype.map */ \
TFJ(TypedArrayPrototypeMap, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \ TFJ(TypedArrayPrototypeMap, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 %TypedArray%.prototype.forEach */ \
TFJ(TypedArrayPrototypeForEach, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 %TypedArray%.of */ \ /* ES6 %TypedArray%.of */ \
TFJ(TypedArrayOf, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \ TFJ(TypedArrayOf, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 %TypedArray%.from */ \ /* ES6 %TypedArray%.from */ \
......
// Copyright 2019 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.
#include 'src/builtins/builtins-typed-array-gen.h'
namespace typed_array_foreach {
const kBuiltinName: constexpr string = '%TypedArray%.prototype.forEach';
transitioning macro ForEachAllElements(implicit context: Context)(
array: typed_array::AttachedJSTypedArray, callbackfn: Callable,
thisArg: Object): Object {
let witness = typed_array::NewAttachedJSTypedArrayWitness(array);
const length: Smi = Convert<Smi>(array.length);
for (let k: Smi = 0; k < length; k++) {
// BUG(4895): We should throw on detached buffers rather than simply exit.
witness.Recheck() otherwise break;
const value: Object = witness.Load(k);
Call(context, callbackfn, thisArg, value, k, witness.GetStable());
}
return Undefined;
}
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.every
transitioning javascript builtin
TypedArrayPrototypeForEach(implicit context: Context)(
receiver: Object, ...arguments): Object {
// arguments[0] = callback
// arguments[1] = this_arg.
try {
const array: JSTypedArray = Cast<JSTypedArray>(receiver)
otherwise NotTypedArray;
const uarray = typed_array::EnsureAttached(array) otherwise IsDetached;
const callbackfn = Cast<Callable>(arguments[0]) otherwise NotCallable;
const thisArg = arguments[1];
return ForEachAllElements(uarray, callbackfn, thisArg);
}
label NotCallable deferred {
ThrowTypeError(kCalledNonCallable, arguments[0]);
}
label NotTypedArray deferred {
ThrowTypeError(kNotTypedArray, kBuiltinName);
}
label IsDetached deferred {
ThrowTypeError(kDetachedOperation, kBuiltinName);
}
}
}
// Copyright 2019 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.
#include 'src/builtins/builtins-typed-array-gen.h'
namespace typed_array_reduce {
const kBuiltinName: constexpr string = '%TypedArray%.prototype.reduce';
transitioning macro ReduceAllElements(implicit context: Context)(
array: typed_array::AttachedJSTypedArray, callbackfn: Callable,
initialValue: Object): Object {
let witness = typed_array::NewAttachedJSTypedArrayWitness(array);
const length: Smi = Convert<Smi>(witness.Get().length);
let accumulator = initialValue;
for (let k: Smi = 0; k < length; k++) {
// BUG(4895): We should throw on detached buffers rather than simply exit.
witness.Recheck() otherwise break;
const value: Object = witness.Load(k);
if (accumulator == Hole) {
accumulator = value;
} else {
accumulator = Call(
context, callbackfn, Undefined, accumulator, value, k,
witness.GetStable());
}
}
if (accumulator == Hole) {
ThrowTypeError(kReduceNoInitial, kBuiltinName);
}
return accumulator;
}
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduce
transitioning javascript builtin
TypedArrayPrototypeReduce(implicit context: Context)(
receiver: Object, ...arguments): Object {
// arguments[0] = callback
// arguments[1] = initialValue.
try {
const array: JSTypedArray = Cast<JSTypedArray>(receiver)
otherwise NotTypedArray;
const uarray = typed_array::EnsureAttached(array) otherwise IsDetached;
const callbackfn = Cast<Callable>(arguments[0]) otherwise NotCallable;
const initialValue = arguments.length >= 2 ? arguments[1] : Hole;
return ReduceAllElements(uarray, callbackfn, initialValue);
}
label NotCallable deferred {
ThrowTypeError(kCalledNonCallable, arguments[0]);
}
label NotTypedArray deferred {
ThrowTypeError(kNotTypedArray, kBuiltinName);
}
label IsDetached deferred {
ThrowTypeError(kDetachedOperation, kBuiltinName);
}
}
}
// Copyright 2019 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.
#include 'src/builtins/builtins-typed-array-gen.h'
namespace typed_array_reduceright {
const kBuiltinName: constexpr string = '%TypedArray%.prototype.reduceRight';
transitioning macro ReduceRightAllElements(implicit context: Context)(
array: typed_array::AttachedJSTypedArray, callbackfn: Callable,
initialValue: Object): Object {
let witness = typed_array::NewAttachedJSTypedArrayWitness(array);
const length: Smi = Convert<Smi>(array.length);
let accumulator = initialValue;
for (let k: Smi = length - 1; k >= 0; k--) {
// BUG(4895): We should throw on detached buffers rather than simply exit.
witness.Recheck() otherwise break;
const value: Object = witness.Load(k);
if (accumulator == Hole) {
accumulator = value;
} else {
accumulator = Call(
context, callbackfn, Undefined, accumulator, value, k,
witness.GetStable());
}
}
if (accumulator == Hole) {
ThrowTypeError(kReduceNoInitial, kBuiltinName);
}
return accumulator;
}
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduceright
transitioning javascript builtin
TypedArrayPrototypeReduceRight(implicit context: Context)(
receiver: Object, ...arguments): Object {
// arguments[0] = callback
// arguments[1] = initialValue.
try {
const array: JSTypedArray = Cast<JSTypedArray>(receiver)
otherwise NotTypedArray;
const uarray = typed_array::EnsureAttached(array) otherwise IsDetached;
const callbackfn = Cast<Callable>(arguments[0]) otherwise NotCallable;
const initialValue = arguments.length >= 2 ? arguments[1] : Hole;
return ReduceRightAllElements(uarray, callbackfn, initialValue);
}
label NotCallable deferred {
ThrowTypeError(kCalledNonCallable, arguments[0]);
}
label NotTypedArray deferred {
ThrowTypeError(kNotTypedArray, kBuiltinName);
}
label IsDetached deferred {
ThrowTypeError(kDetachedOperation, kBuiltinName);
}
}
}
...@@ -70,6 +70,83 @@ namespace typed_array { ...@@ -70,6 +70,83 @@ namespace typed_array {
return %RawDownCast<StoreFn>(o); return %RawDownCast<StoreFn>(o);
} }
// AttachedJSTypedArray guards that the array's buffer is not detached.
transient type AttachedJSTypedArray extends JSTypedArray;
macro EnsureAttached(array: JSTypedArray): AttachedJSTypedArray
labels Detached {
if (IsDetachedBuffer(array.buffer)) goto Detached;
return %RawDownCast<AttachedJSTypedArray>(array);
}
struct AttachedJSTypedArrayWitness {
Get(): AttachedJSTypedArray {
return this.unstable;
}
GetStable(): JSTypedArray {
return this.stable;
}
Recheck() labels Detached {
if (IsDetachedBuffer(this.stable.buffer)) goto Detached;
this.unstable = %RawDownCast<AttachedJSTypedArray>(this.stable);
}
Load(implicit context: Context)(k: Smi): Object {
const lf: LoadFn = this.loadfn;
return lf(context, this.unstable, k);
}
stable: JSTypedArray;
unstable: AttachedJSTypedArray;
loadfn: LoadFn;
}
macro NewAttachedJSTypedArrayWitness(array: AttachedJSTypedArray):
AttachedJSTypedArrayWitness {
const kind = array.elements_kind;
return AttachedJSTypedArrayWitness{
array,
array,
GetLoadFnForElementsKind(kind)
};
}
macro GetLoadFnForElementsKind(elementsKind: ElementsKind): LoadFn {
if (IsElementsKindGreaterThan(elementsKind, UINT32_ELEMENTS)) {
if (elementsKind == INT32_ELEMENTS) {
return LoadFixedElement<FixedInt32Array>;
} else if (elementsKind == FLOAT32_ELEMENTS) {
return LoadFixedElement<FixedFloat32Array>;
} else if (elementsKind == FLOAT64_ELEMENTS) {
return LoadFixedElement<FixedFloat64Array>;
} else if (elementsKind == UINT8_CLAMPED_ELEMENTS) {
return LoadFixedElement<FixedUint8ClampedArray>;
} else if (elementsKind == BIGUINT64_ELEMENTS) {
return LoadFixedElement<FixedBigUint64Array>;
} else if (elementsKind == BIGINT64_ELEMENTS) {
return LoadFixedElement<FixedBigInt64Array>;
} else {
unreachable;
}
} else {
if (elementsKind == UINT8_ELEMENTS) {
return LoadFixedElement<FixedUint8Array>;
} else if (elementsKind == INT8_ELEMENTS) {
return LoadFixedElement<FixedInt8Array>;
} else if (elementsKind == UINT16_ELEMENTS) {
return LoadFixedElement<FixedUint16Array>;
} else if (elementsKind == INT16_ELEMENTS) {
return LoadFixedElement<FixedInt16Array>;
} else if (elementsKind == UINT32_ELEMENTS) {
return LoadFixedElement<FixedUint32Array>;
} else {
unreachable;
}
}
}
macro KindForArrayType<T: type>(): constexpr ElementsKind; macro KindForArrayType<T: type>(): constexpr ElementsKind;
KindForArrayType<FixedUint8Array>(): constexpr ElementsKind { KindForArrayType<FixedUint8Array>(): constexpr ElementsKind {
return UINT8_ELEMENTS; return UINT8_ELEMENTS;
......
...@@ -924,6 +924,7 @@ static bool TransitivelyCalledBuiltinHasNoSideEffect(Builtins::Name caller, ...@@ -924,6 +924,7 @@ static bool TransitivelyCalledBuiltinHasNoSideEffect(Builtins::Name caller,
case Builtins::kArraySomeLoopContinuation: case Builtins::kArraySomeLoopContinuation:
case Builtins::kArrayTimSort: case Builtins::kArrayTimSort:
case Builtins::kCall_ReceiverIsAny: case Builtins::kCall_ReceiverIsAny:
case Builtins::kCall_ReceiverIsNullOrUndefined:
case Builtins::kCallWithArrayLike: case Builtins::kCallWithArrayLike:
case Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit: case Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit:
case Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit: case Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit:
......
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