• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/code-factory.h"
9 #include "src/compilation-dependencies.h"
10 #include "src/compiler/access-builder.h"
11 #include "src/compiler/js-graph.h"
12 #include "src/compiler/linkage.h"
13 #include "src/compiler/node-matchers.h"
14 #include "src/compiler/node-properties.h"
15 #include "src/compiler/simplified-operator.h"
16 #include "src/compiler/type-cache.h"
17 #include "src/compiler/types.h"
18 #include "src/objects-inl.h"
19 
20 namespace v8 {
21 namespace internal {
22 namespace compiler {
23 
24 // Helper class to access JSCall nodes that are potential candidates
25 // for reduction when they have a BuiltinFunctionId associated with them.
26 class JSCallReduction {
27  public:
JSCallReduction(Node * node)28   explicit JSCallReduction(Node* node) : node_(node) {}
29 
30   // Determines whether the node is a JSCall operation that targets a
31   // constant callee being a well-known builtin with a BuiltinFunctionId.
HasBuiltinFunctionId()32   bool HasBuiltinFunctionId() {
33     if (node_->opcode() != IrOpcode::kJSCall) return false;
34     HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0));
35     if (!m.HasValue() || !m.Value()->IsJSFunction()) return false;
36     Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
37     return function->shared()->HasBuiltinFunctionId();
38   }
39 
40   // Retrieves the BuiltinFunctionId as described above.
GetBuiltinFunctionId()41   BuiltinFunctionId GetBuiltinFunctionId() {
42     DCHECK_EQ(IrOpcode::kJSCall, node_->opcode());
43     HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0));
44     Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
45     return function->shared()->builtin_function_id();
46   }
47 
ReceiverMatches(Type * type)48   bool ReceiverMatches(Type* type) {
49     return NodeProperties::GetType(receiver())->Is(type);
50   }
51 
52   // Determines whether the call takes zero inputs.
InputsMatchZero()53   bool InputsMatchZero() { return GetJSCallArity() == 0; }
54 
55   // Determines whether the call takes one input of the given type.
InputsMatchOne(Type * t1)56   bool InputsMatchOne(Type* t1) {
57     return GetJSCallArity() == 1 &&
58            NodeProperties::GetType(GetJSCallInput(0))->Is(t1);
59   }
60 
61   // Determines whether the call takes two inputs of the given types.
InputsMatchTwo(Type * t1,Type * t2)62   bool InputsMatchTwo(Type* t1, Type* t2) {
63     return GetJSCallArity() == 2 &&
64            NodeProperties::GetType(GetJSCallInput(0))->Is(t1) &&
65            NodeProperties::GetType(GetJSCallInput(1))->Is(t2);
66   }
67 
68   // Determines whether the call takes inputs all of the given type.
InputsMatchAll(Type * t)69   bool InputsMatchAll(Type* t) {
70     for (int i = 0; i < GetJSCallArity(); i++) {
71       if (!NodeProperties::GetType(GetJSCallInput(i))->Is(t)) {
72         return false;
73       }
74     }
75     return true;
76   }
77 
receiver()78   Node* receiver() { return NodeProperties::GetValueInput(node_, 1); }
left()79   Node* left() { return GetJSCallInput(0); }
right()80   Node* right() { return GetJSCallInput(1); }
81 
GetJSCallArity()82   int GetJSCallArity() {
83     DCHECK_EQ(IrOpcode::kJSCall, node_->opcode());
84     // Skip first (i.e. callee) and second (i.e. receiver) operand.
85     return node_->op()->ValueInputCount() - 2;
86   }
87 
GetJSCallInput(int index)88   Node* GetJSCallInput(int index) {
89     DCHECK_EQ(IrOpcode::kJSCall, node_->opcode());
90     DCHECK_LT(index, GetJSCallArity());
91     // Skip first (i.e. callee) and second (i.e. receiver) operand.
92     return NodeProperties::GetValueInput(node_, index + 2);
93   }
94 
95  private:
96   Node* node_;
97 };
98 
JSBuiltinReducer(Editor * editor,JSGraph * jsgraph,Flags flags,CompilationDependencies * dependencies,Handle<Context> native_context)99 JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph,
100                                    Flags flags,
101                                    CompilationDependencies* dependencies,
102                                    Handle<Context> native_context)
103     : AdvancedReducer(editor),
104       dependencies_(dependencies),
105       flags_(flags),
106       jsgraph_(jsgraph),
107       native_context_(native_context),
108       type_cache_(TypeCache::Get()) {}
109 
110 namespace {
111 
GetMapWitness(Node * node)112 MaybeHandle<Map> GetMapWitness(Node* node) {
113   ZoneHandleSet<Map> maps;
114   Node* receiver = NodeProperties::GetValueInput(node, 1);
115   Node* effect = NodeProperties::GetEffectInput(node);
116   if (NodeProperties::InferReceiverMaps(receiver, effect, &maps)) {
117     if (maps.size() == 1) return MaybeHandle<Map>(maps[0]);
118   }
119   return MaybeHandle<Map>();
120 }
121 
122 // TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map)123 bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
124   DCHECK(!jsarray_map->is_dictionary_map());
125   Isolate* isolate = jsarray_map->GetIsolate();
126   Handle<Name> length_string = isolate->factory()->length_string();
127   DescriptorArray* descriptors = jsarray_map->instance_descriptors();
128   int number =
129       descriptors->SearchWithCache(isolate, *length_string, *jsarray_map);
130   DCHECK_NE(DescriptorArray::kNotFound, number);
131   return descriptors->GetDetails(number).IsReadOnly();
132 }
133 
134 // TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
CanInlineArrayResizeOperation(Handle<Map> receiver_map)135 bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) {
136   Isolate* const isolate = receiver_map->GetIsolate();
137   if (!receiver_map->prototype()->IsJSArray()) return false;
138   Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
139                                      isolate);
140   // Ensure that all prototypes of the {receiver} are stable.
141   for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver);
142        !it.IsAtEnd(); it.Advance()) {
143     Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it);
144     if (!current->map()->is_stable()) return false;
145   }
146   return receiver_map->instance_type() == JS_ARRAY_TYPE &&
147          IsFastElementsKind(receiver_map->elements_kind()) &&
148          !receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
149          (!receiver_map->is_prototype_map() || receiver_map->is_stable()) &&
150          isolate->IsFastArrayConstructorPrototypeChainIntact() &&
151          isolate->IsAnyInitialArrayPrototype(receiver_prototype) &&
152          !IsReadOnlyLengthDescriptor(receiver_map);
153 }
154 
CanInlineJSArrayIteration(Handle<Map> receiver_map)155 bool CanInlineJSArrayIteration(Handle<Map> receiver_map) {
156   Isolate* const isolate = receiver_map->GetIsolate();
157   // Ensure that the [[Prototype]] is actually an exotic Array
158   if (!receiver_map->prototype()->IsJSArray()) return false;
159 
160   // Don't inline JSArrays with slow elements of any kind
161   if (!IsFastElementsKind(receiver_map->elements_kind())) return false;
162 
163   // If the receiver map has packed elements, no need to check the prototype.
164   // This requires a MapCheck where this is used.
165   if (!IsFastHoleyElementsKind(receiver_map->elements_kind())) return true;
166 
167   Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
168                                      isolate);
169   // Ensure all prototypes of the {receiver} are stable.
170   for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver);
171        !it.IsAtEnd(); it.Advance()) {
172     Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it);
173     if (!current->map()->is_stable()) return false;
174   }
175 
176   // For holey Arrays, ensure that the array_protector cell is valid (must be
177   // a CompilationDependency), and the JSArray prototype has not been altered.
178   return receiver_map->instance_type() == JS_ARRAY_TYPE &&
179          (!receiver_map->is_dictionary_map() || receiver_map->is_stable()) &&
180          isolate->IsFastArrayConstructorPrototypeChainIntact() &&
181          isolate->IsAnyInitialArrayPrototype(receiver_prototype);
182 }
183 
184 }  // namespace
185 
ReduceArrayIterator(Node * node,IterationKind kind)186 Reduction JSBuiltinReducer::ReduceArrayIterator(Node* node,
187                                                 IterationKind kind) {
188   Handle<Map> receiver_map;
189   if (GetMapWitness(node).ToHandle(&receiver_map)) {
190     return ReduceArrayIterator(receiver_map, node, kind,
191                                ArrayIteratorKind::kArray);
192   }
193   return NoChange();
194 }
195 
ReduceTypedArrayIterator(Node * node,IterationKind kind)196 Reduction JSBuiltinReducer::ReduceTypedArrayIterator(Node* node,
197                                                      IterationKind kind) {
198   Handle<Map> receiver_map;
199   if (GetMapWitness(node).ToHandle(&receiver_map) &&
200       receiver_map->instance_type() == JS_TYPED_ARRAY_TYPE) {
201     return ReduceArrayIterator(receiver_map, node, kind,
202                                ArrayIteratorKind::kTypedArray);
203   }
204   return NoChange();
205 }
206 
ReduceArrayIterator(Handle<Map> receiver_map,Node * node,IterationKind kind,ArrayIteratorKind iter_kind)207 Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> receiver_map,
208                                                 Node* node, IterationKind kind,
209                                                 ArrayIteratorKind iter_kind) {
210   Node* receiver = NodeProperties::GetValueInput(node, 1);
211   Node* effect = NodeProperties::GetEffectInput(node);
212   Node* control = NodeProperties::GetControlInput(node);
213 
214   if (iter_kind == ArrayIteratorKind::kTypedArray) {
215     // See if we can skip the neutering check.
216     if (isolate()->IsArrayBufferNeuteringIntact()) {
217       // Add a code dependency so we are deoptimized in case an ArrayBuffer
218       // gets neutered.
219       dependencies()->AssumePropertyCell(
220           factory()->array_buffer_neutering_protector());
221     } else {
222       // For JSTypedArray iterator methods, deopt if the buffer is neutered.
223       // This is potentially a deopt loop, but should be extremely unlikely.
224       DCHECK_EQ(JS_TYPED_ARRAY_TYPE, receiver_map->instance_type());
225       Node* buffer = effect = graph()->NewNode(
226           simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
227           receiver, effect, control);
228 
229       // Deoptimize if the {buffer} has been neutered.
230       Node* check = effect = graph()->NewNode(
231           simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
232       check = graph()->NewNode(simplified()->BooleanNot(), check);
233       effect =
234           graph()->NewNode(simplified()->CheckIf(), check, effect, control);
235     }
236   }
237 
238   int map_index = -1;
239   Node* object_map = jsgraph()->UndefinedConstant();
240   switch (receiver_map->instance_type()) {
241     case JS_ARRAY_TYPE:
242       if (kind == IterationKind::kKeys) {
243         map_index = Context::FAST_ARRAY_KEY_ITERATOR_MAP_INDEX;
244       } else {
245         map_index = kind == IterationKind::kValues
246                         ? Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX
247                         : Context::FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX;
248 
249         if (CanInlineJSArrayIteration(receiver_map)) {
250           // Use `generic` elements for holey arrays if there may be elements
251           // on the prototype chain.
252           map_index += static_cast<int>(receiver_map->elements_kind());
253           object_map = jsgraph()->Constant(receiver_map);
254           if (IsFastHoleyElementsKind(receiver_map->elements_kind())) {
255             Handle<JSObject> initial_array_prototype(
256                 native_context()->initial_array_prototype(), isolate());
257             dependencies()->AssumePrototypeMapsStable(receiver_map,
258                                                       initial_array_prototype);
259           }
260         } else {
261           map_index += (Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX -
262                         Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX);
263         }
264       }
265       break;
266     case JS_TYPED_ARRAY_TYPE:
267       if (kind == IterationKind::kKeys) {
268         map_index = Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX;
269       } else {
270         DCHECK_GE(receiver_map->elements_kind(), UINT8_ELEMENTS);
271         DCHECK_LE(receiver_map->elements_kind(), UINT8_CLAMPED_ELEMENTS);
272         map_index = (kind == IterationKind::kValues
273                          ? Context::UINT8_ARRAY_VALUE_ITERATOR_MAP_INDEX
274                          : Context::UINT8_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX) +
275                     (receiver_map->elements_kind() - UINT8_ELEMENTS);
276       }
277       break;
278     default:
279       if (kind == IterationKind::kKeys) {
280         map_index = Context::GENERIC_ARRAY_KEY_ITERATOR_MAP_INDEX;
281       } else if (kind == IterationKind::kValues) {
282         map_index = Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX;
283       } else {
284         map_index = Context::GENERIC_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX;
285       }
286       break;
287   }
288 
289   DCHECK_GE(map_index, Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX);
290   DCHECK_LE(map_index, Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX);
291 
292   Handle<Map> map(Map::cast(native_context()->get(map_index)), isolate());
293 
294   // allocate new iterator
295   effect = graph()->NewNode(
296       common()->BeginRegion(RegionObservability::kNotObservable), effect);
297   Node* value = effect = graph()->NewNode(
298       simplified()->Allocate(NOT_TENURED),
299       jsgraph()->Constant(JSArrayIterator::kSize), effect, control);
300   NodeProperties::SetType(value, Type::OtherObject());
301   effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
302                             value, jsgraph()->Constant(map), effect, control);
303   effect = graph()->NewNode(
304       simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value,
305       jsgraph()->EmptyFixedArrayConstant(), effect, control);
306   effect = graph()->NewNode(
307       simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value,
308       jsgraph()->EmptyFixedArrayConstant(), effect, control);
309 
310   // attach the iterator to this object
311   effect = graph()->NewNode(
312       simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
313       value, receiver, effect, control);
314   effect = graph()->NewNode(
315       simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex()), value,
316       jsgraph()->ZeroConstant(), effect, control);
317   effect = graph()->NewNode(
318       simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObjectMap()),
319       value, object_map, effect, control);
320 
321   value = effect = graph()->NewNode(common()->FinishRegion(), value, effect);
322 
323   // replace it
324   ReplaceWithValue(node, value, effect, control);
325   return Replace(value);
326 }
327 
ReduceFastArrayIteratorNext(Handle<Map> iterator_map,Node * node,IterationKind kind)328 Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
329     Handle<Map> iterator_map, Node* node, IterationKind kind) {
330   Node* iterator = NodeProperties::GetValueInput(node, 1);
331   Node* effect = NodeProperties::GetEffectInput(node);
332   Node* control = NodeProperties::GetControlInput(node);
333   Node* context = NodeProperties::GetContextInput(node);
334 
335   if (kind != IterationKind::kKeys &&
336       !isolate()->IsFastArrayIterationIntact()) {
337     // Avoid deopt loops for non-key iteration if the
338     // fast_array_iteration_protector cell has been invalidated.
339     return NoChange();
340   }
341 
342   ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
343       iterator_map->instance_type());
344 
345   if (IsFastHoleyElementsKind(elements_kind)) {
346     if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
347       return NoChange();
348     } else {
349       Handle<JSObject> initial_array_prototype(
350           native_context()->initial_array_prototype(), isolate());
351       dependencies()->AssumePropertyCell(factory()->array_protector());
352     }
353   }
354 
355   Node* array = effect = graph()->NewNode(
356       simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
357       iterator, effect, control);
358   Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array,
359                                   jsgraph()->UndefinedConstant());
360   Node* branch0 =
361       graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
362 
363   Node* vdone_false0;
364   Node* vfalse0;
365   Node* efalse0 = effect;
366   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
367   {
368     // iterator.[[IteratedObject]] !== undefined, continue iterating.
369     Node* index = efalse0 = graph()->NewNode(
370         simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex(
371             JS_ARRAY_TYPE, elements_kind)),
372         iterator, efalse0, if_false0);
373 
374     Node* length = efalse0 = graph()->NewNode(
375         simplified()->LoadField(AccessBuilder::ForJSArrayLength(elements_kind)),
376         array, efalse0, if_false0);
377     Node* check1 =
378         graph()->NewNode(simplified()->NumberLessThan(), index, length);
379     Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
380                                      check1, if_false0);
381 
382     Node* vdone_true1;
383     Node* vtrue1;
384     Node* etrue1 = efalse0;
385     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
386     {
387       // iterator.[[NextIndex]] < array.length, continue iterating
388       vdone_true1 = jsgraph()->FalseConstant();
389       if (kind == IterationKind::kKeys) {
390         vtrue1 = index;
391       } else {
392         // For value/entry iteration, first step is a mapcheck to ensure
393         // inlining is still valid.
394         Node* array_map = etrue1 =
395             graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
396                              array, etrue1, if_true1);
397         Node* orig_map = etrue1 =
398             graph()->NewNode(simplified()->LoadField(
399                                  AccessBuilder::ForJSArrayIteratorObjectMap()),
400                              iterator, etrue1, if_true1);
401         Node* check_map = graph()->NewNode(simplified()->ReferenceEqual(),
402                                            array_map, orig_map);
403         etrue1 = graph()->NewNode(simplified()->CheckIf(), check_map, etrue1,
404                                   if_true1);
405       }
406 
407       if (kind != IterationKind::kKeys) {
408         Node* elements = etrue1 = graph()->NewNode(
409             simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
410             array, etrue1, if_true1);
411         Node* value = etrue1 = graph()->NewNode(
412             simplified()->LoadElement(
413                 AccessBuilder::ForFixedArrayElement(elements_kind)),
414             elements, index, etrue1, if_true1);
415 
416         // Convert hole to undefined if needed.
417         if (elements_kind == FAST_HOLEY_ELEMENTS ||
418             elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
419           value = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(),
420                                    value);
421         } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
422           // TODO(bmeurer): avoid deopt if not all uses of value are truncated.
423           CheckFloat64HoleMode mode = CheckFloat64HoleMode::kAllowReturnHole;
424           value = etrue1 = graph()->NewNode(
425               simplified()->CheckFloat64Hole(mode), value, etrue1, if_true1);
426         }
427 
428         if (kind == IterationKind::kEntries) {
429           // Allocate elements for key/value pair
430           vtrue1 = etrue1 =
431               graph()->NewNode(javascript()->CreateKeyValueArray(), index,
432                                value, context, etrue1);
433         } else {
434           DCHECK_EQ(kind, IterationKind::kValues);
435           vtrue1 = value;
436         }
437       }
438 
439       Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
440                                           jsgraph()->OneConstant());
441       next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index);
442 
443       etrue1 = graph()->NewNode(
444           simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex(
445               JS_ARRAY_TYPE, elements_kind)),
446           iterator, next_index, etrue1, if_true1);
447     }
448 
449     Node* vdone_false1;
450     Node* vfalse1;
451     Node* efalse1 = efalse0;
452     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
453     {
454       // iterator.[[NextIndex]] >= array.length, stop iterating.
455       vdone_false1 = jsgraph()->TrueConstant();
456       vfalse1 = jsgraph()->UndefinedConstant();
457       efalse1 = graph()->NewNode(
458           simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
459           iterator, vfalse1, efalse1, if_false1);
460     }
461 
462     if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
463     efalse0 =
464         graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
465     vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
466                                vtrue1, vfalse1, if_false0);
467     vdone_false0 =
468         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
469                          vdone_true1, vdone_false1, if_false0);
470   }
471 
472   Node* vdone_true0;
473   Node* vtrue0;
474   Node* etrue0 = effect;
475   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
476   {
477     // iterator.[[IteratedObject]] === undefined, the iterator is done.
478     vdone_true0 = jsgraph()->TrueConstant();
479     vtrue0 = jsgraph()->UndefinedConstant();
480   }
481 
482   control = graph()->NewNode(common()->Merge(2), if_false0, if_true0);
483   effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control);
484   Node* value =
485       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
486                        vfalse0, vtrue0, control);
487   Node* done =
488       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
489                        vdone_false0, vdone_true0, control);
490 
491   // Create IteratorResult object.
492   value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
493                                     value, done, context, effect);
494   ReplaceWithValue(node, value, effect, control);
495   return Replace(value);
496 }
497 
ReduceTypedArrayIteratorNext(Handle<Map> iterator_map,Node * node,IterationKind kind)498 Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(
499     Handle<Map> iterator_map, Node* node, IterationKind kind) {
500   Node* iterator = NodeProperties::GetValueInput(node, 1);
501   Node* effect = NodeProperties::GetEffectInput(node);
502   Node* control = NodeProperties::GetControlInput(node);
503   Node* context = NodeProperties::GetContextInput(node);
504 
505   ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
506       iterator_map->instance_type());
507 
508   Node* array = effect = graph()->NewNode(
509       simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
510       iterator, effect, control);
511   Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array,
512                                   jsgraph()->UndefinedConstant());
513   Node* branch0 =
514       graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
515 
516   Node* vdone_false0;
517   Node* vfalse0;
518   Node* efalse0 = effect;
519   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
520   {
521     // iterator.[[IteratedObject]] !== undefined, continue iterating.
522     Node* index = efalse0 = graph()->NewNode(
523         simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex(
524             JS_TYPED_ARRAY_TYPE, elements_kind)),
525         iterator, efalse0, if_false0);
526 
527     // typedarray.[[ViewedArrayBuffer]]
528     Node* buffer = efalse0 = graph()->NewNode(
529         simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
530         array, efalse0, if_false0);
531 
532     // See if we can skip the neutering check.
533     if (isolate()->IsArrayBufferNeuteringIntact()) {
534       // Add a code dependency so we are deoptimized in case an ArrayBuffer
535       // gets neutered.
536       dependencies()->AssumePropertyCell(
537           factory()->array_buffer_neutering_protector());
538     } else {
539       // Deoptimize if the array buffer was neutered.
540       Node* check1 = efalse0 = graph()->NewNode(
541           simplified()->ArrayBufferWasNeutered(), buffer, efalse0, if_false0);
542       check1 = graph()->NewNode(simplified()->BooleanNot(), check1);
543       efalse0 =
544           graph()->NewNode(simplified()->CheckIf(), check1, efalse0, if_false0);
545     }
546 
547     Node* length = efalse0 = graph()->NewNode(
548         simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()), array,
549         efalse0, if_false0);
550 
551     Node* check2 =
552         graph()->NewNode(simplified()->NumberLessThan(), index, length);
553     Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
554                                      check2, if_false0);
555 
556     Node* vdone_true2;
557     Node* vtrue2;
558     Node* etrue2 = efalse0;
559     Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
560     {
561       // iterator.[[NextIndex]] < array.length, continue iterating
562       vdone_true2 = jsgraph()->FalseConstant();
563       if (kind == IterationKind::kKeys) {
564         vtrue2 = index;
565       }
566 
567       Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
568                                           jsgraph()->OneConstant());
569       next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index);
570 
571       etrue2 = graph()->NewNode(
572           simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex(
573               JS_TYPED_ARRAY_TYPE, elements_kind)),
574           iterator, next_index, etrue2, if_true2);
575 
576       if (kind != IterationKind::kKeys) {
577         Node* elements = etrue2 = graph()->NewNode(
578             simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
579             array, etrue2, if_true2);
580         Node* base_ptr = etrue2 = graph()->NewNode(
581             simplified()->LoadField(
582                 AccessBuilder::ForFixedTypedArrayBaseBasePointer()),
583             elements, etrue2, if_true2);
584         Node* external_ptr = etrue2 = graph()->NewNode(
585             simplified()->LoadField(
586                 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()),
587             elements, etrue2, if_true2);
588 
589         ExternalArrayType array_type = kExternalInt8Array;
590         switch (elements_kind) {
591 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
592   case TYPE##_ELEMENTS:                                 \
593     array_type = kExternal##Type##Array;                \
594     break;
595           TYPED_ARRAYS(TYPED_ARRAY_CASE)
596           default:
597             UNREACHABLE();
598 #undef TYPED_ARRAY_CASE
599         }
600 
601         Node* value = etrue2 =
602             graph()->NewNode(simplified()->LoadTypedElement(array_type), buffer,
603                              base_ptr, external_ptr, index, etrue2, if_true2);
604 
605         if (kind == IterationKind::kEntries) {
606           // Allocate elements for key/value pair
607           vtrue2 = etrue2 =
608               graph()->NewNode(javascript()->CreateKeyValueArray(), index,
609                                value, context, etrue2);
610         } else {
611           DCHECK(kind == IterationKind::kValues);
612           vtrue2 = value;
613         }
614       }
615     }
616 
617     Node* vdone_false2;
618     Node* vfalse2;
619     Node* efalse2 = efalse0;
620     Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
621     {
622       // iterator.[[NextIndex]] >= array.length, stop iterating.
623       vdone_false2 = jsgraph()->TrueConstant();
624       vfalse2 = jsgraph()->UndefinedConstant();
625       efalse2 = graph()->NewNode(
626           simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
627           iterator, vfalse2, efalse2, if_false2);
628     }
629 
630     if_false0 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
631     efalse0 =
632         graph()->NewNode(common()->EffectPhi(2), etrue2, efalse2, if_false0);
633     vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
634                                vtrue2, vfalse2, if_false0);
635     vdone_false0 =
636         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
637                          vdone_true2, vdone_false2, if_false0);
638   }
639 
640   Node* vdone_true0;
641   Node* vtrue0;
642   Node* etrue0 = effect;
643   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
644   {
645     // iterator.[[IteratedObject]] === undefined, the iterator is done.
646     vdone_true0 = jsgraph()->TrueConstant();
647     vtrue0 = jsgraph()->UndefinedConstant();
648   }
649 
650   control = graph()->NewNode(common()->Merge(2), if_false0, if_true0);
651   effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control);
652   Node* value =
653       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
654                        vfalse0, vtrue0, control);
655   Node* done =
656       graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
657                        vdone_false0, vdone_true0, control);
658 
659   // Create IteratorResult object.
660   value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
661                                     value, done, context, effect);
662   ReplaceWithValue(node, value, effect, control);
663   return Replace(value);
664 }
665 
ReduceArrayIteratorNext(Node * node)666 Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
667   Handle<Map> receiver_map;
668   if (GetMapWitness(node).ToHandle(&receiver_map)) {
669     switch (receiver_map->instance_type()) {
670       case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
671         return ReduceTypedArrayIteratorNext(receiver_map, node,
672                                             IterationKind::kKeys);
673 
674       case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
675         return ReduceFastArrayIteratorNext(receiver_map, node,
676                                            IterationKind::kKeys);
677 
678       case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
679       case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
680       case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
681       case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
682       case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
683       case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
684       case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
685       case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE:
686       case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE:
687         return ReduceTypedArrayIteratorNext(receiver_map, node,
688                                             IterationKind::kEntries);
689 
690       case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
691       case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
692       case JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE:
693       case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE:
694       case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
695       case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
696         return ReduceFastArrayIteratorNext(receiver_map, node,
697                                            IterationKind::kEntries);
698 
699       case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE:
700       case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE:
701       case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE:
702       case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE:
703       case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE:
704       case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE:
705       case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE:
706       case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE:
707       case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE:
708         return ReduceTypedArrayIteratorNext(receiver_map, node,
709                                             IterationKind::kValues);
710 
711       case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE:
712       case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE:
713       case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE:
714       case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE:
715       case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
716       case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
717         return ReduceFastArrayIteratorNext(receiver_map, node,
718                                            IterationKind::kValues);
719 
720       default:
721         // Slow array iterators are not reduced
722         return NoChange();
723     }
724   }
725   return NoChange();
726 }
727 
728 // ES6 section 22.1.3.17 Array.prototype.pop ( )
ReduceArrayPop(Node * node)729 Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) {
730   Handle<Map> receiver_map;
731   Node* receiver = NodeProperties::GetValueInput(node, 1);
732   Node* effect = NodeProperties::GetEffectInput(node);
733   Node* control = NodeProperties::GetControlInput(node);
734   // TODO(turbofan): Extend this to also handle fast (holey) double elements
735   // once we got the hole NaN mess sorted out in TurboFan/V8.
736   if (GetMapWitness(node).ToHandle(&receiver_map) &&
737       CanInlineArrayResizeOperation(receiver_map) &&
738       IsFastSmiOrObjectElementsKind(receiver_map->elements_kind())) {
739     // Install code dependencies on the {receiver} prototype maps and the
740     // global array protector cell.
741     dependencies()->AssumePropertyCell(factory()->array_protector());
742     dependencies()->AssumePrototypeMapsStable(receiver_map);
743 
744     // Load the "length" property of the {receiver}.
745     Node* length = effect = graph()->NewNode(
746         simplified()->LoadField(
747             AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
748         receiver, effect, control);
749 
750     // Check if the {receiver} has any elements.
751     Node* check = graph()->NewNode(simplified()->NumberEqual(), length,
752                                    jsgraph()->ZeroConstant());
753     Node* branch =
754         graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
755 
756     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
757     Node* etrue = effect;
758     Node* vtrue = jsgraph()->UndefinedConstant();
759 
760     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
761     Node* efalse = effect;
762     Node* vfalse;
763     {
764       // Load the elements backing store from the {receiver}.
765       Node* elements = efalse = graph()->NewNode(
766           simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
767           receiver, efalse, if_false);
768 
769       // Ensure that we aren't popping from a copy-on-write backing store.
770       elements = efalse =
771           graph()->NewNode(simplified()->EnsureWritableFastElements(), receiver,
772                            elements, efalse, if_false);
773 
774       // Compute the new {length}.
775       length = graph()->NewNode(simplified()->NumberSubtract(), length,
776                                 jsgraph()->OneConstant());
777 
778       // Store the new {length} to the {receiver}.
779       efalse = graph()->NewNode(
780           simplified()->StoreField(
781               AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
782           receiver, length, efalse, if_false);
783 
784       // Load the last entry from the {elements}.
785       vfalse = efalse = graph()->NewNode(
786           simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(
787               receiver_map->elements_kind())),
788           elements, length, efalse, if_false);
789 
790       // Store a hole to the element we just removed from the {receiver}.
791       efalse = graph()->NewNode(
792           simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
793               GetHoleyElementsKind(receiver_map->elements_kind()))),
794           elements, length, jsgraph()->TheHoleConstant(), efalse, if_false);
795     }
796 
797     control = graph()->NewNode(common()->Merge(2), if_true, if_false);
798     effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
799     Node* value =
800         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
801                          vtrue, vfalse, control);
802 
803     // Convert the hole to undefined. Do this last, so that we can optimize
804     // conversion operator via some smart strength reduction in many cases.
805     if (IsFastHoleyElementsKind(receiver_map->elements_kind())) {
806       value =
807           graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
808     }
809 
810     ReplaceWithValue(node, value, effect, control);
811     return Replace(value);
812   }
813   return NoChange();
814 }
815 
816 // ES6 section 22.1.3.18 Array.prototype.push ( )
ReduceArrayPush(Node * node)817 Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) {
818   // We need exactly target, receiver and value parameters.
819   if (node->op()->ValueInputCount() != 3) return NoChange();
820   Node* receiver = NodeProperties::GetValueInput(node, 1);
821   Node* effect = NodeProperties::GetEffectInput(node);
822   Node* control = NodeProperties::GetControlInput(node);
823   Node* value = NodeProperties::GetValueInput(node, 2);
824   ZoneHandleSet<Map> receiver_maps;
825   NodeProperties::InferReceiverMapsResult result =
826       NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
827   if (receiver_maps.size() != 1) return NoChange();
828   DCHECK_NE(NodeProperties::kNoReceiverMaps, result);
829 
830   // TODO(turbofan): Relax this to deal with multiple {receiver} maps.
831   Handle<Map> receiver_map = receiver_maps[0];
832   if (CanInlineArrayResizeOperation(receiver_map)) {
833     // Install code dependencies on the {receiver} prototype maps and the
834     // global array protector cell.
835     dependencies()->AssumePropertyCell(factory()->array_protector());
836     dependencies()->AssumePrototypeMapsStable(receiver_map);
837 
838     // If the {receiver_maps} information is not reliable, we need
839     // to check that the {receiver} still has one of these maps.
840     if (result == NodeProperties::kUnreliableReceiverMaps) {
841       if (receiver_map->is_stable()) {
842         dependencies()->AssumeMapStable(receiver_map);
843       } else {
844         // TODO(turbofan): This is a potential - yet unlikely - deoptimization
845         // loop, since we might not learn from this deoptimization in baseline
846         // code. We need a way to learn from deoptimizations in optimized to
847         // address these problems.
848         effect = graph()->NewNode(
849             simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps),
850             receiver, effect, control);
851       }
852     }
853 
854     // TODO(turbofan): Perform type checks on the {value}. We are not guaranteed
855     // to learn from these checks in case they fail, as the witness (i.e. the
856     // map check from the LoadIC for a.push) might not be executed in baseline
857     // code (after we stored the value in the builtin and thereby changed the
858     // elements kind of a) before be decide to optimize this function again. We
859     // currently don't have a proper way to deal with this; the proper solution
860     // here is to learn on deopt, i.e. disable Array.prototype.push inlining
861     // for this function.
862     if (IsFastSmiElementsKind(receiver_map->elements_kind())) {
863       value = effect =
864           graph()->NewNode(simplified()->CheckSmi(), value, effect, control);
865     } else if (IsFastDoubleElementsKind(receiver_map->elements_kind())) {
866       value = effect =
867           graph()->NewNode(simplified()->CheckNumber(), value, effect, control);
868       // Make sure we do not store signaling NaNs into double arrays.
869       value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
870     }
871 
872     // Load the "length" property of the {receiver}.
873     Node* length = effect = graph()->NewNode(
874         simplified()->LoadField(
875             AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
876         receiver, effect, control);
877 
878     // Load the elements backing store of the {receiver}.
879     Node* elements = effect = graph()->NewNode(
880         simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
881         effect, control);
882 
883     // TODO(turbofan): Check if we need to grow the {elements} backing store.
884     // This will deopt if we cannot grow the array further, and we currently
885     // don't necessarily learn from it. See the comment on the value type check
886     // above.
887     GrowFastElementsFlags flags = GrowFastElementsFlag::kArrayObject;
888     if (IsFastDoubleElementsKind(receiver_map->elements_kind())) {
889       flags |= GrowFastElementsFlag::kDoubleElements;
890     }
891     elements = effect =
892         graph()->NewNode(simplified()->MaybeGrowFastElements(flags), receiver,
893                          elements, length, length, effect, control);
894 
895     // Append the value to the {elements}.
896     effect = graph()->NewNode(
897         simplified()->StoreElement(
898             AccessBuilder::ForFixedArrayElement(receiver_map->elements_kind())),
899         elements, length, value, effect, control);
900 
901     // Return the new length of the {receiver}.
902     value = graph()->NewNode(simplified()->NumberAdd(), length,
903                              jsgraph()->OneConstant());
904 
905     ReplaceWithValue(node, value, effect, control);
906     return Replace(value);
907   }
908   return NoChange();
909 }
910 
911 namespace {
912 
HasInstanceTypeWitness(Node * receiver,Node * effect,InstanceType instance_type)913 bool HasInstanceTypeWitness(Node* receiver, Node* effect,
914                             InstanceType instance_type) {
915   for (Node* dominator = effect;;) {
916     if (dominator->opcode() == IrOpcode::kCheckMaps &&
917         NodeProperties::IsSame(dominator->InputAt(0), receiver)) {
918       ZoneHandleSet<Map> const& maps =
919           CheckMapsParametersOf(dominator->op()).maps();
920       // Check if all maps have the given {instance_type}.
921       for (size_t i = 0; i < maps.size(); ++i) {
922         if (maps[i]->instance_type() != instance_type) return false;
923       }
924       return true;
925     }
926     // The instance type doesn't change for JSReceiver values, so we
927     // don't need to pay attention to potentially side-effecting nodes
928     // here. Strings and internal structures like FixedArray and
929     // FixedDoubleArray are weird here, but we don't use this function then.
930     DCHECK_LE(FIRST_JS_RECEIVER_TYPE, instance_type);
931     DCHECK_EQ(1, dominator->op()->EffectOutputCount());
932     if (dominator->op()->EffectInputCount() != 1) {
933       // Didn't find any appropriate CheckMaps node.
934       return false;
935     }
936     dominator = NodeProperties::GetEffectInput(dominator);
937   }
938 }
939 
940 }  // namespace
941 
942 // ES6 section 20.3.3.1 Date.now ( )
ReduceDateNow(Node * node)943 Reduction JSBuiltinReducer::ReduceDateNow(Node* node) {
944   NodeProperties::RemoveValueInputs(node);
945   NodeProperties::ChangeOp(
946       node, javascript()->CallRuntime(Runtime::kDateCurrentTime));
947   return Changed(node);
948 }
949 
950 // ES6 section 20.3.4.10 Date.prototype.getTime ( )
ReduceDateGetTime(Node * node)951 Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) {
952   Node* receiver = NodeProperties::GetValueInput(node, 1);
953   Node* effect = NodeProperties::GetEffectInput(node);
954   Node* control = NodeProperties::GetControlInput(node);
955   if (HasInstanceTypeWitness(receiver, effect, JS_DATE_TYPE)) {
956     Node* value = effect = graph()->NewNode(
957         simplified()->LoadField(AccessBuilder::ForJSDateValue()), receiver,
958         effect, control);
959     ReplaceWithValue(node, value, effect, control);
960     return Replace(value);
961   }
962   return NoChange();
963 }
964 
965 // ES6 section 18.2.2 isFinite ( number )
ReduceGlobalIsFinite(Node * node)966 Reduction JSBuiltinReducer::ReduceGlobalIsFinite(Node* node) {
967   JSCallReduction r(node);
968   if (r.InputsMatchOne(Type::PlainPrimitive())) {
969     // isFinite(a:plain-primitive) -> NumberEqual(a', a')
970     // where a' = NumberSubtract(ToNumber(a), ToNumber(a))
971     Node* input = ToNumber(r.GetJSCallInput(0));
972     Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input);
973     Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff);
974     return Replace(value);
975   }
976   return NoChange();
977 }
978 
979 // ES6 section 18.2.3 isNaN ( number )
ReduceGlobalIsNaN(Node * node)980 Reduction JSBuiltinReducer::ReduceGlobalIsNaN(Node* node) {
981   JSCallReduction r(node);
982   if (r.InputsMatchOne(Type::PlainPrimitive())) {
983     // isNaN(a:plain-primitive) -> BooleanNot(NumberEqual(a', a'))
984     // where a' = ToNumber(a)
985     Node* input = ToNumber(r.GetJSCallInput(0));
986     Node* check = graph()->NewNode(simplified()->NumberEqual(), input, input);
987     Node* value = graph()->NewNode(simplified()->BooleanNot(), check);
988     return Replace(value);
989   }
990   return NoChange();
991 }
992 
993 // ES6 section 20.2.2.1 Math.abs ( x )
ReduceMathAbs(Node * node)994 Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) {
995   JSCallReduction r(node);
996   if (r.InputsMatchOne(Type::PlainPrimitive())) {
997     // Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a))
998     Node* input = ToNumber(r.GetJSCallInput(0));
999     Node* value = graph()->NewNode(simplified()->NumberAbs(), input);
1000     return Replace(value);
1001   }
1002   return NoChange();
1003 }
1004 
1005 // ES6 section 20.2.2.2 Math.acos ( x )
ReduceMathAcos(Node * node)1006 Reduction JSBuiltinReducer::ReduceMathAcos(Node* node) {
1007   JSCallReduction r(node);
1008   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1009     // Math.acos(a:plain-primitive) -> NumberAcos(ToNumber(a))
1010     Node* input = ToNumber(r.GetJSCallInput(0));
1011     Node* value = graph()->NewNode(simplified()->NumberAcos(), input);
1012     return Replace(value);
1013   }
1014   return NoChange();
1015 }
1016 
1017 // ES6 section 20.2.2.3 Math.acosh ( x )
ReduceMathAcosh(Node * node)1018 Reduction JSBuiltinReducer::ReduceMathAcosh(Node* node) {
1019   JSCallReduction r(node);
1020   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1021     // Math.acosh(a:plain-primitive) -> NumberAcosh(ToNumber(a))
1022     Node* input = ToNumber(r.GetJSCallInput(0));
1023     Node* value = graph()->NewNode(simplified()->NumberAcosh(), input);
1024     return Replace(value);
1025   }
1026   return NoChange();
1027 }
1028 
1029 // ES6 section 20.2.2.4 Math.asin ( x )
ReduceMathAsin(Node * node)1030 Reduction JSBuiltinReducer::ReduceMathAsin(Node* node) {
1031   JSCallReduction r(node);
1032   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1033     // Math.asin(a:plain-primitive) -> NumberAsin(ToNumber(a))
1034     Node* input = ToNumber(r.GetJSCallInput(0));
1035     Node* value = graph()->NewNode(simplified()->NumberAsin(), input);
1036     return Replace(value);
1037   }
1038   return NoChange();
1039 }
1040 
1041 // ES6 section 20.2.2.5 Math.asinh ( x )
ReduceMathAsinh(Node * node)1042 Reduction JSBuiltinReducer::ReduceMathAsinh(Node* node) {
1043   JSCallReduction r(node);
1044   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1045     // Math.asinh(a:plain-primitive) -> NumberAsinh(ToNumber(a))
1046     Node* input = ToNumber(r.GetJSCallInput(0));
1047     Node* value = graph()->NewNode(simplified()->NumberAsinh(), input);
1048     return Replace(value);
1049   }
1050   return NoChange();
1051 }
1052 
1053 // ES6 section 20.2.2.6 Math.atan ( x )
ReduceMathAtan(Node * node)1054 Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) {
1055   JSCallReduction r(node);
1056   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1057     // Math.atan(a:plain-primitive) -> NumberAtan(ToNumber(a))
1058     Node* input = ToNumber(r.GetJSCallInput(0));
1059     Node* value = graph()->NewNode(simplified()->NumberAtan(), input);
1060     return Replace(value);
1061   }
1062   return NoChange();
1063 }
1064 
1065 // ES6 section 20.2.2.7 Math.atanh ( x )
ReduceMathAtanh(Node * node)1066 Reduction JSBuiltinReducer::ReduceMathAtanh(Node* node) {
1067   JSCallReduction r(node);
1068   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1069     // Math.atanh(a:plain-primitive) -> NumberAtanh(ToNumber(a))
1070     Node* input = ToNumber(r.GetJSCallInput(0));
1071     Node* value = graph()->NewNode(simplified()->NumberAtanh(), input);
1072     return Replace(value);
1073   }
1074   return NoChange();
1075 }
1076 
1077 // ES6 section 20.2.2.8 Math.atan2 ( y, x )
ReduceMathAtan2(Node * node)1078 Reduction JSBuiltinReducer::ReduceMathAtan2(Node* node) {
1079   JSCallReduction r(node);
1080   if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
1081     // Math.atan2(a:plain-primitive,
1082     //            b:plain-primitive) -> NumberAtan2(ToNumber(a),
1083     //                                              ToNumber(b))
1084     Node* left = ToNumber(r.left());
1085     Node* right = ToNumber(r.right());
1086     Node* value = graph()->NewNode(simplified()->NumberAtan2(), left, right);
1087     return Replace(value);
1088   }
1089   return NoChange();
1090 }
1091 
1092 // ES6 section 20.2.2.10 Math.ceil ( x )
ReduceMathCeil(Node * node)1093 Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) {
1094   JSCallReduction r(node);
1095   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1096     // Math.ceil(a:plain-primitive) -> NumberCeil(ToNumber(a))
1097     Node* input = ToNumber(r.GetJSCallInput(0));
1098     Node* value = graph()->NewNode(simplified()->NumberCeil(), input);
1099     return Replace(value);
1100   }
1101   return NoChange();
1102 }
1103 
1104 // ES6 section 20.2.2.11 Math.clz32 ( x )
ReduceMathClz32(Node * node)1105 Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) {
1106   JSCallReduction r(node);
1107   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1108     // Math.clz32(a:plain-primitive) -> NumberClz32(ToUint32(a))
1109     Node* input = ToUint32(r.GetJSCallInput(0));
1110     Node* value = graph()->NewNode(simplified()->NumberClz32(), input);
1111     return Replace(value);
1112   }
1113   return NoChange();
1114 }
1115 
1116 // ES6 section 20.2.2.12 Math.cos ( x )
ReduceMathCos(Node * node)1117 Reduction JSBuiltinReducer::ReduceMathCos(Node* node) {
1118   JSCallReduction r(node);
1119   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1120     // Math.cos(a:plain-primitive) -> NumberCos(ToNumber(a))
1121     Node* input = ToNumber(r.GetJSCallInput(0));
1122     Node* value = graph()->NewNode(simplified()->NumberCos(), input);
1123     return Replace(value);
1124   }
1125   return NoChange();
1126 }
1127 
1128 // ES6 section 20.2.2.13 Math.cosh ( x )
ReduceMathCosh(Node * node)1129 Reduction JSBuiltinReducer::ReduceMathCosh(Node* node) {
1130   JSCallReduction r(node);
1131   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1132     // Math.cosh(a:plain-primitive) -> NumberCosh(ToNumber(a))
1133     Node* input = ToNumber(r.GetJSCallInput(0));
1134     Node* value = graph()->NewNode(simplified()->NumberCosh(), input);
1135     return Replace(value);
1136   }
1137   return NoChange();
1138 }
1139 
1140 // ES6 section 20.2.2.14 Math.exp ( x )
ReduceMathExp(Node * node)1141 Reduction JSBuiltinReducer::ReduceMathExp(Node* node) {
1142   JSCallReduction r(node);
1143   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1144     // Math.exp(a:plain-primitive) -> NumberExp(ToNumber(a))
1145     Node* input = ToNumber(r.GetJSCallInput(0));
1146     Node* value = graph()->NewNode(simplified()->NumberExp(), input);
1147     return Replace(value);
1148   }
1149   return NoChange();
1150 }
1151 
1152 // ES6 section 20.2.2.15 Math.expm1 ( x )
ReduceMathExpm1(Node * node)1153 Reduction JSBuiltinReducer::ReduceMathExpm1(Node* node) {
1154   JSCallReduction r(node);
1155   if (r.InputsMatchOne(Type::Number())) {
1156     // Math.expm1(a:number) -> NumberExpm1(a)
1157     Node* value = graph()->NewNode(simplified()->NumberExpm1(), r.left());
1158     return Replace(value);
1159   }
1160   return NoChange();
1161 }
1162 
1163 // ES6 section 20.2.2.16 Math.floor ( x )
ReduceMathFloor(Node * node)1164 Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) {
1165   JSCallReduction r(node);
1166   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1167     // Math.floor(a:plain-primitive) -> NumberFloor(ToNumber(a))
1168     Node* input = ToNumber(r.GetJSCallInput(0));
1169     Node* value = graph()->NewNode(simplified()->NumberFloor(), input);
1170     return Replace(value);
1171   }
1172   return NoChange();
1173 }
1174 
1175 // ES6 section 20.2.2.17 Math.fround ( x )
ReduceMathFround(Node * node)1176 Reduction JSBuiltinReducer::ReduceMathFround(Node* node) {
1177   JSCallReduction r(node);
1178   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1179     // Math.fround(a:plain-primitive) -> NumberFround(ToNumber(a))
1180     Node* input = ToNumber(r.GetJSCallInput(0));
1181     Node* value = graph()->NewNode(simplified()->NumberFround(), input);
1182     return Replace(value);
1183   }
1184   return NoChange();
1185 }
1186 
1187 // ES6 section 20.2.2.19 Math.imul ( x, y )
ReduceMathImul(Node * node)1188 Reduction JSBuiltinReducer::ReduceMathImul(Node* node) {
1189   JSCallReduction r(node);
1190   if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
1191     // Math.imul(a:plain-primitive,
1192     //           b:plain-primitive) -> NumberImul(ToUint32(a),
1193     //                                            ToUint32(b))
1194     Node* left = ToUint32(r.left());
1195     Node* right = ToUint32(r.right());
1196     Node* value = graph()->NewNode(simplified()->NumberImul(), left, right);
1197     return Replace(value);
1198   }
1199   return NoChange();
1200 }
1201 
1202 // ES6 section 20.2.2.20 Math.log ( x )
ReduceMathLog(Node * node)1203 Reduction JSBuiltinReducer::ReduceMathLog(Node* node) {
1204   JSCallReduction r(node);
1205   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1206     // Math.log(a:plain-primitive) -> NumberLog(ToNumber(a))
1207     Node* input = ToNumber(r.GetJSCallInput(0));
1208     Node* value = graph()->NewNode(simplified()->NumberLog(), input);
1209     return Replace(value);
1210   }
1211   return NoChange();
1212 }
1213 
1214 // ES6 section 20.2.2.21 Math.log1p ( x )
ReduceMathLog1p(Node * node)1215 Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) {
1216   JSCallReduction r(node);
1217   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1218     // Math.log1p(a:plain-primitive) -> NumberLog1p(ToNumber(a))
1219     Node* input = ToNumber(r.GetJSCallInput(0));
1220     Node* value = graph()->NewNode(simplified()->NumberLog1p(), input);
1221     return Replace(value);
1222   }
1223   return NoChange();
1224 }
1225 
1226 // ES6 section 20.2.2.22 Math.log10 ( x )
ReduceMathLog10(Node * node)1227 Reduction JSBuiltinReducer::ReduceMathLog10(Node* node) {
1228   JSCallReduction r(node);
1229   if (r.InputsMatchOne(Type::Number())) {
1230     // Math.log10(a:number) -> NumberLog10(a)
1231     Node* value = graph()->NewNode(simplified()->NumberLog10(), r.left());
1232     return Replace(value);
1233   }
1234   return NoChange();
1235 }
1236 
1237 // ES6 section 20.2.2.23 Math.log2 ( x )
ReduceMathLog2(Node * node)1238 Reduction JSBuiltinReducer::ReduceMathLog2(Node* node) {
1239   JSCallReduction r(node);
1240   if (r.InputsMatchOne(Type::Number())) {
1241     // Math.log2(a:number) -> NumberLog(a)
1242     Node* value = graph()->NewNode(simplified()->NumberLog2(), r.left());
1243     return Replace(value);
1244   }
1245   return NoChange();
1246 }
1247 
1248 // ES6 section 20.2.2.24 Math.max ( value1, value2, ...values )
ReduceMathMax(Node * node)1249 Reduction JSBuiltinReducer::ReduceMathMax(Node* node) {
1250   JSCallReduction r(node);
1251   if (r.InputsMatchZero()) {
1252     // Math.max() -> -Infinity
1253     return Replace(jsgraph()->Constant(-V8_INFINITY));
1254   }
1255   if (r.InputsMatchAll(Type::PlainPrimitive())) {
1256     // Math.max(a:plain-primitive, b:plain-primitive, ...)
1257     Node* value = ToNumber(r.GetJSCallInput(0));
1258     for (int i = 1; i < r.GetJSCallArity(); i++) {
1259       Node* input = ToNumber(r.GetJSCallInput(i));
1260       value = graph()->NewNode(simplified()->NumberMax(), value, input);
1261     }
1262     return Replace(value);
1263   }
1264   return NoChange();
1265 }
1266 
1267 // ES6 section 20.2.2.25 Math.min ( value1, value2, ...values )
ReduceMathMin(Node * node)1268 Reduction JSBuiltinReducer::ReduceMathMin(Node* node) {
1269   JSCallReduction r(node);
1270   if (r.InputsMatchZero()) {
1271     // Math.min() -> Infinity
1272     return Replace(jsgraph()->Constant(V8_INFINITY));
1273   }
1274   if (r.InputsMatchAll(Type::PlainPrimitive())) {
1275     // Math.min(a:plain-primitive, b:plain-primitive, ...)
1276     Node* value = ToNumber(r.GetJSCallInput(0));
1277     for (int i = 1; i < r.GetJSCallArity(); i++) {
1278       Node* input = ToNumber(r.GetJSCallInput(i));
1279       value = graph()->NewNode(simplified()->NumberMin(), value, input);
1280     }
1281     return Replace(value);
1282   }
1283   return NoChange();
1284 }
1285 
1286 // ES6 section 20.2.2.26 Math.pow ( x, y )
ReduceMathPow(Node * node)1287 Reduction JSBuiltinReducer::ReduceMathPow(Node* node) {
1288   JSCallReduction r(node);
1289   if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
1290     // Math.pow(a:plain-primitive,
1291     //          b:plain-primitive) -> NumberPow(ToNumber(a), ToNumber(b))
1292     Node* left = ToNumber(r.left());
1293     Node* right = ToNumber(r.right());
1294     Node* value = graph()->NewNode(simplified()->NumberPow(), left, right);
1295     return Replace(value);
1296   }
1297   return NoChange();
1298 }
1299 
1300 // ES6 section 20.2.2.28 Math.round ( x )
ReduceMathRound(Node * node)1301 Reduction JSBuiltinReducer::ReduceMathRound(Node* node) {
1302   JSCallReduction r(node);
1303   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1304     // Math.round(a:plain-primitive) -> NumberRound(ToNumber(a))
1305     Node* input = ToNumber(r.GetJSCallInput(0));
1306     Node* value = graph()->NewNode(simplified()->NumberRound(), input);
1307     return Replace(value);
1308   }
1309   return NoChange();
1310 }
1311 
1312 // ES6 section 20.2.2.9 Math.cbrt ( x )
ReduceMathCbrt(Node * node)1313 Reduction JSBuiltinReducer::ReduceMathCbrt(Node* node) {
1314   JSCallReduction r(node);
1315   if (r.InputsMatchOne(Type::Number())) {
1316     // Math.cbrt(a:number) -> NumberCbrt(a)
1317     Node* value = graph()->NewNode(simplified()->NumberCbrt(), r.left());
1318     return Replace(value);
1319   }
1320   return NoChange();
1321 }
1322 
1323 // ES6 section 20.2.2.29 Math.sign ( x )
ReduceMathSign(Node * node)1324 Reduction JSBuiltinReducer::ReduceMathSign(Node* node) {
1325   JSCallReduction r(node);
1326   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1327     // Math.sign(a:plain-primitive) -> NumberSign(ToNumber(a))
1328     Node* input = ToNumber(r.GetJSCallInput(0));
1329     Node* value = graph()->NewNode(simplified()->NumberSign(), input);
1330     return Replace(value);
1331   }
1332   return NoChange();
1333 }
1334 
1335 // ES6 section 20.2.2.30 Math.sin ( x )
ReduceMathSin(Node * node)1336 Reduction JSBuiltinReducer::ReduceMathSin(Node* node) {
1337   JSCallReduction r(node);
1338   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1339     // Math.sin(a:plain-primitive) -> NumberSin(ToNumber(a))
1340     Node* input = ToNumber(r.GetJSCallInput(0));
1341     Node* value = graph()->NewNode(simplified()->NumberSin(), input);
1342     return Replace(value);
1343   }
1344   return NoChange();
1345 }
1346 
1347 // ES6 section 20.2.2.31 Math.sinh ( x )
ReduceMathSinh(Node * node)1348 Reduction JSBuiltinReducer::ReduceMathSinh(Node* node) {
1349   JSCallReduction r(node);
1350   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1351     // Math.sinh(a:plain-primitive) -> NumberSinh(ToNumber(a))
1352     Node* input = ToNumber(r.GetJSCallInput(0));
1353     Node* value = graph()->NewNode(simplified()->NumberSinh(), input);
1354     return Replace(value);
1355   }
1356   return NoChange();
1357 }
1358 
1359 // ES6 section 20.2.2.32 Math.sqrt ( x )
ReduceMathSqrt(Node * node)1360 Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) {
1361   JSCallReduction r(node);
1362   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1363     // Math.sqrt(a:plain-primitive) -> NumberSqrt(ToNumber(a))
1364     Node* input = ToNumber(r.GetJSCallInput(0));
1365     Node* value = graph()->NewNode(simplified()->NumberSqrt(), input);
1366     return Replace(value);
1367   }
1368   return NoChange();
1369 }
1370 
1371 // ES6 section 20.2.2.33 Math.tan ( x )
ReduceMathTan(Node * node)1372 Reduction JSBuiltinReducer::ReduceMathTan(Node* node) {
1373   JSCallReduction r(node);
1374   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1375     // Math.tan(a:plain-primitive) -> NumberTan(ToNumber(a))
1376     Node* input = ToNumber(r.GetJSCallInput(0));
1377     Node* value = graph()->NewNode(simplified()->NumberTan(), input);
1378     return Replace(value);
1379   }
1380   return NoChange();
1381 }
1382 
1383 // ES6 section 20.2.2.34 Math.tanh ( x )
ReduceMathTanh(Node * node)1384 Reduction JSBuiltinReducer::ReduceMathTanh(Node* node) {
1385   JSCallReduction r(node);
1386   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1387     // Math.tanh(a:plain-primitive) -> NumberTanh(ToNumber(a))
1388     Node* input = ToNumber(r.GetJSCallInput(0));
1389     Node* value = graph()->NewNode(simplified()->NumberTanh(), input);
1390     return Replace(value);
1391   }
1392   return NoChange();
1393 }
1394 
1395 // ES6 section 20.2.2.35 Math.trunc ( x )
ReduceMathTrunc(Node * node)1396 Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) {
1397   JSCallReduction r(node);
1398   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1399     // Math.trunc(a:plain-primitive) -> NumberTrunc(ToNumber(a))
1400     Node* input = ToNumber(r.GetJSCallInput(0));
1401     Node* value = graph()->NewNode(simplified()->NumberTrunc(), input);
1402     return Replace(value);
1403   }
1404   return NoChange();
1405 }
1406 
1407 // ES6 section 20.1.2.2 Number.isFinite ( number )
ReduceNumberIsFinite(Node * node)1408 Reduction JSBuiltinReducer::ReduceNumberIsFinite(Node* node) {
1409   JSCallReduction r(node);
1410   if (r.InputsMatchOne(Type::Number())) {
1411     // Number.isFinite(a:number) -> NumberEqual(a', a')
1412     // where a' = NumberSubtract(a, a)
1413     Node* input = r.GetJSCallInput(0);
1414     Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input);
1415     Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff);
1416     return Replace(value);
1417   }
1418   return NoChange();
1419 }
1420 
1421 // ES6 section 20.1.2.3 Number.isInteger ( number )
ReduceNumberIsInteger(Node * node)1422 Reduction JSBuiltinReducer::ReduceNumberIsInteger(Node* node) {
1423   JSCallReduction r(node);
1424   if (r.InputsMatchOne(Type::Number())) {
1425     // Number.isInteger(x:number) -> NumberEqual(NumberSubtract(x, x'), #0)
1426     // where x' = NumberTrunc(x)
1427     Node* input = r.GetJSCallInput(0);
1428     Node* trunc = graph()->NewNode(simplified()->NumberTrunc(), input);
1429     Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, trunc);
1430     Node* value = graph()->NewNode(simplified()->NumberEqual(), diff,
1431                                    jsgraph()->ZeroConstant());
1432     return Replace(value);
1433   }
1434   return NoChange();
1435 }
1436 
1437 // ES6 section 20.1.2.4 Number.isNaN ( number )
ReduceNumberIsNaN(Node * node)1438 Reduction JSBuiltinReducer::ReduceNumberIsNaN(Node* node) {
1439   JSCallReduction r(node);
1440   if (r.InputsMatchOne(Type::Number())) {
1441     // Number.isNaN(a:number) -> BooleanNot(NumberEqual(a, a))
1442     Node* input = r.GetJSCallInput(0);
1443     Node* check = graph()->NewNode(simplified()->NumberEqual(), input, input);
1444     Node* value = graph()->NewNode(simplified()->BooleanNot(), check);
1445     return Replace(value);
1446   }
1447   return NoChange();
1448 }
1449 
1450 // ES6 section 20.1.2.5 Number.isSafeInteger ( number )
ReduceNumberIsSafeInteger(Node * node)1451 Reduction JSBuiltinReducer::ReduceNumberIsSafeInteger(Node* node) {
1452   JSCallReduction r(node);
1453   if (r.InputsMatchOne(type_cache_.kSafeInteger)) {
1454     // Number.isInteger(x:safe-integer) -> #true
1455     Node* value = jsgraph()->TrueConstant();
1456     return Replace(value);
1457   }
1458   return NoChange();
1459 }
1460 
1461 // ES6 section 20.1.2.13 Number.parseInt ( string, radix )
ReduceNumberParseInt(Node * node)1462 Reduction JSBuiltinReducer::ReduceNumberParseInt(Node* node) {
1463   JSCallReduction r(node);
1464   if (r.InputsMatchOne(type_cache_.kSafeInteger) ||
1465       r.InputsMatchTwo(type_cache_.kSafeInteger,
1466                        type_cache_.kZeroOrUndefined) ||
1467       r.InputsMatchTwo(type_cache_.kSafeInteger, type_cache_.kTenOrUndefined)) {
1468     // Number.parseInt(a:safe-integer) -> a
1469     // Number.parseInt(a:safe-integer,b:#0\/undefined) -> a
1470     // Number.parseInt(a:safe-integer,b:#10\/undefined) -> a
1471     Node* value = r.GetJSCallInput(0);
1472     return Replace(value);
1473   }
1474   return NoChange();
1475 }
1476 
1477 // ES6 section #sec-object.create Object.create(proto, properties)
ReduceObjectCreate(Node * node)1478 Reduction JSBuiltinReducer::ReduceObjectCreate(Node* node) {
1479   // We need exactly target, receiver and value parameters.
1480   int arg_count = node->op()->ValueInputCount();
1481   if (arg_count != 3) return NoChange();
1482   Node* effect = NodeProperties::GetEffectInput(node);
1483   Node* control = NodeProperties::GetControlInput(node);
1484   Node* prototype = NodeProperties::GetValueInput(node, 2);
1485   Type* prototype_type = NodeProperties::GetType(prototype);
1486   Handle<Map> instance_map;
1487   if (!prototype_type->IsHeapConstant()) return NoChange();
1488   Handle<HeapObject> prototype_const =
1489       prototype_type->AsHeapConstant()->Value();
1490   if (!prototype_const->IsNull(isolate()) && !prototype_const->IsJSReceiver()) {
1491     return NoChange();
1492   }
1493   instance_map = Map::GetObjectCreateMap(prototype_const);
1494   Node* properties = jsgraph()->EmptyFixedArrayConstant();
1495   if (instance_map->is_dictionary_map()) {
1496     // Allocated an empty NameDictionary as backing store for the properties.
1497     Handle<Map> map(isolate()->heap()->hash_table_map(), isolate());
1498     int capacity =
1499         NameDictionary::ComputeCapacity(NameDictionary::kInitialCapacity);
1500     DCHECK(base::bits::IsPowerOfTwo32(capacity));
1501     int length = NameDictionary::EntryToIndex(capacity);
1502     int size = NameDictionary::SizeFor(length);
1503 
1504     effect = graph()->NewNode(
1505         common()->BeginRegion(RegionObservability::kNotObservable), effect);
1506 
1507     Node* value = effect =
1508         graph()->NewNode(simplified()->Allocate(NOT_TENURED),
1509                          jsgraph()->Constant(size), effect, control);
1510     effect =
1511         graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
1512                          value, jsgraph()->HeapConstant(map), effect, control);
1513 
1514     // Initialize FixedArray fields.
1515     effect = graph()->NewNode(
1516         simplified()->StoreField(AccessBuilder::ForFixedArrayLength()), value,
1517         jsgraph()->SmiConstant(length), effect, control);
1518     // Initialize HashTable fields.
1519     effect =
1520         graph()->NewNode(simplified()->StoreField(
1521                              AccessBuilder::ForHashTableBaseNumberOfElements()),
1522                          value, jsgraph()->SmiConstant(0), effect, control);
1523     effect = graph()->NewNode(
1524         simplified()->StoreField(
1525             AccessBuilder::ForHashTableBaseNumberOfDeletedElement()),
1526         value, jsgraph()->SmiConstant(0), effect, control);
1527     effect = graph()->NewNode(
1528         simplified()->StoreField(AccessBuilder::ForHashTableBaseCapacity()),
1529         value, jsgraph()->SmiConstant(capacity), effect, control);
1530     // Initialize Dictionary fields.
1531     Node* undefined = jsgraph()->UndefinedConstant();
1532     effect = graph()->NewNode(
1533         simplified()->StoreField(AccessBuilder::ForDictionaryMaxNumberKey()),
1534         value, undefined, effect, control);
1535     effect = graph()->NewNode(
1536         simplified()->StoreField(
1537             AccessBuilder::ForDictionaryNextEnumerationIndex()),
1538         value, jsgraph()->SmiConstant(PropertyDetails::kInitialIndex), effect,
1539         control);
1540     // Initialize hte Properties fields.
1541     for (int index = NameDictionary::kNextEnumerationIndexIndex + 1;
1542          index < length; index++) {
1543       effect = graph()->NewNode(
1544           simplified()->StoreField(
1545               AccessBuilder::ForFixedArraySlot(index, kNoWriteBarrier)),
1546           value, undefined, effect, control);
1547     }
1548     properties = effect =
1549         graph()->NewNode(common()->FinishRegion(), value, effect);
1550   }
1551 
1552   int const instance_size = instance_map->instance_size();
1553   if (instance_size > kMaxRegularHeapObjectSize) return NoChange();
1554   dependencies()->AssumeInitialMapCantChange(instance_map);
1555 
1556   // Emit code to allocate the JSObject instance for the given
1557   // {instance_map}.
1558   effect = graph()->NewNode(
1559       common()->BeginRegion(RegionObservability::kNotObservable), effect);
1560   Node* value = effect =
1561       graph()->NewNode(simplified()->Allocate(NOT_TENURED),
1562                        jsgraph()->Constant(instance_size), effect, control);
1563   effect =
1564       graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), value,
1565                        jsgraph()->HeapConstant(instance_map), effect, control);
1566   effect = graph()->NewNode(
1567       simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value,
1568       properties, effect, control);
1569   effect = graph()->NewNode(
1570       simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value,
1571       jsgraph()->EmptyFixedArrayConstant(), effect, control);
1572   // Initialize Object fields.
1573   Node* undefined = jsgraph()->UndefinedConstant();
1574   for (int offset = JSObject::kHeaderSize; offset < instance_size;
1575        offset += kPointerSize) {
1576     effect = graph()->NewNode(
1577         simplified()->StoreField(
1578             AccessBuilder::ForJSObjectOffset(offset, kNoWriteBarrier)),
1579         value, undefined, effect, control);
1580   }
1581   value = effect = graph()->NewNode(common()->FinishRegion(), value, effect);
1582 
1583   // replace it
1584   ReplaceWithValue(node, value, effect, control);
1585   return Replace(value);
1586 }
1587 
1588 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits )
ReduceStringFromCharCode(Node * node)1589 Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) {
1590   JSCallReduction r(node);
1591   if (r.InputsMatchOne(Type::PlainPrimitive())) {
1592     // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a)
1593     Node* input = ToNumber(r.GetJSCallInput(0));
1594     Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input);
1595     return Replace(value);
1596   }
1597   return NoChange();
1598 }
1599 
1600 namespace {
1601 
GetStringWitness(Node * node)1602 Node* GetStringWitness(Node* node) {
1603   Node* receiver = NodeProperties::GetValueInput(node, 1);
1604   Type* receiver_type = NodeProperties::GetType(receiver);
1605   Node* effect = NodeProperties::GetEffectInput(node);
1606   if (receiver_type->Is(Type::String())) return receiver;
1607   // Check if the {node} is dominated by a CheckString renaming for
1608   // it's {receiver}, and if so use that renaming as {receiver} for
1609   // the lowering below.
1610   for (Node* dominator = effect;;) {
1611     if (dominator->opcode() == IrOpcode::kCheckString &&
1612         NodeProperties::IsSame(dominator->InputAt(0), receiver)) {
1613       return dominator;
1614     }
1615     if (dominator->op()->EffectInputCount() != 1) {
1616       // Didn't find any appropriate CheckString node.
1617       return nullptr;
1618     }
1619     dominator = NodeProperties::GetEffectInput(dominator);
1620   }
1621 }
1622 
1623 }  // namespace
1624 
1625 // ES6 section 21.1.3.1 String.prototype.charAt ( pos )
ReduceStringCharAt(Node * node)1626 Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) {
1627   // We need at least target, receiver and index parameters.
1628   if (node->op()->ValueInputCount() >= 3) {
1629     Node* index = NodeProperties::GetValueInput(node, 2);
1630     Type* index_type = NodeProperties::GetType(index);
1631     Node* effect = NodeProperties::GetEffectInput(node);
1632     Node* control = NodeProperties::GetControlInput(node);
1633 
1634     if (index_type->Is(Type::Integral32OrMinusZeroOrNaN())) {
1635       if (Node* receiver = GetStringWitness(node)) {
1636         if (!index_type->Is(Type::Unsigned32())) {
1637           // Map -0 and NaN to 0 (as per ToInteger), and the values in
1638           // the [-2^31,-1] range to the [2^31,2^32-1] range, which will
1639           // be considered out-of-bounds as well, because of the maximal
1640           // String length limit in V8.
1641           STATIC_ASSERT(String::kMaxLength <= kMaxInt);
1642           index = graph()->NewNode(simplified()->NumberToUint32(), index);
1643         }
1644 
1645         // Determine the {receiver} length.
1646         Node* receiver_length = effect = graph()->NewNode(
1647             simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
1648             effect, control);
1649 
1650         // Check if {index} is less than {receiver} length.
1651         Node* check = graph()->NewNode(simplified()->NumberLessThan(), index,
1652                                        receiver_length);
1653         Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1654                                         check, control);
1655 
1656         // Return the character from the {receiver} as single character string.
1657         Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1658         Node* vtrue = graph()->NewNode(simplified()->StringCharAt(), receiver,
1659                                        index, if_true);
1660 
1661         // Return the empty string otherwise.
1662         Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1663         Node* vfalse = jsgraph()->EmptyStringConstant();
1664 
1665         control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1666         Node* value =
1667             graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1668                              vtrue, vfalse, control);
1669 
1670         ReplaceWithValue(node, value, effect, control);
1671         return Replace(value);
1672       }
1673     }
1674   }
1675 
1676   return NoChange();
1677 }
1678 
1679 // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
ReduceStringCharCodeAt(Node * node)1680 Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) {
1681   // We need at least target, receiver and index parameters.
1682   if (node->op()->ValueInputCount() >= 3) {
1683     Node* index = NodeProperties::GetValueInput(node, 2);
1684     Type* index_type = NodeProperties::GetType(index);
1685     Node* effect = NodeProperties::GetEffectInput(node);
1686     Node* control = NodeProperties::GetControlInput(node);
1687 
1688     if (index_type->Is(Type::Integral32OrMinusZeroOrNaN())) {
1689       if (Node* receiver = GetStringWitness(node)) {
1690         if (!index_type->Is(Type::Unsigned32())) {
1691           // Map -0 and NaN to 0 (as per ToInteger), and the values in
1692           // the [-2^31,-1] range to the [2^31,2^32-1] range, which will
1693           // be considered out-of-bounds as well, because of the maximal
1694           // String length limit in V8.
1695           STATIC_ASSERT(String::kMaxLength <= kMaxInt);
1696           index = graph()->NewNode(simplified()->NumberToUint32(), index);
1697         }
1698 
1699         // Determine the {receiver} length.
1700         Node* receiver_length = effect = graph()->NewNode(
1701             simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
1702             effect, control);
1703 
1704         // Check if {index} is less than {receiver} length.
1705         Node* check = graph()->NewNode(simplified()->NumberLessThan(), index,
1706                                        receiver_length);
1707         Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1708                                         check, control);
1709 
1710         // Load the character from the {receiver}.
1711         Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1712         Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(),
1713                                        receiver, index, if_true);
1714 
1715         // Return NaN otherwise.
1716         Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1717         Node* vfalse = jsgraph()->NaNConstant();
1718 
1719         control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1720         Node* value =
1721             graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1722                              vtrue, vfalse, control);
1723 
1724         ReplaceWithValue(node, value, effect, control);
1725         return Replace(value);
1726       }
1727     }
1728   }
1729 
1730   return NoChange();
1731 }
1732 
1733 // ES6 String.prototype.indexOf(searchString [, position])
1734 // #sec-string.prototype.indexof
ReduceStringIndexOf(Node * node)1735 Reduction JSBuiltinReducer::ReduceStringIndexOf(Node* node) {
1736   // We need at least target, receiver and search_string parameters.
1737   if (node->op()->ValueInputCount() >= 3) {
1738     Node* search_string = NodeProperties::GetValueInput(node, 2);
1739     Type* search_string_type = NodeProperties::GetType(search_string);
1740     Node* position = (node->op()->ValueInputCount() >= 4)
1741                          ? NodeProperties::GetValueInput(node, 3)
1742                          : jsgraph()->ZeroConstant();
1743     Type* position_type = NodeProperties::GetType(position);
1744 
1745     if (search_string_type->Is(Type::String()) &&
1746         position_type->Is(Type::SignedSmall())) {
1747       if (Node* receiver = GetStringWitness(node)) {
1748         RelaxEffectsAndControls(node);
1749         node->ReplaceInput(0, receiver);
1750         node->ReplaceInput(1, search_string);
1751         node->ReplaceInput(2, position);
1752         node->TrimInputCount(3);
1753         NodeProperties::ChangeOp(node, simplified()->StringIndexOf());
1754         return Changed(node);
1755       }
1756     }
1757   }
1758   return NoChange();
1759 }
1760 
ReduceStringIterator(Node * node)1761 Reduction JSBuiltinReducer::ReduceStringIterator(Node* node) {
1762   if (Node* receiver = GetStringWitness(node)) {
1763     Node* effect = NodeProperties::GetEffectInput(node);
1764     Node* control = NodeProperties::GetControlInput(node);
1765 
1766     Node* map = jsgraph()->HeapConstant(
1767         handle(native_context()->string_iterator_map(), isolate()));
1768 
1769     // allocate new iterator
1770     effect = graph()->NewNode(
1771         common()->BeginRegion(RegionObservability::kNotObservable), effect);
1772     Node* value = effect = graph()->NewNode(
1773         simplified()->Allocate(NOT_TENURED),
1774         jsgraph()->Constant(JSStringIterator::kSize), effect, control);
1775     NodeProperties::SetType(value, Type::OtherObject());
1776     effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
1777                               value, map, effect, control);
1778     effect = graph()->NewNode(
1779         simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value,
1780         jsgraph()->EmptyFixedArrayConstant(), effect, control);
1781     effect = graph()->NewNode(
1782         simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value,
1783         jsgraph()->EmptyFixedArrayConstant(), effect, control);
1784 
1785     // attach the iterator to this string
1786     effect = graph()->NewNode(
1787         simplified()->StoreField(AccessBuilder::ForJSStringIteratorString()),
1788         value, receiver, effect, control);
1789     effect = graph()->NewNode(
1790         simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()),
1791         value, jsgraph()->SmiConstant(0), effect, control);
1792 
1793     value = effect = graph()->NewNode(common()->FinishRegion(), value, effect);
1794 
1795     // replace it
1796     ReplaceWithValue(node, value, effect, control);
1797     return Replace(value);
1798   }
1799   return NoChange();
1800 }
1801 
ReduceStringIteratorNext(Node * node)1802 Reduction JSBuiltinReducer::ReduceStringIteratorNext(Node* node) {
1803   Node* receiver = NodeProperties::GetValueInput(node, 1);
1804   Node* effect = NodeProperties::GetEffectInput(node);
1805   Node* control = NodeProperties::GetControlInput(node);
1806   Node* context = NodeProperties::GetContextInput(node);
1807   if (HasInstanceTypeWitness(receiver, effect, JS_STRING_ITERATOR_TYPE)) {
1808     Node* string = effect = graph()->NewNode(
1809         simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()),
1810         receiver, effect, control);
1811     Node* index = effect = graph()->NewNode(
1812         simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()),
1813         receiver, effect, control);
1814     Node* length = effect = graph()->NewNode(
1815         simplified()->LoadField(AccessBuilder::ForStringLength()), string,
1816         effect, control);
1817 
1818     // branch0: if (index < length)
1819     Node* check0 =
1820         graph()->NewNode(simplified()->NumberLessThan(), index, length);
1821     Node* branch0 =
1822         graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
1823 
1824     Node* etrue0 = effect;
1825     Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1826     Node* done_true;
1827     Node* vtrue0;
1828     {
1829       done_true = jsgraph()->FalseConstant();
1830       Node* lead = graph()->NewNode(simplified()->StringCharCodeAt(), string,
1831                                     index, if_true0);
1832 
1833       // branch1: if ((lead & 0xFC00) === 0xD800)
1834       Node* check1 =
1835           graph()->NewNode(simplified()->NumberEqual(),
1836                            graph()->NewNode(simplified()->NumberBitwiseAnd(),
1837                                             lead, jsgraph()->Constant(0xFC00)),
1838                            jsgraph()->Constant(0xD800));
1839       Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1840                                        check1, if_true0);
1841       Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1842       Node* vtrue1;
1843       {
1844         Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
1845                                             jsgraph()->OneConstant());
1846         // branch2: if ((index + 1) < length)
1847         Node* check2 = graph()->NewNode(simplified()->NumberLessThan(),
1848                                         next_index, length);
1849         Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1850                                          check2, if_true1);
1851         Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1852         Node* vtrue2;
1853         {
1854           Node* trail = graph()->NewNode(simplified()->StringCharCodeAt(),
1855                                          string, next_index, if_true2);
1856           // branch3: if ((trail & 0xFC00) === 0xDC00)
1857           Node* check3 = graph()->NewNode(
1858               simplified()->NumberEqual(),
1859               graph()->NewNode(simplified()->NumberBitwiseAnd(), trail,
1860                                jsgraph()->Constant(0xFC00)),
1861               jsgraph()->Constant(0xDC00));
1862           Node* branch3 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1863                                            check3, if_true2);
1864           Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
1865           Node* vtrue3;
1866           {
1867             vtrue3 = graph()->NewNode(
1868                 simplified()->NumberBitwiseOr(),
1869 // Need to swap the order for big-endian platforms
1870 #if V8_TARGET_BIG_ENDIAN
1871                 graph()->NewNode(simplified()->NumberShiftLeft(), lead,
1872                                  jsgraph()->Constant(16)),
1873                 trail);
1874 #else
1875                 graph()->NewNode(simplified()->NumberShiftLeft(), trail,
1876                                  jsgraph()->Constant(16)),
1877                 lead);
1878 #endif
1879           }
1880 
1881           Node* if_false3 = graph()->NewNode(common()->IfFalse(), branch3);
1882           Node* vfalse3 = lead;
1883           if_true2 = graph()->NewNode(common()->Merge(2), if_true3, if_false3);
1884           vtrue2 =
1885               graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
1886                                vtrue3, vfalse3, if_true2);
1887         }
1888 
1889         Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
1890         Node* vfalse2 = lead;
1891         if_true1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
1892         vtrue1 =
1893             graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
1894                              vtrue2, vfalse2, if_true1);
1895       }
1896 
1897       Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1898       Node* vfalse1 = lead;
1899       if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
1900       vtrue0 =
1901           graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
1902                            vtrue1, vfalse1, if_true0);
1903       vtrue0 = graph()->NewNode(
1904           simplified()->StringFromCodePoint(UnicodeEncoding::UTF16), vtrue0);
1905 
1906       // Update iterator.[[NextIndex]]
1907       Node* char_length = etrue0 = graph()->NewNode(
1908           simplified()->LoadField(AccessBuilder::ForStringLength()), vtrue0,
1909           etrue0, if_true0);
1910       index = graph()->NewNode(simplified()->NumberAdd(), index, char_length);
1911       etrue0 = graph()->NewNode(
1912           simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()),
1913           receiver, index, etrue0, if_true0);
1914     }
1915 
1916     Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1917     Node* done_false;
1918     Node* vfalse0;
1919     {
1920       vfalse0 = jsgraph()->UndefinedConstant();
1921       done_false = jsgraph()->TrueConstant();
1922     }
1923 
1924     control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
1925     effect = graph()->NewNode(common()->EffectPhi(2), etrue0, effect, control);
1926     Node* value =
1927         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1928                          vtrue0, vfalse0, control);
1929     Node* done =
1930         graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1931                          done_true, done_false, control);
1932 
1933     value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
1934                                       value, done, context, effect);
1935 
1936     ReplaceWithValue(node, value, effect, control);
1937     return Replace(value);
1938   }
1939   return NoChange();
1940 }
1941 
ReduceArrayBufferViewAccessor(Node * node,InstanceType instance_type,FieldAccess const & access)1942 Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor(
1943     Node* node, InstanceType instance_type, FieldAccess const& access) {
1944   Node* receiver = NodeProperties::GetValueInput(node, 1);
1945   Node* effect = NodeProperties::GetEffectInput(node);
1946   Node* control = NodeProperties::GetControlInput(node);
1947   if (HasInstanceTypeWitness(receiver, effect, instance_type)) {
1948     // Load the {receiver}s field.
1949     Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
1950                                             receiver, effect, control);
1951 
1952     // See if we can skip the neutering check.
1953     if (isolate()->IsArrayBufferNeuteringIntact()) {
1954       // Add a code dependency so we are deoptimized in case an ArrayBuffer
1955       // gets neutered.
1956       dependencies()->AssumePropertyCell(
1957           factory()->array_buffer_neutering_protector());
1958     } else {
1959       // Check if the {receiver}s buffer was neutered.
1960       Node* receiver_buffer = effect = graph()->NewNode(
1961           simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
1962           receiver, effect, control);
1963       Node* check = effect =
1964           graph()->NewNode(simplified()->ArrayBufferWasNeutered(),
1965                            receiver_buffer, effect, control);
1966 
1967       // Default to zero if the {receiver}s buffer was neutered.
1968       value = graph()->NewNode(
1969           common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
1970           check, jsgraph()->ZeroConstant(), value);
1971     }
1972 
1973     ReplaceWithValue(node, value, effect, control);
1974     return Replace(value);
1975   }
1976   return NoChange();
1977 }
1978 
Reduce(Node * node)1979 Reduction JSBuiltinReducer::Reduce(Node* node) {
1980   Reduction reduction = NoChange();
1981   JSCallReduction r(node);
1982 
1983   // Dispatch according to the BuiltinFunctionId if present.
1984   if (!r.HasBuiltinFunctionId()) return NoChange();
1985   switch (r.GetBuiltinFunctionId()) {
1986     case kArrayEntries:
1987       return ReduceArrayIterator(node, IterationKind::kEntries);
1988     case kArrayKeys:
1989       return ReduceArrayIterator(node, IterationKind::kKeys);
1990     case kArrayValues:
1991       return ReduceArrayIterator(node, IterationKind::kValues);
1992     case kArrayIteratorNext:
1993       return ReduceArrayIteratorNext(node);
1994     case kArrayPop:
1995       return ReduceArrayPop(node);
1996     case kArrayPush:
1997       return ReduceArrayPush(node);
1998     case kDateNow:
1999       return ReduceDateNow(node);
2000     case kDateGetTime:
2001       return ReduceDateGetTime(node);
2002     case kGlobalIsFinite:
2003       reduction = ReduceGlobalIsFinite(node);
2004       break;
2005     case kGlobalIsNaN:
2006       reduction = ReduceGlobalIsNaN(node);
2007       break;
2008     case kMathAbs:
2009       reduction = ReduceMathAbs(node);
2010       break;
2011     case kMathAcos:
2012       reduction = ReduceMathAcos(node);
2013       break;
2014     case kMathAcosh:
2015       reduction = ReduceMathAcosh(node);
2016       break;
2017     case kMathAsin:
2018       reduction = ReduceMathAsin(node);
2019       break;
2020     case kMathAsinh:
2021       reduction = ReduceMathAsinh(node);
2022       break;
2023     case kMathAtan:
2024       reduction = ReduceMathAtan(node);
2025       break;
2026     case kMathAtanh:
2027       reduction = ReduceMathAtanh(node);
2028       break;
2029     case kMathAtan2:
2030       reduction = ReduceMathAtan2(node);
2031       break;
2032     case kMathCbrt:
2033       reduction = ReduceMathCbrt(node);
2034       break;
2035     case kMathCeil:
2036       reduction = ReduceMathCeil(node);
2037       break;
2038     case kMathClz32:
2039       reduction = ReduceMathClz32(node);
2040       break;
2041     case kMathCos:
2042       reduction = ReduceMathCos(node);
2043       break;
2044     case kMathCosh:
2045       reduction = ReduceMathCosh(node);
2046       break;
2047     case kMathExp:
2048       reduction = ReduceMathExp(node);
2049       break;
2050     case kMathExpm1:
2051       reduction = ReduceMathExpm1(node);
2052       break;
2053     case kMathFloor:
2054       reduction = ReduceMathFloor(node);
2055       break;
2056     case kMathFround:
2057       reduction = ReduceMathFround(node);
2058       break;
2059     case kMathImul:
2060       reduction = ReduceMathImul(node);
2061       break;
2062     case kMathLog:
2063       reduction = ReduceMathLog(node);
2064       break;
2065     case kMathLog1p:
2066       reduction = ReduceMathLog1p(node);
2067       break;
2068     case kMathLog10:
2069       reduction = ReduceMathLog10(node);
2070       break;
2071     case kMathLog2:
2072       reduction = ReduceMathLog2(node);
2073       break;
2074     case kMathMax:
2075       reduction = ReduceMathMax(node);
2076       break;
2077     case kMathMin:
2078       reduction = ReduceMathMin(node);
2079       break;
2080     case kMathPow:
2081       reduction = ReduceMathPow(node);
2082       break;
2083     case kMathRound:
2084       reduction = ReduceMathRound(node);
2085       break;
2086     case kMathSign:
2087       reduction = ReduceMathSign(node);
2088       break;
2089     case kMathSin:
2090       reduction = ReduceMathSin(node);
2091       break;
2092     case kMathSinh:
2093       reduction = ReduceMathSinh(node);
2094       break;
2095     case kMathSqrt:
2096       reduction = ReduceMathSqrt(node);
2097       break;
2098     case kMathTan:
2099       reduction = ReduceMathTan(node);
2100       break;
2101     case kMathTanh:
2102       reduction = ReduceMathTanh(node);
2103       break;
2104     case kMathTrunc:
2105       reduction = ReduceMathTrunc(node);
2106       break;
2107     case kNumberIsFinite:
2108       reduction = ReduceNumberIsFinite(node);
2109       break;
2110     case kNumberIsInteger:
2111       reduction = ReduceNumberIsInteger(node);
2112       break;
2113     case kNumberIsNaN:
2114       reduction = ReduceNumberIsNaN(node);
2115       break;
2116     case kNumberIsSafeInteger:
2117       reduction = ReduceNumberIsSafeInteger(node);
2118       break;
2119     case kNumberParseInt:
2120       reduction = ReduceNumberParseInt(node);
2121       break;
2122     case kObjectCreate:
2123       reduction = ReduceObjectCreate(node);
2124       break;
2125     case kStringFromCharCode:
2126       reduction = ReduceStringFromCharCode(node);
2127       break;
2128     case kStringCharAt:
2129       return ReduceStringCharAt(node);
2130     case kStringCharCodeAt:
2131       return ReduceStringCharCodeAt(node);
2132     case kStringIndexOf:
2133       return ReduceStringIndexOf(node);
2134     case kStringIterator:
2135       return ReduceStringIterator(node);
2136     case kStringIteratorNext:
2137       return ReduceStringIteratorNext(node);
2138     case kDataViewByteLength:
2139       return ReduceArrayBufferViewAccessor(
2140           node, JS_DATA_VIEW_TYPE,
2141           AccessBuilder::ForJSArrayBufferViewByteLength());
2142     case kDataViewByteOffset:
2143       return ReduceArrayBufferViewAccessor(
2144           node, JS_DATA_VIEW_TYPE,
2145           AccessBuilder::ForJSArrayBufferViewByteOffset());
2146     case kTypedArrayByteLength:
2147       return ReduceArrayBufferViewAccessor(
2148           node, JS_TYPED_ARRAY_TYPE,
2149           AccessBuilder::ForJSArrayBufferViewByteLength());
2150     case kTypedArrayByteOffset:
2151       return ReduceArrayBufferViewAccessor(
2152           node, JS_TYPED_ARRAY_TYPE,
2153           AccessBuilder::ForJSArrayBufferViewByteOffset());
2154     case kTypedArrayLength:
2155       return ReduceArrayBufferViewAccessor(
2156           node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
2157     case kTypedArrayEntries:
2158       return ReduceTypedArrayIterator(node, IterationKind::kEntries);
2159     case kTypedArrayKeys:
2160       return ReduceTypedArrayIterator(node, IterationKind::kKeys);
2161     case kTypedArrayValues:
2162       return ReduceTypedArrayIterator(node, IterationKind::kValues);
2163     default:
2164       break;
2165   }
2166 
2167   // Replace builtin call assuming replacement nodes are pure values that don't
2168   // produce an effect. Replaces {node} with {reduction} and relaxes effects.
2169   if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement());
2170 
2171   return reduction;
2172 }
2173 
ToNumber(Node * input)2174 Node* JSBuiltinReducer::ToNumber(Node* input) {
2175   Type* input_type = NodeProperties::GetType(input);
2176   if (input_type->Is(Type::Number())) return input;
2177   return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), input);
2178 }
2179 
ToUint32(Node * input)2180 Node* JSBuiltinReducer::ToUint32(Node* input) {
2181   input = ToNumber(input);
2182   Type* input_type = NodeProperties::GetType(input);
2183   if (input_type->Is(Type::Unsigned32())) return input;
2184   return graph()->NewNode(simplified()->NumberToUint32(), input);
2185 }
2186 
graph() const2187 Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); }
2188 
factory() const2189 Factory* JSBuiltinReducer::factory() const { return isolate()->factory(); }
2190 
isolate() const2191 Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); }
2192 
2193 
common() const2194 CommonOperatorBuilder* JSBuiltinReducer::common() const {
2195   return jsgraph()->common();
2196 }
2197 
2198 
simplified() const2199 SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const {
2200   return jsgraph()->simplified();
2201 }
2202 
javascript() const2203 JSOperatorBuilder* JSBuiltinReducer::javascript() const {
2204   return jsgraph()->javascript();
2205 }
2206 
2207 }  // namespace compiler
2208 }  // namespace internal
2209 }  // namespace v8
2210