Chromium Code Reviews| Index: src/builtins/builtins-array-gen.cc |
| diff --git a/src/builtins/builtins-array-gen.cc b/src/builtins/builtins-array-gen.cc |
| index 75ec67e05494155f0ee3e29b74fbfaf1c2a5f6a9..8080fdc728a7385164426832ac9fbea0fb2eb1ab 100644 |
| --- a/src/builtins/builtins-array-gen.cc |
| +++ b/src/builtins/builtins-array-gen.cc |
| @@ -14,13 +14,22 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state) |
| : CodeStubAssembler(state) {} |
| - typedef std::function<Node*(Node* o, Node* len)> BuiltinResultGenerator; |
| - typedef std::function<void(Node* a, Node* pK, Node* value)> |
| + typedef std::function<std::pair<Node*, Node*>( |
|
danno
2017/03/17 10:26:31
Per Camillo's comments, I am going to add comments
|
| + ArrayBuiltinCodeStubAssembler* masm, Node* this_arg, Node* o, Node* len)> |
| + BuiltinResultGenerator; |
| + |
| + typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm, |
| + Node* context, Node* callbackfn, Node* this_arg, |
| + Node* k_value, Node* k, Node* o, Node* a)> |
| CallResultProcessor; |
| + typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm, Node* context, |
| + Node* a)> |
| + PostLoopAction; |
| + |
| void GenerateIteratingArrayBuiltinBody( |
| const char* name, const BuiltinResultGenerator& generator, |
| - const CallResultProcessor& processor, |
| + const CallResultProcessor& processor, const PostLoopAction& action, |
| const Callable& slow_case_continuation) { |
| Node* receiver = Parameter(IteratingArrayBuiltinDescriptor::kReceiver); |
| Node* callbackfn = Parameter(IteratingArrayBuiltinDescriptor::kCallback); |
| @@ -29,7 +38,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| Node* new_target = Parameter(IteratingArrayBuiltinDescriptor::kNewTarget); |
| Variable k(this, MachineRepresentation::kTagged, SmiConstant(0)); |
| - Label non_array(this), slow(this, &k), array_changes(this, &k); |
| + Variable a(this, MachineRepresentation::kTagged, UndefinedConstant()); |
| + Label non_array(this), slow(this, {&k, &a}), array_changes(this, {&k, &a}); |
| // TODO(danno): Seriously? Do we really need to throw the exact error |
| // message on null and undefined so that the webkit tests pass? |
| @@ -85,16 +95,19 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| Bind(&done); |
| - Node* a = generator(o, len); |
| + Node* initial_a; |
| + Node* initial_k; |
| + std::tie(initial_a, initial_k) = generator(this, this_arg, o, len); |
| // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. |
| // [Already done by the arguments adapter] |
| - HandleFastElements(context, this_arg, o, len, callbackfn, processor, a, k, |
| - &slow); |
| - |
| // 7. Let k be 0. |
| - // Already done above in initialization of the Variable k |
| + k.Bind(initial_k); |
| + a.Bind(initial_a); |
| + |
| + HandleFastElements(context, this_arg, o, len, callbackfn, processor, action, |
| + a, k, &slow); |
| Bind(&slow); |
| @@ -103,16 +116,16 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| TailCallStub( |
| slow_case_continuation, context, target, new_target, |
| Int32Constant(IteratingArrayBuiltinLoopContinuationDescriptor::kArity), |
| - receiver, callbackfn, this_arg, a, o, k.value(), len); |
| + receiver, callbackfn, this_arg, a.value(), o, k.value(), len); |
| } |
| void GenerateIteratingArrayBuiltinLoopContinuation( |
| - const CallResultProcessor& processor) { |
| + const CallResultProcessor& processor, const PostLoopAction& action) { |
| Node* callbackfn = |
| Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kCallback); |
| Node* this_arg = |
| Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kThisArg); |
| - Node* a = |
| + Node* initial_a = |
| Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kArray); |
| Node* o = |
| Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kObject); |
| @@ -125,7 +138,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| // 8. Repeat, while k < len |
| Variable k(this, MachineRepresentation::kTagged, initial_k); |
| - Label loop(this, &k); |
| + Variable a(this, MachineRepresentation::kTagged, initial_a); |
| + Label loop(this, {&k, &a}); |
| Label after_loop(this); |
| Goto(&loop); |
| Bind(&loop); |
| @@ -149,10 +163,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). |
| // iv. ReturnIfAbrupt(funcResult). |
| - Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn, |
| - this_arg, k_value, k.value(), o); |
| - |
| - processor(a, p_k, result); |
| + a.Bind(processor(this, context, callbackfn, this_arg, k_value, k.value(), |
| + o, a.value())); |
| Goto(&done_element); |
| Bind(&done_element); |
| @@ -161,42 +173,136 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| Goto(&loop); |
| } |
| Bind(&after_loop); |
| - Return(a); |
| + |
| + action(this, context, a.value()); |
| + |
| + Return(a.value()); |
| } |
| - void ForEachProcessor(Node* a, Node* p_k, Node* value) {} |
| + std::pair<Node*, Node*> ForEachResultGenerator(Node* this_arg, Node* o, |
| + Node* len) { |
| + return std::make_pair(UndefinedConstant(), SmiConstant(0)); |
| + } |
| - void SomeProcessor(Node* a, Node* p_k, Node* value) { |
| + Node* ForEachProcessor(Node* context, Node* callbackfn, Node* this_arg, |
| + Node* k_value, Node* k, Node* o, Node* a) { |
| + CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, k_value, |
| + k, o); |
| + return a; |
| + } |
| + |
| + std::pair<Node*, Node*> SomeResultGenerator(Node* this_arg, Node* o, |
| + Node* len) { |
| + return std::make_pair(FalseConstant(), SmiConstant(0)); |
| + } |
| + |
| + Node* SomeProcessor(Node* context, Node* callbackfn, Node* this_arg, |
| + Node* k_value, Node* k, Node* o, Node* a) { |
| + Node* value = CallJS(CodeFactory::Call(isolate()), context, callbackfn, |
| + this_arg, k_value, k, o); |
| Label false_continue(this), return_true(this); |
| BranchIfToBooleanIsTrue(value, &return_true, &false_continue); |
| Bind(&return_true); |
| Return(TrueConstant()); |
| Bind(&false_continue); |
| + return a; |
| + } |
| + |
| + std::pair<Node*, Node*> EveryResultGenerator(Node* this_arg, Node* o, |
| + Node* len) { |
| + return std::make_pair(TrueConstant(), SmiConstant(0)); |
| } |
| - void EveryProcessor(Node* a, Node* p_k, Node* value) { |
| + Node* EveryProcessor(Node* context, Node* callbackfn, Node* this_arg, |
| + Node* k_value, Node* k, Node* o, Node* a) { |
| + Node* value = CallJS(CodeFactory::Call(isolate()), context, callbackfn, |
| + this_arg, k_value, k, o); |
| Label true_continue(this), return_false(this); |
| BranchIfToBooleanIsTrue(value, &true_continue, &return_false); |
| Bind(&return_false); |
| Return(FalseConstant()); |
| Bind(&true_continue); |
| + return a; |
| + } |
| + |
| + std::pair<Node*, Node*> ReduceResultGenerator(Node* initial_value, Node* o, |
| + Node* len) { |
| + Variable a(this, MachineRepresentation::kTagged, UndefinedConstant()); |
| + Label no_initial_value(this), has_initial_value(this), done(this, {&a}); |
| + |
| + // 8. If initialValue is present, then |
| + Node* parent_frame_ptr = LoadParentFramePointer(); |
| + Node* marker_or_function = LoadBufferObject( |
| + parent_frame_ptr, CommonFrameConstants::kContextOrFrameTypeOffset); |
| + GotoIf( |
| + MarkerIsNotFrameType(marker_or_function, StackFrame::ARGUMENTS_ADAPTOR), |
| + &has_initial_value); |
| + |
| + // Has arguments adapter, check count. |
| + Node* adapted_parameter_count = LoadBufferObject( |
| + parent_frame_ptr, ArgumentsAdaptorFrameConstants::kLengthOffset); |
| + Branch(SmiLessThan(adapted_parameter_count, |
| + SmiConstant(IteratingArrayBuiltinDescriptor::kThisArg)), |
| + &no_initial_value, &has_initial_value); |
| + |
| + // a. Set accumulator to initialValue. |
| + Bind(&has_initial_value); |
| + a.Bind(initial_value); |
| + Goto(&done); |
| + |
| + // 9. Else initialValue is not present, |
| + Bind(&no_initial_value); |
| + |
| + // a. Let kPresent be false. |
| + a.Bind(TheHoleConstant()); |
| + Goto(&done); |
| + Bind(&done); |
| + return std::make_pair(a.value(), SmiConstant(0)); |
| } |
| + Node* ReduceProcessor(Node* context, Node* callbackfn, Node* this_arg, |
| + Node* k_value, Node* k, Node* o, Node* a) { |
| + Variable result(this, 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 ReducePostLoopAction(Node* context, Node* a) { |
| + Label ok(this); |
| + GotoIf(WordNotEqual(a, TheHoleConstant()), &ok); |
| + CallRuntime(Runtime::kThrowTypeError, context, |
| + SmiConstant(MessageTemplate::kReduceNoInitial)); |
| + Unreachable(); |
| + Bind(&ok); |
| + } |
| + |
| + void NullPostLoopAction(Node* context, Node* a) {} |
| + |
| private: |
| Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind, |
| Node* this_arg, Node* o, Node* len, |
| Node* callbackfn, |
| const CallResultProcessor& processor, |
| - Node* a, Label* array_changed, |
| + Variable& a, Label* array_changed, |
| ParameterMode mode) { |
| Comment("begin VisitAllFastElementsOneKind"); |
| Variable original_map(this, MachineRepresentation::kTagged); |
| original_map.Bind(LoadMap(o)); |
| - VariableList list({&original_map}, zone()); |
| + VariableList list({&original_map, &a}, zone()); |
| Node* last_index = nullptr; |
| BuildFastLoop( |
| list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), |
| - [=, &original_map, &last_index](Node* index) { |
| + [=, &a, &original_map, &last_index](Node* index) { |
| last_index = index; |
| Label one_element_done(this), hole_element(this); |
| @@ -231,9 +337,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| LoadDoubleWithHoleCheck(elements, offset, &hole_element); |
| value = AllocateHeapNumberWithValue(double_value); |
| } |
| - Node* result = CallJS(CodeFactory::Call(isolate()), context, |
| - callbackfn, this_arg, value, tagged_index, o); |
| - processor(a, tagged_index, result); |
| + a.Bind(processor(this, context, callbackfn, this_arg, value, |
| + tagged_index, o, a.value())); |
| Goto(&one_element_done); |
| Bind(&hole_element); |
| @@ -250,8 +355,10 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| } |
| void HandleFastElements(Node* context, Node* this_arg, Node* o, Node* len, |
| - Node* callbackfn, CallResultProcessor processor, |
| - Node* a, Variable& k, Label* slow) { |
| + Node* callbackfn, |
| + const CallResultProcessor& processor, |
| + const PostLoopAction& action, Variable& a, |
| + Variable& k, Label* slow) { |
| Label switch_on_elements_kind(this), fast_elements(this), |
| maybe_double_elements(this), fast_double_elements(this); |
| @@ -279,8 +386,10 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| context, FAST_ELEMENTS, this_arg, o, len, callbackfn, processor, a, |
| &array_changed, mode); |
| + action(this, context, a.value()); |
| + |
| // No exception, return success |
| - Return(a); |
| + Return(a.value()); |
| Bind(&array_changed); |
| k.Bind(ParameterToTagged(last_index, mode)); |
| @@ -298,8 +407,10 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, callbackfn, |
| processor, a, &array_changed, mode); |
| + action(this, context, a.value()); |
| + |
| // No exception, return success |
| - Return(a); |
| + Return(a.value()); |
| Bind(&array_changed); |
| k.Bind(ParameterToTagged(last_index, mode)); |
| @@ -464,51 +575,64 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) { |
| TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
| GenerateIteratingArrayBuiltinLoopContinuation( |
| - [this](Node* a, Node* p_k, Node* value) { |
| - ForEachProcessor(a, p_k, value); |
| - }); |
| + &ArrayBuiltinCodeStubAssembler::ForEachProcessor, |
| + &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); |
| } |
| TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { |
| GenerateIteratingArrayBuiltinBody( |
| "Array.prototype.forEach", |
| - [=](Node*, Node*) { return UndefinedConstant(); }, |
| - [this](Node* a, Node* p_k, Node* value) { |
| - ForEachProcessor(a, p_k, value); |
| - }, |
| + &ArrayBuiltinCodeStubAssembler::ForEachResultGenerator, |
| + &ArrayBuiltinCodeStubAssembler::ForEachProcessor, |
| + &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, |
| CodeFactory::ArrayForEachLoopContinuation(isolate())); |
| } |
| TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
| GenerateIteratingArrayBuiltinLoopContinuation( |
| - [this](Node* a, Node* p_k, Node* value) { |
| - SomeProcessor(a, p_k, value); |
| - }); |
| + &ArrayBuiltinCodeStubAssembler::SomeProcessor, |
| + &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); |
| } |
| TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) { |
| GenerateIteratingArrayBuiltinBody( |
| - "Array.prototype.some", [=](Node*, Node*) { return FalseConstant(); }, |
| - [this](Node* a, Node* p_k, Node* value) { SomeProcessor(a, p_k, value); }, |
| + "Array.prototype.some", |
| + &ArrayBuiltinCodeStubAssembler::SomeResultGenerator, |
| + &ArrayBuiltinCodeStubAssembler::SomeProcessor, |
| + &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, |
| CodeFactory::ArraySomeLoopContinuation(isolate())); |
| } |
| TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
| GenerateIteratingArrayBuiltinLoopContinuation( |
| - [this](Node* a, Node* p_k, Node* value) { |
| - EveryProcessor(a, p_k, value); |
| - }); |
| + &ArrayBuiltinCodeStubAssembler::EveryProcessor, |
| + &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); |
| } |
| TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) { |
| GenerateIteratingArrayBuiltinBody( |
| - "Array.prototype.every", [=](Node*, Node*) { return TrueConstant(); }, |
| - [this](Node* a, Node* p_k, Node* value) { |
| - EveryProcessor(a, p_k, value); |
| - }, |
| + "Array.prototype.every", |
| + &ArrayBuiltinCodeStubAssembler::EveryResultGenerator, |
| + &ArrayBuiltinCodeStubAssembler::EveryProcessor, |
| + &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, |
| CodeFactory::ArrayEveryLoopContinuation(isolate())); |
| } |
| +TF_BUILTIN(ArrayReduceLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
| + GenerateIteratingArrayBuiltinLoopContinuation( |
| + &ArrayBuiltinCodeStubAssembler::ReduceProcessor, |
| + &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction); |
| +} |
| + |
| +TF_BUILTIN(ArrayReduce, ArrayBuiltinCodeStubAssembler) { |
| + GenerateIteratingArrayBuiltinBody( |
| + "Array.prototype.reduce", |
| + &ArrayBuiltinCodeStubAssembler::ReduceResultGenerator, |
| + &ArrayBuiltinCodeStubAssembler::ReduceProcessor, |
| + &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction, |
| + CodeFactory::ArrayReduceLoopContinuation(isolate())); |
| +} |
| + |
| TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { |
| Node* object = Parameter(1); |
| Node* context = Parameter(4); |