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

Side by Side Diff: src/builtins/builtins-array-gen.cc

Issue 2775503006: [builtins] Improve performance of array.prototype.filter and map (Closed)
Patch Set: Code comments Created 3 years, 8 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 unified diff | Download patch
« no previous file with comments | « src/bootstrapper.cc ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 the V8 project authors. All rights reserved. 1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/builtins/builtins-utils-gen.h" 5 #include "src/builtins/builtins-utils-gen.h"
6 #include "src/builtins/builtins.h" 6 #include "src/builtins/builtins.h"
7 #include "src/code-stub-assembler.h" 7 #include "src/code-stub-assembler.h"
8 8
9 namespace v8 { 9 namespace v8 {
10 namespace internal { 10 namespace internal {
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 130
131 Node* FilterProcessor(Node* k_value, Node* k) { 131 Node* FilterProcessor(Node* k_value, Node* k) {
132 // ii. Let selected be ToBoolean(? Call(callbackfn, T, kValue, k, O)). 132 // ii. Let selected be ToBoolean(? Call(callbackfn, T, kValue, k, O)).
133 Node* selected = CallJS(CodeFactory::Call(isolate()), context(), 133 Node* selected = CallJS(CodeFactory::Call(isolate()), context(),
134 callbackfn(), this_arg(), k_value, k, o()); 134 callbackfn(), this_arg(), k_value, k, o());
135 Label true_continue(this, &to_), false_continue(this); 135 Label true_continue(this, &to_), false_continue(this);
136 BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue); 136 BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue);
137 BIND(&true_continue); 137 BIND(&true_continue);
138 // iii. If selected is true, then... 138 // iii. If selected is true, then...
139 { 139 {
140 // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue). 140 Label after_work(this, &to_);
141 CallRuntime(Runtime::kCreateDataProperty, context(), a(), to_.value(), 141 Node* kind = nullptr;
142 k_value);
143 142
144 // 2. Increase to by 1. 143 // If a() is a JSArray, we can have a fast path.
145 to_.Bind(NumberInc(to_.value())); 144 Label fast(this);
146 Goto(&false_continue); 145 Label runtime(this);
146 Label object_push_pre(this), object_push(this), double_push(this);
147 BranchIfFastJSArray(a(), context(), FastJSArrayAccessMode::ANY_ACCESS,
148 &fast, &runtime);
149
150 BIND(&fast);
151 {
152 kind = EnsureArrayPushable(a(), &runtime);
153 GotoIf(IsElementsKindGreaterThan(kind, FAST_HOLEY_SMI_ELEMENTS),
154 &object_push_pre);
155
156 BuildAppendJSArray(FAST_SMI_ELEMENTS, a(), k_value, &runtime);
157 Goto(&after_work);
158 }
159
160 BIND(&object_push_pre);
161 {
162 Branch(IsElementsKindGreaterThan(kind, FAST_HOLEY_ELEMENTS),
163 &double_push, &object_push);
164 }
165
166 BIND(&object_push);
167 {
168 BuildAppendJSArray(FAST_ELEMENTS, a(), k_value, &runtime);
169 Goto(&after_work);
170 }
171
172 BIND(&double_push);
173 {
174 BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, a(), k_value, &runtime);
175 Goto(&after_work);
176 }
177
178 BIND(&runtime);
179 {
180 // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue).
181 CallRuntime(Runtime::kCreateDataProperty, context(), a(), to_.value(),
182 k_value);
183 Goto(&after_work);
184 }
185
186 BIND(&after_work);
187 {
188 // 2. Increase to by 1.
189 to_.Bind(NumberInc(to_.value()));
190 Goto(&false_continue);
191 }
147 } 192 }
148 BIND(&false_continue); 193 BIND(&false_continue);
149 return a(); 194 return a();
150 } 195 }
151 196
152 Node* MapResultGenerator() { 197 Node* MapResultGenerator() {
153 // 5. Let A be ? ArraySpeciesCreate(O, len). 198 // 5. Let A be ? ArraySpeciesCreate(O, len).
154 return ArraySpeciesCreate(context(), o(), len_); 199 return ArraySpeciesCreate(context(), o(), len_);
155 } 200 }
156 201
157 Node* MapProcessor(Node* k_value, Node* k) { 202 Node* MapProcessor(Node* k_value, Node* k) {
158 // i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor. 203 // i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor.
159 // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O). 204 // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O).
160 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), 205 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(),
161 callbackfn(), this_arg(), k_value, k, o()); 206 callbackfn(), this_arg(), k_value, k, o());
162 207
163 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). 208 Label finished(this);
164 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue); 209 Node* kind = nullptr;
210 Node* elements = nullptr;
211
212 // If a() is a JSArray, we can have a fast path.
213 // mode is SMI_PARAMETERS because k has tagged representation.
214 ParameterMode mode = SMI_PARAMETERS;
215 Label fast(this);
216 Label runtime(this);
217 Label object_push_pre(this), object_push(this), double_push(this);
218 BranchIfFastJSArray(a(), context(), FastJSArrayAccessMode::ANY_ACCESS,
219 &fast, &runtime);
220
221 BIND(&fast);
222 {
223 kind = EnsureArrayPushable(a(), &runtime);
224 elements = LoadElements(a());
225 GotoIf(IsElementsKindGreaterThan(kind, FAST_HOLEY_SMI_ELEMENTS),
226 &object_push_pre);
227 TryStoreArrayElement(FAST_SMI_ELEMENTS, mode, &runtime, elements, k,
228 mappedValue);
229 Goto(&finished);
230 }
231
232 BIND(&object_push_pre);
233 {
234 Branch(IsElementsKindGreaterThan(kind, FAST_HOLEY_ELEMENTS), &double_push,
235 &object_push);
236 }
237
238 BIND(&object_push);
239 {
240 TryStoreArrayElement(FAST_ELEMENTS, mode, &runtime, elements, k,
241 mappedValue);
242 Goto(&finished);
243 }
244
245 BIND(&double_push);
246 {
247 TryStoreArrayElement(FAST_DOUBLE_ELEMENTS, mode, &runtime, elements, k,
248 mappedValue);
249 Goto(&finished);
250 }
251
252 BIND(&runtime);
253 {
254 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
255 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue);
256 Goto(&finished);
257 }
258
259 BIND(&finished);
165 return a(); 260 return a();
166 } 261 }
167 262
168 void NullPostLoopAction() {} 263 void NullPostLoopAction() {}
169 264
170 protected: 265 protected:
171 Node* context() { return context_; } 266 Node* context() { return context_; }
172 Node* receiver() { return receiver_; } 267 Node* receiver() { return receiver_; }
173 Node* new_target() { return new_target_; } 268 Node* new_target() { return new_target_; }
174 Node* o() { return o_; } 269 Node* o() { return o_; }
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 663
569 BranchIfFastJSArray(o(), context(), 664 BranchIfFastJSArray(o(), context(),
570 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, 665 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
571 &switch_on_elements_kind, slow); 666 &switch_on_elements_kind, slow);
572 667
573 BIND(&switch_on_elements_kind); 668 BIND(&switch_on_elements_kind);
574 // Select by ElementsKind 669 // Select by ElementsKind
575 Node* o_map = LoadMap(o()); 670 Node* o_map = LoadMap(o());
576 Node* bit_field2 = LoadMapBitField2(o_map); 671 Node* bit_field2 = LoadMapBitField2(o_map);
577 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); 672 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
578 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), 673 Branch(IsElementsKindGreaterThan(kind, FAST_HOLEY_ELEMENTS),
579 &maybe_double_elements, &fast_elements); 674 &maybe_double_elements, &fast_elements);
580 675
581 ParameterMode mode = OptimalParameterMode(); 676 ParameterMode mode = OptimalParameterMode();
582 BIND(&fast_elements); 677 BIND(&fast_elements);
583 { 678 {
584 VisitAllFastElementsOneKind(FAST_ELEMENTS, processor, slow, mode, 679 VisitAllFastElementsOneKind(FAST_ELEMENTS, processor, slow, mode,
585 direction); 680 direction);
586 681
587 action(this); 682 action(this);
588 683
589 // No exception, return success 684 // No exception, return success
590 Return(a_.value()); 685 Return(a_.value());
591 } 686 }
592 687
593 BIND(&maybe_double_elements); 688 BIND(&maybe_double_elements);
594 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), 689 Branch(IsElementsKindGreaterThan(kind, FAST_HOLEY_DOUBLE_ELEMENTS), slow,
595 slow, &fast_double_elements); 690 &fast_double_elements);
596 691
597 BIND(&fast_double_elements); 692 BIND(&fast_double_elements);
598 { 693 {
599 VisitAllFastElementsOneKind(FAST_DOUBLE_ELEMENTS, processor, slow, mode, 694 VisitAllFastElementsOneKind(FAST_DOUBLE_ELEMENTS, processor, slow, mode,
600 direction); 695 direction);
601 696
602 action(this); 697 action(this);
603 698
604 // No exception, return success 699 // No exception, return success
605 Return(a_.value()); 700 Return(a_.value());
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); 732 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
638 Node* receiver = args.GetReceiver(); 733 Node* receiver = args.GetReceiver();
639 Node* kind = nullptr; 734 Node* kind = nullptr;
640 735
641 Label fast(this); 736 Label fast(this);
642 BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS, 737 BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS,
643 &fast, &runtime); 738 &fast, &runtime);
644 739
645 BIND(&fast); 740 BIND(&fast);
646 { 741 {
647 // Disallow pushing onto prototypes. It might be the JSArray prototype.
648 // Disallow pushing onto non-extensible objects.
649 Comment("Disallow pushing onto prototypes");
650 Node* map = LoadMap(receiver);
651 Node* bit_field2 = LoadMapBitField2(map);
652 int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) |
653 (1 << Map::kIsExtensible);
654 Node* test = Word32And(bit_field2, Int32Constant(mask));
655 GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)),
656 &runtime);
657
658 // Disallow pushing onto arrays in dictionary named property mode. We need
659 // to figure out whether the length property is still writable.
660 Comment("Disallow pushing onto arrays in dictionary named property mode");
661 GotoIf(IsDictionaryMap(map), &runtime);
662
663 // Check whether the length property is writable. The length property is the
664 // only default named property on arrays. It's nonconfigurable, hence is
665 // guaranteed to stay the first property.
666 Node* descriptors = LoadMapDescriptors(map);
667 Node* details =
668 LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0));
669 GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask),
670 &runtime);
671
672 arg_index.Bind(IntPtrConstant(0)); 742 arg_index.Bind(IntPtrConstant(0));
673 kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); 743 kind = EnsureArrayPushable(receiver, &runtime);
674 744 GotoIf(IsElementsKindGreaterThan(kind, FAST_HOLEY_SMI_ELEMENTS),
675 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)),
676 &object_push_pre); 745 &object_push_pre);
677 746
678 Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver, 747 Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, receiver, args,
679 args, arg_index, &smi_transition); 748 arg_index, &smi_transition);
680 args.PopAndReturn(new_length); 749 args.PopAndReturn(new_length);
681 } 750 }
682 751
683 // If the argument is not a smi, then use a heavyweight SetProperty to 752 // If the argument is not a smi, then use a heavyweight SetProperty to
684 // transition the array for only the single next element. If the argument is 753 // transition the array for only the single next element. If the argument is
685 // a smi, the failure is due to some other reason and we should fall back on 754 // a smi, the failure is due to some other reason and we should fall back on
686 // the most generic implementation for the rest of the array. 755 // the most generic implementation for the rest of the array.
687 BIND(&smi_transition); 756 BIND(&smi_transition);
688 { 757 {
689 Node* arg = args.AtIndex(arg_index.value()); 758 Node* arg = args.AtIndex(arg_index.value());
(...skipping 11 matching lines...) Expand all
701 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); 770 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
702 GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)), 771 GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
703 &default_label); 772 &default_label);
704 773
705 GotoIfNotNumber(arg, &object_push); 774 GotoIfNotNumber(arg, &object_push);
706 Goto(&double_push); 775 Goto(&double_push);
707 } 776 }
708 777
709 BIND(&object_push_pre); 778 BIND(&object_push_pre);
710 { 779 {
711 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), 780 Branch(IsElementsKindGreaterThan(kind, FAST_HOLEY_ELEMENTS), &double_push,
712 &double_push, &object_push); 781 &object_push);
713 } 782 }
714 783
715 BIND(&object_push); 784 BIND(&object_push);
716 { 785 {
717 Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, context, receiver, 786 Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, receiver, args,
718 args, arg_index, &default_label); 787 arg_index, &default_label);
719 args.PopAndReturn(new_length); 788 args.PopAndReturn(new_length);
720 } 789 }
721 790
722 BIND(&double_push); 791 BIND(&double_push);
723 { 792 {
724 Node* new_length = 793 Node* new_length = BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, receiver, args,
725 BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, args, 794 arg_index, &double_transition);
726 arg_index, &double_transition);
727 args.PopAndReturn(new_length); 795 args.PopAndReturn(new_length);
728 } 796 }
729 797
730 // If the argument is not a double, then use a heavyweight SetProperty to 798 // If the argument is not a double, then use a heavyweight SetProperty to
731 // transition the array for only the single next element. If the argument is 799 // transition the array for only the single next element. If the argument is
732 // a double, the failure is due to some other reason and we should fall back 800 // a double, the failure is due to some other reason and we should fall back
733 // on the most generic implementation for the rest of the array. 801 // on the most generic implementation for the rest of the array.
734 BIND(&double_transition); 802 BIND(&double_transition);
735 { 803 {
736 Node* arg = args.AtIndex(arg_index.value()); 804 Node* arg = args.AtIndex(arg_index.value());
(...skipping 1427 matching lines...) Expand 10 before | Expand all | Expand 10 after
2164 { 2232 {
2165 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); 2233 Node* message = SmiConstant(MessageTemplate::kDetachedOperation);
2166 CallRuntime(Runtime::kThrowTypeError, context, message, 2234 CallRuntime(Runtime::kThrowTypeError, context, message,
2167 HeapConstant(operation)); 2235 HeapConstant(operation));
2168 Unreachable(); 2236 Unreachable();
2169 } 2237 }
2170 } 2238 }
2171 2239
2172 } // namespace internal 2240 } // namespace internal
2173 } // namespace v8 2241 } // namespace v8
OLDNEW
« no previous file with comments | « src/bootstrapper.cc ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698