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

Side by Side Diff: src/compiler/js-builtin-reducer.cc

Issue 2239703002: [turbofan] Add inlined Array.prototype.pop support. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Only convert hole to undefined for holey elements Created 4 years, 4 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/compiler/js-builtin-reducer.h ('k') | src/compiler/pipeline.cc » ('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 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 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/compiler/js-builtin-reducer.h" 5 #include "src/compiler/js-builtin-reducer.h"
6 6
7 #include "src/compilation-dependencies.h"
7 #include "src/compiler/access-builder.h" 8 #include "src/compiler/access-builder.h"
8 #include "src/compiler/js-graph.h" 9 #include "src/compiler/js-graph.h"
9 #include "src/compiler/node-matchers.h" 10 #include "src/compiler/node-matchers.h"
10 #include "src/compiler/node-properties.h" 11 #include "src/compiler/node-properties.h"
11 #include "src/compiler/simplified-operator.h" 12 #include "src/compiler/simplified-operator.h"
12 #include "src/objects-inl.h" 13 #include "src/objects-inl.h"
13 #include "src/type-cache.h" 14 #include "src/type-cache.h"
14 #include "src/types.h" 15 #include "src/types.h"
15 16
16 namespace v8 { 17 namespace v8 {
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); 87 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode());
87 DCHECK_LT(index, GetJSCallArity()); 88 DCHECK_LT(index, GetJSCallArity());
88 // Skip first (i.e. callee) and second (i.e. receiver) operand. 89 // Skip first (i.e. callee) and second (i.e. receiver) operand.
89 return NodeProperties::GetValueInput(node_, index + 2); 90 return NodeProperties::GetValueInput(node_, index + 2);
90 } 91 }
91 92
92 private: 93 private:
93 Node* node_; 94 Node* node_;
94 }; 95 };
95 96
96 JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph) 97 JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph,
98 Flags flags,
99 CompilationDependencies* dependencies)
97 : AdvancedReducer(editor), 100 : AdvancedReducer(editor),
101 dependencies_(dependencies),
102 flags_(flags),
98 jsgraph_(jsgraph), 103 jsgraph_(jsgraph),
99 type_cache_(TypeCache::Get()) {} 104 type_cache_(TypeCache::Get()) {}
100 105
106 namespace {
107
108 MaybeHandle<Map> GetMapWitness(Node* node) {
109 Node* receiver = NodeProperties::GetValueInput(node, 1);
110 Node* effect = NodeProperties::GetEffectInput(node);
111 // Check if the {node} is dominated by a CheckMaps with a single map
112 // for the {receiver}, and if so use that map for the lowering below.
113 for (Node* dominator = effect;;) {
114 if (dominator->opcode() == IrOpcode::kCheckMaps &&
115 dominator->InputAt(0) == receiver) {
116 if (dominator->op()->ValueInputCount() == 2) {
117 HeapObjectMatcher m(dominator->InputAt(1));
118 if (m.HasValue()) return Handle<Map>::cast(m.Value());
119 }
120 return MaybeHandle<Map>();
121 }
122 if (dominator->op()->EffectInputCount() != 1) {
123 // Didn't find any appropriate CheckMaps node.
124 return MaybeHandle<Map>();
125 }
126 dominator = NodeProperties::GetEffectInput(dominator);
127 }
128 }
129
130 // TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
131 bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
132 DCHECK(!jsarray_map->is_dictionary_map());
133 Isolate* isolate = jsarray_map->GetIsolate();
134 Handle<Name> length_string = isolate->factory()->length_string();
135 DescriptorArray* descriptors = jsarray_map->instance_descriptors();
136 int number =
137 descriptors->SearchWithCache(isolate, *length_string, *jsarray_map);
138 DCHECK_NE(DescriptorArray::kNotFound, number);
139 return descriptors->GetDetails(number).IsReadOnly();
140 }
141
142 // TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
143 bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) {
144 Isolate* const isolate = receiver_map->GetIsolate();
145 if (!receiver_map->prototype()->IsJSArray()) return false;
146 Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
147 isolate);
148 return receiver_map->instance_type() == JS_ARRAY_TYPE &&
149 IsFastElementsKind(receiver_map->elements_kind()) &&
150 !receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
151 (!receiver_map->is_prototype_map() || receiver_map->is_stable()) &&
152 receiver_prototype->map()->is_stable() &&
153 isolate->IsFastArrayConstructorPrototypeChainIntact() &&
154 isolate->IsAnyInitialArrayPrototype(receiver_prototype) &&
155 !IsReadOnlyLengthDescriptor(receiver_map);
156 }
157
158 } // namespace
159
160 // ES6 section 22.1.3.17 Array.prototype.pop ( )
161 Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) {
162 Handle<Map> receiver_map;
163 Node* receiver = NodeProperties::GetValueInput(node, 1);
164 Node* effect = NodeProperties::GetEffectInput(node);
165 Node* control = NodeProperties::GetControlInput(node);
166 // TODO(turbofan): Extend this to also handle fast (holey) double elements
167 // once we got the hole NaN mess sorted out in TurboFan/V8.
168 if (GetMapWitness(node).ToHandle(&receiver_map) &&
169 CanInlineArrayResizeOperation(receiver_map) &&
170 IsFastSmiOrObjectElementsKind(receiver_map->elements_kind())) {
171 // Install code dependencies on the {receiver} prototype maps and the
172 // global array protector cell.
173 dependencies()->AssumePropertyCell(factory()->array_protector());
174 dependencies()->AssumePrototypeMapsStable(receiver_map);
175
176 // Load the "length" property of the {receiver}.
177 Node* length = effect = graph()->NewNode(
178 simplified()->LoadField(
179 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
180 receiver, effect, control);
181
182 // Check if the {receiver} has any elements.
183 Node* check = graph()->NewNode(simplified()->NumberEqual(), length,
184 jsgraph()->ZeroConstant());
185 Node* branch =
186 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
187
188 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
189 Node* etrue = effect;
190 Node* vtrue = jsgraph()->UndefinedConstant();
191
192 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
193 Node* efalse = effect;
194 Node* vfalse;
195 {
196 // Load the elements backing store from the {receiver}.
197 Node* elements = efalse = graph()->NewNode(
198 simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
199 receiver, efalse, if_false);
200
201 // Ensure that we aren't popping from a copy-on-write backing store.
202 elements = efalse =
203 graph()->NewNode(simplified()->EnsureWritableFastElements(), receiver,
204 elements, efalse, if_false);
205
206 // Compute the new {length}.
207 length = graph()->NewNode(simplified()->NumberSubtract(), length,
208 jsgraph()->OneConstant());
209
210 // Store the new {length} to the {receiver}.
211 efalse = graph()->NewNode(
212 simplified()->StoreField(
213 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
214 receiver, length, efalse, if_false);
215
216 // Load the last entry from the {elements}.
217 vfalse = efalse = graph()->NewNode(
218 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(
219 receiver_map->elements_kind())),
220 elements, length, efalse, if_false);
221
222 // Store a hole to the element we just removed from the {receiver}.
223 efalse = graph()->NewNode(
224 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
225 GetHoleyElementsKind(receiver_map->elements_kind()))),
226 elements, length, jsgraph()->TheHoleConstant(), efalse, if_false);
227 }
228
229 control = graph()->NewNode(common()->Merge(2), if_true, if_false);
230 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
231 Node* value =
232 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
233 vtrue, vfalse, control);
234
235 // Convert the hole to undefined. Do this last, so that we can optimize
236 // conversion operator via some smart strength reduction in many cases.
237 if (IsFastHoleyElementsKind(receiver_map->elements_kind())) {
238 value =
239 graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
240 }
241
242 ReplaceWithValue(node, value, effect, control);
243 return Replace(value);
244 }
245 return NoChange();
246 }
247
101 // ES6 section 20.2.2.1 Math.abs ( x ) 248 // ES6 section 20.2.2.1 Math.abs ( x )
102 Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) { 249 Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) {
103 JSCallReduction r(node); 250 JSCallReduction r(node);
104 if (r.InputsMatchOne(Type::PlainPrimitive())) { 251 if (r.InputsMatchOne(Type::PlainPrimitive())) {
105 // Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a)) 252 // Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a))
106 Node* input = ToNumber(r.GetJSCallInput(0)); 253 Node* input = ToNumber(r.GetJSCallInput(0));
107 Node* value = graph()->NewNode(simplified()->NumberAbs(), input); 254 Node* value = graph()->NewNode(simplified()->NumberAbs(), input);
108 return Replace(value); 255 return Replace(value);
109 } 256 }
110 return NoChange(); 257 return NoChange();
(...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after
742 return NoChange(); 889 return NoChange();
743 } 890 }
744 891
745 Reduction JSBuiltinReducer::Reduce(Node* node) { 892 Reduction JSBuiltinReducer::Reduce(Node* node) {
746 Reduction reduction = NoChange(); 893 Reduction reduction = NoChange();
747 JSCallReduction r(node); 894 JSCallReduction r(node);
748 895
749 // Dispatch according to the BuiltinFunctionId if present. 896 // Dispatch according to the BuiltinFunctionId if present.
750 if (!r.HasBuiltinFunctionId()) return NoChange(); 897 if (!r.HasBuiltinFunctionId()) return NoChange();
751 switch (r.GetBuiltinFunctionId()) { 898 switch (r.GetBuiltinFunctionId()) {
899 case kArrayPop:
900 return ReduceArrayPop(node);
752 case kMathAbs: 901 case kMathAbs:
753 reduction = ReduceMathAbs(node); 902 reduction = ReduceMathAbs(node);
754 break; 903 break;
755 case kMathAcos: 904 case kMathAcos:
756 reduction = ReduceMathAcos(node); 905 reduction = ReduceMathAcos(node);
757 break; 906 break;
758 case kMathAcosh: 907 case kMathAcosh:
759 reduction = ReduceMathAcosh(node); 908 reduction = ReduceMathAcosh(node);
760 break; 909 break;
761 case kMathAsin: 910 case kMathAsin:
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
896 1045
897 Node* JSBuiltinReducer::ToUint32(Node* input) { 1046 Node* JSBuiltinReducer::ToUint32(Node* input) {
898 input = ToNumber(input); 1047 input = ToNumber(input);
899 Type* input_type = NodeProperties::GetType(input); 1048 Type* input_type = NodeProperties::GetType(input);
900 if (input_type->Is(Type::Unsigned32())) return input; 1049 if (input_type->Is(Type::Unsigned32())) return input;
901 return graph()->NewNode(simplified()->NumberToUint32(), input); 1050 return graph()->NewNode(simplified()->NumberToUint32(), input);
902 } 1051 }
903 1052
904 Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); } 1053 Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); }
905 1054
1055 Factory* JSBuiltinReducer::factory() const { return isolate()->factory(); }
906 1056
907 Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); } 1057 Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); }
908 1058
909 1059
910 CommonOperatorBuilder* JSBuiltinReducer::common() const { 1060 CommonOperatorBuilder* JSBuiltinReducer::common() const {
911 return jsgraph()->common(); 1061 return jsgraph()->common();
912 } 1062 }
913 1063
914 1064
915 SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const { 1065 SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const {
916 return jsgraph()->simplified(); 1066 return jsgraph()->simplified();
917 } 1067 }
918 1068
919 } // namespace compiler 1069 } // namespace compiler
920 } // namespace internal 1070 } // namespace internal
921 } // namespace v8 1071 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-builtin-reducer.h ('k') | src/compiler/pipeline.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698