[typedarray] Port TypedArray#filter to Torque.

Also ports GrowableFixedArray to Torque. The CSA version is preserved
for now, as the Torque structs are not consumable by CSA builtins yet
(Struct methods are inlined).

TypedArrayPrototypeFilter builtin size decreased by 24% (Mac x64.release):
  TFJ Builtin, TypedArrayPrototypeFilter, 5689 -> 4298

TypedArrays/Filter micro benchmarks have improved 10-15% (Mac x64.release):
  TypedArrays-Uint8Array(Score):     746 -> 857
  TypedArrays-Uint16Array(Score):    758 -> 862
  TypedArrays-Uint32Array(Score):    746 -> 855
  TypedArrays-Float32Array(Score):   749 -> 817
  TypedArrays-Float64Array(Score):   751 -> 839
  TypedArrays-BigUint64Array(Score): 562 -> 625

Bug: v8:8906
Change-Id: I1172b7407de95b067448e680ec327e726e9194cf
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1501469
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Simon Zünd <szuend@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60035}
This commit is contained in:
peterwmwong 2019-03-05 08:24:43 -06:00 committed by Commit Bot
parent e4bff229b2
commit 7c89c29b78
6 changed files with 131 additions and 105 deletions

View File

@ -896,6 +896,7 @@ action("postmortem-metadata") {
torque_files = [
"src/builtins/base.tq",
"src/builtins/growable-fixed-array.tq",
"src/builtins/frames.tq",
"src/builtins/arguments.tq",
"src/builtins/array.tq",
@ -925,6 +926,7 @@ torque_files = [
"src/builtins/string-startswith.tq",
"src/builtins/typed-array.tq",
"src/builtins/typed-array-createtypedarray.tq",
"src/builtins/typed-array-filter.tq",
"src/builtins/typed-array-foreach.tq",
"src/builtins/typed-array-reduce.tq",
"src/builtins/typed-array-reduceright.tq",
@ -954,12 +956,14 @@ torque_namespaces = [
"collections",
"data-view",
"extras-utils",
"growable-fixed-array",
"iterator",
"object",
"string",
"test",
"typed-array",
"typed-array-createtypedarray",
"typed-array-filter",
"typed-array-foreach",
"typed-array-reduce",
"typed-array-reduceright",

View File

@ -1434,6 +1434,8 @@ extern operator '.objects[]=' macro StoreFixedArrayElement(
FixedArray, Smi, Smi): void;
extern operator '.objects[]=' macro StoreFixedArrayElement(
FixedArray, intptr, HeapObject): void;
extern operator '.objects[]=' macro StoreFixedArrayElement(
FixedArray, intptr, Object): void;
extern operator '.objects[]=' macro StoreFixedArrayElement(
FixedArray, constexpr int31, Smi): void;
extern operator '.objects[]=' macro StoreFixedArrayElement(
@ -1529,6 +1531,7 @@ extern macro CopyFixedArrayElements(
extern macro AllocateJSArray(constexpr ElementsKind, Map, intptr, Smi): JSArray;
extern macro AllocateJSArray(constexpr ElementsKind, Map, Smi, Smi): JSArray;
extern macro AllocateJSArray(Map, FixedArrayBase, Smi): JSArray;
extern macro AllocateJSObjectFromMap(Map): JSObject;
extern macro LoadDoubleWithHoleCheck(FixedDoubleArray, Smi): float64

View File

@ -1121,9 +1121,6 @@ namespace internal {
CPP(TypedArrayPrototypeCopyWithin) \
/* ES6 #sec-%typedarray%.prototype.fill */ \
CPP(TypedArrayPrototypeFill) \
/* ES6 #sec-%typedarray%.prototype.filter */ \
TFJ(TypedArrayPrototypeFilter, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 %TypedArray%.prototype.find */ \
TFJ(TypedArrayPrototypeFind, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \

View File

@ -1081,108 +1081,6 @@ TF_BUILTIN(TypedArrayFrom, TypedArrayBuiltinsAssembler) {
"%TypedArray%.from");
}
// ES %TypedArray%.prototype.filter
TF_BUILTIN(TypedArrayPrototypeFilter, TypedArrayBuiltinsAssembler) {
const char* method_name = "%TypedArray%.prototype.filter";
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
CodeStubArguments args(
this,
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
Label if_callback_not_callable(this, Label::kDeferred),
detached(this, Label::kDeferred);
// 1. Let O be the this value.
// 2. Perform ? ValidateTypedArray(O).
TNode<Object> receiver = args.GetReceiver();
TNode<JSTypedArray> source =
ValidateTypedArray(context, receiver, method_name);
// 3. Let len be O.[[ArrayLength]].
TNode<Smi> length = LoadJSTypedArrayLength(source);
// 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
TNode<Object> callbackfn = args.GetOptionalArgumentValue(0);
GotoIf(TaggedIsSmi(callbackfn), &if_callback_not_callable);
GotoIfNot(IsCallable(CAST(callbackfn)), &if_callback_not_callable);
// 5. If thisArg is present, let T be thisArg; else let T be undefined.
TNode<Object> this_arg = args.GetOptionalArgumentValue(1);
TNode<JSArrayBuffer> source_buffer =
LoadObjectField<JSArrayBuffer>(source, JSArrayBufferView::kBufferOffset);
TNode<Word32T> elements_kind = LoadElementsKind(source);
GrowableFixedArray values(state());
VariableList vars(
{values.var_array(), values.var_length(), values.var_capacity()}, zone());
// 6. Let kept be a new empty List.
// 7. Let k be 0.
// 8. Let captured be 0.
// 9. Repeat, while k < len
BuildFastLoop(
vars, SmiConstant(0), length,
[&](Node* index) {
GotoIf(IsDetachedBuffer(source_buffer), &detached);
TVARIABLE(Numeric, value);
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
DispatchTypedArrayByElementsKind(
elements_kind,
[&](ElementsKind kind, int size, int typed_array_fun_index) {
TNode<IntPtrT> backing_store =
UncheckedCast<IntPtrT>(LoadDataPtr(source));
value = CAST(LoadFixedTypedArrayElementAsTagged(
backing_store, index, kind, ParameterMode::SMI_PARAMETERS));
});
// c. Let selected be ToBoolean(Call(callbackfn, T, kValue, k, O))
Node* selected =
CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg,
value.value(), index, source);
Label true_continue(this), false_continue(this);
BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue);
BIND(&true_continue);
// d. If selected is true, then
// i. Append kValue to the end of kept.
// ii. Increase captured by 1.
values.Push(value.value());
Goto(&false_continue);
BIND(&false_continue);
},
1, ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);
TNode<JSArray> values_array = values.ToJSArray(context);
TNode<Smi> captured = LoadFastJSArrayLength(values_array);
// 10. Let A be ? TypedArraySpeciesCreate(O, captured).
TypedArrayCreatetypedarrayBuiltinsFromDSLAssembler typedarray_asm(state());
TNode<JSTypedArray> result_array =
typedarray_asm.TypedArraySpeciesCreateByLength(context, method_name,
source, captured);
// 11. Let n be 0.
// 12. For each element e of kept, do
// a. Perform ! Set(A, ! ToString(n), e, true).
// b. Increment n by 1.
CallRuntime(Runtime::kTypedArrayCopyElements, context, result_array,
values_array, captured);
// 13. Return A.
args.PopAndReturn(result_array);
BIND(&if_callback_not_callable);
ThrowTypeError(context, MessageTemplate::kCalledNonCallable, callbackfn);
BIND(&detached);
ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
}
#undef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
} // namespace internal

View File

@ -0,0 +1,45 @@
// 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.
namespace growable_fixed_array {
// TODO(pwong): Support FixedTypedArrays.
struct GrowableFixedArray {
Push(obj: Object) {
this.EnsureCapacity();
this.array.objects[this.length++] = obj;
}
ResizeFixedArray(newCapacity: intptr): FixedArray {
assert(this.length >= 0);
assert(newCapacity >= 0);
assert(newCapacity >= this.length);
const first: intptr = 0;
return ExtractFixedArray(
this.array, first, this.length, newCapacity, kFixedArrays);
}
EnsureCapacity() {
assert(this.length <= this.capacity);
if (this.capacity == this.length) {
// Growth rate is analog to JSObject::NewElementsCapacity:
// new_capacity = (current_capacity + (current_capacity >> 1)) + 16.
this.capacity = this.capacity + (this.capacity >> 1) + 16;
this.array = this.ResizeFixedArray(this.capacity);
}
}
ToJSArray(implicit context: Context)(): JSArray {
const nativeContext: NativeContext = LoadNativeContext(context);
const map: Map = LoadJSArrayElementsMap(PACKED_ELEMENTS, nativeContext);
const fixedArray: FixedArray = this.ResizeFixedArray(this.length);
const lengthSmi = Convert<Smi>(this.length);
return AllocateJSArray(map, fixedArray, lengthSmi);
}
array: FixedArray;
capacity: intptr;
length: intptr;
}
macro NewGrowableFixedArray(): GrowableFixedArray {
return GrowableFixedArray{kEmptyFixedArray, 0, 0};
}
}

View File

@ -0,0 +1,79 @@
// 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.
namespace typed_array_filter {
const kBuiltinName: constexpr string = '%TypedArray%.prototype.filter';
extern runtime TypedArrayCopyElements(Context, JSTypedArray, Object, Number):
void;
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.filter
transitioning javascript builtin TypedArrayPrototypeFilter(
context: Context, receiver: Object, ...arguments): Object {
// arguments[0] = callback
// arguments[1] = thisArg
try {
// 1. Let O be the this value.
// 2. Perform ? ValidateTypedArray(O).
const array: JSTypedArray = Cast<JSTypedArray>(receiver)
otherwise ThrowTypeError(kNotTypedArray, kBuiltinName);
const src = typed_array::EnsureAttached(array) otherwise IsDetached;
// 3. Let len be O.[[ArrayLength]].
const len: Smi = src.length;
// 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
const callbackfn = Cast<Callable>(arguments[0])
otherwise ThrowTypeError(kCalledNonCallable, arguments[0]);
// 5. If thisArg is present, let T be thisArg; else let T be undefined.
const thisArg: Object = arguments[1];
// 6. Let kept be a new empty List.
let kept = growable_fixed_array::NewGrowableFixedArray();
let witness = typed_array::NewAttachedJSTypedArrayWitness(src);
// 7. Let k be 0.
// 8. Let captured be 0.
// 9. Repeat, while k < len
for (let k: Smi = 0; k < len; k++) {
witness.Recheck() otherwise IsDetached;
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
const value: Object = witness.Load(k);
// c. Let selected be ToBoolean(? Call(callbackfn, T, « kValue, k, O
// »)).
const selected: Object =
Call(context, callbackfn, thisArg, value, k, witness.GetStable());
// d. If selected is true, then
// i. Append kValue to the end of kept.
// ii. Increase captured by 1.
if (BranchIfToBooleanIsTrue(selected)) kept.Push(value);
// e.Increase k by 1.
}
// 10. Let A be ? TypedArraySpeciesCreate(O, captured).
const lengthSmi: Smi = Convert<Smi>(kept.length);
const typedArray: JSTypedArray =
typed_array_createtypedarray::TypedArraySpeciesCreateByLength(
kBuiltinName, array, lengthSmi);
// 11. Let n be 0.
// 12. For each element e of kept, do
// a. Perform ! Set(A, ! ToString(n), e, true).
// b. Increment n by 1.
TypedArrayCopyElements(context, typedArray, kept.ToJSArray(), lengthSmi);
// 13. Return A.
return typedArray;
}
label IsDetached deferred {
ThrowTypeError(kDetachedOperation, kBuiltinName);
}
}
}