| // 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 { |
| const kBuiltinNameFilter: constexpr string = '%TypedArray%.prototype.filter'; |
| |
| // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.filter |
| transitioning javascript builtin TypedArrayPrototypeFilter( |
| js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { |
| // 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( |
| MessageTemplate::kNotTypedArray, kBuiltinNameFilter); |
| const src = typed_array::EnsureAttached(array) otherwise IsDetached; |
| |
| // 3. Let len be O.[[ArrayLength]]. |
| const len: uintptr = src.length; |
| |
| // 4. If IsCallable(callbackfn) is false, throw a TypeError exception. |
| const callbackfn = Cast<Callable>(arguments[0]) |
| otherwise ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]); |
| |
| // 5. If thisArg is present, let T be thisArg; else let T be undefined. |
| const thisArg: JSAny = arguments[1]; |
| |
| // 6. Let kept be a new empty List. |
| // TODO(v8:4153): Support huge TypedArrays here. (growable fixed arrays |
| // can't be longer than kMaxSmiValue). |
| 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: uintptr = 0; k < len; k++) { |
| witness.Recheck() otherwise IsDetached; |
| |
| // a. Let Pk be ! ToString(k). |
| // b. Let kValue be ? Get(O, Pk). |
| const value: JSAny = witness.Load(k); |
| |
| // c. Let selected be ToBoolean(? Call(callbackfn, T, « kValue, k, O |
| // »)). |
| // TODO(v8:4153): Consider versioning this loop for Smi and non-Smi |
| // indices to optimize Convert<Number>(k) for the most common case. |
| const selected: JSAny = Call( |
| context, callbackfn, thisArg, value, Convert<Number>(k), |
| witness.GetStable()); |
| |
| // d. If selected is true, then |
| // i. Append kValue to the end of kept. |
| // ii. Increase captured by 1. |
| if (ToBoolean(selected)) kept.Push(value); |
| |
| // e.Increase k by 1. |
| } |
| |
| // 10. Let A be ? TypedArraySpeciesCreate(O, captured). |
| const typedArray: JSTypedArray = TypedArraySpeciesCreateByLength( |
| kBuiltinNameFilter, array, Unsigned(kept.length)); |
| |
| // 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. |
| // TODO(v8:4153): Consider passing growable typed array directly to |
| // TypedArrayCopyElements() to avoid JSArray materialization. Or collect |
| // indices instead of values the loop above. |
| const lengthNumber = Convert<Number>(Unsigned(kept.length)); |
| TypedArrayCopyElements(context, typedArray, kept.ToJSArray(), lengthNumber); |
| |
| // 13. Return A. |
| return typedArray; |
| } label IsDetached deferred { |
| ThrowTypeError(MessageTemplate::kDetachedOperation, kBuiltinNameFilter); |
| } |
| } |
| } |