@@ -3845,5 +3845,260 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
38453845 }
38463846}
38473847
3848+ namespace {
3849+
3850+ class ArrayFlattenAssembler : public CodeStubAssembler {
3851+ public:
3852+ explicit ArrayFlattenAssembler (compiler::CodeAssemblerState* state)
3853+ : CodeStubAssembler(state) {}
3854+
3855+ // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
3856+ Node* FlattenIntoArray (Node* context, Node* target, Node* source,
3857+ Node* source_length, Node* start, Node* depth,
3858+ Node* mapper_function = nullptr ,
3859+ Node* this_arg = nullptr ) {
3860+ CSA_ASSERT (this , IsJSReceiver (target));
3861+ CSA_ASSERT (this , IsJSReceiver (source));
3862+ CSA_ASSERT (this , IsNumberPositive (source_length));
3863+ CSA_ASSERT (this , IsNumberPositive (start));
3864+ CSA_ASSERT (this , IsNumber (depth));
3865+
3866+ // 1. Let targetIndex be start.
3867+ VARIABLE (var_target_index, MachineRepresentation::kTagged , start);
3868+
3869+ // 2. Let sourceIndex be 0.
3870+ VARIABLE (var_source_index, MachineRepresentation::kTagged , SmiConstant (0 ));
3871+
3872+ // 3. Repeat...
3873+ Label loop (this , {&var_target_index, &var_source_index}), done_loop (this );
3874+ Goto (&loop);
3875+ BIND (&loop);
3876+ {
3877+ Node* const source_index = var_source_index.value ();
3878+ Node* const target_index = var_target_index.value ();
3879+
3880+ // ...while sourceIndex < sourceLen
3881+ GotoIfNumberGreaterThanOrEqual (source_index, source_length, &done_loop);
3882+
3883+ // a. Let P be ! ToString(sourceIndex).
3884+ // b. Let exists be ? HasProperty(source, P).
3885+ CSA_ASSERT (this , SmiGreaterThanOrEqual (source_index, SmiConstant (0 )));
3886+ Node* const exists =
3887+ HasProperty (source, source_index, context, kHasProperty );
3888+
3889+ // c. If exists is true, then
3890+ Label next (this );
3891+ GotoIfNot (IsTrue (exists), &next);
3892+ {
3893+ // i. Let element be ? Get(source, P).
3894+ Node* element = GetProperty (context, source, source_index);
3895+
3896+ // ii. If mapperFunction is present, then
3897+ if (mapper_function != nullptr ) {
3898+ CSA_ASSERT (this , Word32Or (IsUndefined (mapper_function),
3899+ IsCallable (mapper_function)));
3900+ DCHECK_NOT_NULL (this_arg);
3901+
3902+ // 1. Set element to ? Call(mapperFunction, thisArg , « element,
3903+ // sourceIndex, source »).
3904+ element =
3905+ CallJS (CodeFactory::Call (isolate ()), context, mapper_function,
3906+ this_arg, element, source_index, source);
3907+ }
3908+
3909+ // iii. Let shouldFlatten be false.
3910+ Label if_flatten_array (this ), if_flatten_proxy (this , Label::kDeferred ),
3911+ if_noflatten (this );
3912+ // iv. If depth > 0, then
3913+ GotoIfNumberGreaterThanOrEqual (SmiConstant (0 ), depth, &if_noflatten);
3914+ // 1. Set shouldFlatten to ? IsArray(element).
3915+ GotoIf (TaggedIsSmi (element), &if_noflatten);
3916+ GotoIf (IsJSArray (element), &if_flatten_array);
3917+ GotoIfNot (IsJSProxy (element), &if_noflatten);
3918+ Branch (IsTrue (CallRuntime (Runtime::kArrayIsArray , context, element)),
3919+ &if_flatten_proxy, &if_noflatten);
3920+
3921+ BIND (&if_flatten_array);
3922+ {
3923+ CSA_ASSERT (this , IsJSArray (element));
3924+
3925+ // 1. Let elementLen be ? ToLength(? Get(element, "length")).
3926+ Node* const element_length =
3927+ LoadObjectField (element, JSArray::kLengthOffset );
3928+
3929+ // 2. Set targetIndex to ? FlattenIntoArray(target, element,
3930+ // elementLen, targetIndex,
3931+ // depth - 1).
3932+ var_target_index.Bind (
3933+ CallBuiltin (Builtins::kFlattenIntoArray , context, target, element,
3934+ element_length, target_index, NumberDec (depth)));
3935+ Goto (&next);
3936+ }
3937+
3938+ BIND (&if_flatten_proxy);
3939+ {
3940+ CSA_ASSERT (this , IsJSProxy (element));
3941+
3942+ // 1. Let elementLen be ? ToLength(? Get(element, "length")).
3943+ Node* const element_length = ToLength_Inline (
3944+ context, GetProperty (context, element, LengthStringConstant ()));
3945+
3946+ // 2. Set targetIndex to ? FlattenIntoArray(target, element,
3947+ // elementLen, targetIndex,
3948+ // depth - 1).
3949+ var_target_index.Bind (
3950+ CallBuiltin (Builtins::kFlattenIntoArray , context, target, element,
3951+ element_length, target_index, NumberDec (depth)));
3952+ Goto (&next);
3953+ }
3954+
3955+ BIND (&if_noflatten);
3956+ {
3957+ // 1. If targetIndex >= 2^53-1, throw a TypeError exception.
3958+ Label throw_error (this , Label::kDeferred );
3959+ GotoIfNumberGreaterThanOrEqual (
3960+ target_index, NumberConstant (kMaxSafeInteger ), &throw_error);
3961+
3962+ // 2. Perform ? CreateDataPropertyOrThrow(target,
3963+ // ! ToString(targetIndex),
3964+ // element).
3965+ CallRuntime (Runtime::kCreateDataProperty , context, target,
3966+ target_index, element);
3967+
3968+ // 3. Increase targetIndex by 1.
3969+ var_target_index.Bind (NumberInc (target_index));
3970+ Goto (&next);
3971+
3972+ BIND (&throw_error);
3973+ ThrowTypeError (context, MessageTemplate::kFlattenPastSafeLength ,
3974+ source_length, target_index);
3975+ }
3976+ }
3977+ BIND (&next);
3978+
3979+ // d. Increase sourceIndex by 1.
3980+ var_source_index.Bind (NumberInc (source_index));
3981+ Goto (&loop);
3982+ }
3983+
3984+ BIND (&done_loop);
3985+ return var_target_index.value ();
3986+ }
3987+ };
3988+
3989+ } // namespace
3990+
3991+ // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
3992+ TF_BUILTIN (FlattenIntoArray, ArrayFlattenAssembler) {
3993+ Node* const context = Parameter (Descriptor::kContext );
3994+ Node* const target = Parameter (Descriptor::kTarget );
3995+ Node* const source = Parameter (Descriptor::kSource );
3996+ Node* const source_length = Parameter (Descriptor::kSourceLength );
3997+ Node* const start = Parameter (Descriptor::kStart );
3998+ Node* const depth = Parameter (Descriptor::kDepth );
3999+
4000+ Return (
4001+ FlattenIntoArray (context, target, source, source_length, start, depth));
4002+ }
4003+
4004+ // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
4005+ TF_BUILTIN (FlatMapIntoArray, ArrayFlattenAssembler) {
4006+ Node* const context = Parameter (Descriptor::kContext );
4007+ Node* const target = Parameter (Descriptor::kTarget );
4008+ Node* const source = Parameter (Descriptor::kSource );
4009+ Node* const source_length = Parameter (Descriptor::kSourceLength );
4010+ Node* const start = Parameter (Descriptor::kStart );
4011+ Node* const depth = Parameter (Descriptor::kDepth );
4012+ Node* const mapper_function = Parameter (Descriptor::kMapperFunction );
4013+ Node* const this_arg = Parameter (Descriptor::kThisArg );
4014+
4015+ Return (FlattenIntoArray (context, target, source, source_length, start, depth,
4016+ mapper_function, this_arg));
4017+ }
4018+
4019+ // https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatten
4020+ TF_BUILTIN (ArrayPrototypeFlatten, CodeStubAssembler) {
4021+ Node* const argc =
4022+ ChangeInt32ToIntPtr (Parameter (BuiltinDescriptor::kArgumentsCount ));
4023+ CodeStubArguments args (this , argc);
4024+ Node* const context = Parameter (BuiltinDescriptor::kContext );
4025+ Node* const receiver = args.GetReceiver ();
4026+ Node* const depth = args.GetOptionalArgumentValue (0 );
4027+
4028+ // 1. Let O be ? ToObject(this value).
4029+ Node* const o = ToObject (context, receiver);
4030+
4031+ // 2. Let sourceLen be ? ToLength(? Get(O, "length")).
4032+ Node* const source_length =
4033+ ToLength_Inline (context, GetProperty (context, o, LengthStringConstant ()));
4034+
4035+ // 3. Let depthNum be 1.
4036+ VARIABLE (var_depth_num, MachineRepresentation::kTagged , SmiConstant (1 ));
4037+
4038+ // 4. If depth is not undefined, then
4039+ Label done (this );
4040+ GotoIf (IsUndefined (depth), &done);
4041+ {
4042+ // a. Set depthNum to ? ToInteger(depth).
4043+ var_depth_num.Bind (ToInteger_Inline (context, depth));
4044+ Goto (&done);
4045+ }
4046+ BIND (&done);
4047+
4048+ // 5. Let A be ? ArraySpeciesCreate(O, 0).
4049+ Node* const constructor =
4050+ CallRuntime (Runtime::kArraySpeciesConstructor , context, o);
4051+ Node* const a = ConstructJS (CodeFactory::Construct (isolate ()), context,
4052+ constructor, SmiConstant (0 ));
4053+
4054+ // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
4055+ CallBuiltin (Builtins::kFlattenIntoArray , context, a, o, source_length,
4056+ SmiConstant (0 ), var_depth_num.value ());
4057+
4058+ // 7. Return A.
4059+ args.PopAndReturn (a);
4060+ }
4061+
4062+ // https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap
4063+ TF_BUILTIN (ArrayPrototypeFlatMap, CodeStubAssembler) {
4064+ Node* const argc =
4065+ ChangeInt32ToIntPtr (Parameter (BuiltinDescriptor::kArgumentsCount ));
4066+ CodeStubArguments args (this , argc);
4067+ Node* const context = Parameter (BuiltinDescriptor::kContext );
4068+ Node* const receiver = args.GetReceiver ();
4069+ Node* const mapper_function = args.GetOptionalArgumentValue (0 );
4070+
4071+ // 1. Let O be ? ToObject(this value).
4072+ Node* const o = ToObject (context, receiver);
4073+
4074+ // 2. Let sourceLen be ? ToLength(? Get(O, "length")).
4075+ Node* const source_length =
4076+ ToLength_Inline (context, GetProperty (context, o, LengthStringConstant ()));
4077+
4078+ // 3. If IsCallable(mapperFunction) is false, throw a TypeError exception.
4079+ Label if_not_callable (this , Label::kDeferred );
4080+ GotoIf (TaggedIsSmi (mapper_function), &if_not_callable);
4081+ GotoIfNot (IsCallable (mapper_function), &if_not_callable);
4082+
4083+ // 4. If thisArg is present, let T be thisArg; else let T be undefined.
4084+ Node* const t = args.GetOptionalArgumentValue (1 );
4085+
4086+ // 5. Let A be ? ArraySpeciesCreate(O, 0).
4087+ Node* const constructor =
4088+ CallRuntime (Runtime::kArraySpeciesConstructor , context, o);
4089+ Node* const a = ConstructJS (CodeFactory::Construct (isolate ()), context,
4090+ constructor, SmiConstant (0 ));
4091+
4092+ // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T).
4093+ CallBuiltin (Builtins::kFlatMapIntoArray , context, a, o, source_length,
4094+ SmiConstant (0 ), SmiConstant (1 ), mapper_function, t);
4095+
4096+ // 7. Return A.
4097+ args.PopAndReturn (a);
4098+
4099+ BIND (&if_not_callable);
4100+ { ThrowTypeError (context, MessageTemplate::kMapperFunctionNonCallable ); }
4101+ }
4102+
38484103} // namespace internal
38494104} // namespace v8
0 commit comments