Commit 6141f6e2 authored by danno's avatar danno Committed by Commit bot

[builtins] Implement Array.prototype.reduceRight in the CSA

BUG=v8:1956

Review-Url: https://codereview.chromium.org/2776433003
Cr-Commit-Position: refs/heads/master@{#44105}
parent 8b8dfda8
...@@ -4197,6 +4197,10 @@ bool Genesis::InstallNatives(GlobalContextType context_type) { ...@@ -4197,6 +4197,10 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
// Install Array.prototype.reduce // Install Array.prototype.reduce
InstallArrayBuiltinFunction(proto, "reduce", Builtins::kArrayReduce, 2); InstallArrayBuiltinFunction(proto, "reduce", Builtins::kArrayReduce, 2);
// Install Array.prototype.reduceRight
InstallArrayBuiltinFunction(proto, "reduceRight",
Builtins::kArrayReduceRight, 2);
} }
// Install InternalArray.prototype.concat // Install InternalArray.prototype.concat
......
...@@ -194,7 +194,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -194,7 +194,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
void GenerateIteratingArrayBuiltinBody( void GenerateIteratingArrayBuiltinBody(
const char* name, const BuiltinResultGenerator& generator, const char* name, const BuiltinResultGenerator& generator,
const CallResultProcessor& processor, const PostLoopAction& action, const CallResultProcessor& processor, const PostLoopAction& action,
const Callable& slow_case_continuation) { const Callable& slow_case_continuation,
ForEachDirection direction = ForEachDirection::kForward) {
Label non_array(this), slow(this, {&k_, &a_, &to_}), Label non_array(this), slow(this, {&k_, &a_, &to_}),
array_changes(this, {&k_, &a_, &to_}); array_changes(this, {&k_, &a_, &to_});
...@@ -256,12 +257,17 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -256,12 +257,17 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
// 6. If thisArg was supplied, let T be thisArg; else let T be undefined. // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
// [Already done by the arguments adapter] // [Already done by the arguments adapter]
// 7. Let k be 0. if (direction == ForEachDirection::kForward) {
// [Already done in code assembler initialization] // 7. Let k be 0.
k_.Bind(SmiConstant(0));
} else {
k_.Bind(len());
k_.Bind(NumberDec(k_.value()));
}
a_.Bind(generator(this)); a_.Bind(generator(this));
HandleFastElements(processor, action, &slow); HandleFastElements(processor, action, &slow, direction);
Bind(&slow); Bind(&slow);
...@@ -290,14 +296,21 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -290,14 +296,21 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
} }
void GenerateIteratingArrayBuiltinLoopContinuation( void GenerateIteratingArrayBuiltinLoopContinuation(
const CallResultProcessor& processor, const PostLoopAction& action) { const CallResultProcessor& processor, const PostLoopAction& action,
// 8. Repeat, while k < len ForEachDirection direction = ForEachDirection::kForward) {
Label loop(this, {&k_, &a_, &to_}); Label loop(this, {&k_, &a_, &to_});
Label after_loop(this); Label after_loop(this);
Goto(&loop); Goto(&loop);
Bind(&loop); Bind(&loop);
{ {
GotoUnlessNumberLessThan(k(), len_, &after_loop); if (direction == ForEachDirection::kForward) {
// 8. Repeat, while k < len
GotoUnlessNumberLessThan(k(), len_, &after_loop);
} else {
// OR
// 10. Repeat, while k >= 0
GotoUnlessNumberLessThan(SmiConstant(-1), k(), &after_loop);
}
Label done_element(this, &to_); Label done_element(this, &to_);
// a. Let Pk be ToString(k). // a. Let Pk be ToString(k).
...@@ -321,8 +334,13 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -321,8 +334,13 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
Bind(&done_element); Bind(&done_element);
// e. Increase k by 1. if (direction == ForEachDirection::kForward) {
k_.Bind(NumberInc(k_.value())); // e. Increase k by 1.
k_.Bind(NumberInc(k()));
} else {
// e. Decrease k by 1.
k_.Bind(NumberDec(k()));
}
Goto(&loop); Goto(&loop);
} }
Bind(&after_loop); Bind(&after_loop);
...@@ -334,13 +352,20 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -334,13 +352,20 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
private: private:
void VisitAllFastElementsOneKind(ElementsKind kind, void VisitAllFastElementsOneKind(ElementsKind kind,
const CallResultProcessor& processor, const CallResultProcessor& processor,
Label* array_changed, ParameterMode mode) { Label* array_changed, ParameterMode mode,
ForEachDirection direction) {
Comment("begin VisitAllFastElementsOneKind"); Comment("begin VisitAllFastElementsOneKind");
Variable original_map(this, MachineRepresentation::kTagged); Variable original_map(this, MachineRepresentation::kTagged);
original_map.Bind(LoadMap(o())); original_map.Bind(LoadMap(o()));
VariableList list({&original_map, &a_, &k_, &to_}, zone()); VariableList list({&original_map, &a_, &k_, &to_}, zone());
Node* start = IntPtrOrSmiConstant(0, mode);
Node* end = TaggedToParameter(len(), mode);
IndexAdvanceMode advance_mode = direction == ForEachDirection::kReverse
? IndexAdvanceMode::kPre
: IndexAdvanceMode::kPost;
if (direction == ForEachDirection::kReverse) std::swap(start, end);
BuildFastLoop( BuildFastLoop(
list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len(), mode), list, start, end,
[=, &original_map](Node* index) { [=, &original_map](Node* index) {
k_.Bind(ParameterToTagged(index, mode)); k_.Bind(ParameterToTagged(index, mode));
Label one_element_done(this), hole_element(this); Label one_element_done(this), hole_element(this);
...@@ -386,12 +411,13 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -386,12 +411,13 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
Bind(&one_element_done); Bind(&one_element_done);
}, },
1, mode, IndexAdvanceMode::kPost); 1, mode, advance_mode);
Comment("end VisitAllFastElementsOneKind"); Comment("end VisitAllFastElementsOneKind");
} }
void HandleFastElements(const CallResultProcessor& processor, void HandleFastElements(const CallResultProcessor& processor,
const PostLoopAction& action, Label* slow) { const PostLoopAction& action, Label* slow,
ForEachDirection direction) {
Label switch_on_elements_kind(this), fast_elements(this), Label switch_on_elements_kind(this), fast_elements(this),
maybe_double_elements(this), fast_double_elements(this); maybe_double_elements(this), fast_double_elements(this);
...@@ -414,7 +440,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -414,7 +440,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
ParameterMode mode = OptimalParameterMode(); ParameterMode mode = OptimalParameterMode();
Bind(&fast_elements); Bind(&fast_elements);
{ {
VisitAllFastElementsOneKind(FAST_ELEMENTS, processor, slow, mode); VisitAllFastElementsOneKind(FAST_ELEMENTS, processor, slow, mode,
direction);
action(this); action(this);
...@@ -428,7 +455,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -428,7 +455,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
Bind(&fast_double_elements); Bind(&fast_double_elements);
{ {
VisitAllFastElementsOneKind(FAST_DOUBLE_ELEMENTS, processor, slow, mode); VisitAllFastElementsOneKind(FAST_DOUBLE_ELEMENTS, processor, slow, mode,
direction);
action(this); action(this);
...@@ -757,6 +785,46 @@ TF_BUILTIN(ArrayReduce, ArrayBuiltinCodeStubAssembler) { ...@@ -757,6 +785,46 @@ TF_BUILTIN(ArrayReduce, ArrayBuiltinCodeStubAssembler) {
CodeFactory::ArrayReduceLoopContinuation(isolate())); CodeFactory::ArrayReduceLoopContinuation(isolate()));
} }
TF_BUILTIN(ArrayReduceRightLoopContinuation, ArrayBuiltinCodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* receiver = Parameter(Descriptor::kReceiver);
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
Node* this_arg = Parameter(Descriptor::kThisArg);
Node* accumulator = Parameter(Descriptor::kAccumulator);
Node* object = Parameter(Descriptor::kObject);
Node* initial_k = Parameter(Descriptor::kInitialK);
Node* len = Parameter(Descriptor::kLength);
Node* to = Parameter(Descriptor::kTo);
InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
this_arg, accumulator, object,
initial_k, len, to);
GenerateIteratingArrayBuiltinLoopContinuation(
&ArrayBuiltinCodeStubAssembler::ReduceProcessor,
&ArrayBuiltinCodeStubAssembler::ReducePostLoopAction,
ForEachDirection::kReverse);
}
TF_BUILTIN(ArrayReduceRight, ArrayBuiltinCodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* receiver = Parameter(Descriptor::kReceiver);
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
Node* initial_value = Parameter(Descriptor::kInitialValue);
Node* new_target = Parameter(Descriptor::kNewTarget);
InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
new_target);
GenerateIteratingArrayBuiltinBody(
"Array.prototype.reduceRight",
&ArrayBuiltinCodeStubAssembler::ReduceResultGenerator,
&ArrayBuiltinCodeStubAssembler::ReduceProcessor,
&ArrayBuiltinCodeStubAssembler::ReducePostLoopAction,
CodeFactory::ArrayReduceRightLoopContinuation(isolate()),
ForEachDirection::kReverse);
}
TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinCodeStubAssembler) { TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinCodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext); Node* context = Parameter(Descriptor::kContext);
Node* receiver = Parameter(Descriptor::kReceiver); Node* receiver = Parameter(Descriptor::kReceiver);
......
...@@ -308,6 +308,10 @@ class Isolate; ...@@ -308,6 +308,10 @@ class Isolate;
TFJ(ArrayReduceLoopContinuation, 7, kCallbackFn, kThisArg, kAccumulator, \ TFJ(ArrayReduceLoopContinuation, 7, kCallbackFn, kThisArg, kAccumulator, \
kObject, kInitialK, kLength, kTo) \ kObject, kInitialK, kLength, kTo) \
TFJ(ArrayReduce, 2, kCallbackFn, kInitialValue) \ TFJ(ArrayReduce, 2, kCallbackFn, kInitialValue) \
/* ES6 #sec-array.prototype.reduceRight */ \
TFJ(ArrayReduceRightLoopContinuation, 7, kCallbackFn, kThisArg, \
kAccumulator, kObject, kInitialK, kLength, kTo) \
TFJ(ArrayReduceRight, 2, kCallbackFn, kInitialValue) \
/* ES6 #sec-array.prototype.entries */ \ /* ES6 #sec-array.prototype.entries */ \
TFJ(ArrayPrototypeEntries, 0) \ TFJ(ArrayPrototypeEntries, 0) \
/* ES6 #sec-array.prototype.keys */ \ /* ES6 #sec-array.prototype.keys */ \
......
...@@ -543,6 +543,12 @@ Callable CodeFactory::ArrayReduceLoopContinuation(Isolate* isolate) { ...@@ -543,6 +543,12 @@ Callable CodeFactory::ArrayReduceLoopContinuation(Isolate* isolate) {
IteratingArrayBuiltinLoopContinuationDescriptor(isolate)); IteratingArrayBuiltinLoopContinuationDescriptor(isolate));
} }
// static
Callable CodeFactory::ArrayReduceRightLoopContinuation(Isolate* isolate) {
return Callable(isolate->builtins()->ArrayReduceRightLoopContinuation(),
IteratingArrayBuiltinLoopContinuationDescriptor(isolate));
}
// static // static
Callable CodeFactory::FunctionPrototypeBind(Isolate* isolate) { Callable CodeFactory::FunctionPrototypeBind(Isolate* isolate) {
return Callable(isolate->builtins()->FunctionPrototypeBind(), return Callable(isolate->builtins()->FunctionPrototypeBind(),
......
...@@ -190,6 +190,7 @@ class V8_EXPORT_PRIVATE CodeFactory final { ...@@ -190,6 +190,7 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable ArraySomeLoopContinuation(Isolate* isolate); static Callable ArraySomeLoopContinuation(Isolate* isolate);
static Callable ArrayEveryLoopContinuation(Isolate* isolate); static Callable ArrayEveryLoopContinuation(Isolate* isolate);
static Callable ArrayReduceLoopContinuation(Isolate* isolate); static Callable ArrayReduceLoopContinuation(Isolate* isolate);
static Callable ArrayReduceRightLoopContinuation(Isolate* isolate);
static Callable FunctionPrototypeBind(Isolate* isolate); static Callable FunctionPrototypeBind(Isolate* isolate);
static Callable PromiseHandleReject(Isolate* isolate); static Callable PromiseHandleReject(Isolate* isolate);
}; };
......
...@@ -7860,6 +7860,58 @@ Node* CodeStubAssembler::NumberInc(Node* value) { ...@@ -7860,6 +7860,58 @@ Node* CodeStubAssembler::NumberInc(Node* value) {
return var_result.value(); return var_result.value();
} }
Node* CodeStubAssembler::NumberDec(Node* value) {
Variable var_result(this, MachineRepresentation::kTagged),
var_fdec_value(this, MachineRepresentation::kFloat64);
Label if_issmi(this), if_isnotsmi(this), do_fdec(this), end(this);
Branch(TaggedIsSmi(value), &if_issmi, &if_isnotsmi);
Bind(&if_issmi);
{
// Try fast Smi addition first.
Node* one = SmiConstant(Smi::FromInt(1));
Node* pair = IntPtrSubWithOverflow(BitcastTaggedToWord(value),
BitcastTaggedToWord(one));
Node* overflow = Projection(1, pair);
// Check if the Smi addition overflowed.
Label if_overflow(this), if_notoverflow(this);
Branch(overflow, &if_overflow, &if_notoverflow);
Bind(&if_notoverflow);
var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
Goto(&end);
Bind(&if_overflow);
{
var_fdec_value.Bind(SmiToFloat64(value));
Goto(&do_fdec);
}
}
Bind(&if_isnotsmi);
{
// Check if the value is a HeapNumber.
CSA_ASSERT(this, IsHeapNumberMap(LoadMap(value)));
// Load the HeapNumber value.
var_fdec_value.Bind(LoadHeapNumberValue(value));
Goto(&do_fdec);
}
Bind(&do_fdec);
{
Node* fdec_value = var_fdec_value.value();
Node* minus_one = Float64Constant(-1.0);
Node* fdec_result = Float64Add(fdec_value, minus_one);
var_result.Bind(AllocateHeapNumberWithValue(fdec_result));
Goto(&end);
}
Bind(&end);
return var_result.value();
}
void CodeStubAssembler::GotoIfNotNumber(Node* input, Label* is_not_number) { void CodeStubAssembler::GotoIfNotNumber(Node* input, Label* is_not_number) {
Label is_number(this); Label is_number(this);
GotoIf(TaggedIsSmi(input), &is_number); GotoIf(TaggedIsSmi(input), &is_number);
......
...@@ -240,6 +240,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -240,6 +240,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
// Smi | HeapNumber operations. // Smi | HeapNumber operations.
Node* NumberInc(Node* value); Node* NumberInc(Node* value);
Node* NumberDec(Node* value);
void GotoIfNotNumber(Node* value, Label* is_not_number); void GotoIfNotNumber(Node* value, Label* is_not_number);
void GotoIfNumber(Node* value, Label* is_number); void GotoIfNumber(Node* value, Label* is_number);
......
...@@ -442,6 +442,7 @@ bool BuiltinHasNoSideEffect(Builtins::Name id) { ...@@ -442,6 +442,7 @@ bool BuiltinHasNoSideEffect(Builtins::Name id) {
case Builtins::kArrayEvery: case Builtins::kArrayEvery:
case Builtins::kArraySome: case Builtins::kArraySome:
case Builtins::kArrayReduce: case Builtins::kArrayReduce:
case Builtins::kArrayReduceRight:
// Boolean bulitins. // Boolean bulitins.
case Builtins::kBooleanConstructor: case Builtins::kBooleanConstructor:
case Builtins::kBooleanPrototypeToString: case Builtins::kBooleanPrototypeToString:
......
...@@ -1106,45 +1106,6 @@ function ArrayLastIndexOf(element, index) { ...@@ -1106,45 +1106,6 @@ function ArrayLastIndexOf(element, index) {
return -1; return -1;
} }
function InnerArrayReduceRight(callback, current, array, length,
argumentsLength) {
if (!IS_CALLABLE(callback)) {
throw %make_type_error(kCalledNonCallable, callback);
}
var i = length - 1;
find_initial: if (argumentsLength < 2) {
for (; i >= 0; i--) {
if (i in array) {
current = array[i--];
break find_initial;
}
}
throw %make_type_error(kReduceNoInitial);
}
for (; i >= 0; i--) {
if (i in array) {
var element = array[i];
current = callback(current, element, i, array);
}
}
return current;
}
function ArrayReduceRight(callback, current) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reduceRight");
// Pull out the length so that side effects are visible before the
// callback function is checked.
var array = TO_OBJECT(this);
var length = TO_LENGTH(array.length);
return InnerArrayReduceRight(callback, current, array, length,
arguments.length);
}
// ES#sec-array.prototype.copywithin // ES#sec-array.prototype.copywithin
// (Array.prototype.copyWithin ( target, start [ , end ] ) // (Array.prototype.copyWithin ( target, start [ , end ] )
function ArrayCopyWithin(target, start, end) { function ArrayCopyWithin(target, start, end) {
...@@ -1425,7 +1386,6 @@ utils.InstallFunctions(GlobalArray.prototype, DONT_ENUM, [ ...@@ -1425,7 +1386,6 @@ utils.InstallFunctions(GlobalArray.prototype, DONT_ENUM, [
"map", getFunction("map", ArrayMap, 1), "map", getFunction("map", ArrayMap, 1),
"indexOf", getFunction("indexOf", null, 1), "indexOf", getFunction("indexOf", null, 1),
"lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1), "lastIndexOf", getFunction("lastIndexOf", ArrayLastIndexOf, 1),
"reduceRight", getFunction("reduceRight", ArrayReduceRight, 1),
"copyWithin", getFunction("copyWithin", ArrayCopyWithin, 2), "copyWithin", getFunction("copyWithin", ArrayCopyWithin, 2),
"find", getFunction("find", ArrayFind, 1), "find", getFunction("find", ArrayFind, 1),
"findIndex", getFunction("findIndex", ArrayFindIndex, 1), "findIndex", getFunction("findIndex", ArrayFindIndex, 1),
...@@ -1484,7 +1444,6 @@ utils.Export(function(to) { ...@@ -1484,7 +1444,6 @@ utils.Export(function(to) {
to.InnerArrayFind = InnerArrayFind; to.InnerArrayFind = InnerArrayFind;
to.InnerArrayFindIndex = InnerArrayFindIndex; to.InnerArrayFindIndex = InnerArrayFindIndex;
to.InnerArrayJoin = InnerArrayJoin; to.InnerArrayJoin = InnerArrayJoin;
to.InnerArrayReduceRight = InnerArrayReduceRight;
to.InnerArraySort = InnerArraySort; to.InnerArraySort = InnerArraySort;
to.InnerArrayToLocaleString = InnerArrayToLocaleString; to.InnerArrayToLocaleString = InnerArrayToLocaleString;
to.PackedArrayReverse = PackedArrayReverse; to.PackedArrayReverse = PackedArrayReverse;
......
...@@ -24,7 +24,6 @@ var InnerArrayFilter; ...@@ -24,7 +24,6 @@ var InnerArrayFilter;
var InnerArrayFind; var InnerArrayFind;
var InnerArrayFindIndex; var InnerArrayFindIndex;
var InnerArrayJoin; var InnerArrayJoin;
var InnerArrayReduceRight;
var InnerArraySort; var InnerArraySort;
var InnerArrayToLocaleString; var InnerArrayToLocaleString;
var InternalArray = utils.InternalArray; var InternalArray = utils.InternalArray;
...@@ -66,7 +65,6 @@ utils.Import(function(from) { ...@@ -66,7 +65,6 @@ utils.Import(function(from) {
InnerArrayFind = from.InnerArrayFind; InnerArrayFind = from.InnerArrayFind;
InnerArrayFindIndex = from.InnerArrayFindIndex; InnerArrayFindIndex = from.InnerArrayFindIndex;
InnerArrayJoin = from.InnerArrayJoin; InnerArrayJoin = from.InnerArrayJoin;
InnerArrayReduceRight = from.InnerArrayReduceRight;
InnerArraySort = from.InnerArraySort; InnerArraySort = from.InnerArraySort;
InnerArrayToLocaleString = from.InnerArrayToLocaleString; InnerArrayToLocaleString = from.InnerArrayToLocaleString;
MaxSimple = from.MaxSimple; MaxSimple = from.MaxSimple;
...@@ -572,6 +570,31 @@ function TypedArrayReduce(callback, current) { ...@@ -572,6 +570,31 @@ function TypedArrayReduce(callback, current) {
} }
%FunctionSetLength(TypedArrayReduce, 1); %FunctionSetLength(TypedArrayReduce, 1);
function InnerArrayReduceRight(callback, current, array, length,
argumentsLength) {
if (!IS_CALLABLE(callback)) {
throw %make_type_error(kCalledNonCallable, callback);
}
var i = length - 1;
find_initial: if (argumentsLength < 2) {
for (; i >= 0; i--) {
if (i in array) {
current = array[i--];
break find_initial;
}
}
throw %make_type_error(kReduceNoInitial);
}
for (; i >= 0; i--) {
if (i in array) {
var element = array[i];
current = callback(current, element, i, array);
}
}
return current;
}
// ES6 draft 07-15-13, section 22.2.3.19 // ES6 draft 07-15-13, section 22.2.3.19
function TypedArrayReduceRight(callback, current) { function TypedArrayReduceRight(callback, current) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment