[builtins] Port Array.p.{find,findIndex} to CSA
- Removes JS implementation and InnerArrayFind/InnerArrayFindIndex - Adds TFJ, with TFS for slow continuation path Some quick benchmarks show ~2x improvement for unoptimized code and up to 16% improvement against optimized code (diminishes with larger arrays as iterating dominates). https://github.com/peterwmwong/v8-perf/blob/master/array-find-findIndex/README.md Bug: chromium:791045, v8:1956, v8:5049, v8:7165 Change-Id: Ie16252ed495bbd91fe548b16d5ef6764de791a50 Reviewed-on: https://chromium-review.googlesource.com/804704 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#49851}
This commit is contained in:
parent
cc07ac73a4
commit
99b5f699ab
@ -1679,6 +1679,10 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
DONT_ENUM);
|
||||
|
||||
SimpleInstallFunction(proto, "concat", Builtins::kArrayConcat, 1, false);
|
||||
SimpleInstallFunction(proto, "find", Builtins::kArrayPrototypeFind, 1,
|
||||
false);
|
||||
SimpleInstallFunction(proto, "findIndex",
|
||||
Builtins::kArrayPrototypeFindIndex, 1, false);
|
||||
SimpleInstallFunction(proto, "pop", Builtins::kFastArrayPop, 0, false);
|
||||
SimpleInstallFunction(proto, "push", Builtins::kFastArrayPush, 1, false);
|
||||
SimpleInstallFunction(proto, "shift", Builtins::kFastArrayShift, 0, false);
|
||||
|
@ -31,6 +31,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
|
||||
typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)>
|
||||
PostLoopAction;
|
||||
|
||||
enum class MissingPropertyMode { kSkip, kUseUndefined };
|
||||
|
||||
void FindResultGenerator() { a_.Bind(UndefinedConstant()); }
|
||||
|
||||
Node* FindProcessor(Node* k_value, Node* k) {
|
||||
@ -383,6 +385,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
|
||||
const char* name, const BuiltinResultGenerator& generator,
|
||||
const CallResultProcessor& processor, const PostLoopAction& action,
|
||||
const Callable& slow_case_continuation,
|
||||
MissingPropertyMode missing_property_mode,
|
||||
ForEachDirection direction = ForEachDirection::kForward) {
|
||||
Label non_array(this), array_changes(this, {&k_, &a_, &to_});
|
||||
|
||||
@ -439,7 +442,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
|
||||
|
||||
generator(this);
|
||||
|
||||
HandleFastElements(processor, action, &fully_spec_compliant_, direction);
|
||||
HandleFastElements(processor, action, &fully_spec_compliant_, direction,
|
||||
missing_property_mode);
|
||||
|
||||
BIND(&fully_spec_compliant_);
|
||||
|
||||
@ -550,6 +554,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
|
||||
|
||||
void GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
const CallResultProcessor& processor, const PostLoopAction& action,
|
||||
MissingPropertyMode missing_property_mode,
|
||||
ForEachDirection direction = ForEachDirection::kForward) {
|
||||
Label loop(this, {&k_, &a_, &to_});
|
||||
Label after_loop(this);
|
||||
@ -572,12 +577,14 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
|
||||
// index in the range [0, 2^32-1).
|
||||
CSA_ASSERT(this, IsNumberArrayIndex(k()));
|
||||
|
||||
// b. Let kPresent be HasProperty(O, Pk).
|
||||
// c. ReturnIfAbrupt(kPresent).
|
||||
Node* k_present = HasProperty(o(), k(), context(), kHasProperty);
|
||||
if (missing_property_mode == MissingPropertyMode::kSkip) {
|
||||
// b. Let kPresent be HasProperty(O, Pk).
|
||||
// c. ReturnIfAbrupt(kPresent).
|
||||
Node* k_present = HasProperty(o(), k(), context(), kHasProperty);
|
||||
|
||||
// d. If kPresent is true, then
|
||||
GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element);
|
||||
// d. If kPresent is true, then
|
||||
GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element);
|
||||
}
|
||||
|
||||
// i. Let kValue be Get(O, Pk).
|
||||
// ii. ReturnIfAbrupt(kValue).
|
||||
@ -655,7 +662,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
|
||||
void VisitAllFastElementsOneKind(ElementsKind kind,
|
||||
const CallResultProcessor& processor,
|
||||
Label* array_changed, ParameterMode mode,
|
||||
ForEachDirection direction) {
|
||||
ForEachDirection direction,
|
||||
MissingPropertyMode missing_property_mode) {
|
||||
Comment("begin VisitAllFastElementsOneKind");
|
||||
VARIABLE(original_map, MachineRepresentation::kTagged);
|
||||
original_map.Bind(LoadMap(o()));
|
||||
@ -670,7 +678,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
|
||||
list, start, end,
|
||||
[=, &original_map](Node* index) {
|
||||
k_.Bind(ParameterToTagged(index, mode));
|
||||
Label one_element_done(this), hole_element(this);
|
||||
Label one_element_done(this), hole_element(this),
|
||||
process_element(this);
|
||||
|
||||
// Check if o's map has changed during the callback. If so, we have to
|
||||
// fall back to the slower spec implementation for the rest of the
|
||||
@ -693,24 +702,32 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
|
||||
? FixedArray::kHeaderSize
|
||||
: (FixedArray::kHeaderSize - kHeapObjectTag);
|
||||
Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size);
|
||||
Node* value = nullptr;
|
||||
VARIABLE(value, MachineRepresentation::kTagged);
|
||||
if (kind == PACKED_ELEMENTS) {
|
||||
value = LoadObjectField(elements, offset);
|
||||
GotoIf(WordEqual(value, TheHoleConstant()), &hole_element);
|
||||
value.Bind(LoadObjectField(elements, offset));
|
||||
GotoIf(WordEqual(value.value(), TheHoleConstant()), &hole_element);
|
||||
} else {
|
||||
Node* double_value =
|
||||
LoadDoubleWithHoleCheck(elements, offset, &hole_element);
|
||||
value = AllocateHeapNumberWithValue(double_value);
|
||||
value.Bind(AllocateHeapNumberWithValue(double_value));
|
||||
}
|
||||
a_.Bind(processor(this, value, k()));
|
||||
Goto(&one_element_done);
|
||||
Goto(&process_element);
|
||||
|
||||
BIND(&hole_element);
|
||||
// Check if o's prototype change unexpectedly has elements after the
|
||||
// callback in the case of a hole.
|
||||
BranchIfPrototypesHaveNoElements(o_map, &one_element_done,
|
||||
array_changed);
|
||||
|
||||
if (missing_property_mode == MissingPropertyMode::kSkip) {
|
||||
// Check if o's prototype change unexpectedly has elements after
|
||||
// the callback in the case of a hole.
|
||||
BranchIfPrototypesHaveNoElements(o_map, &one_element_done,
|
||||
array_changed);
|
||||
} else {
|
||||
value.Bind(UndefinedConstant());
|
||||
Goto(&process_element);
|
||||
}
|
||||
BIND(&process_element);
|
||||
{
|
||||
a_.Bind(processor(this, value.value(), k()));
|
||||
Goto(&one_element_done);
|
||||
}
|
||||
BIND(&one_element_done);
|
||||
},
|
||||
1, mode, advance_mode);
|
||||
@ -719,7 +736,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
|
||||
|
||||
void HandleFastElements(const CallResultProcessor& processor,
|
||||
const PostLoopAction& action, Label* slow,
|
||||
ForEachDirection direction) {
|
||||
ForEachDirection direction,
|
||||
MissingPropertyMode missing_property_mode) {
|
||||
Label switch_on_elements_kind(this), fast_elements(this),
|
||||
maybe_double_elements(this), fast_double_elements(this);
|
||||
|
||||
@ -742,7 +760,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
|
||||
BIND(&fast_elements);
|
||||
{
|
||||
VisitAllFastElementsOneKind(PACKED_ELEMENTS, processor, slow, mode,
|
||||
direction);
|
||||
direction, missing_property_mode);
|
||||
|
||||
action(this);
|
||||
|
||||
@ -757,7 +775,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
|
||||
BIND(&fast_double_elements);
|
||||
{
|
||||
VisitAllFastElementsOneKind(PACKED_DOUBLE_ELEMENTS, processor, slow, mode,
|
||||
direction);
|
||||
direction, missing_property_mode);
|
||||
|
||||
action(this);
|
||||
|
||||
@ -1619,6 +1637,95 @@ TF_BUILTIN(CloneFastJSArray, ArrayBuiltinCodeStubAssembler) {
|
||||
Return(CloneFastJSArray(context, array, mode));
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayFindLoopContinuation, ArrayBuiltinCodeStubAssembler) {
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
Node* receiver = Parameter(Descriptor::kReceiver);
|
||||
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
|
||||
Node* this_arg = Parameter(Descriptor::kThisArg);
|
||||
Node* array = Parameter(Descriptor::kArray);
|
||||
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, array, object, initial_k,
|
||||
len, to);
|
||||
|
||||
GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
&ArrayBuiltinCodeStubAssembler::FindProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
|
||||
}
|
||||
|
||||
// ES #sec-get-%typedarray%.prototype.find
|
||||
TF_BUILTIN(ArrayPrototypeFind, ArrayBuiltinCodeStubAssembler) {
|
||||
Node* argc =
|
||||
ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
|
||||
CodeStubArguments args(this, argc);
|
||||
Node* context = Parameter(BuiltinDescriptor::kContext);
|
||||
Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
|
||||
Node* receiver = args.GetReceiver();
|
||||
Node* callbackfn = args.GetOptionalArgumentValue(0);
|
||||
Node* this_arg = args.GetOptionalArgumentValue(1);
|
||||
|
||||
InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
|
||||
new_target, argc);
|
||||
|
||||
GenerateIteratingArrayBuiltinBody(
|
||||
"Array.prototype.find",
|
||||
&ArrayBuiltinCodeStubAssembler::FindResultGenerator,
|
||||
&ArrayBuiltinCodeStubAssembler::FindProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
Builtins::CallableFor(isolate(), Builtins::kArrayFindLoopContinuation),
|
||||
MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayFindIndexLoopContinuation, ArrayBuiltinCodeStubAssembler) {
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
Node* receiver = Parameter(Descriptor::kReceiver);
|
||||
Node* callbackfn = Parameter(Descriptor::kCallbackFn);
|
||||
Node* this_arg = Parameter(Descriptor::kThisArg);
|
||||
Node* array = Parameter(Descriptor::kArray);
|
||||
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, array, object, initial_k,
|
||||
len, to);
|
||||
|
||||
GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
&ArrayBuiltinCodeStubAssembler::FindIndexProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
|
||||
}
|
||||
|
||||
// ES #sec-get-%typedarray%.prototype.findIndex
|
||||
TF_BUILTIN(ArrayPrototypeFindIndex, ArrayBuiltinCodeStubAssembler) {
|
||||
Node* argc =
|
||||
ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
|
||||
CodeStubArguments args(this, argc);
|
||||
Node* context = Parameter(BuiltinDescriptor::kContext);
|
||||
Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
|
||||
Node* receiver = args.GetReceiver();
|
||||
Node* callbackfn = args.GetOptionalArgumentValue(0);
|
||||
Node* this_arg = args.GetOptionalArgumentValue(1);
|
||||
|
||||
InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
|
||||
new_target, argc);
|
||||
|
||||
GenerateIteratingArrayBuiltinBody(
|
||||
"Array.prototype.findIndex",
|
||||
&ArrayBuiltinCodeStubAssembler::FindIndexResultGenerator,
|
||||
&ArrayBuiltinCodeStubAssembler::FindIndexProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
Builtins::CallableFor(isolate(),
|
||||
Builtins::kArrayFindIndexLoopContinuation),
|
||||
MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
|
||||
}
|
||||
|
||||
// ES #sec-get-%typedarray%.prototype.find
|
||||
TF_BUILTIN(TypedArrayPrototypeFind, ArrayBuiltinCodeStubAssembler) {
|
||||
Node* argc =
|
||||
@ -1678,7 +1785,8 @@ TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinCodeStubAssembler) {
|
||||
|
||||
GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
&ArrayBuiltinCodeStubAssembler::ForEachProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayForEachLoopEagerDeoptContinuation,
|
||||
@ -1731,8 +1839,8 @@ TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) {
|
||||
&ArrayBuiltinCodeStubAssembler::ForEachResultGenerator,
|
||||
&ArrayBuiltinCodeStubAssembler::ForEachProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
Builtins::CallableFor(isolate(),
|
||||
Builtins::kArrayForEachLoopContinuation));
|
||||
Builtins::CallableFor(isolate(), Builtins::kArrayForEachLoopContinuation),
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(TypedArrayPrototypeForEach, ArrayBuiltinCodeStubAssembler) {
|
||||
@ -1772,7 +1880,8 @@ TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinCodeStubAssembler) {
|
||||
|
||||
GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
&ArrayBuiltinCodeStubAssembler::SomeProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) {
|
||||
@ -1793,7 +1902,8 @@ TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) {
|
||||
&ArrayBuiltinCodeStubAssembler::SomeResultGenerator,
|
||||
&ArrayBuiltinCodeStubAssembler::SomeProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
Builtins::CallableFor(isolate(), Builtins::kArraySomeLoopContinuation));
|
||||
Builtins::CallableFor(isolate(), Builtins::kArraySomeLoopContinuation),
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(TypedArrayPrototypeSome, ArrayBuiltinCodeStubAssembler) {
|
||||
@ -1833,7 +1943,8 @@ TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinCodeStubAssembler) {
|
||||
|
||||
GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
&ArrayBuiltinCodeStubAssembler::EveryProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) {
|
||||
@ -1854,7 +1965,8 @@ TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) {
|
||||
&ArrayBuiltinCodeStubAssembler::EveryResultGenerator,
|
||||
&ArrayBuiltinCodeStubAssembler::EveryProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
Builtins::CallableFor(isolate(), Builtins::kArrayEveryLoopContinuation));
|
||||
Builtins::CallableFor(isolate(), Builtins::kArrayEveryLoopContinuation),
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(TypedArrayPrototypeEvery, ArrayBuiltinCodeStubAssembler) {
|
||||
@ -1894,7 +2006,8 @@ TF_BUILTIN(ArrayReduceLoopContinuation, ArrayBuiltinCodeStubAssembler) {
|
||||
|
||||
GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
&ArrayBuiltinCodeStubAssembler::ReduceProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::ReducePostLoopAction);
|
||||
&ArrayBuiltinCodeStubAssembler::ReducePostLoopAction,
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayReduce, ArrayBuiltinCodeStubAssembler) {
|
||||
@ -1915,7 +2028,8 @@ TF_BUILTIN(ArrayReduce, ArrayBuiltinCodeStubAssembler) {
|
||||
&ArrayBuiltinCodeStubAssembler::ReduceResultGenerator,
|
||||
&ArrayBuiltinCodeStubAssembler::ReduceProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::ReducePostLoopAction,
|
||||
Builtins::CallableFor(isolate(), Builtins::kArrayReduceLoopContinuation));
|
||||
Builtins::CallableFor(isolate(), Builtins::kArrayReduceLoopContinuation),
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(TypedArrayPrototypeReduce, ArrayBuiltinCodeStubAssembler) {
|
||||
@ -1956,7 +2070,7 @@ TF_BUILTIN(ArrayReduceRightLoopContinuation, ArrayBuiltinCodeStubAssembler) {
|
||||
GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
&ArrayBuiltinCodeStubAssembler::ReduceProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::ReducePostLoopAction,
|
||||
ForEachDirection::kReverse);
|
||||
MissingPropertyMode::kSkip, ForEachDirection::kReverse);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayReduceRight, ArrayBuiltinCodeStubAssembler) {
|
||||
@ -1979,7 +2093,7 @@ TF_BUILTIN(ArrayReduceRight, ArrayBuiltinCodeStubAssembler) {
|
||||
&ArrayBuiltinCodeStubAssembler::ReducePostLoopAction,
|
||||
Builtins::CallableFor(isolate(),
|
||||
Builtins::kArrayReduceRightLoopContinuation),
|
||||
ForEachDirection::kReverse);
|
||||
MissingPropertyMode::kSkip, ForEachDirection::kReverse);
|
||||
}
|
||||
|
||||
TF_BUILTIN(TypedArrayPrototypeReduceRight, ArrayBuiltinCodeStubAssembler) {
|
||||
@ -2020,7 +2134,8 @@ TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinCodeStubAssembler) {
|
||||
|
||||
GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
&ArrayBuiltinCodeStubAssembler::FilterProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayFilterLoopEagerDeoptContinuation,
|
||||
@ -2101,7 +2216,8 @@ TF_BUILTIN(ArrayFilter, ArrayBuiltinCodeStubAssembler) {
|
||||
&ArrayBuiltinCodeStubAssembler::FilterResultGenerator,
|
||||
&ArrayBuiltinCodeStubAssembler::FilterProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
Builtins::CallableFor(isolate(), Builtins::kArrayFilterLoopContinuation));
|
||||
Builtins::CallableFor(isolate(), Builtins::kArrayFilterLoopContinuation),
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayMapLoopContinuation, ArrayBuiltinCodeStubAssembler) {
|
||||
@ -2121,7 +2237,8 @@ TF_BUILTIN(ArrayMapLoopContinuation, ArrayBuiltinCodeStubAssembler) {
|
||||
|
||||
GenerateIteratingArrayBuiltinLoopContinuation(
|
||||
&ArrayBuiltinCodeStubAssembler::SpecCompliantMapProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ArrayMapLoopEagerDeoptContinuation, ArrayBuiltinCodeStubAssembler) {
|
||||
@ -2182,7 +2299,8 @@ TF_BUILTIN(ArrayMap, ArrayBuiltinCodeStubAssembler) {
|
||||
"Array.prototype.map", &ArrayBuiltinCodeStubAssembler::MapResultGenerator,
|
||||
&ArrayBuiltinCodeStubAssembler::FastMapProcessor,
|
||||
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
|
||||
Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation));
|
||||
Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation),
|
||||
MissingPropertyMode::kSkip);
|
||||
}
|
||||
|
||||
TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinCodeStubAssembler) {
|
||||
|
@ -316,6 +316,15 @@ namespace internal {
|
||||
TFJ(ArrayReduceRight, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-array.prototype.entries */ \
|
||||
TFJ(ArrayPrototypeEntries, 0) \
|
||||
/* ES6 #sec-array.prototype.find */ \
|
||||
TFS(ArrayFindLoopContinuation, kReceiver, kCallbackFn, kThisArg, kArray, \
|
||||
kObject, kInitialK, kLength, kTo) \
|
||||
TFJ(ArrayPrototypeFind, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-array.prototype.findIndex */ \
|
||||
TFS(ArrayFindIndexLoopContinuation, kReceiver, kCallbackFn, kThisArg, \
|
||||
kArray, kObject, kInitialK, kLength, kTo) \
|
||||
TFJ(ArrayPrototypeFindIndex, \
|
||||
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-array.prototype.keys */ \
|
||||
TFJ(ArrayPrototypeKeys, 0) \
|
||||
/* ES6 #sec-array.prototype.values */ \
|
||||
|
@ -522,6 +522,8 @@ bool BuiltinHasNoSideEffect(Builtins::Name id) {
|
||||
case Builtins::kArrayPrototypeValues:
|
||||
case Builtins::kArrayIncludes:
|
||||
case Builtins::kArrayPrototypeEntries:
|
||||
case Builtins::kArrayPrototypeFind:
|
||||
case Builtins::kArrayPrototypeFindIndex:
|
||||
case Builtins::kArrayPrototypeKeys:
|
||||
case Builtins::kArrayForEach:
|
||||
case Builtins::kArrayEvery:
|
||||
|
@ -1118,64 +1118,6 @@ DEFINE_METHOD_LEN(
|
||||
);
|
||||
|
||||
|
||||
function InnerArrayFind(predicate, thisArg, array, length) {
|
||||
if (!IS_CALLABLE(predicate)) {
|
||||
throw %make_type_error(kCalledNonCallable, predicate);
|
||||
}
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
var element = array[i];
|
||||
if (%_Call(predicate, thisArg, element, i, array)) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// ES6 draft 07-15-13, section 15.4.3.23
|
||||
DEFINE_METHOD_LEN(
|
||||
GlobalArray.prototype,
|
||||
find(predicate, thisArg) {
|
||||
var array = TO_OBJECT(this);
|
||||
var length = TO_INTEGER(array.length);
|
||||
|
||||
return InnerArrayFind(predicate, thisArg, array, length);
|
||||
},
|
||||
1 /* Set function length */
|
||||
);
|
||||
|
||||
|
||||
function InnerArrayFindIndex(predicate, thisArg, array, length) {
|
||||
if (!IS_CALLABLE(predicate)) {
|
||||
throw %make_type_error(kCalledNonCallable, predicate);
|
||||
}
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
var element = array[i];
|
||||
if (%_Call(predicate, thisArg, element, i, array)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// ES6 draft 07-15-13, section 15.4.3.24
|
||||
DEFINE_METHOD_LEN(
|
||||
GlobalArray.prototype,
|
||||
findIndex(predicate, thisArg) {
|
||||
var array = TO_OBJECT(this);
|
||||
var length = TO_INTEGER(array.length);
|
||||
|
||||
return InnerArrayFindIndex(predicate, thisArg, array, length);
|
||||
},
|
||||
1 /* Set function length */
|
||||
);
|
||||
|
||||
|
||||
// ES6, draft 04-05-14, section 22.1.3.6
|
||||
DEFINE_METHOD_LEN(
|
||||
GlobalArray.prototype,
|
||||
|
@ -73,6 +73,31 @@
|
||||
assertEquals(3, count);
|
||||
for (var i in a) assertEquals(2, a[i]);
|
||||
|
||||
// Skip over missing properties.
|
||||
a = {
|
||||
"0": 0,
|
||||
"2": 2,
|
||||
length: 3
|
||||
};
|
||||
var received = [];
|
||||
assertArrayEquals([2],
|
||||
Array.prototype.filter.call(a, function(n) {
|
||||
received.push(n);
|
||||
return n == 2;
|
||||
}));
|
||||
assertArrayEquals([0, 2], received);
|
||||
|
||||
// Modify array prototype
|
||||
a = [0, , 2];
|
||||
received = [];
|
||||
assertArrayEquals([2],
|
||||
Array.prototype.filter.call(a, function(n) {
|
||||
a.__proto__ = null;
|
||||
received.push(n);
|
||||
return n == 2;
|
||||
}));
|
||||
assertArrayEquals([0, 2], received);
|
||||
|
||||
// Create a new object in each function call when receiver is a
|
||||
// primitive value. See ECMA-262, Annex C.
|
||||
a = [];
|
||||
@ -131,6 +156,26 @@
|
||||
a.forEach(function(n) { count++; });
|
||||
assertEquals(1, count);
|
||||
|
||||
// Skip over missing properties.
|
||||
a = {
|
||||
"0": 0,
|
||||
"2": 2,
|
||||
length: 3
|
||||
};
|
||||
var received = [];
|
||||
Array.prototype.forEach.call(a, function(n) { received.push(n); });
|
||||
assertArrayEquals([0, 2], received);
|
||||
|
||||
// Modify array prototype
|
||||
a = [0, , 2];
|
||||
received = [];
|
||||
Array.prototype.forEach.call(a, function(n) {
|
||||
a.__proto__ = null;
|
||||
received.push(n);
|
||||
return n == 2;
|
||||
});
|
||||
assertArrayEquals([0, 2], received);
|
||||
|
||||
// Create a new object in each function call when receiver is a
|
||||
// primitive value. See ECMA-262, Annex C.
|
||||
a = [];
|
||||
@ -194,6 +239,31 @@
|
||||
assertTrue(a.every(function(n) { count++; return n == 2; }));
|
||||
assertEquals(2, count);
|
||||
|
||||
// Skip over missing properties.
|
||||
a = {
|
||||
"0": 2,
|
||||
"2": 2,
|
||||
length: 3
|
||||
};
|
||||
var received = [];
|
||||
assertTrue(
|
||||
Array.prototype.every.call(a, function(n) {
|
||||
received.push(n);
|
||||
return n == 2;
|
||||
}));
|
||||
assertArrayEquals([2, 2], received);
|
||||
|
||||
// Modify array prototype
|
||||
a = [2, , 2];
|
||||
received = [];
|
||||
assertTrue(
|
||||
Array.prototype.every.call(a, function(n) {
|
||||
a.__proto__ = null;
|
||||
received.push(n);
|
||||
return n == 2;
|
||||
}));
|
||||
assertArrayEquals([2, 2], received);
|
||||
|
||||
// Create a new object in each function call when receiver is a
|
||||
// primitive value. See ECMA-262, Annex C.
|
||||
a = [];
|
||||
@ -252,6 +322,31 @@
|
||||
a = a.map(function(n) { return 2*n; });
|
||||
for (var i in a) assertEquals(4, a[i]);
|
||||
|
||||
// Skip over missing properties.
|
||||
a = {
|
||||
"0": 1,
|
||||
"2": 2,
|
||||
length: 3
|
||||
};
|
||||
var received = [];
|
||||
assertArrayEquals([2, , 4],
|
||||
Array.prototype.map.call(a, function(n) {
|
||||
received.push(n);
|
||||
return n * 2;
|
||||
}));
|
||||
assertArrayEquals([1, 2], received);
|
||||
|
||||
// Modify array prototype
|
||||
a = [1, , 2];
|
||||
received = [];
|
||||
assertArrayEquals([2, , 4],
|
||||
Array.prototype.map.call(a, function(n) {
|
||||
a.__proto__ = null;
|
||||
received.push(n);
|
||||
return n * 2;
|
||||
}));
|
||||
assertArrayEquals([1, 2], received);
|
||||
|
||||
// Create a new object in each function call when receiver is a
|
||||
// primitive value. See ECMA-262, Annex C.
|
||||
a = [];
|
||||
|
@ -233,6 +233,40 @@ assertEquals(22, a.find(function(val) { return 22 === val; }), undefined);
|
||||
})();
|
||||
|
||||
|
||||
//
|
||||
// Test predicate is called for missing properties
|
||||
//
|
||||
(function() {
|
||||
const obj = {
|
||||
"0": 0,
|
||||
"2": 2,
|
||||
length: 3
|
||||
};
|
||||
const received = [];
|
||||
const predicate = (v) => { received.push(v); return false; };
|
||||
const found = Array.prototype.find.call(obj, predicate);
|
||||
assertEquals(undefined, found);
|
||||
assertArrayEquals([0, undefined, 2], received);
|
||||
})();
|
||||
|
||||
|
||||
//
|
||||
// Test predicate modifying array prototype
|
||||
//
|
||||
(function() {
|
||||
const a = [0, , 2];
|
||||
const received = [];
|
||||
const predicate = (v) => {
|
||||
a.__proto__ = null;
|
||||
received.push(v);
|
||||
return false;
|
||||
};
|
||||
const found = Array.prototype.find.call(a, predicate);
|
||||
assertEquals(undefined, found);
|
||||
assertArrayEquals([0, undefined, 2], received);
|
||||
})();
|
||||
|
||||
|
||||
//
|
||||
// Test thisArg
|
||||
//
|
||||
|
@ -233,6 +233,40 @@ assertEquals(3, a.findIndex(function(val) { return 24 === val; }));
|
||||
})();
|
||||
|
||||
|
||||
//
|
||||
// Test predicate is called for missing properties
|
||||
//
|
||||
(function() {
|
||||
const obj = {
|
||||
"0": 0,
|
||||
"2": 2,
|
||||
length: 3
|
||||
};
|
||||
const received = [];
|
||||
const predicate = (v) => { received.push(v); return false; };
|
||||
const found = Array.prototype.findIndex.call(obj, predicate);
|
||||
assertEquals(-1, found);
|
||||
assertArrayEquals([0, undefined, 2], received);
|
||||
})();
|
||||
|
||||
|
||||
//
|
||||
// Test predicate modifying array prototype
|
||||
//
|
||||
(function() {
|
||||
const a = [0, , 2];
|
||||
const received = [];
|
||||
const predicate = (v) => {
|
||||
a.__proto__ = null;
|
||||
received.push(v);
|
||||
return false;
|
||||
};
|
||||
const found = Array.prototype.findIndex.call(a, predicate);
|
||||
assertEquals(-1, found);
|
||||
assertArrayEquals([0, undefined, 2], received);
|
||||
})();
|
||||
|
||||
|
||||
//
|
||||
// Test thisArg
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user