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