[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:
parent
e4bff229b2
commit
7c89c29b78
4
BUILD.gn
4
BUILD.gn
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
45
src/builtins/growable-fixed-array.tq
Normal file
45
src/builtins/growable-fixed-array.tq
Normal 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};
|
||||
}
|
||||
}
|
79
src/builtins/typed-array-filter.tq
Normal file
79
src/builtins/typed-array-filter.tq
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user