Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include "src/compiler/js-builtin-reducer.h"
6 :
7 : #include "src/base/bits.h"
8 : #include "src/builtins/builtins-utils.h"
9 : #include "src/code-factory.h"
10 : #include "src/compilation-dependencies.h"
11 : #include "src/compiler/access-builder.h"
12 : #include "src/compiler/allocation-builder.h"
13 : #include "src/compiler/js-graph.h"
14 : #include "src/compiler/linkage.h"
15 : #include "src/compiler/node-matchers.h"
16 : #include "src/compiler/node-properties.h"
17 : #include "src/compiler/simplified-operator.h"
18 : #include "src/compiler/type-cache.h"
19 : #include "src/compiler/types.h"
20 : #include "src/objects-inl.h"
21 :
22 : namespace v8 {
23 : namespace internal {
24 : namespace compiler {
25 :
26 : // Helper class to access JSCall nodes that are potential candidates
27 : // for reduction when they have a BuiltinFunctionId associated with them.
28 : class JSCallReduction {
29 : public:
30 31994988 : explicit JSCallReduction(Node* node) : node_(node) {}
31 :
32 : // Determines whether the node is a JSCall operation that targets a
33 : // constant callee being a well-known builtin with a BuiltinFunctionId.
34 31934250 : bool HasBuiltinFunctionId() {
35 63868500 : if (node_->opcode() != IrOpcode::kJSCall) return false;
36 509615 : HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0));
37 731576 : if (!m.HasValue() || !m.Value()->IsJSFunction()) return false;
38 : Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
39 221905 : return function->shared()->HasBuiltinFunctionId();
40 : }
41 :
42 : // Retrieves the BuiltinFunctionId as described above.
43 70911 : BuiltinFunctionId GetBuiltinFunctionId() {
44 : DCHECK_EQ(IrOpcode::kJSCall, node_->opcode());
45 70911 : HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0));
46 : Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
47 70911 : return function->shared()->builtin_function_id();
48 : }
49 :
50 : bool ReceiverMatches(Type* type) {
51 : return NodeProperties::GetType(receiver())->Is(type);
52 : }
53 :
54 : // Determines whether the call takes zero inputs.
55 : bool InputsMatchZero() { return GetJSCallArity() == 0; }
56 :
57 : // Determines whether the call takes one input of the given type.
58 57471 : bool InputsMatchOne(Type* t1) {
59 114861 : return GetJSCallArity() == 1 &&
60 57471 : NodeProperties::GetType(GetJSCallInput(0))->Is(t1);
61 : }
62 :
63 : // Determines whether the call takes two inputs of the given types.
64 3355 : bool InputsMatchTwo(Type* t1, Type* t2) {
65 2616 : return GetJSCallArity() == 2 &&
66 4920 : NodeProperties::GetType(GetJSCallInput(0))->Is(t1) &&
67 3355 : NodeProperties::GetType(GetJSCallInput(1))->Is(t2);
68 : }
69 :
70 : // Determines whether the call takes inputs all of the given type.
71 923 : bool InputsMatchAll(Type* t) {
72 4912 : for (int i = 0; i < GetJSCallArity(); i++) {
73 1709 : if (!NodeProperties::GetType(GetJSCallInput(i))->Is(t)) {
74 : return false;
75 : }
76 : }
77 : return true;
78 : }
79 :
80 : Node* receiver() { return NodeProperties::GetValueInput(node_, 1); }
81 : Node* left() { return GetJSCallInput(0); }
82 : Node* right() { return GetJSCallInput(1); }
83 :
84 : int GetJSCallArity() {
85 : DCHECK_EQ(IrOpcode::kJSCall, node_->opcode());
86 : // Skip first (i.e. callee) and second (i.e. receiver) operand.
87 69753 : return node_->op()->ValueInputCount() - 2;
88 : }
89 :
90 : Node* GetJSCallInput(int index) {
91 : DCHECK_EQ(IrOpcode::kJSCall, node_->opcode());
92 : DCHECK_LT(index, GetJSCallArity());
93 : // Skip first (i.e. callee) and second (i.e. receiver) operand.
94 88956 : return NodeProperties::GetValueInput(node_, index + 2);
95 : }
96 :
97 : private:
98 : Node* node_;
99 : };
100 :
101 444099 : JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph,
102 : CompilationDependencies* dependencies,
103 : Handle<Context> native_context)
104 : : AdvancedReducer(editor),
105 : dependencies_(dependencies),
106 : jsgraph_(jsgraph),
107 : native_context_(native_context),
108 444099 : type_cache_(TypeCache::Get()) {}
109 :
110 : namespace {
111 :
112 1789 : MaybeHandle<Map> GetMapWitness(Node* node) {
113 : ZoneHandleSet<Map> maps;
114 1789 : Node* receiver = NodeProperties::GetValueInput(node, 1);
115 1789 : Node* effect = NodeProperties::GetEffectInput(node);
116 : NodeProperties::InferReceiverMapsResult result =
117 1789 : NodeProperties::InferReceiverMaps(receiver, effect, &maps);
118 3424 : if (result == NodeProperties::kReliableReceiverMaps && maps.size() == 1) {
119 1630 : return maps[0];
120 : }
121 159 : return MaybeHandle<Map>();
122 : }
123 :
124 : // TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
125 1699 : bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
126 : DCHECK(!jsarray_map->is_dictionary_map());
127 : Isolate* isolate = jsarray_map->GetIsolate();
128 : Handle<Name> length_string = isolate->factory()->length_string();
129 : DescriptorArray* descriptors = jsarray_map->instance_descriptors();
130 : int number =
131 : descriptors->SearchWithCache(isolate, *length_string, *jsarray_map);
132 : DCHECK_NE(DescriptorArray::kNotFound, number);
133 3398 : return descriptors->GetDetails(number).IsReadOnly();
134 : }
135 :
136 : // TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
137 2632 : bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) {
138 : Isolate* const isolate = receiver_map->GetIsolate();
139 2632 : if (!receiver_map->prototype()->IsJSArray()) return false;
140 : Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
141 : isolate);
142 : // Ensure that all prototypes of the {receiver} are stable.
143 7429 : for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver);
144 3705 : !it.IsAtEnd(); it.Advance()) {
145 : Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it);
146 3724 : if (!current->map()->is_stable()) return false;
147 : }
148 1835 : return receiver_map->instance_type() == JS_ARRAY_TYPE &&
149 1787 : IsFastElementsKind(receiver_map->elements_kind()) &&
150 3574 : !receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
151 1787 : (!receiver_map->is_prototype_map() || receiver_map->is_stable()) &&
152 3478 : isolate->IsFastArrayConstructorPrototypeChainIntact() &&
153 5241 : isolate->IsAnyInitialArrayPrototype(receiver_prototype) &&
154 3542 : !IsReadOnlyLengthDescriptor(receiver_map);
155 : }
156 :
157 494 : bool CanInlineJSArrayIteration(Handle<Map> receiver_map) {
158 : Isolate* const isolate = receiver_map->GetIsolate();
159 : // Ensure that the [[Prototype]] is actually an exotic Array
160 494 : if (!receiver_map->prototype()->IsJSArray()) return false;
161 :
162 : // Don't inline JSArrays with slow elements of any kind
163 494 : if (!IsFastElementsKind(receiver_map->elements_kind())) return false;
164 :
165 : // If the receiver map has packed elements, no need to check the prototype.
166 : // This requires a MapCheck where this is used.
167 494 : if (!IsHoleyElementsKind(receiver_map->elements_kind())) return true;
168 :
169 : Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
170 : isolate);
171 : // Ensure all prototypes of the {receiver} are stable.
172 113 : for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver);
173 55 : !it.IsAtEnd(); it.Advance()) {
174 : Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it);
175 58 : if (!current->map()->is_stable()) return false;
176 : }
177 :
178 : // For holey Arrays, ensure that the array_protector cell is valid (must be
179 : // a CompilationDependency), and the JSArray prototype has not been altered.
180 26 : return receiver_map->instance_type() == JS_ARRAY_TYPE &&
181 26 : (!receiver_map->is_dictionary_map() || receiver_map->is_stable()) &&
182 78 : isolate->IsFastArrayConstructorPrototypeChainIntact() &&
183 52 : isolate->IsAnyInitialArrayPrototype(receiver_prototype);
184 : }
185 :
186 : } // namespace
187 :
188 610 : Reduction JSBuiltinReducer::ReduceArrayIterator(Node* node,
189 : IterationKind kind) {
190 : Handle<Map> receiver_map;
191 1220 : if (GetMapWitness(node).ToHandle(&receiver_map)) {
192 : return ReduceArrayIterator(receiver_map, node, kind,
193 502 : ArrayIteratorKind::kArray);
194 : }
195 : return NoChange();
196 : }
197 :
198 50 : Reduction JSBuiltinReducer::ReduceTypedArrayIterator(Node* node,
199 : IterationKind kind) {
200 : Handle<Map> receiver_map;
201 150 : if (GetMapWitness(node).ToHandle(&receiver_map) &&
202 : receiver_map->instance_type() == JS_TYPED_ARRAY_TYPE) {
203 : return ReduceArrayIterator(receiver_map, node, kind,
204 50 : ArrayIteratorKind::kTypedArray);
205 : }
206 : return NoChange();
207 : }
208 :
209 552 : Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> receiver_map,
210 : Node* node, IterationKind kind,
211 3288 : ArrayIteratorKind iter_kind) {
212 552 : Node* receiver = NodeProperties::GetValueInput(node, 1);
213 552 : Node* effect = NodeProperties::GetEffectInput(node);
214 552 : Node* control = NodeProperties::GetControlInput(node);
215 :
216 552 : if (iter_kind == ArrayIteratorKind::kTypedArray) {
217 : // See if we can skip the neutering check.
218 50 : if (isolate()->IsArrayBufferNeuteringIntact()) {
219 : // Add a code dependency so we are deoptimized in case an ArrayBuffer
220 : // gets neutered.
221 : dependencies()->AssumePropertyCell(
222 : factory()->array_buffer_neutering_protector());
223 : } else {
224 : // For JSTypedArray iterator methods, deopt if the buffer is neutered.
225 : // This is potentially a deopt loop, but should be extremely unlikely.
226 : DCHECK_EQ(JS_TYPED_ARRAY_TYPE, receiver_map->instance_type());
227 : Node* buffer = effect = graph()->NewNode(
228 : simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
229 117 : receiver, effect, control);
230 :
231 : // Deoptimize if the {buffer} has been neutered.
232 : Node* check = effect = graph()->NewNode(
233 39 : simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
234 39 : check = graph()->NewNode(simplified()->BooleanNot(), check);
235 : effect = graph()->NewNode(
236 : simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered),
237 39 : check, effect, control);
238 : }
239 : }
240 :
241 : int map_index = -1;
242 552 : Node* object_map = jsgraph()->UndefinedConstant();
243 552 : switch (receiver_map->instance_type()) {
244 : case JS_ARRAY_TYPE:
245 502 : if (kind == IterationKind::kKeys) {
246 : map_index = Context::FAST_ARRAY_KEY_ITERATOR_MAP_INDEX;
247 : } else {
248 : map_index = kind == IterationKind::kValues
249 : ? Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX
250 494 : : Context::FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX;
251 :
252 494 : if (CanInlineJSArrayIteration(receiver_map)) {
253 : // Use `generic` elements for holey arrays if there may be elements
254 : // on the prototype chain.
255 491 : map_index += static_cast<int>(receiver_map->elements_kind());
256 491 : object_map = jsgraph()->Constant(receiver_map);
257 491 : if (IsHoleyElementsKind(receiver_map->elements_kind())) {
258 : Handle<JSObject> initial_array_prototype(
259 : native_context()->initial_array_prototype(), isolate());
260 : dependencies()->AssumePrototypeMapsStable(receiver_map,
261 26 : initial_array_prototype);
262 : }
263 : } else {
264 : map_index += (Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX -
265 3 : Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX);
266 : }
267 : }
268 : break;
269 : case JS_TYPED_ARRAY_TYPE:
270 50 : if (kind == IterationKind::kKeys) {
271 : map_index = Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX;
272 : } else {
273 : DCHECK_GE(receiver_map->elements_kind(), UINT8_ELEMENTS);
274 : DCHECK_LE(receiver_map->elements_kind(), UINT8_CLAMPED_ELEMENTS);
275 : map_index = (kind == IterationKind::kValues
276 : ? Context::UINT8_ARRAY_VALUE_ITERATOR_MAP_INDEX
277 50 : : Context::UINT8_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX) +
278 50 : (receiver_map->elements_kind() - UINT8_ELEMENTS);
279 : }
280 : break;
281 : default:
282 0 : if (kind == IterationKind::kKeys) {
283 : map_index = Context::GENERIC_ARRAY_KEY_ITERATOR_MAP_INDEX;
284 0 : } else if (kind == IterationKind::kValues) {
285 : map_index = Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX;
286 : } else {
287 : map_index = Context::GENERIC_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX;
288 : }
289 : break;
290 : }
291 :
292 : DCHECK_GE(map_index, Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX);
293 : DCHECK_LE(map_index, Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX);
294 :
295 : Handle<Map> map(Map::cast(native_context()->get(map_index)), isolate());
296 :
297 : // Allocate new iterator and attach the iterator to this object.
298 : AllocationBuilder a(jsgraph(), effect, control);
299 552 : a.Allocate(JSArrayIterator::kSize, NOT_TENURED, Type::OtherObject());
300 552 : a.Store(AccessBuilder::ForMap(), map);
301 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
302 552 : jsgraph()->EmptyFixedArrayConstant());
303 : a.Store(AccessBuilder::ForJSObjectElements(),
304 552 : jsgraph()->EmptyFixedArrayConstant());
305 552 : a.Store(AccessBuilder::ForJSArrayIteratorObject(), receiver);
306 552 : a.Store(AccessBuilder::ForJSArrayIteratorIndex(), jsgraph()->ZeroConstant());
307 552 : a.Store(AccessBuilder::ForJSArrayIteratorObjectMap(), object_map);
308 552 : Node* value = effect = a.Finish();
309 :
310 : // Replace it.
311 552 : ReplaceWithValue(node, value, effect, control);
312 552 : return Replace(value);
313 : }
314 :
315 669 : Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
316 4458 : Handle<Map> iterator_map, Node* node, IterationKind kind) {
317 669 : Node* iterator = NodeProperties::GetValueInput(node, 1);
318 669 : Node* effect = NodeProperties::GetEffectInput(node);
319 669 : Node* control = NodeProperties::GetControlInput(node);
320 669 : Node* context = NodeProperties::GetContextInput(node);
321 :
322 1330 : if (kind != IterationKind::kKeys &&
323 : !isolate()->IsFastArrayIterationIntact()) {
324 : // Avoid deopt loops for non-key iteration if the
325 : // fast_array_iteration_protector cell has been invalidated.
326 : return NoChange();
327 : }
328 :
329 : ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
330 633 : iterator_map->instance_type());
331 :
332 633 : if (IsHoleyElementsKind(elements_kind)) {
333 27 : if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
334 : return NoChange();
335 : } else {
336 : Handle<JSObject> initial_array_prototype(
337 : native_context()->initial_array_prototype(), isolate());
338 : dependencies()->AssumePropertyCell(factory()->array_protector());
339 : }
340 : }
341 :
342 : Node* array = effect = graph()->NewNode(
343 : simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
344 1899 : iterator, effect, control);
345 : Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array,
346 1266 : jsgraph()->UndefinedConstant());
347 : Node* branch0 =
348 633 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
349 :
350 : Node* vdone_false0;
351 : Node* vfalse0;
352 : Node* efalse0 = effect;
353 633 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
354 : {
355 : // iterator.[[IteratedObject]] !== undefined, continue iterating.
356 : Node* index = efalse0 = graph()->NewNode(
357 : simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex(
358 : JS_ARRAY_TYPE, elements_kind)),
359 1899 : iterator, efalse0, if_false0);
360 :
361 : Node* length = efalse0 = graph()->NewNode(
362 : simplified()->LoadField(AccessBuilder::ForJSArrayLength(elements_kind)),
363 1899 : array, efalse0, if_false0);
364 : Node* check1 =
365 633 : graph()->NewNode(simplified()->NumberLessThan(), index, length);
366 : Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
367 633 : check1, if_false0);
368 :
369 : Node* vdone_true1;
370 : Node* vtrue1;
371 : Node* etrue1 = efalse0;
372 633 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
373 : {
374 : // iterator.[[NextIndex]] < array.length, continue iterating
375 633 : vdone_true1 = jsgraph()->FalseConstant();
376 633 : if (kind == IterationKind::kKeys) {
377 : vtrue1 = index;
378 : } else {
379 : // For value/entry iteration, first step is a mapcheck to ensure
380 : // inlining is still valid.
381 : Node* array_map = etrue1 =
382 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
383 1875 : array, etrue1, if_true1);
384 : Node* orig_map = etrue1 =
385 : graph()->NewNode(simplified()->LoadField(
386 : AccessBuilder::ForJSArrayIteratorObjectMap()),
387 1875 : iterator, etrue1, if_true1);
388 : Node* check_map = graph()->NewNode(simplified()->ReferenceEqual(),
389 625 : array_map, orig_map);
390 : etrue1 =
391 : graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongMap),
392 625 : check_map, etrue1, if_true1);
393 : }
394 :
395 633 : if (kind != IterationKind::kKeys) {
396 : Node* elements = etrue1 = graph()->NewNode(
397 : simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
398 1875 : array, etrue1, if_true1);
399 : Node* value = etrue1 = graph()->NewNode(
400 : simplified()->LoadElement(
401 : AccessBuilder::ForFixedArrayElement(elements_kind)),
402 1875 : elements, index, etrue1, if_true1);
403 :
404 : // Convert hole to undefined if needed.
405 625 : if (elements_kind == HOLEY_ELEMENTS ||
406 : elements_kind == HOLEY_SMI_ELEMENTS) {
407 : value = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(),
408 19 : value);
409 606 : } else if (elements_kind == HOLEY_DOUBLE_ELEMENTS) {
410 : // TODO(6587): avoid deopt if not all uses of value are truncated.
411 : CheckFloat64HoleMode mode = CheckFloat64HoleMode::kAllowReturnHole;
412 : value = etrue1 = graph()->NewNode(
413 8 : simplified()->CheckFloat64Hole(mode), value, etrue1, if_true1);
414 : }
415 :
416 625 : if (kind == IterationKind::kEntries) {
417 : // Allocate elements for key/value pair
418 : vtrue1 = etrue1 =
419 : graph()->NewNode(javascript()->CreateKeyValueArray(), index,
420 7 : value, context, etrue1);
421 : } else {
422 : DCHECK_EQ(kind, IterationKind::kValues);
423 : vtrue1 = value;
424 : }
425 : }
426 :
427 : Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
428 1266 : jsgraph()->OneConstant());
429 633 : next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index);
430 :
431 : etrue1 = graph()->NewNode(
432 : simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex(
433 : JS_ARRAY_TYPE, elements_kind)),
434 1899 : iterator, next_index, etrue1, if_true1);
435 : }
436 :
437 : Node* vdone_false1;
438 : Node* vfalse1;
439 : Node* efalse1 = efalse0;
440 633 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
441 : {
442 : // iterator.[[NextIndex]] >= array.length, stop iterating.
443 633 : vdone_false1 = jsgraph()->TrueConstant();
444 633 : vfalse1 = jsgraph()->UndefinedConstant();
445 : efalse1 = graph()->NewNode(
446 : simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
447 1899 : iterator, vfalse1, efalse1, if_false1);
448 : }
449 :
450 633 : if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
451 : efalse0 =
452 633 : graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
453 : vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
454 633 : vtrue1, vfalse1, if_false0);
455 : vdone_false0 =
456 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
457 633 : vdone_true1, vdone_false1, if_false0);
458 : }
459 :
460 : Node* vdone_true0;
461 : Node* vtrue0;
462 : Node* etrue0 = effect;
463 633 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
464 : {
465 : // iterator.[[IteratedObject]] === undefined, the iterator is done.
466 633 : vdone_true0 = jsgraph()->TrueConstant();
467 633 : vtrue0 = jsgraph()->UndefinedConstant();
468 : }
469 :
470 633 : control = graph()->NewNode(common()->Merge(2), if_false0, if_true0);
471 633 : effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control);
472 : Node* value =
473 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
474 633 : vfalse0, vtrue0, control);
475 : Node* done =
476 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
477 633 : vdone_false0, vdone_true0, control);
478 :
479 : // Create IteratorResult object.
480 : value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
481 633 : value, done, context, effect);
482 633 : ReplaceWithValue(node, value, effect, control);
483 : return Replace(value);
484 : }
485 :
486 50 : Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(
487 361 : Handle<Map> iterator_map, Node* node, IterationKind kind) {
488 50 : Node* iterator = NodeProperties::GetValueInput(node, 1);
489 50 : Node* effect = NodeProperties::GetEffectInput(node);
490 50 : Node* control = NodeProperties::GetControlInput(node);
491 50 : Node* context = NodeProperties::GetContextInput(node);
492 :
493 : ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
494 50 : iterator_map->instance_type());
495 :
496 : Node* array = effect = graph()->NewNode(
497 : simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
498 150 : iterator, effect, control);
499 : Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array,
500 100 : jsgraph()->UndefinedConstant());
501 : Node* branch0 =
502 50 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
503 :
504 : Node* vdone_false0;
505 : Node* vfalse0;
506 : Node* efalse0 = effect;
507 50 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
508 : {
509 : // iterator.[[IteratedObject]] !== undefined, continue iterating.
510 : Node* index = efalse0 = graph()->NewNode(
511 : simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex(
512 : JS_TYPED_ARRAY_TYPE, elements_kind)),
513 150 : iterator, efalse0, if_false0);
514 :
515 : // typedarray.[[ViewedArrayBuffer]]
516 : Node* buffer = efalse0 = graph()->NewNode(
517 : simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
518 150 : array, efalse0, if_false0);
519 :
520 : // See if we can skip the neutering check.
521 50 : if (isolate()->IsArrayBufferNeuteringIntact()) {
522 : // Add a code dependency so we are deoptimized in case an ArrayBuffer
523 : // gets neutered.
524 : dependencies()->AssumePropertyCell(
525 : factory()->array_buffer_neutering_protector());
526 : } else {
527 : // Deoptimize if the array buffer was neutered.
528 : Node* check1 = efalse0 = graph()->NewNode(
529 39 : simplified()->ArrayBufferWasNeutered(), buffer, efalse0, if_false0);
530 39 : check1 = graph()->NewNode(simplified()->BooleanNot(), check1);
531 : efalse0 = graph()->NewNode(
532 : simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered),
533 39 : check1, efalse0, if_false0);
534 : }
535 :
536 : Node* length = efalse0 = graph()->NewNode(
537 : simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()), array,
538 150 : efalse0, if_false0);
539 :
540 : Node* check2 =
541 50 : graph()->NewNode(simplified()->NumberLessThan(), index, length);
542 : Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
543 50 : check2, if_false0);
544 :
545 : Node* vdone_true2;
546 : Node* vtrue2;
547 : Node* etrue2 = efalse0;
548 50 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
549 : {
550 : // iterator.[[NextIndex]] < array.length, continue iterating
551 50 : vdone_true2 = jsgraph()->FalseConstant();
552 50 : if (kind == IterationKind::kKeys) {
553 : vtrue2 = index;
554 : }
555 :
556 : Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
557 100 : jsgraph()->OneConstant());
558 50 : next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index);
559 :
560 : etrue2 = graph()->NewNode(
561 : simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex(
562 : JS_TYPED_ARRAY_TYPE, elements_kind)),
563 150 : iterator, next_index, etrue2, if_true2);
564 :
565 50 : if (kind != IterationKind::kKeys) {
566 : Node* elements = etrue2 = graph()->NewNode(
567 : simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
568 150 : array, etrue2, if_true2);
569 : Node* base_ptr = etrue2 = graph()->NewNode(
570 : simplified()->LoadField(
571 : AccessBuilder::ForFixedTypedArrayBaseBasePointer()),
572 150 : elements, etrue2, if_true2);
573 : Node* external_ptr = etrue2 = graph()->NewNode(
574 : simplified()->LoadField(
575 : AccessBuilder::ForFixedTypedArrayBaseExternalPointer()),
576 150 : elements, etrue2, if_true2);
577 :
578 50 : ExternalArrayType array_type = kExternalInt8Array;
579 50 : switch (elements_kind) {
580 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
581 : case TYPE##_ELEMENTS: \
582 : array_type = kExternal##Type##Array; \
583 : break;
584 18 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
585 : default:
586 0 : UNREACHABLE();
587 : #undef TYPED_ARRAY_CASE
588 : }
589 :
590 : Node* value = etrue2 =
591 : graph()->NewNode(simplified()->LoadTypedElement(array_type), buffer,
592 50 : base_ptr, external_ptr, index, etrue2, if_true2);
593 :
594 50 : if (kind == IterationKind::kEntries) {
595 : // Allocate elements for key/value pair
596 : vtrue2 = etrue2 =
597 : graph()->NewNode(javascript()->CreateKeyValueArray(), index,
598 7 : value, context, etrue2);
599 : } else {
600 : DCHECK_EQ(IterationKind::kValues, kind);
601 : vtrue2 = value;
602 : }
603 : }
604 : }
605 :
606 : Node* vdone_false2;
607 : Node* vfalse2;
608 : Node* efalse2 = efalse0;
609 50 : Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
610 : {
611 : // iterator.[[NextIndex]] >= array.length, stop iterating.
612 50 : vdone_false2 = jsgraph()->TrueConstant();
613 50 : vfalse2 = jsgraph()->UndefinedConstant();
614 : efalse2 = graph()->NewNode(
615 : simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
616 150 : iterator, vfalse2, efalse2, if_false2);
617 : }
618 :
619 50 : if_false0 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
620 : efalse0 =
621 50 : graph()->NewNode(common()->EffectPhi(2), etrue2, efalse2, if_false0);
622 : vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
623 50 : vtrue2, vfalse2, if_false0);
624 : vdone_false0 =
625 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
626 50 : vdone_true2, vdone_false2, if_false0);
627 : }
628 :
629 : Node* vdone_true0;
630 : Node* vtrue0;
631 : Node* etrue0 = effect;
632 50 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
633 : {
634 : // iterator.[[IteratedObject]] === undefined, the iterator is done.
635 50 : vdone_true0 = jsgraph()->TrueConstant();
636 50 : vtrue0 = jsgraph()->UndefinedConstant();
637 : }
638 :
639 50 : control = graph()->NewNode(common()->Merge(2), if_false0, if_true0);
640 50 : effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control);
641 : Node* value =
642 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
643 50 : vfalse0, vtrue0, control);
644 : Node* done =
645 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
646 50 : vdone_false0, vdone_true0, control);
647 :
648 : // Create IteratorResult object.
649 : value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
650 50 : value, done, context, effect);
651 50 : ReplaceWithValue(node, value, effect, control);
652 50 : return Replace(value);
653 : }
654 :
655 : // ES #sec-get-%typedarray%.prototype-@@tostringtag
656 504 : Reduction JSBuiltinReducer::ReduceTypedArrayToStringTag(Node* node) {
657 21 : Node* receiver = NodeProperties::GetValueInput(node, 1);
658 21 : Node* effect = NodeProperties::GetEffectInput(node);
659 21 : Node* control = NodeProperties::GetControlInput(node);
660 :
661 21 : NodeVector values(graph()->zone());
662 21 : NodeVector effects(graph()->zone());
663 21 : NodeVector controls(graph()->zone());
664 :
665 21 : Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
666 : control =
667 63 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
668 :
669 42 : values.push_back(jsgraph()->UndefinedConstant());
670 21 : effects.push_back(effect);
671 84 : controls.push_back(graph()->NewNode(common()->IfTrue(), control));
672 :
673 63 : control = graph()->NewNode(common()->IfFalse(), control);
674 : Node* receiver_map = effect =
675 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
676 63 : receiver, effect, control);
677 : Node* receiver_bit_field2 = effect = graph()->NewNode(
678 : simplified()->LoadField(AccessBuilder::ForMapBitField2()), receiver_map,
679 63 : effect, control);
680 : Node* receiver_elements_kind = graph()->NewNode(
681 : simplified()->NumberShiftRightLogical(),
682 : graph()->NewNode(simplified()->NumberBitwiseAnd(), receiver_bit_field2,
683 : jsgraph()->Constant(Map::ElementsKindBits::kMask)),
684 84 : jsgraph()->Constant(Map::ElementsKindBits::kShift));
685 :
686 : // Offset the elements kind by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
687 : // so that the branch cascade below is turned into a simple table
688 : // switch by the ControlFlowOptimizer later.
689 : receiver_elements_kind = graph()->NewNode(
690 : simplified()->NumberSubtract(), receiver_elements_kind,
691 42 : jsgraph()->Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
692 :
693 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
694 : do { \
695 : Node* check = graph()->NewNode( \
696 : simplified()->NumberEqual(), receiver_elements_kind, \
697 : jsgraph()->Constant(TYPE##_ELEMENTS - \
698 : FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)); \
699 : control = graph()->NewNode(common()->Branch(), check, control); \
700 : values.push_back(jsgraph()->HeapConstant( \
701 : factory()->InternalizeUtf8String(#Type "Array"))); \
702 : effects.push_back(effect); \
703 : controls.push_back(graph()->NewNode(common()->IfTrue(), control)); \
704 : control = graph()->NewNode(common()->IfFalse(), control); \
705 : } while (false);
706 2457 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
707 : #undef TYPED_ARRAY_CASE
708 :
709 42 : values.push_back(jsgraph()->UndefinedConstant());
710 21 : effects.push_back(effect);
711 21 : controls.push_back(control);
712 :
713 42 : int const count = static_cast<int>(controls.size());
714 42 : control = graph()->NewNode(common()->Merge(count), count, &controls.front());
715 21 : effects.push_back(control);
716 : effect =
717 63 : graph()->NewNode(common()->EffectPhi(count), count + 1, &effects.front());
718 21 : values.push_back(control);
719 : Node* value =
720 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
721 42 : count + 1, &values.front());
722 21 : ReplaceWithValue(node, value, effect, control);
723 21 : return Replace(value);
724 : }
725 :
726 728 : Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
727 : Handle<Map> receiver_map;
728 1456 : if (GetMapWitness(node).ToHandle(&receiver_map)) {
729 719 : switch (receiver_map->instance_type()) {
730 : case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
731 : return ReduceTypedArrayIteratorNext(receiver_map, node,
732 0 : IterationKind::kKeys);
733 :
734 : case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
735 : return ReduceFastArrayIteratorNext(receiver_map, node,
736 8 : IterationKind::kKeys);
737 :
738 : case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
739 : case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
740 : case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
741 : case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
742 : case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
743 : case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
744 : case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
745 : case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE:
746 : case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE:
747 : return ReduceTypedArrayIteratorNext(receiver_map, node,
748 7 : IterationKind::kEntries);
749 :
750 : case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
751 : case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
752 : case JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE:
753 : case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE:
754 : case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
755 : case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
756 : return ReduceFastArrayIteratorNext(receiver_map, node,
757 7 : IterationKind::kEntries);
758 :
759 : case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE:
760 : case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE:
761 : case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE:
762 : case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE:
763 : case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE:
764 : case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE:
765 : case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE:
766 : case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE:
767 : case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE:
768 : return ReduceTypedArrayIteratorNext(receiver_map, node,
769 43 : IterationKind::kValues);
770 :
771 : case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE:
772 : case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE:
773 : case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE:
774 : case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE:
775 : case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
776 : case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
777 : return ReduceFastArrayIteratorNext(receiver_map, node,
778 654 : IterationKind::kValues);
779 :
780 : default:
781 : // Slow array iterators are not reduced
782 : return NoChange();
783 : }
784 : }
785 : return NoChange();
786 : }
787 :
788 : // ES6 section 22.1.2.2 Array.isArray ( arg )
789 52 : Reduction JSBuiltinReducer::ReduceArrayIsArray(Node* node) {
790 : // We certainly know that undefined is not an array.
791 28 : if (node->op()->ValueInputCount() < 3) {
792 0 : Node* value = jsgraph()->FalseConstant();
793 14 : ReplaceWithValue(node, value);
794 : return Replace(value);
795 : }
796 14 : Node* value = NodeProperties::GetValueInput(node, 2);
797 : Type* value_type = NodeProperties::GetType(value);
798 14 : Node* context = NodeProperties::GetContextInput(node);
799 14 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
800 14 : Node* effect = NodeProperties::GetEffectInput(node);
801 14 : Node* control = NodeProperties::GetControlInput(node);
802 :
803 : // Constant-fold based on {value} type.
804 14 : if (value_type->Is(Type::Array())) {
805 8 : Node* value = jsgraph()->TrueConstant();
806 : ReplaceWithValue(node, value);
807 : return Replace(value);
808 6 : } else if (!value_type->Maybe(Type::ArrayOrProxy())) {
809 0 : Node* value = jsgraph()->FalseConstant();
810 : ReplaceWithValue(node, value);
811 : return Replace(value);
812 : }
813 :
814 : int count = 0;
815 : Node* values[5];
816 : Node* effects[5];
817 : Node* controls[4];
818 :
819 : // Check if the {value} is a Smi.
820 6 : Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
821 : control =
822 6 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
823 :
824 : // The {value} is a Smi.
825 12 : controls[count] = graph()->NewNode(common()->IfTrue(), control);
826 6 : effects[count] = effect;
827 6 : values[count] = jsgraph()->FalseConstant();
828 : count++;
829 :
830 6 : control = graph()->NewNode(common()->IfFalse(), control);
831 :
832 : // Load the {value}s instance type.
833 : Node* value_map = effect = graph()->NewNode(
834 18 : simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
835 : Node* value_instance_type = effect = graph()->NewNode(
836 : simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
837 18 : effect, control);
838 :
839 : // Check if the {value} is a JSArray.
840 : check = graph()->NewNode(simplified()->NumberEqual(), value_instance_type,
841 12 : jsgraph()->Constant(JS_ARRAY_TYPE));
842 6 : control = graph()->NewNode(common()->Branch(), check, control);
843 :
844 : // The {value} is a JSArray.
845 12 : controls[count] = graph()->NewNode(common()->IfTrue(), control);
846 6 : effects[count] = effect;
847 6 : values[count] = jsgraph()->TrueConstant();
848 : count++;
849 :
850 6 : control = graph()->NewNode(common()->IfFalse(), control);
851 :
852 : // Check if the {value} is a JSProxy.
853 : check = graph()->NewNode(simplified()->NumberEqual(), value_instance_type,
854 12 : jsgraph()->Constant(JS_PROXY_TYPE));
855 : control =
856 6 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
857 :
858 : // The {value} is neither a JSArray nor a JSProxy.
859 12 : controls[count] = graph()->NewNode(common()->IfFalse(), control);
860 6 : effects[count] = effect;
861 6 : values[count] = jsgraph()->FalseConstant();
862 : count++;
863 :
864 6 : control = graph()->NewNode(common()->IfTrue(), control);
865 :
866 : // Let the %ArrayIsArray runtime function deal with the JSProxy {value}.
867 : value = effect = control =
868 : graph()->NewNode(javascript()->CallRuntime(Runtime::kArrayIsArray), value,
869 6 : context, frame_state, effect, control);
870 : NodeProperties::SetType(value, Type::Boolean());
871 :
872 : // Update potential {IfException} uses of {node} to point to the above
873 : // %ArrayIsArray runtime call node instead.
874 6 : Node* on_exception = nullptr;
875 6 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
876 0 : NodeProperties::ReplaceControlInput(on_exception, control);
877 0 : NodeProperties::ReplaceEffectInput(on_exception, effect);
878 0 : control = graph()->NewNode(common()->IfSuccess(), control);
879 0 : Revisit(on_exception);
880 : }
881 :
882 : // The {value} is neither a JSArray nor a JSProxy.
883 6 : controls[count] = control;
884 6 : effects[count] = effect;
885 6 : values[count] = value;
886 : count++;
887 :
888 12 : control = graph()->NewNode(common()->Merge(count), count, controls);
889 6 : effects[count] = control;
890 6 : values[count] = control;
891 12 : effect = graph()->NewNode(common()->EffectPhi(count), count + 1, effects);
892 : value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
893 12 : count + 1, values);
894 : ReplaceWithValue(node, value, effect, control);
895 : return Replace(value);
896 : }
897 :
898 : // ES6 section 22.1.3.17 Array.prototype.pop ( )
899 870 : Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) {
900 : Handle<Map> receiver_map;
901 198 : Node* receiver = NodeProperties::GetValueInput(node, 1);
902 198 : Node* effect = NodeProperties::GetEffectInput(node);
903 198 : Node* control = NodeProperties::GetControlInput(node);
904 : // TODO(turbofan): Extend this to also handle fast holey double elements
905 : // once we got the hole NaN mess sorted out in TurboFan/V8.
906 589 : if (GetMapWitness(node).ToHandle(&receiver_map) &&
907 310 : CanInlineArrayResizeOperation(receiver_map) &&
908 : receiver_map->elements_kind() != HOLEY_DOUBLE_ELEMENTS) {
909 : // Install code dependencies on the {receiver} prototype maps and the
910 : // global array protector cell.
911 : dependencies()->AssumePropertyCell(factory()->array_protector());
912 112 : dependencies()->AssumePrototypeMapsStable(receiver_map);
913 :
914 : // Load the "length" property of the {receiver}.
915 : Node* length = effect = graph()->NewNode(
916 : simplified()->LoadField(
917 : AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
918 336 : receiver, effect, control);
919 :
920 : // Check if the {receiver} has any elements.
921 : Node* check = graph()->NewNode(simplified()->NumberEqual(), length,
922 224 : jsgraph()->ZeroConstant());
923 : Node* branch =
924 112 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
925 :
926 112 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
927 : Node* etrue = effect;
928 112 : Node* vtrue = jsgraph()->UndefinedConstant();
929 :
930 112 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
931 : Node* efalse = effect;
932 : Node* vfalse;
933 : {
934 : // TODO(tebbi): We should trim the backing store if the capacity is too
935 : // big, as implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
936 :
937 : // Load the elements backing store from the {receiver}.
938 : Node* elements = efalse = graph()->NewNode(
939 : simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
940 336 : receiver, efalse, if_false);
941 :
942 : // Ensure that we aren't popping from a copy-on-write backing store.
943 112 : if (IsSmiOrObjectElementsKind(receiver_map->elements_kind())) {
944 : elements = efalse =
945 : graph()->NewNode(simplified()->EnsureWritableFastElements(),
946 78 : receiver, elements, efalse, if_false);
947 : }
948 :
949 : // Compute the new {length}.
950 : length = graph()->NewNode(simplified()->NumberSubtract(), length,
951 224 : jsgraph()->OneConstant());
952 :
953 : // Store the new {length} to the {receiver}.
954 : efalse = graph()->NewNode(
955 : simplified()->StoreField(
956 : AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
957 336 : receiver, length, efalse, if_false);
958 :
959 : // Load the last entry from the {elements}.
960 : vfalse = efalse = graph()->NewNode(
961 : simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(
962 : receiver_map->elements_kind())),
963 336 : elements, length, efalse, if_false);
964 :
965 : // Store a hole to the element we just removed from the {receiver}.
966 : efalse = graph()->NewNode(
967 : simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
968 : GetHoleyElementsKind(receiver_map->elements_kind()))),
969 448 : elements, length, jsgraph()->TheHoleConstant(), efalse, if_false);
970 : }
971 :
972 112 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
973 112 : effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
974 : Node* value =
975 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
976 112 : vtrue, vfalse, control);
977 :
978 : // Convert the hole to undefined. Do this last, so that we can optimize
979 : // conversion operator via some smart strength reduction in many cases.
980 112 : if (IsHoleyElementsKind(receiver_map->elements_kind())) {
981 : value =
982 22 : graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
983 : }
984 :
985 112 : ReplaceWithValue(node, value, effect, control);
986 : return Replace(value);
987 : }
988 : return NoChange();
989 : }
990 :
991 : // ES6 section 22.1.3.18 Array.prototype.push ( )
992 9814 : Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) {
993 : DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
994 4952 : int const num_values = node->op()->ValueInputCount() - 2;
995 2476 : Node* receiver = NodeProperties::GetValueInput(node, 1);
996 2476 : Node* effect = NodeProperties::GetEffectInput(node);
997 2476 : Node* control = NodeProperties::GetControlInput(node);
998 : ZoneHandleSet<Map> receiver_maps;
999 : NodeProperties::InferReceiverMapsResult result =
1000 2476 : NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
1001 2476 : if (receiver_maps.size() != 1) return NoChange();
1002 : DCHECK_NE(NodeProperties::kNoReceiverMaps, result);
1003 :
1004 : // TODO(turbofan): Relax this to deal with multiple {receiver} maps.
1005 : Handle<Map> receiver_map = receiver_maps[0];
1006 2273 : if (CanInlineArrayResizeOperation(receiver_map)) {
1007 : // Collect the value inputs to push.
1008 1454 : std::vector<Node*> values(num_values);
1009 3076 : for (int i = 0; i < num_values; ++i) {
1010 3244 : values[i] = NodeProperties::GetValueInput(node, 2 + i);
1011 : }
1012 :
1013 : // Install code dependencies on the {receiver} prototype maps and the
1014 : // global array protector cell.
1015 : dependencies()->AssumePropertyCell(factory()->array_protector());
1016 1454 : dependencies()->AssumePrototypeMapsStable(receiver_map);
1017 :
1018 : // If the {receiver_maps} information is not reliable, we need
1019 : // to check that the {receiver} still has one of these maps.
1020 1454 : if (result == NodeProperties::kUnreliableReceiverMaps) {
1021 306 : if (receiver_map->is_stable()) {
1022 0 : dependencies()->AssumeMapStable(receiver_map);
1023 : } else {
1024 : // TODO(turbofan): This is a potential - yet unlikely - deoptimization
1025 : // loop, since we might not learn from this deoptimization in baseline
1026 : // code. We need a way to learn from deoptimizations in optimized to
1027 : // address these problems.
1028 : effect = graph()->NewNode(
1029 : simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps),
1030 612 : receiver, effect, control);
1031 : }
1032 : }
1033 :
1034 : // TODO(turbofan): Perform type checks on the {values}. We are not
1035 : // guaranteed to learn from these checks in case they fail, as the witness
1036 : // (i.e. the map check from the LoadIC for a.push) might not be executed in
1037 : // baseline code (after we stored the value in the builtin and thereby
1038 : // changed the elements kind of a) before be decide to optimize this
1039 : // function again. We currently don't have a proper way to deal with this;
1040 : // the proper solution here is to learn on deopt, i.e. disable
1041 : // Array.prototype.push inlining for this function.
1042 4530 : for (auto& value : values) {
1043 1622 : if (IsSmiElementsKind(receiver_map->elements_kind())) {
1044 : value = effect =
1045 2688 : graph()->NewNode(simplified()->CheckSmi(), value, effect, control);
1046 726 : } else if (IsDoubleElementsKind(receiver_map->elements_kind())) {
1047 : value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
1048 648 : effect, control);
1049 : // Make sure we do not store signaling NaNs into double arrays.
1050 432 : value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
1051 : }
1052 : }
1053 :
1054 : // Load the "length" property of the {receiver}.
1055 : Node* length = effect = graph()->NewNode(
1056 : simplified()->LoadField(
1057 : AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
1058 4362 : receiver, effect, control);
1059 : Node* value = length;
1060 :
1061 : // Check if we have any {values} to push.
1062 1454 : if (num_values > 0) {
1063 : // Compute the resulting "length" of the {receiver}.
1064 : Node* new_length = value = graph()->NewNode(
1065 2808 : simplified()->NumberAdd(), length, jsgraph()->Constant(num_values));
1066 :
1067 : // Load the elements backing store of the {receiver}.
1068 : Node* elements = effect = graph()->NewNode(
1069 : simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
1070 4212 : receiver, effect, control);
1071 : Node* elements_length = effect = graph()->NewNode(
1072 : simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
1073 4212 : elements, effect, control);
1074 :
1075 : // TODO(turbofan): Check if we need to grow the {elements} backing store.
1076 : // This will deopt if we cannot grow the array further, and we currently
1077 : // don't necessarily learn from it. See the comment on the value type
1078 : // check above.
1079 : GrowFastElementsMode mode =
1080 : IsDoubleElementsKind(receiver_map->elements_kind())
1081 : ? GrowFastElementsMode::kDoubleElements
1082 1404 : : GrowFastElementsMode::kSmiOrObjectElements;
1083 : elements = effect = graph()->NewNode(
1084 : simplified()->MaybeGrowFastElements(mode), receiver, elements,
1085 : graph()->NewNode(simplified()->NumberAdd(), length,
1086 : jsgraph()->Constant(num_values - 1)),
1087 5616 : elements_length, effect, control);
1088 :
1089 : // Update the JSArray::length field. Since this is observable,
1090 : // there must be no other check after this.
1091 : effect = graph()->NewNode(
1092 : simplified()->StoreField(
1093 : AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
1094 4212 : receiver, new_length, effect, control);
1095 :
1096 : // Append the {values} to the {elements}.
1097 3026 : for (int i = 0; i < num_values; ++i) {
1098 3244 : Node* value = values[i];
1099 : Node* index = graph()->NewNode(simplified()->NumberAdd(), length,
1100 3244 : jsgraph()->Constant(i));
1101 : effect = graph()->NewNode(
1102 : simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
1103 : receiver_map->elements_kind())),
1104 4866 : elements, index, value, effect, control);
1105 : }
1106 : }
1107 :
1108 1454 : ReplaceWithValue(node, value, effect, control);
1109 : return Replace(value);
1110 : }
1111 : return NoChange();
1112 : }
1113 :
1114 : // ES6 section 22.1.3.22 Array.prototype.shift ( )
1115 1643 : Reduction JSBuiltinReducer::ReduceArrayShift(Node* node) {
1116 203 : Node* target = NodeProperties::GetValueInput(node, 0);
1117 203 : Node* receiver = NodeProperties::GetValueInput(node, 1);
1118 203 : Node* context = NodeProperties::GetContextInput(node);
1119 203 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1120 203 : Node* effect = NodeProperties::GetEffectInput(node);
1121 203 : Node* control = NodeProperties::GetControlInput(node);
1122 :
1123 : // TODO(turbofan): Extend this to also handle fast holey double elements
1124 : // once we got the hole NaN mess sorted out in TurboFan/V8.
1125 : Handle<Map> receiver_map;
1126 572 : if (GetMapWitness(node).ToHandle(&receiver_map) &&
1127 291 : CanInlineArrayResizeOperation(receiver_map) &&
1128 : receiver_map->elements_kind() != HOLEY_DOUBLE_ELEMENTS) {
1129 : // Install code dependencies on the {receiver} prototype maps and the
1130 : // global array protector cell.
1131 : dependencies()->AssumePropertyCell(factory()->array_protector());
1132 80 : dependencies()->AssumePrototypeMapsStable(receiver_map);
1133 :
1134 : // Load length of the {receiver}.
1135 : Node* length = effect = graph()->NewNode(
1136 : simplified()->LoadField(
1137 : AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
1138 240 : receiver, effect, control);
1139 :
1140 : // Return undefined if {receiver} has no elements.
1141 : Node* check0 = graph()->NewNode(simplified()->NumberEqual(), length,
1142 160 : jsgraph()->ZeroConstant());
1143 : Node* branch0 =
1144 80 : graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
1145 :
1146 80 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1147 : Node* etrue0 = effect;
1148 80 : Node* vtrue0 = jsgraph()->UndefinedConstant();
1149 :
1150 80 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1151 : Node* efalse0 = effect;
1152 : Node* vfalse0;
1153 : {
1154 : // Check if we should take the fast-path.
1155 : Node* check1 =
1156 : graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
1157 160 : jsgraph()->Constant(JSArray::kMaxCopyElements));
1158 : Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1159 80 : check1, if_false0);
1160 :
1161 80 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1162 : Node* etrue1 = efalse0;
1163 : Node* vtrue1;
1164 : {
1165 : Node* elements = etrue1 = graph()->NewNode(
1166 : simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
1167 240 : receiver, etrue1, if_true1);
1168 :
1169 : // Load the first element here, which we return below.
1170 : vtrue1 = etrue1 = graph()->NewNode(
1171 : simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(
1172 : receiver_map->elements_kind())),
1173 320 : elements, jsgraph()->ZeroConstant(), etrue1, if_true1);
1174 :
1175 : // Ensure that we aren't shifting a copy-on-write backing store.
1176 80 : if (IsSmiOrObjectElementsKind(receiver_map->elements_kind())) {
1177 : elements = etrue1 =
1178 : graph()->NewNode(simplified()->EnsureWritableFastElements(),
1179 68 : receiver, elements, etrue1, if_true1);
1180 : }
1181 :
1182 : // Shift the remaining {elements} by one towards the start.
1183 80 : Node* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1);
1184 : Node* eloop =
1185 80 : graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop);
1186 : Node* index = graph()->NewNode(
1187 : common()->Phi(MachineRepresentation::kTagged, 2),
1188 : jsgraph()->OneConstant(),
1189 240 : jsgraph()->Constant(JSArray::kMaxCopyElements - 1), loop);
1190 :
1191 : {
1192 : Node* check2 =
1193 80 : graph()->NewNode(simplified()->NumberLessThan(), index, length);
1194 80 : Node* branch2 = graph()->NewNode(common()->Branch(), check2, loop);
1195 :
1196 80 : if_true1 = graph()->NewNode(common()->IfFalse(), branch2);
1197 : etrue1 = eloop;
1198 :
1199 80 : Node* control = graph()->NewNode(common()->IfTrue(), branch2);
1200 : Node* effect = etrue1;
1201 :
1202 : ElementAccess const access = AccessBuilder::ForFixedArrayElement(
1203 80 : receiver_map->elements_kind());
1204 : Node* value = effect =
1205 : graph()->NewNode(simplified()->LoadElement(access), elements,
1206 80 : index, effect, control);
1207 : effect = graph()->NewNode(
1208 : simplified()->StoreElement(access), elements,
1209 : graph()->NewNode(simplified()->NumberSubtract(), index,
1210 : jsgraph()->OneConstant()),
1211 240 : value, effect, control);
1212 :
1213 80 : loop->ReplaceInput(1, control);
1214 80 : eloop->ReplaceInput(1, effect);
1215 : index->ReplaceInput(1,
1216 : graph()->NewNode(simplified()->NumberAdd(), index,
1217 240 : jsgraph()->OneConstant()));
1218 : }
1219 :
1220 : // Compute the new {length}.
1221 : length = graph()->NewNode(simplified()->NumberSubtract(), length,
1222 160 : jsgraph()->OneConstant());
1223 :
1224 : // Store the new {length} to the {receiver}.
1225 : etrue1 = graph()->NewNode(
1226 : simplified()->StoreField(
1227 : AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
1228 240 : receiver, length, etrue1, if_true1);
1229 :
1230 : // Store a hole to the element we just removed from the {receiver}.
1231 : etrue1 = graph()->NewNode(
1232 : simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
1233 : GetHoleyElementsKind(receiver_map->elements_kind()))),
1234 320 : elements, length, jsgraph()->TheHoleConstant(), etrue1, if_true1);
1235 : }
1236 :
1237 80 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1238 : Node* efalse1 = efalse0;
1239 : Node* vfalse1;
1240 : {
1241 : // Call the generic C++ implementation.
1242 : const int builtin_index = Builtins::kArrayShift;
1243 : CallDescriptor const* const desc = Linkage::GetCEntryStubCallDescriptor(
1244 : graph()->zone(), 1, BuiltinArguments::kNumExtraArgsWithReceiver,
1245 : Builtins::name(builtin_index), node->op()->properties(),
1246 160 : CallDescriptor::kNeedsFrameState);
1247 : Node* stub_code = jsgraph()->CEntryStubConstant(1, kDontSaveFPRegs,
1248 80 : kArgvOnStack, true);
1249 80 : Address builtin_entry = Builtins::CppEntryOf(builtin_index);
1250 : Node* entry = jsgraph()->ExternalConstant(
1251 160 : ExternalReference(builtin_entry, isolate()));
1252 : Node* argc =
1253 80 : jsgraph()->Constant(BuiltinArguments::kNumExtraArgsWithReceiver);
1254 : if_false1 = efalse1 = vfalse1 =
1255 : graph()->NewNode(common()->Call(desc), stub_code, receiver,
1256 : jsgraph()->PaddingConstant(), argc, target,
1257 : jsgraph()->UndefinedConstant(), entry, argc,
1258 160 : context, frame_state, efalse1, if_false1);
1259 : }
1260 :
1261 80 : if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
1262 : efalse0 =
1263 80 : graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
1264 : vfalse0 =
1265 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1266 80 : vtrue1, vfalse1, if_false0);
1267 : }
1268 :
1269 80 : control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
1270 80 : effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
1271 : Node* value =
1272 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1273 80 : vtrue0, vfalse0, control);
1274 :
1275 : // Convert the hole to undefined. Do this last, so that we can optimize
1276 : // conversion operator via some smart strength reduction in many cases.
1277 80 : if (IsHoleyElementsKind(receiver_map->elements_kind())) {
1278 : value =
1279 14 : graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
1280 : }
1281 :
1282 80 : ReplaceWithValue(node, value, effect, control);
1283 : return Replace(value);
1284 : }
1285 : return NoChange();
1286 : }
1287 :
1288 : namespace {
1289 :
1290 514 : bool HasInstanceTypeWitness(Node* receiver, Node* effect,
1291 : InstanceType instance_type) {
1292 : ZoneHandleSet<Map> receiver_maps;
1293 : NodeProperties::InferReceiverMapsResult result =
1294 514 : NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
1295 514 : switch (result) {
1296 : case NodeProperties::kUnreliableReceiverMaps:
1297 : case NodeProperties::kReliableReceiverMaps:
1298 : DCHECK_NE(0, receiver_maps.size());
1299 1956 : for (size_t i = 0; i < receiver_maps.size(); ++i) {
1300 721 : if (receiver_maps[i]->instance_type() != instance_type) return false;
1301 : }
1302 : return true;
1303 :
1304 : case NodeProperties::kNoReceiverMaps:
1305 : return false;
1306 : }
1307 0 : UNREACHABLE();
1308 : }
1309 :
1310 : } // namespace
1311 :
1312 142 : Reduction JSBuiltinReducer::ReduceCollectionIterator(
1313 : Node* node, InstanceType collection_instance_type,
1314 568 : int collection_iterator_map_index) {
1315 : DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1316 142 : Node* receiver = NodeProperties::GetValueInput(node, 1);
1317 142 : Node* effect = NodeProperties::GetEffectInput(node);
1318 142 : Node* control = NodeProperties::GetControlInput(node);
1319 142 : if (HasInstanceTypeWitness(receiver, effect, collection_instance_type)) {
1320 : // Figure out the proper collection iterator map.
1321 : Handle<Map> collection_iterator_map(
1322 : Map::cast(native_context()->get(collection_iterator_map_index)),
1323 : isolate());
1324 :
1325 : // Load the OrderedHashTable from the {receiver}.
1326 : Node* table = effect = graph()->NewNode(
1327 : simplified()->LoadField(AccessBuilder::ForJSCollectionTable()),
1328 426 : receiver, effect, control);
1329 :
1330 : // Create the JSCollectionIterator result.
1331 : AllocationBuilder a(jsgraph(), effect, control);
1332 142 : a.Allocate(JSCollectionIterator::kSize, NOT_TENURED, Type::OtherObject());
1333 142 : a.Store(AccessBuilder::ForMap(), collection_iterator_map);
1334 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
1335 142 : jsgraph()->EmptyFixedArrayConstant());
1336 : a.Store(AccessBuilder::ForJSObjectElements(),
1337 142 : jsgraph()->EmptyFixedArrayConstant());
1338 142 : a.Store(AccessBuilder::ForJSCollectionIteratorTable(), table);
1339 : a.Store(AccessBuilder::ForJSCollectionIteratorIndex(),
1340 142 : jsgraph()->ZeroConstant());
1341 142 : Node* value = effect = a.Finish();
1342 142 : ReplaceWithValue(node, value, effect, control);
1343 : return Replace(value);
1344 : }
1345 : return NoChange();
1346 : }
1347 :
1348 0 : Reduction JSBuiltinReducer::ReduceCollectionSize(
1349 : Node* node, InstanceType collection_instance_type) {
1350 : DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1351 0 : Node* receiver = NodeProperties::GetValueInput(node, 1);
1352 0 : Node* effect = NodeProperties::GetEffectInput(node);
1353 0 : Node* control = NodeProperties::GetControlInput(node);
1354 0 : if (HasInstanceTypeWitness(receiver, effect, collection_instance_type)) {
1355 : Node* table = effect = graph()->NewNode(
1356 : simplified()->LoadField(AccessBuilder::ForJSCollectionTable()),
1357 0 : receiver, effect, control);
1358 : Node* value = effect = graph()->NewNode(
1359 : simplified()->LoadField(
1360 : AccessBuilder::ForOrderedHashTableBaseNumberOfElements()),
1361 0 : table, effect, control);
1362 0 : ReplaceWithValue(node, value, effect, control);
1363 : return Replace(value);
1364 : }
1365 : return NoChange();
1366 : }
1367 :
1368 266 : Reduction JSBuiltinReducer::ReduceCollectionIteratorNext(
1369 : Node* node, int entry_size,
1370 : InstanceType collection_iterator_instance_type_first,
1371 2464 : InstanceType collection_iterator_instance_type_last) {
1372 : DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
1373 266 : Node* receiver = NodeProperties::GetValueInput(node, 1);
1374 266 : Node* context = NodeProperties::GetContextInput(node);
1375 266 : Node* effect = NodeProperties::GetEffectInput(node);
1376 266 : Node* control = NodeProperties::GetControlInput(node);
1377 :
1378 : // A word of warning to begin with: This whole method might look a bit
1379 : // strange at times, but that's mostly because it was carefully handcrafted
1380 : // to allow for full escape analysis and scalar replacement of both the
1381 : // collection iterator object and the iterator results, including the
1382 : // key-value arrays in case of Set/Map entry iteration.
1383 : //
1384 : // TODO(turbofan): Currently the escape analysis (and the store-load
1385 : // forwarding) is unable to eliminate the allocations for the key-value
1386 : // arrays in case of Set/Map entry iteration, and we should investigate
1387 : // how to update the escape analysis / arrange the graph in a way that
1388 : // this becomes possible.
1389 :
1390 : // Infer the {receiver} instance type.
1391 : InstanceType receiver_instance_type;
1392 : ZoneHandleSet<Map> receiver_maps;
1393 : NodeProperties::InferReceiverMapsResult result =
1394 266 : NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
1395 266 : if (result == NodeProperties::kNoReceiverMaps) return NoChange();
1396 : DCHECK_NE(0, receiver_maps.size());
1397 : receiver_instance_type = receiver_maps[0]->instance_type();
1398 532 : for (size_t i = 1; i < receiver_maps.size(); ++i) {
1399 0 : if (receiver_maps[i]->instance_type() != receiver_instance_type) {
1400 : return NoChange();
1401 : }
1402 : }
1403 532 : if (receiver_instance_type < collection_iterator_instance_type_first ||
1404 266 : receiver_instance_type > collection_iterator_instance_type_last) {
1405 : return NoChange();
1406 : }
1407 :
1408 : // Transition the JSCollectionIterator {receiver} if necessary
1409 : // (i.e. there were certain mutations while we're iterating).
1410 : {
1411 : Node* done_loop;
1412 : Node* done_eloop;
1413 : Node* loop = control =
1414 266 : graph()->NewNode(common()->Loop(2), control, control);
1415 : Node* eloop = effect =
1416 266 : graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1417 :
1418 : // Check if reached the final table of the {receiver}.
1419 : Node* table = effect = graph()->NewNode(
1420 : simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorTable()),
1421 798 : receiver, effect, control);
1422 : Node* next_table = effect =
1423 : graph()->NewNode(simplified()->LoadField(
1424 : AccessBuilder::ForOrderedHashTableBaseNextTable()),
1425 798 : table, effect, control);
1426 266 : Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), next_table);
1427 : control =
1428 266 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1429 :
1430 : // Abort the {loop} when we reach the final table.
1431 266 : done_loop = graph()->NewNode(common()->IfTrue(), control);
1432 : done_eloop = effect;
1433 :
1434 : // Migrate to the {next_table} otherwise.
1435 266 : control = graph()->NewNode(common()->IfFalse(), control);
1436 :
1437 : // Self-heal the {receiver}s index.
1438 : Node* index = effect = graph()->NewNode(
1439 : simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorIndex()),
1440 798 : receiver, effect, control);
1441 : Callable const callable =
1442 266 : Builtins::CallableFor(isolate(), Builtins::kOrderedHashTableHealIndex);
1443 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1444 : isolate(), graph()->zone(), callable.descriptor(), 0,
1445 798 : CallDescriptor::kNoFlags, Operator::kEliminatable);
1446 : index = effect = graph()->NewNode(
1447 : common()->Call(desc), jsgraph()->HeapConstant(callable.code()), table,
1448 798 : index, jsgraph()->NoContextConstant(), effect);
1449 :
1450 : // Update the {index} and {table} on the {receiver}.
1451 : effect = graph()->NewNode(
1452 : simplified()->StoreField(AccessBuilder::ForJSCollectionIteratorIndex()),
1453 798 : receiver, index, effect, control);
1454 : effect = graph()->NewNode(
1455 : simplified()->StoreField(AccessBuilder::ForJSCollectionIteratorTable()),
1456 798 : receiver, next_table, effect, control);
1457 :
1458 : // Tie the knot.
1459 266 : loop->ReplaceInput(1, control);
1460 266 : eloop->ReplaceInput(1, effect);
1461 :
1462 : control = done_loop;
1463 : effect = done_eloop;
1464 : }
1465 :
1466 : // Get current index and table from the JSCollectionIterator {receiver}.
1467 : Node* index = effect = graph()->NewNode(
1468 : simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorIndex()),
1469 798 : receiver, effect, control);
1470 : Node* table = effect = graph()->NewNode(
1471 : simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorTable()),
1472 798 : receiver, effect, control);
1473 :
1474 : // Create the {JSIteratorResult} first to ensure that we always have
1475 : // a dominating Allocate node for the allocation folding phase.
1476 : Node* iterator_result = effect = graph()->NewNode(
1477 : javascript()->CreateIterResultObject(), jsgraph()->UndefinedConstant(),
1478 798 : jsgraph()->TrueConstant(), context, effect);
1479 :
1480 : // Look for the next non-holey key, starting from {index} in the {table}.
1481 : Node* controls[2];
1482 : Node* effects[3];
1483 : {
1484 : // Compute the currently used capacity.
1485 : Node* number_of_buckets = effect = graph()->NewNode(
1486 : simplified()->LoadField(
1487 : AccessBuilder::ForOrderedHashTableBaseNumberOfBuckets()),
1488 798 : table, effect, control);
1489 : Node* number_of_elements = effect = graph()->NewNode(
1490 : simplified()->LoadField(
1491 : AccessBuilder::ForOrderedHashTableBaseNumberOfElements()),
1492 798 : table, effect, control);
1493 : Node* number_of_deleted_elements = effect = graph()->NewNode(
1494 : simplified()->LoadField(
1495 : AccessBuilder::ForOrderedHashTableBaseNumberOfDeletedElements()),
1496 798 : table, effect, control);
1497 : Node* used_capacity =
1498 : graph()->NewNode(simplified()->NumberAdd(), number_of_elements,
1499 266 : number_of_deleted_elements);
1500 :
1501 : // Skip holes and update the {index}.
1502 266 : Node* loop = graph()->NewNode(common()->Loop(2), control, control);
1503 : Node* eloop =
1504 266 : graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1505 : Node* iloop = graph()->NewNode(
1506 266 : common()->Phi(MachineRepresentation::kTagged, 2), index, index, loop);
1507 266 : NodeProperties::SetType(iloop, type_cache_.kFixedArrayLengthType);
1508 : {
1509 : Node* check0 = graph()->NewNode(simplified()->NumberLessThan(), iloop,
1510 266 : used_capacity);
1511 : Node* branch0 =
1512 266 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, loop);
1513 :
1514 266 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1515 : Node* efalse0 = eloop;
1516 : {
1517 : // Mark the {receiver} as exhausted.
1518 : efalse0 = graph()->NewNode(
1519 : simplified()->StoreField(
1520 : AccessBuilder::ForJSCollectionIteratorTable()),
1521 : receiver,
1522 : jsgraph()->HeapConstant(factory()->empty_ordered_hash_table()),
1523 798 : efalse0, if_false0);
1524 :
1525 266 : controls[0] = if_false0;
1526 266 : effects[0] = efalse0;
1527 : }
1528 :
1529 266 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1530 : Node* etrue0 = eloop;
1531 : {
1532 : // Load the key of the entry.
1533 : Node* entry_start_position = graph()->NewNode(
1534 : simplified()->NumberAdd(),
1535 : graph()->NewNode(
1536 : simplified()->NumberAdd(),
1537 : graph()->NewNode(simplified()->NumberMultiply(), iloop,
1538 : jsgraph()->Constant(entry_size)),
1539 : number_of_buckets),
1540 1330 : jsgraph()->Constant(OrderedHashTableBase::kHashTableStartIndex));
1541 : Node* entry_key = etrue0 = graph()->NewNode(
1542 : simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
1543 798 : table, entry_start_position, etrue0, if_true0);
1544 :
1545 : // Advance the index.
1546 : Node* index = graph()->NewNode(simplified()->NumberAdd(), iloop,
1547 532 : jsgraph()->OneConstant());
1548 :
1549 : Node* check1 =
1550 : graph()->NewNode(simplified()->ReferenceEqual(), entry_key,
1551 532 : jsgraph()->TheHoleConstant());
1552 : Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1553 266 : check1, if_true0);
1554 :
1555 : {
1556 : // Abort loop with resulting value.
1557 266 : Node* control = graph()->NewNode(common()->IfFalse(), branch1);
1558 : Node* effect = etrue0;
1559 : Node* value = graph()->NewNode(
1560 266 : common()->TypeGuard(Type::NonInternal()), entry_key, control);
1561 266 : Node* done = jsgraph()->FalseConstant();
1562 :
1563 : // Advance the index on the {receiver}.
1564 : effect = graph()->NewNode(
1565 : simplified()->StoreField(
1566 : AccessBuilder::ForJSCollectionIteratorIndex()),
1567 798 : receiver, index, effect, control);
1568 :
1569 : // The actual {value} depends on the {receiver} iteration type.
1570 266 : switch (receiver_instance_type) {
1571 : case JS_MAP_KEY_ITERATOR_TYPE:
1572 : case JS_SET_VALUE_ITERATOR_TYPE:
1573 : break;
1574 :
1575 : case JS_SET_KEY_VALUE_ITERATOR_TYPE:
1576 : value = effect =
1577 : graph()->NewNode(javascript()->CreateKeyValueArray(), value,
1578 35 : value, context, effect);
1579 35 : break;
1580 :
1581 : case JS_MAP_VALUE_ITERATOR_TYPE:
1582 : value = effect = graph()->NewNode(
1583 : simplified()->LoadElement(
1584 : AccessBuilder::ForFixedArrayElement()),
1585 : table,
1586 : graph()->NewNode(
1587 : simplified()->NumberAdd(), entry_start_position,
1588 : jsgraph()->Constant(OrderedHashMap::kValueOffset)),
1589 175 : effect, control);
1590 35 : break;
1591 :
1592 : case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
1593 : value = effect = graph()->NewNode(
1594 : simplified()->LoadElement(
1595 : AccessBuilder::ForFixedArrayElement()),
1596 : table,
1597 : graph()->NewNode(
1598 : simplified()->NumberAdd(), entry_start_position,
1599 : jsgraph()->Constant(OrderedHashMap::kValueOffset)),
1600 175 : effect, control);
1601 : value = effect =
1602 : graph()->NewNode(javascript()->CreateKeyValueArray(),
1603 35 : entry_key, value, context, effect);
1604 35 : break;
1605 :
1606 : default:
1607 0 : UNREACHABLE();
1608 : break;
1609 : }
1610 :
1611 : // Store final {value} and {done} into the {iterator_result}.
1612 : effect =
1613 : graph()->NewNode(simplified()->StoreField(
1614 : AccessBuilder::ForJSIteratorResultValue()),
1615 798 : iterator_result, value, effect, control);
1616 : effect =
1617 : graph()->NewNode(simplified()->StoreField(
1618 : AccessBuilder::ForJSIteratorResultDone()),
1619 798 : iterator_result, done, effect, control);
1620 :
1621 266 : controls[1] = control;
1622 266 : effects[1] = effect;
1623 : }
1624 :
1625 : // Continue with next loop index.
1626 532 : loop->ReplaceInput(1, graph()->NewNode(common()->IfTrue(), branch1));
1627 266 : eloop->ReplaceInput(1, etrue0);
1628 266 : iloop->ReplaceInput(1, index);
1629 : }
1630 : }
1631 :
1632 532 : control = effects[2] = graph()->NewNode(common()->Merge(2), 2, controls);
1633 532 : effect = graph()->NewNode(common()->EffectPhi(2), 3, effects);
1634 : }
1635 :
1636 : // Yield the final {iterator_result}.
1637 266 : ReplaceWithValue(node, iterator_result, effect, control);
1638 : return Replace(iterator_result);
1639 : }
1640 :
1641 : // ES6 section 20.3.3.1 Date.now ( )
1642 8 : Reduction JSBuiltinReducer::ReduceDateNow(Node* node) {
1643 8 : NodeProperties::RemoveValueInputs(node);
1644 : NodeProperties::ChangeOp(
1645 8 : node, javascript()->CallRuntime(Runtime::kDateCurrentTime));
1646 8 : return Changed(node);
1647 : }
1648 :
1649 : // ES6 section 20.3.4.10 Date.prototype.getTime ( )
1650 0 : Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) {
1651 0 : Node* receiver = NodeProperties::GetValueInput(node, 1);
1652 0 : Node* effect = NodeProperties::GetEffectInput(node);
1653 0 : Node* control = NodeProperties::GetControlInput(node);
1654 0 : if (HasInstanceTypeWitness(receiver, effect, JS_DATE_TYPE)) {
1655 : Node* value = effect = graph()->NewNode(
1656 : simplified()->LoadField(AccessBuilder::ForJSDateValue()), receiver,
1657 0 : effect, control);
1658 0 : ReplaceWithValue(node, value, effect, control);
1659 : return Replace(value);
1660 : }
1661 : return NoChange();
1662 : }
1663 :
1664 : // ES6 section 18.2.2 isFinite ( number )
1665 54 : Reduction JSBuiltinReducer::ReduceGlobalIsFinite(Node* node) {
1666 : JSCallReduction r(node);
1667 54 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1668 : // isFinite(a:plain-primitive) -> NumberEqual(a', a')
1669 : // where a' = NumberSubtract(ToNumber(a), ToNumber(a))
1670 37 : Node* input = ToNumber(r.GetJSCallInput(0));
1671 37 : Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input);
1672 37 : Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff);
1673 : return Replace(value);
1674 : }
1675 : return NoChange();
1676 : }
1677 :
1678 : // ES6 section 18.2.3 isNaN ( number )
1679 11096 : Reduction JSBuiltinReducer::ReduceGlobalIsNaN(Node* node) {
1680 : JSCallReduction r(node);
1681 11096 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1682 : // isNaN(a:plain-primitive) -> BooleanNot(NumberEqual(a', a'))
1683 : // where a' = ToNumber(a)
1684 2954 : Node* input = ToNumber(r.GetJSCallInput(0));
1685 2954 : Node* check = graph()->NewNode(simplified()->NumberEqual(), input, input);
1686 2954 : Node* value = graph()->NewNode(simplified()->BooleanNot(), check);
1687 : return Replace(value);
1688 : }
1689 : return NoChange();
1690 : }
1691 :
1692 24 : Reduction JSBuiltinReducer::ReduceMapGet(Node* node) {
1693 : // We only optimize if we have target, receiver and key parameters.
1694 8 : if (node->op()->ValueInputCount() != 3) return NoChange();
1695 8 : Node* receiver = NodeProperties::GetValueInput(node, 1);
1696 8 : Node* effect = NodeProperties::GetEffectInput(node);
1697 8 : Node* control = NodeProperties::GetControlInput(node);
1698 8 : Node* key = NodeProperties::GetValueInput(node, 2);
1699 :
1700 8 : if (!HasInstanceTypeWitness(receiver, effect, JS_MAP_TYPE)) return NoChange();
1701 :
1702 : Node* table = effect = graph()->NewNode(
1703 : simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
1704 24 : effect, control);
1705 :
1706 : Node* entry = effect = graph()->NewNode(
1707 8 : simplified()->FindOrderedHashMapEntry(), table, key, effect, control);
1708 :
1709 : Node* check = graph()->NewNode(simplified()->NumberEqual(), entry,
1710 16 : jsgraph()->MinusOneConstant());
1711 :
1712 8 : Node* branch = graph()->NewNode(common()->Branch(), check, control);
1713 :
1714 : // Key not found.
1715 8 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1716 : Node* etrue = effect;
1717 8 : Node* vtrue = jsgraph()->UndefinedConstant();
1718 :
1719 : // Key found.
1720 8 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1721 : Node* efalse = effect;
1722 : Node* vfalse = efalse = graph()->NewNode(
1723 : simplified()->LoadElement(AccessBuilder::ForOrderedHashMapEntryValue()),
1724 24 : table, entry, efalse, if_false);
1725 :
1726 8 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1727 : Node* value = graph()->NewNode(
1728 8 : common()->Phi(MachineRepresentation::kTagged, 2), vtrue, vfalse, control);
1729 8 : effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1730 :
1731 8 : ReplaceWithValue(node, value, effect, control);
1732 : return Replace(value);
1733 : }
1734 :
1735 0 : Reduction JSBuiltinReducer::ReduceMapHas(Node* node) {
1736 : // We only optimize if we have target, receiver and key parameters.
1737 0 : if (node->op()->ValueInputCount() != 3) return NoChange();
1738 0 : Node* receiver = NodeProperties::GetValueInput(node, 1);
1739 0 : Node* effect = NodeProperties::GetEffectInput(node);
1740 0 : Node* control = NodeProperties::GetControlInput(node);
1741 0 : Node* key = NodeProperties::GetValueInput(node, 2);
1742 :
1743 0 : if (!HasInstanceTypeWitness(receiver, effect, JS_MAP_TYPE)) return NoChange();
1744 :
1745 : Node* table = effect = graph()->NewNode(
1746 : simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
1747 0 : effect, control);
1748 :
1749 : Node* index = effect = graph()->NewNode(
1750 0 : simplified()->FindOrderedHashMapEntry(), table, key, effect, control);
1751 :
1752 : Node* value = graph()->NewNode(simplified()->NumberEqual(), index,
1753 0 : jsgraph()->MinusOneConstant());
1754 0 : value = graph()->NewNode(simplified()->BooleanNot(), value);
1755 :
1756 0 : ReplaceWithValue(node, value, effect, control);
1757 : return Replace(value);
1758 : }
1759 :
1760 : // ES6 section 20.2.2.1 Math.abs ( x )
1761 466 : Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) {
1762 : JSCallReduction r(node);
1763 466 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1764 : // Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a))
1765 390 : Node* input = ToNumber(r.GetJSCallInput(0));
1766 390 : Node* value = graph()->NewNode(simplified()->NumberAbs(), input);
1767 : return Replace(value);
1768 : }
1769 : return NoChange();
1770 : }
1771 :
1772 : // ES6 section 20.2.2.2 Math.acos ( x )
1773 14 : Reduction JSBuiltinReducer::ReduceMathAcos(Node* node) {
1774 : JSCallReduction r(node);
1775 14 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1776 : // Math.acos(a:plain-primitive) -> NumberAcos(ToNumber(a))
1777 14 : Node* input = ToNumber(r.GetJSCallInput(0));
1778 14 : Node* value = graph()->NewNode(simplified()->NumberAcos(), input);
1779 : return Replace(value);
1780 : }
1781 : return NoChange();
1782 : }
1783 :
1784 : // ES6 section 20.2.2.3 Math.acosh ( x )
1785 13 : Reduction JSBuiltinReducer::ReduceMathAcosh(Node* node) {
1786 : JSCallReduction r(node);
1787 13 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1788 : // Math.acosh(a:plain-primitive) -> NumberAcosh(ToNumber(a))
1789 13 : Node* input = ToNumber(r.GetJSCallInput(0));
1790 13 : Node* value = graph()->NewNode(simplified()->NumberAcosh(), input);
1791 : return Replace(value);
1792 : }
1793 : return NoChange();
1794 : }
1795 :
1796 : // ES6 section 20.2.2.4 Math.asin ( x )
1797 14 : Reduction JSBuiltinReducer::ReduceMathAsin(Node* node) {
1798 : JSCallReduction r(node);
1799 14 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1800 : // Math.asin(a:plain-primitive) -> NumberAsin(ToNumber(a))
1801 14 : Node* input = ToNumber(r.GetJSCallInput(0));
1802 14 : Node* value = graph()->NewNode(simplified()->NumberAsin(), input);
1803 : return Replace(value);
1804 : }
1805 : return NoChange();
1806 : }
1807 :
1808 : // ES6 section 20.2.2.5 Math.asinh ( x )
1809 13 : Reduction JSBuiltinReducer::ReduceMathAsinh(Node* node) {
1810 : JSCallReduction r(node);
1811 13 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1812 : // Math.asinh(a:plain-primitive) -> NumberAsinh(ToNumber(a))
1813 13 : Node* input = ToNumber(r.GetJSCallInput(0));
1814 13 : Node* value = graph()->NewNode(simplified()->NumberAsinh(), input);
1815 : return Replace(value);
1816 : }
1817 : return NoChange();
1818 : }
1819 :
1820 : // ES6 section 20.2.2.6 Math.atan ( x )
1821 14 : Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) {
1822 : JSCallReduction r(node);
1823 14 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1824 : // Math.atan(a:plain-primitive) -> NumberAtan(ToNumber(a))
1825 14 : Node* input = ToNumber(r.GetJSCallInput(0));
1826 14 : Node* value = graph()->NewNode(simplified()->NumberAtan(), input);
1827 : return Replace(value);
1828 : }
1829 : return NoChange();
1830 : }
1831 :
1832 : // ES6 section 20.2.2.7 Math.atanh ( x )
1833 13 : Reduction JSBuiltinReducer::ReduceMathAtanh(Node* node) {
1834 : JSCallReduction r(node);
1835 13 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1836 : // Math.atanh(a:plain-primitive) -> NumberAtanh(ToNumber(a))
1837 13 : Node* input = ToNumber(r.GetJSCallInput(0));
1838 13 : Node* value = graph()->NewNode(simplified()->NumberAtanh(), input);
1839 : return Replace(value);
1840 : }
1841 : return NoChange();
1842 : }
1843 :
1844 : // ES6 section 20.2.2.8 Math.atan2 ( y, x )
1845 162 : Reduction JSBuiltinReducer::ReduceMathAtan2(Node* node) {
1846 : JSCallReduction r(node);
1847 162 : if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
1848 : // Math.atan2(a:plain-primitive,
1849 : // b:plain-primitive) -> NumberAtan2(ToNumber(a),
1850 : // ToNumber(b))
1851 162 : Node* left = ToNumber(r.left());
1852 162 : Node* right = ToNumber(r.right());
1853 162 : Node* value = graph()->NewNode(simplified()->NumberAtan2(), left, right);
1854 : return Replace(value);
1855 : }
1856 : return NoChange();
1857 : }
1858 :
1859 : // ES6 section 20.2.2.10 Math.ceil ( x )
1860 7252 : Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) {
1861 : JSCallReduction r(node);
1862 7252 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1863 : // Math.ceil(a:plain-primitive) -> NumberCeil(ToNumber(a))
1864 5424 : Node* input = ToNumber(r.GetJSCallInput(0));
1865 5424 : Node* value = graph()->NewNode(simplified()->NumberCeil(), input);
1866 : return Replace(value);
1867 : }
1868 : return NoChange();
1869 : }
1870 :
1871 : // ES6 section 20.2.2.11 Math.clz32 ( x )
1872 46 : Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) {
1873 : JSCallReduction r(node);
1874 46 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1875 : // Math.clz32(a:plain-primitive) -> NumberClz32(ToUint32(a))
1876 17 : Node* input = ToUint32(r.GetJSCallInput(0));
1877 17 : Node* value = graph()->NewNode(simplified()->NumberClz32(), input);
1878 : return Replace(value);
1879 : }
1880 : return NoChange();
1881 : }
1882 :
1883 : // ES6 section 20.2.2.12 Math.cos ( x )
1884 34 : Reduction JSBuiltinReducer::ReduceMathCos(Node* node) {
1885 : JSCallReduction r(node);
1886 34 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1887 : // Math.cos(a:plain-primitive) -> NumberCos(ToNumber(a))
1888 14 : Node* input = ToNumber(r.GetJSCallInput(0));
1889 14 : Node* value = graph()->NewNode(simplified()->NumberCos(), input);
1890 : return Replace(value);
1891 : }
1892 : return NoChange();
1893 : }
1894 :
1895 : // ES6 section 20.2.2.13 Math.cosh ( x )
1896 21 : Reduction JSBuiltinReducer::ReduceMathCosh(Node* node) {
1897 : JSCallReduction r(node);
1898 21 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1899 : // Math.cosh(a:plain-primitive) -> NumberCosh(ToNumber(a))
1900 21 : Node* input = ToNumber(r.GetJSCallInput(0));
1901 21 : Node* value = graph()->NewNode(simplified()->NumberCosh(), input);
1902 : return Replace(value);
1903 : }
1904 : return NoChange();
1905 : }
1906 :
1907 : // ES6 section 20.2.2.14 Math.exp ( x )
1908 64 : Reduction JSBuiltinReducer::ReduceMathExp(Node* node) {
1909 : JSCallReduction r(node);
1910 64 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1911 : // Math.exp(a:plain-primitive) -> NumberExp(ToNumber(a))
1912 49 : Node* input = ToNumber(r.GetJSCallInput(0));
1913 49 : Node* value = graph()->NewNode(simplified()->NumberExp(), input);
1914 : return Replace(value);
1915 : }
1916 : return NoChange();
1917 : }
1918 :
1919 : // ES6 section 20.2.2.15 Math.expm1 ( x )
1920 0 : Reduction JSBuiltinReducer::ReduceMathExpm1(Node* node) {
1921 : JSCallReduction r(node);
1922 0 : if (r.InputsMatchOne(Type::Number())) {
1923 : // Math.expm1(a:number) -> NumberExpm1(a)
1924 0 : Node* value = graph()->NewNode(simplified()->NumberExpm1(), r.left());
1925 : return Replace(value);
1926 : }
1927 : return NoChange();
1928 : }
1929 :
1930 : // ES6 section 20.2.2.16 Math.floor ( x )
1931 27376 : Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) {
1932 : JSCallReduction r(node);
1933 27376 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1934 : // Math.floor(a:plain-primitive) -> NumberFloor(ToNumber(a))
1935 9306 : Node* input = ToNumber(r.GetJSCallInput(0));
1936 9306 : Node* value = graph()->NewNode(simplified()->NumberFloor(), input);
1937 : return Replace(value);
1938 : }
1939 : return NoChange();
1940 : }
1941 :
1942 : // ES6 section 20.2.2.17 Math.fround ( x )
1943 1295 : Reduction JSBuiltinReducer::ReduceMathFround(Node* node) {
1944 : JSCallReduction r(node);
1945 1295 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1946 : // Math.fround(a:plain-primitive) -> NumberFround(ToNumber(a))
1947 802 : Node* input = ToNumber(r.GetJSCallInput(0));
1948 802 : Node* value = graph()->NewNode(simplified()->NumberFround(), input);
1949 : return Replace(value);
1950 : }
1951 : return NoChange();
1952 : }
1953 :
1954 : // ES6 section 20.2.2.19 Math.imul ( x, y )
1955 851 : Reduction JSBuiltinReducer::ReduceMathImul(Node* node) {
1956 : JSCallReduction r(node);
1957 851 : if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
1958 : // Math.imul(a:plain-primitive,
1959 : // b:plain-primitive) -> NumberImul(ToUint32(a),
1960 : // ToUint32(b))
1961 33 : Node* left = ToUint32(r.left());
1962 33 : Node* right = ToUint32(r.right());
1963 33 : Node* value = graph()->NewNode(simplified()->NumberImul(), left, right);
1964 : return Replace(value);
1965 : }
1966 : return NoChange();
1967 : }
1968 :
1969 : // ES6 section 20.2.2.20 Math.log ( x )
1970 205 : Reduction JSBuiltinReducer::ReduceMathLog(Node* node) {
1971 : JSCallReduction r(node);
1972 205 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1973 : // Math.log(a:plain-primitive) -> NumberLog(ToNumber(a))
1974 198 : Node* input = ToNumber(r.GetJSCallInput(0));
1975 198 : Node* value = graph()->NewNode(simplified()->NumberLog(), input);
1976 : return Replace(value);
1977 : }
1978 : return NoChange();
1979 : }
1980 :
1981 : // ES6 section 20.2.2.21 Math.log1p ( x )
1982 13 : Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) {
1983 : JSCallReduction r(node);
1984 13 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
1985 : // Math.log1p(a:plain-primitive) -> NumberLog1p(ToNumber(a))
1986 13 : Node* input = ToNumber(r.GetJSCallInput(0));
1987 13 : Node* value = graph()->NewNode(simplified()->NumberLog1p(), input);
1988 : return Replace(value);
1989 : }
1990 : return NoChange();
1991 : }
1992 :
1993 : // ES6 section 20.2.2.22 Math.log10 ( x )
1994 0 : Reduction JSBuiltinReducer::ReduceMathLog10(Node* node) {
1995 : JSCallReduction r(node);
1996 0 : if (r.InputsMatchOne(Type::Number())) {
1997 : // Math.log10(a:number) -> NumberLog10(a)
1998 0 : Node* value = graph()->NewNode(simplified()->NumberLog10(), r.left());
1999 : return Replace(value);
2000 : }
2001 : return NoChange();
2002 : }
2003 :
2004 : // ES6 section 20.2.2.23 Math.log2 ( x )
2005 0 : Reduction JSBuiltinReducer::ReduceMathLog2(Node* node) {
2006 : JSCallReduction r(node);
2007 0 : if (r.InputsMatchOne(Type::Number())) {
2008 : // Math.log2(a:number) -> NumberLog(a)
2009 0 : Node* value = graph()->NewNode(simplified()->NumberLog2(), r.left());
2010 : return Replace(value);
2011 : }
2012 : return NoChange();
2013 : }
2014 :
2015 : // ES6 section 20.2.2.24 Math.max ( value1, value2, ...values )
2016 484 : Reduction JSBuiltinReducer::ReduceMathMax(Node* node) {
2017 : JSCallReduction r(node);
2018 483 : if (r.InputsMatchZero()) {
2019 : // Math.max() -> -Infinity
2020 1 : return Replace(jsgraph()->Constant(-V8_INFINITY));
2021 : }
2022 482 : if (r.InputsMatchAll(Type::PlainPrimitive())) {
2023 : // Math.max(a:plain-primitive, b:plain-primitive, ...)
2024 343 : Node* value = ToNumber(r.GetJSCallInput(0));
2025 1348 : for (int i = 1; i < r.GetJSCallArity(); i++) {
2026 331 : Node* input = ToNumber(r.GetJSCallInput(i));
2027 331 : value = graph()->NewNode(simplified()->NumberMax(), value, input);
2028 : }
2029 : return Replace(value);
2030 : }
2031 : return NoChange();
2032 : }
2033 :
2034 : // ES6 section 20.2.2.25 Math.min ( value1, value2, ...values )
2035 443 : Reduction JSBuiltinReducer::ReduceMathMin(Node* node) {
2036 : JSCallReduction r(node);
2037 442 : if (r.InputsMatchZero()) {
2038 : // Math.min() -> Infinity
2039 1 : return Replace(jsgraph()->Constant(V8_INFINITY));
2040 : }
2041 441 : if (r.InputsMatchAll(Type::PlainPrimitive())) {
2042 : // Math.min(a:plain-primitive, b:plain-primitive, ...)
2043 404 : Node* value = ToNumber(r.GetJSCallInput(0));
2044 1592 : for (int i = 1; i < r.GetJSCallArity(); i++) {
2045 392 : Node* input = ToNumber(r.GetJSCallInput(i));
2046 392 : value = graph()->NewNode(simplified()->NumberMin(), value, input);
2047 : }
2048 : return Replace(value);
2049 : }
2050 : return NoChange();
2051 : }
2052 :
2053 : // ES6 section 20.2.2.26 Math.pow ( x, y )
2054 1247 : Reduction JSBuiltinReducer::ReduceMathPow(Node* node) {
2055 : JSCallReduction r(node);
2056 1247 : if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
2057 : // Math.pow(a:plain-primitive,
2058 : // b:plain-primitive) -> NumberPow(ToNumber(a), ToNumber(b))
2059 1205 : Node* left = ToNumber(r.left());
2060 1205 : Node* right = ToNumber(r.right());
2061 1205 : Node* value = graph()->NewNode(simplified()->NumberPow(), left, right);
2062 : return Replace(value);
2063 : }
2064 : return NoChange();
2065 : }
2066 :
2067 : // ES6 section 20.2.2.28 Math.round ( x )
2068 1578 : Reduction JSBuiltinReducer::ReduceMathRound(Node* node) {
2069 : JSCallReduction r(node);
2070 1578 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
2071 : // Math.round(a:plain-primitive) -> NumberRound(ToNumber(a))
2072 120 : Node* input = ToNumber(r.GetJSCallInput(0));
2073 120 : Node* value = graph()->NewNode(simplified()->NumberRound(), input);
2074 : return Replace(value);
2075 : }
2076 : return NoChange();
2077 : }
2078 :
2079 : // ES6 section 20.2.2.9 Math.cbrt ( x )
2080 0 : Reduction JSBuiltinReducer::ReduceMathCbrt(Node* node) {
2081 : JSCallReduction r(node);
2082 0 : if (r.InputsMatchOne(Type::Number())) {
2083 : // Math.cbrt(a:number) -> NumberCbrt(a)
2084 0 : Node* value = graph()->NewNode(simplified()->NumberCbrt(), r.left());
2085 : return Replace(value);
2086 : }
2087 : return NoChange();
2088 : }
2089 :
2090 : // ES6 section 20.2.2.29 Math.sign ( x )
2091 34 : Reduction JSBuiltinReducer::ReduceMathSign(Node* node) {
2092 : JSCallReduction r(node);
2093 34 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
2094 : // Math.sign(a:plain-primitive) -> NumberSign(ToNumber(a))
2095 34 : Node* input = ToNumber(r.GetJSCallInput(0));
2096 34 : Node* value = graph()->NewNode(simplified()->NumberSign(), input);
2097 : return Replace(value);
2098 : }
2099 : return NoChange();
2100 : }
2101 :
2102 : // ES6 section 20.2.2.30 Math.sin ( x )
2103 58 : Reduction JSBuiltinReducer::ReduceMathSin(Node* node) {
2104 : JSCallReduction r(node);
2105 58 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
2106 : // Math.sin(a:plain-primitive) -> NumberSin(ToNumber(a))
2107 49 : Node* input = ToNumber(r.GetJSCallInput(0));
2108 49 : Node* value = graph()->NewNode(simplified()->NumberSin(), input);
2109 : return Replace(value);
2110 : }
2111 : return NoChange();
2112 : }
2113 :
2114 : // ES6 section 20.2.2.31 Math.sinh ( x )
2115 21 : Reduction JSBuiltinReducer::ReduceMathSinh(Node* node) {
2116 : JSCallReduction r(node);
2117 21 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
2118 : // Math.sinh(a:plain-primitive) -> NumberSinh(ToNumber(a))
2119 21 : Node* input = ToNumber(r.GetJSCallInput(0));
2120 21 : Node* value = graph()->NewNode(simplified()->NumberSinh(), input);
2121 : return Replace(value);
2122 : }
2123 : return NoChange();
2124 : }
2125 :
2126 : // ES6 section 20.2.2.32 Math.sqrt ( x )
2127 93 : Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) {
2128 : JSCallReduction r(node);
2129 93 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
2130 : // Math.sqrt(a:plain-primitive) -> NumberSqrt(ToNumber(a))
2131 58 : Node* input = ToNumber(r.GetJSCallInput(0));
2132 58 : Node* value = graph()->NewNode(simplified()->NumberSqrt(), input);
2133 : return Replace(value);
2134 : }
2135 : return NoChange();
2136 : }
2137 :
2138 : // ES6 section 20.2.2.33 Math.tan ( x )
2139 63 : Reduction JSBuiltinReducer::ReduceMathTan(Node* node) {
2140 : JSCallReduction r(node);
2141 63 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
2142 : // Math.tan(a:plain-primitive) -> NumberTan(ToNumber(a))
2143 22 : Node* input = ToNumber(r.GetJSCallInput(0));
2144 22 : Node* value = graph()->NewNode(simplified()->NumberTan(), input);
2145 : return Replace(value);
2146 : }
2147 : return NoChange();
2148 : }
2149 :
2150 : // ES6 section 20.2.2.34 Math.tanh ( x )
2151 21 : Reduction JSBuiltinReducer::ReduceMathTanh(Node* node) {
2152 : JSCallReduction r(node);
2153 21 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
2154 : // Math.tanh(a:plain-primitive) -> NumberTanh(ToNumber(a))
2155 21 : Node* input = ToNumber(r.GetJSCallInput(0));
2156 21 : Node* value = graph()->NewNode(simplified()->NumberTanh(), input);
2157 : return Replace(value);
2158 : }
2159 : return NoChange();
2160 : }
2161 :
2162 : // ES6 section 20.2.2.35 Math.trunc ( x )
2163 6951 : Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) {
2164 : JSCallReduction r(node);
2165 6951 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
2166 : // Math.trunc(a:plain-primitive) -> NumberTrunc(ToNumber(a))
2167 1343 : Node* input = ToNumber(r.GetJSCallInput(0));
2168 1343 : Node* value = graph()->NewNode(simplified()->NumberTrunc(), input);
2169 : return Replace(value);
2170 : }
2171 : return NoChange();
2172 : }
2173 :
2174 : // ES6 section 20.1.2.2 Number.isFinite ( number )
2175 19 : Reduction JSBuiltinReducer::ReduceNumberIsFinite(Node* node) {
2176 : JSCallReduction r(node);
2177 19 : if (r.InputsMatchOne(Type::Number())) {
2178 : // Number.isFinite(a:number) -> NumberEqual(a', a')
2179 : // where a' = NumberSubtract(a, a)
2180 : Node* input = r.GetJSCallInput(0);
2181 19 : Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input);
2182 19 : Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff);
2183 : return Replace(value);
2184 : }
2185 : return NoChange();
2186 : }
2187 :
2188 : // ES6 section 20.1.2.3 Number.isInteger ( number )
2189 38 : Reduction JSBuiltinReducer::ReduceNumberIsInteger(Node* node) {
2190 : JSCallReduction r(node);
2191 19 : if (r.InputsMatchOne(Type::Number())) {
2192 : // Number.isInteger(x:number) -> NumberEqual(NumberSubtract(x, x'), #0)
2193 : // where x' = NumberTrunc(x)
2194 : Node* input = r.GetJSCallInput(0);
2195 19 : Node* trunc = graph()->NewNode(simplified()->NumberTrunc(), input);
2196 19 : Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, trunc);
2197 : Node* value = graph()->NewNode(simplified()->NumberEqual(), diff,
2198 38 : jsgraph()->ZeroConstant());
2199 : return Replace(value);
2200 : }
2201 : return NoChange();
2202 : }
2203 :
2204 : // ES6 section 20.1.2.4 Number.isNaN ( number )
2205 75 : Reduction JSBuiltinReducer::ReduceNumberIsNaN(Node* node) {
2206 : JSCallReduction r(node);
2207 67 : if (r.InputsMatchZero()) {
2208 : // Number.isNaN() -> #false
2209 8 : Node* value = jsgraph()->FalseConstant();
2210 : return Replace(value);
2211 : }
2212 : // Number.isNaN(a:number) -> ObjectIsNaN(a)
2213 : Node* input = r.GetJSCallInput(0);
2214 59 : Node* value = graph()->NewNode(simplified()->ObjectIsNaN(), input);
2215 : return Replace(value);
2216 : }
2217 :
2218 : // ES6 section 20.1.2.5 Number.isSafeInteger ( number )
2219 21 : Reduction JSBuiltinReducer::ReduceNumberIsSafeInteger(Node* node) {
2220 : JSCallReduction r(node);
2221 14 : if (r.InputsMatchOne(type_cache_.kSafeInteger)) {
2222 : // Number.isInteger(x:safe-integer) -> #true
2223 7 : Node* value = jsgraph()->TrueConstant();
2224 : return Replace(value);
2225 : }
2226 : return NoChange();
2227 : }
2228 :
2229 : // ES6 section 20.1.2.13 Number.parseInt ( string, radix )
2230 415 : Reduction JSBuiltinReducer::ReduceNumberParseInt(Node* node) {
2231 : JSCallReduction r(node);
2232 1230 : if (r.InputsMatchOne(type_cache_.kSafeInteger) ||
2233 : r.InputsMatchTwo(type_cache_.kSafeInteger,
2234 794 : type_cache_.kZeroOrUndefined) ||
2235 379 : r.InputsMatchTwo(type_cache_.kSafeInteger, type_cache_.kTenOrUndefined)) {
2236 : // Number.parseInt(a:safe-integer) -> a
2237 : // Number.parseInt(a:safe-integer,b:#0\/undefined) -> a
2238 : // Number.parseInt(a:safe-integer,b:#10\/undefined) -> a
2239 : Node* value = r.GetJSCallInput(0);
2240 : return Replace(value);
2241 : }
2242 : return NoChange();
2243 : }
2244 :
2245 : // ES6 section #sec-object.create Object.create(proto, properties)
2246 58 : Reduction JSBuiltinReducer::ReduceObjectCreate(Node* node) {
2247 : // We need exactly target, receiver and value parameters.
2248 58 : int arg_count = node->op()->ValueInputCount();
2249 58 : if (arg_count != 3) return NoChange();
2250 58 : Node* effect = NodeProperties::GetEffectInput(node);
2251 58 : Node* control = NodeProperties::GetControlInput(node);
2252 58 : Node* prototype = NodeProperties::GetValueInput(node, 2);
2253 : Type* prototype_type = NodeProperties::GetType(prototype);
2254 : Handle<Map> instance_map;
2255 58 : if (!prototype_type->IsHeapConstant()) return NoChange();
2256 : Handle<HeapObject> prototype_const =
2257 : prototype_type->AsHeapConstant()->Value();
2258 0 : if (!prototype_const->IsNull(isolate()) && !prototype_const->IsJSReceiver()) {
2259 : return NoChange();
2260 : }
2261 0 : instance_map = Map::GetObjectCreateMap(prototype_const);
2262 0 : Node* properties = jsgraph()->EmptyFixedArrayConstant();
2263 0 : if (instance_map->is_dictionary_map()) {
2264 : // Allocated an empty NameDictionary as backing store for the properties.
2265 0 : Handle<Map> map(isolate()->heap()->hash_table_map(), isolate());
2266 : int capacity =
2267 : NameDictionary::ComputeCapacity(NameDictionary::kInitialCapacity);
2268 : DCHECK(base::bits::IsPowerOfTwo(capacity));
2269 : int length = NameDictionary::EntryToIndex(capacity);
2270 : int size = NameDictionary::SizeFor(length);
2271 :
2272 : AllocationBuilder a(jsgraph(), effect, control);
2273 0 : a.Allocate(size, NOT_TENURED, Type::Any());
2274 0 : a.Store(AccessBuilder::ForMap(), map);
2275 : // Initialize FixedArray fields.
2276 : a.Store(AccessBuilder::ForFixedArrayLength(),
2277 0 : jsgraph()->SmiConstant(length));
2278 : // Initialize HashTable fields.
2279 : a.Store(AccessBuilder::ForHashTableBaseNumberOfElements(),
2280 0 : jsgraph()->SmiConstant(0));
2281 : a.Store(AccessBuilder::ForHashTableBaseNumberOfDeletedElement(),
2282 0 : jsgraph()->SmiConstant(0));
2283 : a.Store(AccessBuilder::ForHashTableBaseCapacity(),
2284 0 : jsgraph()->SmiConstant(capacity));
2285 : // Initialize Dictionary fields.
2286 : a.Store(AccessBuilder::ForDictionaryNextEnumerationIndex(),
2287 0 : jsgraph()->SmiConstant(PropertyDetails::kInitialIndex));
2288 : a.Store(AccessBuilder::ForDictionaryObjectHashIndex(),
2289 0 : jsgraph()->SmiConstant(PropertyArray::kNoHashSentinel));
2290 : // Initialize the Properties fields.
2291 0 : Node* undefined = jsgraph()->UndefinedConstant();
2292 : STATIC_ASSERT(NameDictionary::kElementsStartIndex ==
2293 : NameDictionary::kObjectHashIndex + 1);
2294 0 : for (int index = NameDictionary::kElementsStartIndex; index < length;
2295 : index++) {
2296 0 : a.Store(AccessBuilder::ForFixedArraySlot(index, kNoWriteBarrier),
2297 0 : undefined);
2298 : }
2299 0 : properties = effect = a.Finish();
2300 : }
2301 :
2302 : int const instance_size = instance_map->instance_size();
2303 0 : if (instance_size > kMaxRegularHeapObjectSize) return NoChange();
2304 : dependencies()->AssumeInitialMapCantChange(instance_map);
2305 :
2306 : // Emit code to allocate the JSObject instance for the given
2307 : // {instance_map}.
2308 : AllocationBuilder a(jsgraph(), effect, control);
2309 0 : a.Allocate(instance_size, NOT_TENURED, Type::Any());
2310 0 : a.Store(AccessBuilder::ForMap(), instance_map);
2311 0 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
2312 : a.Store(AccessBuilder::ForJSObjectElements(),
2313 0 : jsgraph()->EmptyFixedArrayConstant());
2314 : // Initialize Object fields.
2315 0 : Node* undefined = jsgraph()->UndefinedConstant();
2316 0 : for (int offset = JSObject::kHeaderSize; offset < instance_size;
2317 : offset += kPointerSize) {
2318 : a.Store(AccessBuilder::ForJSObjectOffset(offset, kNoWriteBarrier),
2319 0 : undefined);
2320 : }
2321 0 : Node* value = effect = a.Finish();
2322 :
2323 : // replace it
2324 0 : ReplaceWithValue(node, value, effect, control);
2325 : return Replace(value);
2326 : }
2327 :
2328 : // ES #sec-object.is
2329 90 : Reduction JSBuiltinReducer::ReduceObjectIs(Node* node) {
2330 : // TODO(turbofan): At some point we should probably introduce a new
2331 : // SameValue simplified operator (and also a StrictEqual simplified
2332 : // operator) and create unified handling in SimplifiedLowering.
2333 : JSCallReduction r(node);
2334 158 : if (r.GetJSCallArity() == 2 && r.left() == r.right()) {
2335 : // Object.is(x,x) => #true
2336 7 : Node* value = jsgraph()->TrueConstant();
2337 : return Replace(value);
2338 76 : } else if (r.InputsMatchTwo(Type::Unique(), Type::Unique())) {
2339 : // Object.is(x:Unique,y:Unique) => ReferenceEqual(x,y)
2340 : Node* left = r.GetJSCallInput(0);
2341 : Node* right = r.GetJSCallInput(1);
2342 0 : Node* value = graph()->NewNode(simplified()->ReferenceEqual(), left, right);
2343 : return Replace(value);
2344 76 : } else if (r.InputsMatchTwo(Type::MinusZero(), Type::Any())) {
2345 : // Object.is(x:MinusZero,y) => ObjectIsMinusZero(y)
2346 : Node* input = r.GetJSCallInput(1);
2347 14 : Node* value = graph()->NewNode(simplified()->ObjectIsMinusZero(), input);
2348 : return Replace(value);
2349 62 : } else if (r.InputsMatchTwo(Type::Any(), Type::MinusZero())) {
2350 : // Object.is(x,y:MinusZero) => ObjectIsMinusZero(x)
2351 : Node* input = r.GetJSCallInput(0);
2352 14 : Node* value = graph()->NewNode(simplified()->ObjectIsMinusZero(), input);
2353 : return Replace(value);
2354 48 : } else if (r.InputsMatchTwo(Type::NaN(), Type::Any())) {
2355 : // Object.is(x:NaN,y) => ObjectIsNaN(y)
2356 : Node* input = r.GetJSCallInput(1);
2357 14 : Node* value = graph()->NewNode(simplified()->ObjectIsNaN(), input);
2358 : return Replace(value);
2359 34 : } else if (r.InputsMatchTwo(Type::Any(), Type::NaN())) {
2360 : // Object.is(x,y:NaN) => ObjectIsNaN(x)
2361 : Node* input = r.GetJSCallInput(0);
2362 14 : Node* value = graph()->NewNode(simplified()->ObjectIsNaN(), input);
2363 : return Replace(value);
2364 20 : } else if (r.InputsMatchTwo(Type::String(), Type::String())) {
2365 : // Object.is(x:String,y:String) => StringEqual(x,y)
2366 : Node* left = r.GetJSCallInput(0);
2367 : Node* right = r.GetJSCallInput(1);
2368 7 : Node* value = graph()->NewNode(simplified()->StringEqual(), left, right);
2369 : return Replace(value);
2370 : }
2371 : return NoChange();
2372 : }
2373 :
2374 : // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits )
2375 181 : Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) {
2376 : JSCallReduction r(node);
2377 181 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
2378 : // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a)
2379 154 : Node* input = ToNumber(r.GetJSCallInput(0));
2380 154 : Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input);
2381 : return Replace(value);
2382 : }
2383 : return NoChange();
2384 : }
2385 :
2386 : namespace {
2387 :
2388 673 : Node* GetStringWitness(Node* node) {
2389 673 : Node* receiver = NodeProperties::GetValueInput(node, 1);
2390 : Type* receiver_type = NodeProperties::GetType(receiver);
2391 673 : Node* effect = NodeProperties::GetEffectInput(node);
2392 673 : if (receiver_type->Is(Type::String())) return receiver;
2393 : // Check if the {node} is dominated by a CheckString renaming for
2394 : // it's {receiver}, and if so use that renaming as {receiver} for
2395 : // the lowering below.
2396 547 : for (Node* dominator = effect;;) {
2397 716 : if ((dominator->opcode() == IrOpcode::kCheckString ||
2398 303 : dominator->opcode() == IrOpcode::kCheckInternalizedString ||
2399 692 : dominator->opcode() == IrOpcode::kCheckSeqString) &&
2400 279 : NodeProperties::IsSame(dominator->InputAt(0), receiver)) {
2401 : return dominator;
2402 : }
2403 134 : if (dominator->op()->EffectInputCount() != 1) {
2404 : // Didn't find any appropriate CheckString node.
2405 : return nullptr;
2406 : }
2407 131 : dominator = NodeProperties::GetEffectInput(dominator);
2408 131 : }
2409 : }
2410 :
2411 : } // namespace
2412 :
2413 : // ES6 section 21.1.3.1 String.prototype.charAt ( pos )
2414 179 : Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) {
2415 : // We need at least target, receiver and index parameters.
2416 210 : if (node->op()->ValueInputCount() >= 3) {
2417 105 : Node* index = NodeProperties::GetValueInput(node, 2);
2418 : Type* index_type = NodeProperties::GetType(index);
2419 105 : Node* effect = NodeProperties::GetEffectInput(node);
2420 105 : Node* control = NodeProperties::GetControlInput(node);
2421 :
2422 105 : if (index_type->Is(Type::Integral32OrMinusZeroOrNaN())) {
2423 77 : if (Node* receiver = GetStringWitness(node)) {
2424 74 : if (!index_type->Is(Type::Unsigned32())) {
2425 : // Map -0 and NaN to 0 (as per ToInteger), and the values in
2426 : // the [-2^31,-1] range to the [2^31,2^32-1] range, which will
2427 : // be considered out-of-bounds as well, because of the maximal
2428 : // String length limit in V8.
2429 : STATIC_ASSERT(String::kMaxLength <= kMaxInt);
2430 5 : index = graph()->NewNode(simplified()->NumberToUint32(), index);
2431 : }
2432 :
2433 : // Determine the {receiver} length.
2434 : Node* receiver_length = effect = graph()->NewNode(
2435 : simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
2436 222 : effect, control);
2437 :
2438 : // Check if {index} is less than {receiver} length.
2439 : Node* check = graph()->NewNode(simplified()->NumberLessThan(), index,
2440 74 : receiver_length);
2441 : Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
2442 74 : check, control);
2443 :
2444 : // Return the character from the {receiver} as single character string.
2445 74 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
2446 : Node* vtrue = graph()->NewNode(simplified()->StringCharAt(), receiver,
2447 74 : index, if_true);
2448 :
2449 : // Return the empty string otherwise.
2450 74 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
2451 74 : Node* vfalse = jsgraph()->EmptyStringConstant();
2452 :
2453 74 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
2454 : Node* value =
2455 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2456 74 : vtrue, vfalse, control);
2457 :
2458 74 : ReplaceWithValue(node, value, effect, control);
2459 : return Replace(value);
2460 : }
2461 : }
2462 : }
2463 :
2464 : return NoChange();
2465 : }
2466 :
2467 : // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
2468 798 : Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) {
2469 : // We need at least target, receiver and index parameters.
2470 878 : if (node->op()->ValueInputCount() >= 3) {
2471 439 : Node* index = NodeProperties::GetValueInput(node, 2);
2472 : Type* index_type = NodeProperties::GetType(index);
2473 439 : Node* effect = NodeProperties::GetEffectInput(node);
2474 439 : Node* control = NodeProperties::GetControlInput(node);
2475 :
2476 439 : if (index_type->Is(Type::Integral32OrMinusZeroOrNaN())) {
2477 359 : if (Node* receiver = GetStringWitness(node)) {
2478 359 : if (!index_type->Is(Type::Unsigned32())) {
2479 : // Map -0 and NaN to 0 (as per ToInteger), and the values in
2480 : // the [-2^31,-1] range to the [2^31,2^32-1] range, which will
2481 : // be considered out-of-bounds as well, because of the maximal
2482 : // String length limit in V8.
2483 : STATIC_ASSERT(String::kMaxLength <= kMaxInt);
2484 5 : index = graph()->NewNode(simplified()->NumberToUint32(), index);
2485 : }
2486 :
2487 : // Determine the {receiver} length.
2488 : Node* receiver_length = effect = graph()->NewNode(
2489 : simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
2490 1077 : effect, control);
2491 :
2492 : // Check if {index} is less than {receiver} length.
2493 : Node* check = graph()->NewNode(simplified()->NumberLessThan(), index,
2494 359 : receiver_length);
2495 : Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
2496 359 : check, control);
2497 :
2498 : // Load the character from the {receiver}.
2499 359 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
2500 : Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(),
2501 359 : receiver, index, if_true);
2502 :
2503 : // Return NaN otherwise.
2504 359 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
2505 359 : Node* vfalse = jsgraph()->NaNConstant();
2506 :
2507 359 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
2508 : Node* value =
2509 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2510 359 : vtrue, vfalse, control);
2511 :
2512 359 : ReplaceWithValue(node, value, effect, control);
2513 : return Replace(value);
2514 : }
2515 : }
2516 : }
2517 :
2518 : return NoChange();
2519 : }
2520 :
2521 : // ES6 String.prototype.concat(...args)
2522 : // #sec-string.prototype.concat
2523 1 : Reduction JSBuiltinReducer::ReduceStringConcat(Node* node) {
2524 1 : if (Node* receiver = GetStringWitness(node)) {
2525 : JSCallReduction r(node);
2526 1 : if (r.InputsMatchOne(Type::PlainPrimitive())) {
2527 : // String.prototype.concat(lhs:string, rhs:plain-primitive)
2528 : // -> Call[StringAddStub](lhs, rhs)
2529 0 : StringAddFlags flags = r.InputsMatchOne(Type::String())
2530 : ? STRING_ADD_CHECK_NONE
2531 0 : : STRING_ADD_CONVERT_RIGHT;
2532 : // TODO(turbofan): Massage the FrameState of the {node} here once we
2533 : // have an artificial builtin frame type, so that it looks like the
2534 : // exception from StringAdd overflow came from String.prototype.concat
2535 : // builtin instead of the calling function.
2536 : Callable const callable =
2537 0 : CodeFactory::StringAdd(isolate(), flags, NOT_TENURED);
2538 : CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
2539 : isolate(), graph()->zone(), callable.descriptor(), 0,
2540 : CallDescriptor::kNeedsFrameState,
2541 0 : Operator::kNoDeopt | Operator::kNoWrite);
2542 0 : node->ReplaceInput(0, jsgraph()->HeapConstant(callable.code()));
2543 0 : node->ReplaceInput(1, receiver);
2544 0 : NodeProperties::ChangeOp(node, common()->Call(desc));
2545 : return Changed(node);
2546 : }
2547 : }
2548 :
2549 : return NoChange();
2550 : }
2551 :
2552 : // ES6 String.prototype.indexOf(searchString [, position])
2553 : // #sec-string.prototype.indexof
2554 537 : Reduction JSBuiltinReducer::ReduceStringIndexOf(Node* node) {
2555 : // We need at least target, receiver and search_string parameters.
2556 406 : if (node->op()->ValueInputCount() >= 3) {
2557 203 : Node* search_string = NodeProperties::GetValueInput(node, 2);
2558 : Type* search_string_type = NodeProperties::GetType(search_string);
2559 203 : Node* position = (node->op()->ValueInputCount() >= 4)
2560 : ? NodeProperties::GetValueInput(node, 3)
2561 334 : : jsgraph()->ZeroConstant();
2562 : Type* position_type = NodeProperties::GetType(position);
2563 :
2564 398 : if (search_string_type->Is(Type::String()) &&
2565 : position_type->Is(Type::SignedSmall())) {
2566 195 : if (Node* receiver = GetStringWitness(node)) {
2567 : RelaxEffectsAndControls(node);
2568 195 : node->ReplaceInput(0, receiver);
2569 195 : node->ReplaceInput(1, search_string);
2570 195 : node->ReplaceInput(2, position);
2571 195 : node->TrimInputCount(3);
2572 195 : NodeProperties::ChangeOp(node, simplified()->StringIndexOf());
2573 : return Changed(node);
2574 : }
2575 : }
2576 : }
2577 : return NoChange();
2578 : }
2579 :
2580 246 : Reduction JSBuiltinReducer::ReduceStringIterator(Node* node) {
2581 41 : if (Node* receiver = GetStringWitness(node)) {
2582 41 : Node* effect = NodeProperties::GetEffectInput(node);
2583 41 : Node* control = NodeProperties::GetControlInput(node);
2584 :
2585 : Node* map = jsgraph()->HeapConstant(
2586 41 : handle(native_context()->string_iterator_map(), isolate()));
2587 :
2588 : // Allocate new iterator and attach the iterator to this string.
2589 : AllocationBuilder a(jsgraph(), effect, control);
2590 41 : a.Allocate(JSStringIterator::kSize, NOT_TENURED, Type::OtherObject());
2591 41 : a.Store(AccessBuilder::ForMap(), map);
2592 : a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
2593 41 : jsgraph()->EmptyFixedArrayConstant());
2594 : a.Store(AccessBuilder::ForJSObjectElements(),
2595 41 : jsgraph()->EmptyFixedArrayConstant());
2596 41 : a.Store(AccessBuilder::ForJSStringIteratorString(), receiver);
2597 : a.Store(AccessBuilder::ForJSStringIteratorIndex(),
2598 41 : jsgraph()->SmiConstant(0));
2599 41 : Node* value = effect = a.Finish();
2600 :
2601 : // Replace it.
2602 41 : ReplaceWithValue(node, value, effect, control);
2603 : return Replace(value);
2604 : }
2605 : return NoChange();
2606 : }
2607 :
2608 320 : Reduction JSBuiltinReducer::ReduceStringIteratorNext(Node* node) {
2609 32 : Node* receiver = NodeProperties::GetValueInput(node, 1);
2610 32 : Node* effect = NodeProperties::GetEffectInput(node);
2611 32 : Node* control = NodeProperties::GetControlInput(node);
2612 32 : Node* context = NodeProperties::GetContextInput(node);
2613 32 : if (HasInstanceTypeWitness(receiver, effect, JS_STRING_ITERATOR_TYPE)) {
2614 : Node* string = effect = graph()->NewNode(
2615 : simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()),
2616 96 : receiver, effect, control);
2617 : Node* index = effect = graph()->NewNode(
2618 : simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()),
2619 96 : receiver, effect, control);
2620 : Node* length = effect = graph()->NewNode(
2621 : simplified()->LoadField(AccessBuilder::ForStringLength()), string,
2622 96 : effect, control);
2623 :
2624 : // branch0: if (index < length)
2625 : Node* check0 =
2626 32 : graph()->NewNode(simplified()->NumberLessThan(), index, length);
2627 : Node* branch0 =
2628 32 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
2629 :
2630 : Node* etrue0 = effect;
2631 32 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
2632 : Node* done_true;
2633 : Node* vtrue0;
2634 : {
2635 32 : done_true = jsgraph()->FalseConstant();
2636 : Node* lead = graph()->NewNode(simplified()->StringCharCodeAt(), string,
2637 32 : index, if_true0);
2638 :
2639 : // branch1: if ((lead & 0xFC00) === 0xD800)
2640 : Node* check1 =
2641 : graph()->NewNode(simplified()->NumberEqual(),
2642 : graph()->NewNode(simplified()->NumberBitwiseAnd(),
2643 : lead, jsgraph()->Constant(0xFC00)),
2644 128 : jsgraph()->Constant(0xD800));
2645 : Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
2646 32 : check1, if_true0);
2647 32 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
2648 : Node* vtrue1;
2649 : {
2650 : Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
2651 64 : jsgraph()->OneConstant());
2652 : // branch2: if ((index + 1) < length)
2653 : Node* check2 = graph()->NewNode(simplified()->NumberLessThan(),
2654 32 : next_index, length);
2655 : Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
2656 32 : check2, if_true1);
2657 32 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
2658 : Node* vtrue2;
2659 : {
2660 : Node* trail = graph()->NewNode(simplified()->StringCharCodeAt(),
2661 32 : string, next_index, if_true2);
2662 : // branch3: if ((trail & 0xFC00) === 0xDC00)
2663 : Node* check3 = graph()->NewNode(
2664 : simplified()->NumberEqual(),
2665 : graph()->NewNode(simplified()->NumberBitwiseAnd(), trail,
2666 : jsgraph()->Constant(0xFC00)),
2667 128 : jsgraph()->Constant(0xDC00));
2668 : Node* branch3 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
2669 32 : check3, if_true2);
2670 32 : Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
2671 : Node* vtrue3;
2672 : {
2673 : vtrue3 = graph()->NewNode(
2674 : simplified()->NumberBitwiseOr(),
2675 : // Need to swap the order for big-endian platforms
2676 : #if V8_TARGET_BIG_ENDIAN
2677 : graph()->NewNode(simplified()->NumberShiftLeft(), lead,
2678 : jsgraph()->Constant(16)),
2679 : trail);
2680 : #else
2681 : graph()->NewNode(simplified()->NumberShiftLeft(), trail,
2682 : jsgraph()->Constant(16)),
2683 96 : lead);
2684 : #endif
2685 : }
2686 :
2687 32 : Node* if_false3 = graph()->NewNode(common()->IfFalse(), branch3);
2688 : Node* vfalse3 = lead;
2689 32 : if_true2 = graph()->NewNode(common()->Merge(2), if_true3, if_false3);
2690 : vtrue2 =
2691 : graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
2692 32 : vtrue3, vfalse3, if_true2);
2693 : }
2694 :
2695 32 : Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
2696 : Node* vfalse2 = lead;
2697 32 : if_true1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
2698 : vtrue1 =
2699 : graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
2700 32 : vtrue2, vfalse2, if_true1);
2701 : }
2702 :
2703 32 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
2704 : Node* vfalse1 = lead;
2705 32 : if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
2706 : vtrue0 =
2707 : graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
2708 32 : vtrue1, vfalse1, if_true0);
2709 : vtrue0 = graph()->NewNode(
2710 32 : simplified()->StringFromCodePoint(UnicodeEncoding::UTF16), vtrue0);
2711 :
2712 : // Update iterator.[[NextIndex]]
2713 : Node* char_length = etrue0 = graph()->NewNode(
2714 : simplified()->LoadField(AccessBuilder::ForStringLength()), vtrue0,
2715 96 : etrue0, if_true0);
2716 32 : index = graph()->NewNode(simplified()->NumberAdd(), index, char_length);
2717 : etrue0 = graph()->NewNode(
2718 : simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()),
2719 96 : receiver, index, etrue0, if_true0);
2720 : }
2721 :
2722 32 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
2723 : Node* done_false;
2724 : Node* vfalse0;
2725 : {
2726 32 : vfalse0 = jsgraph()->UndefinedConstant();
2727 32 : done_false = jsgraph()->TrueConstant();
2728 : }
2729 :
2730 32 : control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
2731 32 : effect = graph()->NewNode(common()->EffectPhi(2), etrue0, effect, control);
2732 : Node* value =
2733 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2734 32 : vtrue0, vfalse0, control);
2735 : Node* done =
2736 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2737 32 : done_true, done_false, control);
2738 :
2739 : value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
2740 32 : value, done, context, effect);
2741 :
2742 32 : ReplaceWithValue(node, value, effect, control);
2743 : return Replace(value);
2744 : }
2745 : return NoChange();
2746 : }
2747 :
2748 0 : Reduction JSBuiltinReducer::ReduceStringToLowerCaseIntl(Node* node) {
2749 0 : if (Node* receiver = GetStringWitness(node)) {
2750 : RelaxEffectsAndControls(node);
2751 0 : node->ReplaceInput(0, receiver);
2752 0 : node->TrimInputCount(1);
2753 0 : NodeProperties::ChangeOp(node, simplified()->StringToLowerCaseIntl());
2754 : NodeProperties::SetType(node, Type::String());
2755 : return Changed(node);
2756 : }
2757 : return NoChange();
2758 : }
2759 :
2760 0 : Reduction JSBuiltinReducer::ReduceStringToUpperCaseIntl(Node* node) {
2761 0 : if (Node* receiver = GetStringWitness(node)) {
2762 : RelaxEffectsAndControls(node);
2763 0 : node->ReplaceInput(0, receiver);
2764 0 : node->TrimInputCount(1);
2765 0 : NodeProperties::ChangeOp(node, simplified()->StringToUpperCaseIntl());
2766 : NodeProperties::SetType(node, Type::String());
2767 : return Changed(node);
2768 : }
2769 : return NoChange();
2770 : }
2771 :
2772 0 : Reduction JSBuiltinReducer::ReduceArrayBufferIsView(Node* node) {
2773 0 : Node* value = node->op()->ValueInputCount() >= 3
2774 : ? NodeProperties::GetValueInput(node, 2)
2775 0 : : jsgraph()->UndefinedConstant();
2776 : RelaxEffectsAndControls(node);
2777 0 : node->ReplaceInput(0, value);
2778 0 : node->TrimInputCount(1);
2779 0 : NodeProperties::ChangeOp(node, simplified()->ObjectIsArrayBufferView());
2780 0 : return Changed(node);
2781 : }
2782 :
2783 332 : Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor(
2784 332 : Node* node, InstanceType instance_type, FieldAccess const& access) {
2785 332 : Node* receiver = NodeProperties::GetValueInput(node, 1);
2786 332 : Node* effect = NodeProperties::GetEffectInput(node);
2787 332 : Node* control = NodeProperties::GetControlInput(node);
2788 332 : if (HasInstanceTypeWitness(receiver, effect, instance_type)) {
2789 : // Load the {receiver}s field.
2790 : Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
2791 332 : receiver, effect, control);
2792 :
2793 : // See if we can skip the neutering check.
2794 332 : if (isolate()->IsArrayBufferNeuteringIntact()) {
2795 : // Add a code dependency so we are deoptimized in case an ArrayBuffer
2796 : // gets neutered.
2797 : dependencies()->AssumePropertyCell(
2798 : factory()->array_buffer_neutering_protector());
2799 : } else {
2800 : // Check if the {receiver}s buffer was neutered.
2801 : Node* receiver_buffer = effect = graph()->NewNode(
2802 : simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
2803 63 : receiver, effect, control);
2804 : Node* check = effect =
2805 : graph()->NewNode(simplified()->ArrayBufferWasNeutered(),
2806 21 : receiver_buffer, effect, control);
2807 :
2808 : // Default to zero if the {receiver}s buffer was neutered.
2809 : value = graph()->NewNode(
2810 : common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
2811 42 : check, jsgraph()->ZeroConstant(), value);
2812 : }
2813 :
2814 332 : ReplaceWithValue(node, value, effect, control);
2815 : return Replace(value);
2816 : }
2817 : return NoChange();
2818 : }
2819 :
2820 31934249 : Reduction JSBuiltinReducer::Reduce(Node* node) {
2821 : Reduction reduction = NoChange();
2822 : JSCallReduction r(node);
2823 :
2824 : // Dispatch according to the BuiltinFunctionId if present.
2825 31934249 : if (!r.HasBuiltinFunctionId()) return NoChange();
2826 70911 : switch (r.GetBuiltinFunctionId()) {
2827 : case kArrayEntries:
2828 7 : return ReduceArrayIterator(node, IterationKind::kEntries);
2829 : case kArrayKeys:
2830 8 : return ReduceArrayIterator(node, IterationKind::kKeys);
2831 : case kArrayValues:
2832 595 : return ReduceArrayIterator(node, IterationKind::kValues);
2833 : case kArrayIteratorNext:
2834 728 : return ReduceArrayIteratorNext(node);
2835 : case kArrayIsArray:
2836 14 : return ReduceArrayIsArray(node);
2837 : case kArrayPop:
2838 198 : return ReduceArrayPop(node);
2839 : case kArrayPush:
2840 2476 : return ReduceArrayPush(node);
2841 : case kArrayShift:
2842 203 : return ReduceArrayShift(node);
2843 : case kDateNow:
2844 8 : return ReduceDateNow(node);
2845 : case kDateGetTime:
2846 0 : return ReduceDateGetTime(node);
2847 : case kGlobalIsFinite:
2848 54 : reduction = ReduceGlobalIsFinite(node);
2849 54 : break;
2850 : case kGlobalIsNaN:
2851 11096 : reduction = ReduceGlobalIsNaN(node);
2852 11096 : break;
2853 : case kMapEntries:
2854 : return ReduceCollectionIterator(
2855 14 : node, JS_MAP_TYPE, Context::MAP_KEY_VALUE_ITERATOR_MAP_INDEX);
2856 : case kMapGet:
2857 8 : reduction = ReduceMapGet(node);
2858 8 : break;
2859 : case kMapHas:
2860 0 : reduction = ReduceMapHas(node);
2861 0 : break;
2862 : case kMapKeys:
2863 : return ReduceCollectionIterator(node, JS_MAP_TYPE,
2864 14 : Context::MAP_KEY_ITERATOR_MAP_INDEX);
2865 : case kMapSize:
2866 0 : return ReduceCollectionSize(node, JS_MAP_TYPE);
2867 : case kMapValues:
2868 : return ReduceCollectionIterator(node, JS_MAP_TYPE,
2869 35 : Context::MAP_VALUE_ITERATOR_MAP_INDEX);
2870 : case kMapIteratorNext:
2871 : return ReduceCollectionIteratorNext(node, OrderedHashMap::kEntrySize,
2872 : FIRST_MAP_ITERATOR_TYPE,
2873 105 : LAST_MAP_ITERATOR_TYPE);
2874 : case kMathAbs:
2875 466 : reduction = ReduceMathAbs(node);
2876 466 : break;
2877 : case kMathAcos:
2878 14 : reduction = ReduceMathAcos(node);
2879 14 : break;
2880 : case kMathAcosh:
2881 13 : reduction = ReduceMathAcosh(node);
2882 13 : break;
2883 : case kMathAsin:
2884 14 : reduction = ReduceMathAsin(node);
2885 14 : break;
2886 : case kMathAsinh:
2887 13 : reduction = ReduceMathAsinh(node);
2888 13 : break;
2889 : case kMathAtan:
2890 14 : reduction = ReduceMathAtan(node);
2891 14 : break;
2892 : case kMathAtanh:
2893 13 : reduction = ReduceMathAtanh(node);
2894 13 : break;
2895 : case kMathAtan2:
2896 162 : reduction = ReduceMathAtan2(node);
2897 162 : break;
2898 : case kMathCbrt:
2899 0 : reduction = ReduceMathCbrt(node);
2900 0 : break;
2901 : case kMathCeil:
2902 7252 : reduction = ReduceMathCeil(node);
2903 7252 : break;
2904 : case kMathClz32:
2905 46 : reduction = ReduceMathClz32(node);
2906 46 : break;
2907 : case kMathCos:
2908 34 : reduction = ReduceMathCos(node);
2909 34 : break;
2910 : case kMathCosh:
2911 21 : reduction = ReduceMathCosh(node);
2912 21 : break;
2913 : case kMathExp:
2914 64 : reduction = ReduceMathExp(node);
2915 64 : break;
2916 : case kMathExpm1:
2917 0 : reduction = ReduceMathExpm1(node);
2918 0 : break;
2919 : case kMathFloor:
2920 27376 : reduction = ReduceMathFloor(node);
2921 27376 : break;
2922 : case kMathFround:
2923 1295 : reduction = ReduceMathFround(node);
2924 1295 : break;
2925 : case kMathImul:
2926 851 : reduction = ReduceMathImul(node);
2927 851 : break;
2928 : case kMathLog:
2929 205 : reduction = ReduceMathLog(node);
2930 205 : break;
2931 : case kMathLog1p:
2932 13 : reduction = ReduceMathLog1p(node);
2933 13 : break;
2934 : case kMathLog10:
2935 0 : reduction = ReduceMathLog10(node);
2936 0 : break;
2937 : case kMathLog2:
2938 0 : reduction = ReduceMathLog2(node);
2939 0 : break;
2940 : case kMathMax:
2941 483 : reduction = ReduceMathMax(node);
2942 483 : break;
2943 : case kMathMin:
2944 442 : reduction = ReduceMathMin(node);
2945 442 : break;
2946 : case kMathPow:
2947 1247 : reduction = ReduceMathPow(node);
2948 1247 : break;
2949 : case kMathRound:
2950 1578 : reduction = ReduceMathRound(node);
2951 1578 : break;
2952 : case kMathSign:
2953 34 : reduction = ReduceMathSign(node);
2954 34 : break;
2955 : case kMathSin:
2956 58 : reduction = ReduceMathSin(node);
2957 58 : break;
2958 : case kMathSinh:
2959 21 : reduction = ReduceMathSinh(node);
2960 21 : break;
2961 : case kMathSqrt:
2962 93 : reduction = ReduceMathSqrt(node);
2963 93 : break;
2964 : case kMathTan:
2965 63 : reduction = ReduceMathTan(node);
2966 63 : break;
2967 : case kMathTanh:
2968 21 : reduction = ReduceMathTanh(node);
2969 21 : break;
2970 : case kMathTrunc:
2971 6951 : reduction = ReduceMathTrunc(node);
2972 6951 : break;
2973 : case kNumberIsFinite:
2974 19 : reduction = ReduceNumberIsFinite(node);
2975 19 : break;
2976 : case kNumberIsInteger:
2977 19 : reduction = ReduceNumberIsInteger(node);
2978 19 : break;
2979 : case kNumberIsNaN:
2980 67 : reduction = ReduceNumberIsNaN(node);
2981 67 : break;
2982 : case kNumberIsSafeInteger:
2983 14 : reduction = ReduceNumberIsSafeInteger(node);
2984 14 : break;
2985 : case kNumberParseInt:
2986 415 : reduction = ReduceNumberParseInt(node);
2987 415 : break;
2988 : case kObjectCreate:
2989 58 : reduction = ReduceObjectCreate(node);
2990 58 : break;
2991 : case kObjectIs:
2992 83 : reduction = ReduceObjectIs(node);
2993 83 : break;
2994 : case kSetEntries:
2995 : return ReduceCollectionIterator(
2996 14 : node, JS_SET_TYPE, Context::SET_KEY_VALUE_ITERATOR_MAP_INDEX);
2997 : case kSetSize:
2998 0 : return ReduceCollectionSize(node, JS_SET_TYPE);
2999 : case kSetValues:
3000 : return ReduceCollectionIterator(node, JS_SET_TYPE,
3001 65 : Context::SET_VALUE_ITERATOR_MAP_INDEX);
3002 : case kSetIteratorNext:
3003 : return ReduceCollectionIteratorNext(node, OrderedHashSet::kEntrySize,
3004 : FIRST_SET_ITERATOR_TYPE,
3005 161 : LAST_SET_ITERATOR_TYPE);
3006 : case kStringFromCharCode:
3007 181 : reduction = ReduceStringFromCharCode(node);
3008 181 : break;
3009 : case kStringCharAt:
3010 105 : return ReduceStringCharAt(node);
3011 : case kStringCharCodeAt:
3012 439 : return ReduceStringCharCodeAt(node);
3013 : case kStringConcat:
3014 1 : return ReduceStringConcat(node);
3015 : case kStringIndexOf:
3016 203 : return ReduceStringIndexOf(node);
3017 : case kStringIterator:
3018 41 : return ReduceStringIterator(node);
3019 : case kStringIteratorNext:
3020 32 : return ReduceStringIteratorNext(node);
3021 : case kStringToLowerCaseIntl:
3022 0 : return ReduceStringToLowerCaseIntl(node);
3023 : case kStringToUpperCaseIntl:
3024 0 : return ReduceStringToUpperCaseIntl(node);
3025 : case kArrayBufferIsView:
3026 0 : return ReduceArrayBufferIsView(node);
3027 : case kDataViewByteLength:
3028 : return ReduceArrayBufferViewAccessor(
3029 : node, JS_DATA_VIEW_TYPE,
3030 0 : AccessBuilder::ForJSArrayBufferViewByteLength());
3031 : case kDataViewByteOffset:
3032 : return ReduceArrayBufferViewAccessor(
3033 : node, JS_DATA_VIEW_TYPE,
3034 0 : AccessBuilder::ForJSArrayBufferViewByteOffset());
3035 : case kTypedArrayByteLength:
3036 : return ReduceArrayBufferViewAccessor(
3037 : node, JS_TYPED_ARRAY_TYPE,
3038 0 : AccessBuilder::ForJSArrayBufferViewByteLength());
3039 : case kTypedArrayByteOffset:
3040 : return ReduceArrayBufferViewAccessor(
3041 : node, JS_TYPED_ARRAY_TYPE,
3042 0 : AccessBuilder::ForJSArrayBufferViewByteOffset());
3043 : case kTypedArrayLength:
3044 : return ReduceArrayBufferViewAccessor(
3045 332 : node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
3046 : case kTypedArrayEntries:
3047 7 : return ReduceTypedArrayIterator(node, IterationKind::kEntries);
3048 : case kTypedArrayKeys:
3049 0 : return ReduceTypedArrayIterator(node, IterationKind::kKeys);
3050 : case kTypedArrayValues:
3051 43 : return ReduceTypedArrayIterator(node, IterationKind::kValues);
3052 : case kTypedArrayToStringTag:
3053 21 : return ReduceTypedArrayToStringTag(node);
3054 : default:
3055 : break;
3056 : }
3057 :
3058 : // Replace builtin call assuming replacement nodes are pure values that don't
3059 : // produce an effect. Replaces {node} with {reduction} and relaxes effects.
3060 65042 : if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement());
3061 :
3062 65042 : return reduction;
3063 : }
3064 :
3065 25398 : Node* JSBuiltinReducer::ToNumber(Node* input) {
3066 : Type* input_type = NodeProperties::GetType(input);
3067 25398 : if (input_type->Is(Type::Number())) return input;
3068 1254 : return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), input);
3069 : }
3070 :
3071 83 : Node* JSBuiltinReducer::ToUint32(Node* input) {
3072 83 : input = ToNumber(input);
3073 : Type* input_type = NodeProperties::GetType(input);
3074 83 : if (input_type->Is(Type::Unsigned32())) return input;
3075 134 : return graph()->NewNode(simplified()->NumberToUint32(), input);
3076 : }
3077 :
3078 85123 : Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); }
3079 :
3080 0 : Factory* JSBuiltinReducer::factory() const { return isolate()->factory(); }
3081 :
3082 4648 : Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); }
3083 :
3084 :
3085 20245 : CommonOperatorBuilder* JSBuiltinReducer::common() const {
3086 20245 : return jsgraph()->common();
3087 : }
3088 :
3089 :
3090 63533 : SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const {
3091 63593 : return jsgraph()->simplified();
3092 : }
3093 :
3094 1079 : JSOperatorBuilder* JSBuiltinReducer::javascript() const {
3095 1079 : return jsgraph()->javascript();
3096 : }
3097 :
3098 : } // namespace compiler
3099 : } // namespace internal
3100 : } // namespace v8
|