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); |