Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Unified Diff: src/builtins/builtins-array-gen.cc

Issue 2775503006: [builtins] Improve performance of array.prototype.filter and map (Closed)
Patch Set: Remove old impl. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/builtins/builtins-array-gen.cc
diff --git a/src/builtins/builtins-array-gen.cc b/src/builtins/builtins-array-gen.cc
index 6a51a4ac36e02255bec75da15be8c6baa9b1a747..9b78a4602b8672216c0eb35afca4477b6532d7a7 100644
--- a/src/builtins/builtins-array-gen.cc
+++ b/src/builtins/builtins-array-gen.cc
@@ -24,7 +24,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
BuiltinResultIndexInitializer;
typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm,
- Node* k_value, Node* k)>
+ ElementsKind o_kind, Node* k_value, Node* k)>
CallResultProcessor;
typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)>
@@ -32,7 +32,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
Node* ForEachResultGenerator() { return UndefinedConstant(); }
- Node* ForEachProcessor(Node* k_value, Node* k) {
+ Node* ForEachProcessor(ElementsKind o_kind, Node* k_value, Node* k) {
CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(),
k_value, k, o());
return a();
@@ -40,7 +40,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
Node* SomeResultGenerator() { return FalseConstant(); }
- Node* SomeProcessor(Node* k_value, Node* k) {
+ Node* SomeProcessor(ElementsKind o_kind, Node* k_value, Node* k) {
Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
this_arg(), k_value, k, o());
Label false_continue(this), return_true(this);
@@ -53,7 +53,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
Node* EveryResultGenerator() { return TrueConstant(); }
- Node* EveryProcessor(Node* k_value, Node* k) {
+ Node* EveryProcessor(ElementsKind o_kind, Node* k_value, Node* k) {
Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
this_arg(), k_value, k, o());
Label true_continue(this), return_false(this);
@@ -98,7 +98,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
return a.value();
}
- Node* ReduceProcessor(Node* k_value, Node* k) {
+ Node* ReduceProcessor(ElementsKind o_kind, Node* k_value, Node* k) {
Variable result(this, MachineRepresentation::kTagged);
Label done(this, {&result}), initial(this);
GotoIf(WordEqual(a(), TheHoleConstant()), &initial);
@@ -128,22 +128,68 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
return ArraySpeciesCreate(context(), o(), SmiConstant(0));
}
- Node* FilterProcessor(Node* k_value, Node* k) {
+ Node* FilterProcessor(ElementsKind o_kind, Node* k_value, Node* k) {
// ii. Let selected be ToBoolean(? Call(callbackfn, T, kValue, k, O)).
Node* selected = CallJS(CodeFactory::Call(isolate()), context(),
callbackfn(), this_arg(), k_value, k, o());
Label true_continue(this, &to_), false_continue(this);
BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue);
Bind(&true_continue);
- // iii. If selected is true, then...
{
+ // iii. If selected is true, then...
+ Label after_work(this, &to_);
+ if (o_kind < DICTIONARY_ELEMENTS) {
danno 2017/04/03 15:35:27 Please use the predicates in elements-kind.h, e.g.
mvstanton 2017/04/06 08:57:36 Per our discussion, I'll just remove the o_kind pa
+ Node* kind = nullptr;
+
+ // If a() is a JSArray, we can have a fast path.
+ Label fast(this);
+ Label runtime(this);
+ Label object_push_pre(this), object_push(this), double_push(this);
danno 2017/04/03 15:35:27 I think you can make this slightly better. Since y
mvstanton 2017/04/06 08:57:36 Right, because of the vagaries of what can happen
+ BranchIfFastJSArray(a(), context(), FastJSArrayAccessMode::ANY_ACCESS,
+ &fast, &runtime);
+
+ Bind(&fast);
+ {
+ kind = EnsureArrayPushable(a(), &runtime);
+ GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)),
+ &object_push_pre);
+
+ BuildAppendJSArray(FAST_SMI_ELEMENTS, a(), k_value, &runtime);
+ Goto(&after_work);
+ }
+
+ Bind(&object_push_pre);
+ {
+ Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
+ &double_push, &object_push);
+ }
+
+ Bind(&object_push);
+ {
+ BuildAppendJSArray(FAST_ELEMENTS, a(), k_value, &runtime);
+ Goto(&after_work);
+ }
+
+ Bind(&double_push);
+ {
+ BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, a(), k_value, &runtime);
+ Goto(&after_work);
+ }
+
+ Bind(&runtime);
+ }
+
// 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue).
CallRuntime(Runtime::kCreateDataProperty, context(), a(), to_.value(),
k_value);
+ Goto(&after_work);
- // 2. Increase to by 1.
- to_.Bind(NumberInc(to_.value()));
- Goto(&false_continue);
+ Bind(&after_work);
+ {
+ // 2. Increase to by 1.
+ to_.Bind(NumberInc(to_.value()));
+ Goto(&false_continue);
+ }
}
Bind(&false_continue);
return a();
@@ -154,14 +200,66 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
return ArraySpeciesCreate(context(), o(), len_);
}
- Node* MapProcessor(Node* k_value, Node* k) {
+ Node* MapProcessor(ElementsKind o_kind, Node* k_value, Node* k) {
// i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor.
// ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O).
Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(),
callbackfn(), this_arg(), k_value, k, o());
+ Label finished(this);
+ if (o_kind < DICTIONARY_ELEMENTS) {
+ Node* kind = nullptr;
+ Node* elements = nullptr;
+
+ // If a() is a JSArray, we can have a fast path.
+ // mode is SMI_PARAMETERS because k has tagged representation.
+ ParameterMode mode = SMI_PARAMETERS;
+ Label fast(this);
+ Label runtime(this);
+ Label object_push_pre(this), object_push(this), double_push(this);
+ BranchIfFastJSArray(a(), context(), FastJSArrayAccessMode::ANY_ACCESS,
+ &fast, &runtime);
+
+ Bind(&fast);
+ {
+ kind = EnsureArrayPushable(a(), &runtime);
+ elements = LoadElements(a());
+ GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)),
danno 2017/04/03 15:35:27 Consider adding/using existing predicates in code-
mvstanton 2017/04/06 08:57:36 I use a "greater than" metaphor to avoid multiple
+ &object_push_pre);
+
+ TryStoreArrayElement(FAST_SMI_ELEMENTS, mode, &runtime, elements, k,
+ mappedValue);
+ Goto(&finished);
+ }
+
+ Bind(&object_push_pre);
+ {
+ Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
+ &double_push, &object_push);
+ }
+
+ Bind(&object_push);
+ {
+ TryStoreArrayElement(FAST_ELEMENTS, mode, &runtime, elements, k,
+ mappedValue);
+ Goto(&finished);
+ }
+
+ Bind(&double_push);
+ {
+ TryStoreArrayElement(FAST_DOUBLE_ELEMENTS, mode, &runtime, elements, k,
+ mappedValue);
+ Goto(&finished);
+ }
+
+ Bind(&runtime);
+ }
+
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue);
+ Goto(&finished);
+
+ Bind(&finished);
return a();
}
@@ -420,7 +518,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
// iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
// iv. ReturnIfAbrupt(funcResult).
- a_.Bind(processor(this, k_value, k()));
+ a_.Bind(processor(this, DICTIONARY_ELEMENTS, k_value, k()));
danno 2017/04/03 15:35:27 Although I know what you mean here, the elements m
Goto(&done_element);
Bind(&done_element);
@@ -473,7 +571,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
Node* value = LoadFixedTypedArrayElementAsTagged(data_ptr, index, kind,
SMI_PARAMETERS);
k_.Bind(index);
- a_.Bind(processor(this, value, index));
+ a_.Bind(processor(this, kind, value, index));
};
BuildFastLoop(list, SmiConstant(0), len_, body, 1,
ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);
@@ -529,7 +627,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
LoadDoubleWithHoleCheck(elements, offset, &hole_element);
value = AllocateHeapNumberWithValue(double_value);
}
- a_.Bind(processor(this, value, k()));
+ a_.Bind(processor(this, kind, value, k()));
Goto(&one_element_done);
Bind(&hole_element);
@@ -632,39 +730,13 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
Bind(&fast);
{
- // Disallow pushing onto prototypes. It might be the JSArray prototype.
- // Disallow pushing onto non-extensible objects.
- Comment("Disallow pushing onto prototypes");
- Node* map = LoadMap(receiver);
- Node* bit_field2 = LoadMapBitField2(map);
- int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) |
- (1 << Map::kIsExtensible);
- Node* test = Word32And(bit_field2, Int32Constant(mask));
- GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)),
- &runtime);
-
- // Disallow pushing onto arrays in dictionary named property mode. We need
- // to figure out whether the length property is still writable.
- Comment("Disallow pushing onto arrays in dictionary named property mode");
- GotoIf(IsDictionaryMap(map), &runtime);
-
- // Check whether the length property is writable. The length property is the
- // only default named property on arrays. It's nonconfigurable, hence is
- // guaranteed to stay the first property.
- Node* descriptors = LoadMapDescriptors(map);
- Node* details =
- LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0));
- GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask),
- &runtime);
-
arg_index.Bind(IntPtrConstant(0));
- kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
-
+ kind = EnsureArrayPushable(receiver, &runtime);
GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)),
&object_push_pre);
- Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver,
- args, arg_index, &smi_transition);
+ Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, receiver, args,
+ arg_index, &smi_transition);
args.PopAndReturn(new_length);
}
@@ -702,16 +774,15 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
Bind(&object_push);
{
- Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, context, receiver,
- args, arg_index, &default_label);
+ Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, receiver, args,
+ arg_index, &default_label);
args.PopAndReturn(new_length);
}
Bind(&double_push);
{
- Node* new_length =
- BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, args,
- arg_index, &double_transition);
+ Node* new_length = BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, receiver, args,
+ arg_index, &double_transition);
args.PopAndReturn(new_length);
}
« no previous file with comments | « src/bootstrapper.cc ('k') | src/code-stub-assembler.h » ('j') | src/code-stub-assembler.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698