js-builtin-reducer.cc revision f91f0611dbaf29ca0f1d4aecb357ce243a19d2fa
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/objects-inl.h"
14#include "src/type-cache.h"
15#include "src/types.h"
16
17namespace v8 {
18namespace internal {
19namespace 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.
24class JSCallReduction {
25 public:
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.
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.
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
46  bool ReceiverMatches(Type* type) {
47    return NodeProperties::GetType(receiver())->Is(type);
48  }
49
50  // Determines whether the call takes zero inputs.
51  bool InputsMatchZero() { return GetJSCallArity() == 0; }
52
53  // Determines whether the call takes one input of the given type.
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.
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.
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
76  Node* receiver() { return NodeProperties::GetValueInput(node_, 1); }
77  Node* left() { return GetJSCallInput(0); }
78  Node* right() { return GetJSCallInput(1); }
79
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
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
97JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph,
98                                   Flags flags,
99                                   CompilationDependencies* dependencies)
100    : AdvancedReducer(editor),
101      dependencies_(dependencies),
102      flags_(flags),
103      jsgraph_(jsgraph),
104      type_cache_(TypeCache::Get()) {}
105
106namespace {
107
108MaybeHandle<Map> GetMapWitness(Node* node) {
109  Node* receiver = NodeProperties::GetValueInput(node, 1);
110  Node* effect = NodeProperties::GetEffectInput(node);
111  // Check if the {node} is dominated by a CheckMaps with a single map
112  // for the {receiver}, and if so use that map for the lowering below.
113  for (Node* dominator = effect;;) {
114    if (dominator->opcode() == IrOpcode::kCheckMaps &&
115        dominator->InputAt(0) == receiver) {
116      if (dominator->op()->ValueInputCount() == 2) {
117        HeapObjectMatcher m(dominator->InputAt(1));
118        if (m.HasValue()) return Handle<Map>::cast(m.Value());
119      }
120      return MaybeHandle<Map>();
121    }
122    if (dominator->op()->EffectInputCount() != 1) {
123      // Didn't find any appropriate CheckMaps node.
124      return MaybeHandle<Map>();
125    }
126    dominator = NodeProperties::GetEffectInput(dominator);
127  }
128}
129
130// TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
131bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
132  DCHECK(!jsarray_map->is_dictionary_map());
133  Isolate* isolate = jsarray_map->GetIsolate();
134  Handle<Name> length_string = isolate->factory()->length_string();
135  DescriptorArray* descriptors = jsarray_map->instance_descriptors();
136  int number =
137      descriptors->SearchWithCache(isolate, *length_string, *jsarray_map);
138  DCHECK_NE(DescriptorArray::kNotFound, number);
139  return descriptors->GetDetails(number).IsReadOnly();
140}
141
142// TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
143bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) {
144  Isolate* const isolate = receiver_map->GetIsolate();
145  if (!receiver_map->prototype()->IsJSArray()) return false;
146  Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
147                                     isolate);
148  // Ensure that all prototypes of the {receiver} are stable.
149  for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver);
150       !it.IsAtEnd(); it.Advance()) {
151    Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it);
152    if (!current->map()->is_stable()) return false;
153  }
154  return receiver_map->instance_type() == JS_ARRAY_TYPE &&
155         IsFastElementsKind(receiver_map->elements_kind()) &&
156         !receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
157         (!receiver_map->is_prototype_map() || receiver_map->is_stable()) &&
158         isolate->IsFastArrayConstructorPrototypeChainIntact() &&
159         isolate->IsAnyInitialArrayPrototype(receiver_prototype) &&
160         !IsReadOnlyLengthDescriptor(receiver_map);
161}
162
163}  // namespace
164
165// ES6 section 22.1.3.17 Array.prototype.pop ( )
166Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) {
167  Handle<Map> receiver_map;
168  Node* receiver = NodeProperties::GetValueInput(node, 1);
169  Node* effect = NodeProperties::GetEffectInput(node);
170  Node* control = NodeProperties::GetControlInput(node);
171  // TODO(turbofan): Extend this to also handle fast (holey) double elements
172  // once we got the hole NaN mess sorted out in TurboFan/V8.
173  if (GetMapWitness(node).ToHandle(&receiver_map) &&
174      CanInlineArrayResizeOperation(receiver_map) &&
175      IsFastSmiOrObjectElementsKind(receiver_map->elements_kind())) {
176    // Install code dependencies on the {receiver} prototype maps and the
177    // global array protector cell.
178    dependencies()->AssumePropertyCell(factory()->array_protector());
179    dependencies()->AssumePrototypeMapsStable(receiver_map);
180
181    // Load the "length" property of the {receiver}.
182    Node* length = effect = graph()->NewNode(
183        simplified()->LoadField(
184            AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
185        receiver, effect, control);
186
187    // Check if the {receiver} has any elements.
188    Node* check = graph()->NewNode(simplified()->NumberEqual(), length,
189                                   jsgraph()->ZeroConstant());
190    Node* branch =
191        graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
192
193    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
194    Node* etrue = effect;
195    Node* vtrue = jsgraph()->UndefinedConstant();
196
197    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
198    Node* efalse = effect;
199    Node* vfalse;
200    {
201      // Load the elements backing store from the {receiver}.
202      Node* elements = efalse = graph()->NewNode(
203          simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
204          receiver, efalse, if_false);
205
206      // Ensure that we aren't popping from a copy-on-write backing store.
207      elements = efalse =
208          graph()->NewNode(simplified()->EnsureWritableFastElements(), receiver,
209                           elements, efalse, if_false);
210
211      // Compute the new {length}.
212      length = graph()->NewNode(simplified()->NumberSubtract(), length,
213                                jsgraph()->OneConstant());
214
215      // Store the new {length} to the {receiver}.
216      efalse = graph()->NewNode(
217          simplified()->StoreField(
218              AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
219          receiver, length, efalse, if_false);
220
221      // Load the last entry from the {elements}.
222      vfalse = efalse = graph()->NewNode(
223          simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(
224              receiver_map->elements_kind())),
225          elements, length, efalse, if_false);
226
227      // Store a hole to the element we just removed from the {receiver}.
228      efalse = graph()->NewNode(
229          simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
230              GetHoleyElementsKind(receiver_map->elements_kind()))),
231          elements, length, jsgraph()->TheHoleConstant(), efalse, if_false);
232    }
233
234    control = graph()->NewNode(common()->Merge(2), if_true, if_false);
235    effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
236    Node* value =
237        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
238                         vtrue, vfalse, control);
239
240    // Convert the hole to undefined. Do this last, so that we can optimize
241    // conversion operator via some smart strength reduction in many cases.
242    if (IsFastHoleyElementsKind(receiver_map->elements_kind())) {
243      value =
244          graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
245    }
246
247    ReplaceWithValue(node, value, effect, control);
248    return Replace(value);
249  }
250  return NoChange();
251}
252
253// ES6 section 22.1.3.18 Array.prototype.push ( )
254Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) {
255  Handle<Map> receiver_map;
256  // We need exactly target, receiver and value parameters.
257  if (node->op()->ValueInputCount() != 3) return NoChange();
258  Node* receiver = NodeProperties::GetValueInput(node, 1);
259  Node* effect = NodeProperties::GetEffectInput(node);
260  Node* control = NodeProperties::GetControlInput(node);
261  Node* value = NodeProperties::GetValueInput(node, 2);
262  if (GetMapWitness(node).ToHandle(&receiver_map) &&
263      CanInlineArrayResizeOperation(receiver_map)) {
264    // Install code dependencies on the {receiver} prototype maps and the
265    // global array protector cell.
266    dependencies()->AssumePropertyCell(factory()->array_protector());
267    dependencies()->AssumePrototypeMapsStable(receiver_map);
268
269    // TODO(turbofan): Perform type checks on the {value}. We are not guaranteed
270    // to learn from these checks in case they fail, as the witness (i.e. the
271    // map check from the LoadIC for a.push) might not be executed in baseline
272    // code (after we stored the value in the builtin and thereby changed the
273    // elements kind of a) before be decide to optimize this function again. We
274    // currently don't have a proper way to deal with this; the proper solution
275    // here is to learn on deopt, i.e. disable Array.prototype.push inlining
276    // for this function.
277    if (IsFastSmiElementsKind(receiver_map->elements_kind())) {
278      value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(),
279                                        value, effect, control);
280    } else if (IsFastDoubleElementsKind(receiver_map->elements_kind())) {
281      value = effect =
282          graph()->NewNode(simplified()->CheckNumber(), value, effect, control);
283      // Make sure we do not store signaling NaNs into double arrays.
284      value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
285    }
286
287    // Load the "length" property of the {receiver}.
288    Node* length = effect = graph()->NewNode(
289        simplified()->LoadField(
290            AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())),
291        receiver, effect, control);
292
293    // Load the elements backing store of the {receiver}.
294    Node* elements = effect = graph()->NewNode(
295        simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
296        effect, control);
297
298    // TODO(turbofan): Check if we need to grow the {elements} backing store.
299    // This will deopt if we cannot grow the array further, and we currently
300    // don't necessarily learn from it. See the comment on the value type check
301    // above.
302    GrowFastElementsFlags flags = GrowFastElementsFlag::kArrayObject;
303    if (IsFastDoubleElementsKind(receiver_map->elements_kind())) {
304      flags |= GrowFastElementsFlag::kDoubleElements;
305    }
306    elements = effect =
307        graph()->NewNode(simplified()->MaybeGrowFastElements(flags), receiver,
308                         elements, length, length, effect, control);
309
310    // Append the value to the {elements}.
311    effect = graph()->NewNode(
312        simplified()->StoreElement(
313            AccessBuilder::ForFixedArrayElement(receiver_map->elements_kind())),
314        elements, length, value, effect, control);
315
316    // Return the new length of the {receiver}.
317    value = graph()->NewNode(simplified()->NumberAdd(), length,
318                             jsgraph()->OneConstant());
319
320    ReplaceWithValue(node, value, effect, control);
321    return Replace(value);
322  }
323  return NoChange();
324}
325
326// ES6 section 20.2.2.1 Math.abs ( x )
327Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) {
328  JSCallReduction r(node);
329  if (r.InputsMatchOne(Type::PlainPrimitive())) {
330    // Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a))
331    Node* input = ToNumber(r.GetJSCallInput(0));
332    Node* value = graph()->NewNode(simplified()->NumberAbs(), input);
333    return Replace(value);
334  }
335  return NoChange();
336}
337
338// ES6 section 20.2.2.2 Math.acos ( x )
339Reduction JSBuiltinReducer::ReduceMathAcos(Node* node) {
340  JSCallReduction r(node);
341  if (r.InputsMatchOne(Type::PlainPrimitive())) {
342    // Math.acos(a:plain-primitive) -> NumberAcos(ToNumber(a))
343    Node* input = ToNumber(r.GetJSCallInput(0));
344    Node* value = graph()->NewNode(simplified()->NumberAcos(), input);
345    return Replace(value);
346  }
347  return NoChange();
348}
349
350// ES6 section 20.2.2.3 Math.acosh ( x )
351Reduction JSBuiltinReducer::ReduceMathAcosh(Node* node) {
352  JSCallReduction r(node);
353  if (r.InputsMatchOne(Type::PlainPrimitive())) {
354    // Math.acosh(a:plain-primitive) -> NumberAcosh(ToNumber(a))
355    Node* input = ToNumber(r.GetJSCallInput(0));
356    Node* value = graph()->NewNode(simplified()->NumberAcosh(), input);
357    return Replace(value);
358  }
359  return NoChange();
360}
361
362// ES6 section 20.2.2.4 Math.asin ( x )
363Reduction JSBuiltinReducer::ReduceMathAsin(Node* node) {
364  JSCallReduction r(node);
365  if (r.InputsMatchOne(Type::PlainPrimitive())) {
366    // Math.asin(a:plain-primitive) -> NumberAsin(ToNumber(a))
367    Node* input = ToNumber(r.GetJSCallInput(0));
368    Node* value = graph()->NewNode(simplified()->NumberAsin(), input);
369    return Replace(value);
370  }
371  return NoChange();
372}
373
374// ES6 section 20.2.2.5 Math.asinh ( x )
375Reduction JSBuiltinReducer::ReduceMathAsinh(Node* node) {
376  JSCallReduction r(node);
377  if (r.InputsMatchOne(Type::PlainPrimitive())) {
378    // Math.asinh(a:plain-primitive) -> NumberAsinh(ToNumber(a))
379    Node* input = ToNumber(r.GetJSCallInput(0));
380    Node* value = graph()->NewNode(simplified()->NumberAsinh(), input);
381    return Replace(value);
382  }
383  return NoChange();
384}
385
386// ES6 section 20.2.2.6 Math.atan ( x )
387Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) {
388  JSCallReduction r(node);
389  if (r.InputsMatchOne(Type::PlainPrimitive())) {
390    // Math.atan(a:plain-primitive) -> NumberAtan(ToNumber(a))
391    Node* input = ToNumber(r.GetJSCallInput(0));
392    Node* value = graph()->NewNode(simplified()->NumberAtan(), input);
393    return Replace(value);
394  }
395  return NoChange();
396}
397
398// ES6 section 20.2.2.7 Math.atanh ( x )
399Reduction JSBuiltinReducer::ReduceMathAtanh(Node* node) {
400  JSCallReduction r(node);
401  if (r.InputsMatchOne(Type::PlainPrimitive())) {
402    // Math.atanh(a:plain-primitive) -> NumberAtanh(ToNumber(a))
403    Node* input = ToNumber(r.GetJSCallInput(0));
404    Node* value = graph()->NewNode(simplified()->NumberAtanh(), input);
405    return Replace(value);
406  }
407  return NoChange();
408}
409
410// ES6 section 20.2.2.8 Math.atan2 ( y, x )
411Reduction JSBuiltinReducer::ReduceMathAtan2(Node* node) {
412  JSCallReduction r(node);
413  if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
414    // Math.atan2(a:plain-primitive,
415    //            b:plain-primitive) -> NumberAtan2(ToNumber(a),
416    //                                              ToNumber(b))
417    Node* left = ToNumber(r.left());
418    Node* right = ToNumber(r.right());
419    Node* value = graph()->NewNode(simplified()->NumberAtan2(), left, right);
420    return Replace(value);
421  }
422  return NoChange();
423}
424
425// ES6 section 20.2.2.10 Math.ceil ( x )
426Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) {
427  JSCallReduction r(node);
428  if (r.InputsMatchOne(Type::PlainPrimitive())) {
429    // Math.ceil(a:plain-primitive) -> NumberCeil(ToNumber(a))
430    Node* input = ToNumber(r.GetJSCallInput(0));
431    Node* value = graph()->NewNode(simplified()->NumberCeil(), input);
432    return Replace(value);
433  }
434  return NoChange();
435}
436
437// ES6 section 20.2.2.11 Math.clz32 ( x )
438Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) {
439  JSCallReduction r(node);
440  if (r.InputsMatchOne(Type::PlainPrimitive())) {
441    // Math.clz32(a:plain-primitive) -> NumberClz32(ToUint32(a))
442    Node* input = ToUint32(r.GetJSCallInput(0));
443    Node* value = graph()->NewNode(simplified()->NumberClz32(), input);
444    return Replace(value);
445  }
446  return NoChange();
447}
448
449// ES6 section 20.2.2.12 Math.cos ( x )
450Reduction JSBuiltinReducer::ReduceMathCos(Node* node) {
451  JSCallReduction r(node);
452  if (r.InputsMatchOne(Type::PlainPrimitive())) {
453    // Math.cos(a:plain-primitive) -> NumberCos(ToNumber(a))
454    Node* input = ToNumber(r.GetJSCallInput(0));
455    Node* value = graph()->NewNode(simplified()->NumberCos(), input);
456    return Replace(value);
457  }
458  return NoChange();
459}
460
461// ES6 section 20.2.2.13 Math.cosh ( x )
462Reduction JSBuiltinReducer::ReduceMathCosh(Node* node) {
463  JSCallReduction r(node);
464  if (r.InputsMatchOne(Type::PlainPrimitive())) {
465    // Math.cosh(a:plain-primitive) -> NumberCosh(ToNumber(a))
466    Node* input = ToNumber(r.GetJSCallInput(0));
467    Node* value = graph()->NewNode(simplified()->NumberCosh(), input);
468    return Replace(value);
469  }
470  return NoChange();
471}
472
473// ES6 section 20.2.2.14 Math.exp ( x )
474Reduction JSBuiltinReducer::ReduceMathExp(Node* node) {
475  JSCallReduction r(node);
476  if (r.InputsMatchOne(Type::PlainPrimitive())) {
477    // Math.exp(a:plain-primitive) -> NumberExp(ToNumber(a))
478    Node* input = ToNumber(r.GetJSCallInput(0));
479    Node* value = graph()->NewNode(simplified()->NumberExp(), input);
480    return Replace(value);
481  }
482  return NoChange();
483}
484
485// ES6 section 20.2.2.15 Math.expm1 ( x )
486Reduction JSBuiltinReducer::ReduceMathExpm1(Node* node) {
487  JSCallReduction r(node);
488  if (r.InputsMatchOne(Type::Number())) {
489    // Math.expm1(a:number) -> NumberExpm1(a)
490    Node* value = graph()->NewNode(simplified()->NumberExpm1(), r.left());
491    return Replace(value);
492  }
493  return NoChange();
494}
495
496// ES6 section 20.2.2.16 Math.floor ( x )
497Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) {
498  JSCallReduction r(node);
499  if (r.InputsMatchOne(Type::PlainPrimitive())) {
500    // Math.floor(a:plain-primitive) -> NumberFloor(ToNumber(a))
501    Node* input = ToNumber(r.GetJSCallInput(0));
502    Node* value = graph()->NewNode(simplified()->NumberFloor(), input);
503    return Replace(value);
504  }
505  return NoChange();
506}
507
508// ES6 section 20.2.2.17 Math.fround ( x )
509Reduction JSBuiltinReducer::ReduceMathFround(Node* node) {
510  JSCallReduction r(node);
511  if (r.InputsMatchOne(Type::PlainPrimitive())) {
512    // Math.fround(a:plain-primitive) -> NumberFround(ToNumber(a))
513    Node* input = ToNumber(r.GetJSCallInput(0));
514    Node* value = graph()->NewNode(simplified()->NumberFround(), input);
515    return Replace(value);
516  }
517  return NoChange();
518}
519
520// ES6 section 20.2.2.19 Math.imul ( x, y )
521Reduction JSBuiltinReducer::ReduceMathImul(Node* node) {
522  JSCallReduction r(node);
523  if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
524    // Math.imul(a:plain-primitive,
525    //           b:plain-primitive) -> NumberImul(ToUint32(a),
526    //                                            ToUint32(b))
527    Node* left = ToUint32(r.left());
528    Node* right = ToUint32(r.right());
529    Node* value = graph()->NewNode(simplified()->NumberImul(), left, right);
530    return Replace(value);
531  }
532  return NoChange();
533}
534
535// ES6 section 20.2.2.20 Math.log ( x )
536Reduction JSBuiltinReducer::ReduceMathLog(Node* node) {
537  JSCallReduction r(node);
538  if (r.InputsMatchOne(Type::PlainPrimitive())) {
539    // Math.log(a:plain-primitive) -> NumberLog(ToNumber(a))
540    Node* input = ToNumber(r.GetJSCallInput(0));
541    Node* value = graph()->NewNode(simplified()->NumberLog(), input);
542    return Replace(value);
543  }
544  return NoChange();
545}
546
547// ES6 section 20.2.2.21 Math.log1p ( x )
548Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) {
549  JSCallReduction r(node);
550  if (r.InputsMatchOne(Type::PlainPrimitive())) {
551    // Math.log1p(a:plain-primitive) -> NumberLog1p(ToNumber(a))
552    Node* input = ToNumber(r.GetJSCallInput(0));
553    Node* value = graph()->NewNode(simplified()->NumberLog1p(), input);
554    return Replace(value);
555  }
556  return NoChange();
557}
558
559// ES6 section 20.2.2.22 Math.log10 ( x )
560Reduction JSBuiltinReducer::ReduceMathLog10(Node* node) {
561  JSCallReduction r(node);
562  if (r.InputsMatchOne(Type::Number())) {
563    // Math.log10(a:number) -> NumberLog10(a)
564    Node* value = graph()->NewNode(simplified()->NumberLog10(), r.left());
565    return Replace(value);
566  }
567  return NoChange();
568}
569
570// ES6 section 20.2.2.23 Math.log2 ( x )
571Reduction JSBuiltinReducer::ReduceMathLog2(Node* node) {
572  JSCallReduction r(node);
573  if (r.InputsMatchOne(Type::Number())) {
574    // Math.log2(a:number) -> NumberLog(a)
575    Node* value = graph()->NewNode(simplified()->NumberLog2(), r.left());
576    return Replace(value);
577  }
578  return NoChange();
579}
580
581// ES6 section 20.2.2.24 Math.max ( value1, value2, ...values )
582Reduction JSBuiltinReducer::ReduceMathMax(Node* node) {
583  JSCallReduction r(node);
584  if (r.InputsMatchZero()) {
585    // Math.max() -> -Infinity
586    return Replace(jsgraph()->Constant(-V8_INFINITY));
587  }
588  if (r.InputsMatchAll(Type::PlainPrimitive())) {
589    // Math.max(a:plain-primitive, b:plain-primitive, ...)
590    Node* value = ToNumber(r.GetJSCallInput(0));
591    for (int i = 1; i < r.GetJSCallArity(); i++) {
592      Node* input = ToNumber(r.GetJSCallInput(i));
593      value = graph()->NewNode(simplified()->NumberMax(), value, input);
594    }
595    return Replace(value);
596  }
597  return NoChange();
598}
599
600// ES6 section 20.2.2.25 Math.min ( value1, value2, ...values )
601Reduction JSBuiltinReducer::ReduceMathMin(Node* node) {
602  JSCallReduction r(node);
603  if (r.InputsMatchZero()) {
604    // Math.min() -> Infinity
605    return Replace(jsgraph()->Constant(V8_INFINITY));
606  }
607  if (r.InputsMatchAll(Type::PlainPrimitive())) {
608    // Math.min(a:plain-primitive, b:plain-primitive, ...)
609    Node* value = ToNumber(r.GetJSCallInput(0));
610    for (int i = 1; i < r.GetJSCallArity(); i++) {
611      Node* input = ToNumber(r.GetJSCallInput(i));
612      value = graph()->NewNode(simplified()->NumberMin(), value, input);
613    }
614    return Replace(value);
615  }
616  return NoChange();
617}
618
619// ES6 section 20.2.2.26 Math.pow ( x, y )
620Reduction JSBuiltinReducer::ReduceMathPow(Node* node) {
621  JSCallReduction r(node);
622  if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
623    // Math.pow(a:plain-primitive,
624    //          b:plain-primitive) -> NumberPow(ToNumber(a), ToNumber(b))
625    Node* left = ToNumber(r.left());
626    Node* right = ToNumber(r.right());
627    Node* value = graph()->NewNode(simplified()->NumberPow(), left, right);
628    return Replace(value);
629  }
630  return NoChange();
631}
632
633// ES6 section 20.2.2.28 Math.round ( x )
634Reduction JSBuiltinReducer::ReduceMathRound(Node* node) {
635  JSCallReduction r(node);
636  if (r.InputsMatchOne(Type::PlainPrimitive())) {
637    // Math.round(a:plain-primitive) -> NumberRound(ToNumber(a))
638    Node* input = ToNumber(r.GetJSCallInput(0));
639    Node* value = graph()->NewNode(simplified()->NumberRound(), input);
640    return Replace(value);
641  }
642  return NoChange();
643}
644
645// ES6 section 20.2.2.9 Math.cbrt ( x )
646Reduction JSBuiltinReducer::ReduceMathCbrt(Node* node) {
647  JSCallReduction r(node);
648  if (r.InputsMatchOne(Type::Number())) {
649    // Math.cbrt(a:number) -> NumberCbrt(a)
650    Node* value = graph()->NewNode(simplified()->NumberCbrt(), r.left());
651    return Replace(value);
652  }
653  return NoChange();
654}
655
656// ES6 section 20.2.2.29 Math.sign ( x )
657Reduction JSBuiltinReducer::ReduceMathSign(Node* node) {
658  JSCallReduction r(node);
659  if (r.InputsMatchOne(Type::PlainPrimitive())) {
660    // Math.sign(a:plain-primitive) -> NumberSign(ToNumber(a))
661    Node* input = ToNumber(r.GetJSCallInput(0));
662    Node* value = graph()->NewNode(simplified()->NumberSign(), input);
663    return Replace(value);
664  }
665  return NoChange();
666}
667
668// ES6 section 20.2.2.30 Math.sin ( x )
669Reduction JSBuiltinReducer::ReduceMathSin(Node* node) {
670  JSCallReduction r(node);
671  if (r.InputsMatchOne(Type::PlainPrimitive())) {
672    // Math.sin(a:plain-primitive) -> NumberSin(ToNumber(a))
673    Node* input = ToNumber(r.GetJSCallInput(0));
674    Node* value = graph()->NewNode(simplified()->NumberSin(), input);
675    return Replace(value);
676  }
677  return NoChange();
678}
679
680// ES6 section 20.2.2.31 Math.sinh ( x )
681Reduction JSBuiltinReducer::ReduceMathSinh(Node* node) {
682  JSCallReduction r(node);
683  if (r.InputsMatchOne(Type::PlainPrimitive())) {
684    // Math.sinh(a:plain-primitive) -> NumberSinh(ToNumber(a))
685    Node* input = ToNumber(r.GetJSCallInput(0));
686    Node* value = graph()->NewNode(simplified()->NumberSinh(), input);
687    return Replace(value);
688  }
689  return NoChange();
690}
691
692// ES6 section 20.2.2.32 Math.sqrt ( x )
693Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) {
694  JSCallReduction r(node);
695  if (r.InputsMatchOne(Type::PlainPrimitive())) {
696    // Math.sqrt(a:plain-primitive) -> NumberSqrt(ToNumber(a))
697    Node* input = ToNumber(r.GetJSCallInput(0));
698    Node* value = graph()->NewNode(simplified()->NumberSqrt(), input);
699    return Replace(value);
700  }
701  return NoChange();
702}
703
704// ES6 section 20.2.2.33 Math.tan ( x )
705Reduction JSBuiltinReducer::ReduceMathTan(Node* node) {
706  JSCallReduction r(node);
707  if (r.InputsMatchOne(Type::PlainPrimitive())) {
708    // Math.tan(a:plain-primitive) -> NumberTan(ToNumber(a))
709    Node* input = ToNumber(r.GetJSCallInput(0));
710    Node* value = graph()->NewNode(simplified()->NumberTan(), input);
711    return Replace(value);
712  }
713  return NoChange();
714}
715
716// ES6 section 20.2.2.34 Math.tanh ( x )
717Reduction JSBuiltinReducer::ReduceMathTanh(Node* node) {
718  JSCallReduction r(node);
719  if (r.InputsMatchOne(Type::PlainPrimitive())) {
720    // Math.tanh(a:plain-primitive) -> NumberTanh(ToNumber(a))
721    Node* input = ToNumber(r.GetJSCallInput(0));
722    Node* value = graph()->NewNode(simplified()->NumberTanh(), input);
723    return Replace(value);
724  }
725  return NoChange();
726}
727
728// ES6 section 20.2.2.35 Math.trunc ( x )
729Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) {
730  JSCallReduction r(node);
731  if (r.InputsMatchOne(Type::PlainPrimitive())) {
732    // Math.trunc(a:plain-primitive) -> NumberTrunc(ToNumber(a))
733    Node* input = ToNumber(r.GetJSCallInput(0));
734    Node* value = graph()->NewNode(simplified()->NumberTrunc(), input);
735    return Replace(value);
736  }
737  return NoChange();
738}
739
740// ES6 section 20.1.2.13 Number.parseInt ( string, radix )
741Reduction JSBuiltinReducer::ReduceNumberParseInt(Node* node) {
742  JSCallReduction r(node);
743  if (r.InputsMatchOne(type_cache_.kSafeInteger) ||
744      r.InputsMatchTwo(type_cache_.kSafeInteger,
745                       type_cache_.kZeroOrUndefined) ||
746      r.InputsMatchTwo(type_cache_.kSafeInteger, type_cache_.kTenOrUndefined)) {
747    // Number.parseInt(a:safe-integer) -> NumberToInt32(a)
748    // Number.parseInt(a:safe-integer,b:#0\/undefined) -> NumberToInt32(a)
749    // Number.parseInt(a:safe-integer,b:#10\/undefined) -> NumberToInt32(a)
750    Node* input = r.GetJSCallInput(0);
751    Node* value = graph()->NewNode(simplified()->NumberToInt32(), input);
752    return Replace(value);
753  }
754  return NoChange();
755}
756
757// ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits )
758Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) {
759  JSCallReduction r(node);
760  if (r.InputsMatchOne(Type::PlainPrimitive())) {
761    // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a)
762    Node* input = ToNumber(r.GetJSCallInput(0));
763    Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input);
764    return Replace(value);
765  }
766  return NoChange();
767}
768
769namespace {
770
771Node* GetStringWitness(Node* node) {
772  Node* receiver = NodeProperties::GetValueInput(node, 1);
773  Type* receiver_type = NodeProperties::GetType(receiver);
774  Node* effect = NodeProperties::GetEffectInput(node);
775  if (receiver_type->Is(Type::String())) return receiver;
776  // Check if the {node} is dominated by a CheckString renaming for
777  // it's {receiver}, and if so use that renaming as {receiver} for
778  // the lowering below.
779  for (Node* dominator = effect;;) {
780    if (dominator->opcode() == IrOpcode::kCheckString &&
781        dominator->InputAt(0) == receiver) {
782      return dominator;
783    }
784    if (dominator->op()->EffectInputCount() != 1) {
785      // Didn't find any appropriate CheckString node.
786      return nullptr;
787    }
788    dominator = NodeProperties::GetEffectInput(dominator);
789  }
790}
791
792}  // namespace
793
794// ES6 section 21.1.3.1 String.prototype.charAt ( pos )
795Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) {
796  // We need at least target, receiver and index parameters.
797  if (node->op()->ValueInputCount() >= 3) {
798    Node* index = NodeProperties::GetValueInput(node, 2);
799    Type* index_type = NodeProperties::GetType(index);
800    Node* effect = NodeProperties::GetEffectInput(node);
801    Node* control = NodeProperties::GetControlInput(node);
802
803    if (index_type->Is(Type::Unsigned32())) {
804      if (Node* receiver = GetStringWitness(node)) {
805        // Determine the {receiver} length.
806        Node* receiver_length = effect = graph()->NewNode(
807            simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
808            effect, control);
809
810        // Check if {index} is less than {receiver} length.
811        Node* check = graph()->NewNode(simplified()->NumberLessThan(), index,
812                                       receiver_length);
813        Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
814                                        check, control);
815
816        Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
817        Node* vtrue;
818        {
819          // Load the character from the {receiver}.
820          vtrue = graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
821                                   index, if_true);
822
823          // Return it as single character string.
824          vtrue = graph()->NewNode(simplified()->StringFromCharCode(), vtrue);
825        }
826
827        // Return the empty string otherwise.
828        Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
829        Node* vfalse = jsgraph()->EmptyStringConstant();
830
831        control = graph()->NewNode(common()->Merge(2), if_true, if_false);
832        Node* value =
833            graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
834                             vtrue, vfalse, control);
835
836        ReplaceWithValue(node, value, effect, control);
837        return Replace(value);
838      }
839    }
840  }
841
842  return NoChange();
843}
844
845// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
846Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) {
847  // We need at least target, receiver and index parameters.
848  if (node->op()->ValueInputCount() >= 3) {
849    Node* index = NodeProperties::GetValueInput(node, 2);
850    Type* index_type = NodeProperties::GetType(index);
851    Node* effect = NodeProperties::GetEffectInput(node);
852    Node* control = NodeProperties::GetControlInput(node);
853
854    if (index_type->Is(Type::Unsigned32())) {
855      if (Node* receiver = GetStringWitness(node)) {
856        // Determine the {receiver} length.
857        Node* receiver_length = effect = graph()->NewNode(
858            simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
859            effect, control);
860
861        // Check if {index} is less than {receiver} length.
862        Node* check = graph()->NewNode(simplified()->NumberLessThan(), index,
863                                       receiver_length);
864        Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
865                                        check, control);
866
867        // Load the character from the {receiver}.
868        Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
869        Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(),
870                                       receiver, index, if_true);
871
872        // Return NaN otherwise.
873        Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
874        Node* vfalse = jsgraph()->NaNConstant();
875
876        control = graph()->NewNode(common()->Merge(2), if_true, if_false);
877        Node* value =
878            graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
879                             vtrue, vfalse, control);
880
881        ReplaceWithValue(node, value, effect, control);
882        return Replace(value);
883      }
884    }
885  }
886
887  return NoChange();
888}
889
890namespace {
891
892bool HasInstanceTypeWitness(Node* receiver, Node* effect,
893                            InstanceType instance_type) {
894  for (Node* dominator = effect;;) {
895    if (dominator->opcode() == IrOpcode::kCheckMaps &&
896        dominator->InputAt(0) == receiver) {
897      // Check if all maps have the given {instance_type}.
898      for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) {
899        Node* const map = NodeProperties::GetValueInput(dominator, i);
900        Type* const map_type = NodeProperties::GetType(map);
901        if (!map_type->IsConstant()) return false;
902        Handle<Map> const map_value =
903            Handle<Map>::cast(map_type->AsConstant()->Value());
904        if (map_value->instance_type() != instance_type) return false;
905      }
906      return true;
907    }
908    switch (dominator->opcode()) {
909      case IrOpcode::kStoreField: {
910        FieldAccess const& access = FieldAccessOf(dominator->op());
911        if (access.base_is_tagged == kTaggedBase &&
912            access.offset == HeapObject::kMapOffset) {
913          return false;
914        }
915        break;
916      }
917      case IrOpcode::kStoreElement:
918        break;
919      default: {
920        DCHECK_EQ(1, dominator->op()->EffectOutputCount());
921        if (dominator->op()->EffectInputCount() != 1 ||
922            !dominator->op()->HasProperty(Operator::kNoWrite)) {
923          // Didn't find any appropriate CheckMaps node.
924          return false;
925        }
926        break;
927      }
928    }
929    dominator = NodeProperties::GetEffectInput(dominator);
930  }
931}
932
933}  // namespace
934
935Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor(
936    Node* node, InstanceType instance_type, FieldAccess const& access) {
937  Node* receiver = NodeProperties::GetValueInput(node, 1);
938  Node* effect = NodeProperties::GetEffectInput(node);
939  Node* control = NodeProperties::GetControlInput(node);
940  if (HasInstanceTypeWitness(receiver, effect, instance_type)) {
941    // Load the {receiver}s field.
942    Node* receiver_length = effect = graph()->NewNode(
943        simplified()->LoadField(access), receiver, effect, control);
944
945    // Check if the {receiver}s buffer was neutered.
946    Node* receiver_buffer = effect = graph()->NewNode(
947        simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
948        receiver, effect, control);
949    Node* receiver_buffer_bitfield = effect = graph()->NewNode(
950        simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
951        receiver_buffer, effect, control);
952    Node* check = graph()->NewNode(
953        simplified()->NumberEqual(),
954        graph()->NewNode(
955            simplified()->NumberBitwiseAnd(), receiver_buffer_bitfield,
956            jsgraph()->Constant(JSArrayBuffer::WasNeutered::kMask)),
957        jsgraph()->ZeroConstant());
958
959    // Default to zero if the {receiver}s buffer was neutered.
960    Node* value = graph()->NewNode(
961        common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
962        check, receiver_length, jsgraph()->ZeroConstant());
963
964    ReplaceWithValue(node, value, effect, control);
965    return Replace(value);
966  }
967  return NoChange();
968}
969
970Reduction JSBuiltinReducer::Reduce(Node* node) {
971  Reduction reduction = NoChange();
972  JSCallReduction r(node);
973
974  // Dispatch according to the BuiltinFunctionId if present.
975  if (!r.HasBuiltinFunctionId()) return NoChange();
976  switch (r.GetBuiltinFunctionId()) {
977    case kArrayPop:
978      return ReduceArrayPop(node);
979    case kArrayPush:
980      return ReduceArrayPush(node);
981    case kMathAbs:
982      reduction = ReduceMathAbs(node);
983      break;
984    case kMathAcos:
985      reduction = ReduceMathAcos(node);
986      break;
987    case kMathAcosh:
988      reduction = ReduceMathAcosh(node);
989      break;
990    case kMathAsin:
991      reduction = ReduceMathAsin(node);
992      break;
993    case kMathAsinh:
994      reduction = ReduceMathAsinh(node);
995      break;
996    case kMathAtan:
997      reduction = ReduceMathAtan(node);
998      break;
999    case kMathAtanh:
1000      reduction = ReduceMathAtanh(node);
1001      break;
1002    case kMathAtan2:
1003      reduction = ReduceMathAtan2(node);
1004      break;
1005    case kMathCbrt:
1006      reduction = ReduceMathCbrt(node);
1007      break;
1008    case kMathCeil:
1009      reduction = ReduceMathCeil(node);
1010      break;
1011    case kMathClz32:
1012      reduction = ReduceMathClz32(node);
1013      break;
1014    case kMathCos:
1015      reduction = ReduceMathCos(node);
1016      break;
1017    case kMathCosh:
1018      reduction = ReduceMathCosh(node);
1019      break;
1020    case kMathExp:
1021      reduction = ReduceMathExp(node);
1022      break;
1023    case kMathExpm1:
1024      reduction = ReduceMathExpm1(node);
1025      break;
1026    case kMathFloor:
1027      reduction = ReduceMathFloor(node);
1028      break;
1029    case kMathFround:
1030      reduction = ReduceMathFround(node);
1031      break;
1032    case kMathImul:
1033      reduction = ReduceMathImul(node);
1034      break;
1035    case kMathLog:
1036      reduction = ReduceMathLog(node);
1037      break;
1038    case kMathLog1p:
1039      reduction = ReduceMathLog1p(node);
1040      break;
1041    case kMathLog10:
1042      reduction = ReduceMathLog10(node);
1043      break;
1044    case kMathLog2:
1045      reduction = ReduceMathLog2(node);
1046      break;
1047    case kMathMax:
1048      reduction = ReduceMathMax(node);
1049      break;
1050    case kMathMin:
1051      reduction = ReduceMathMin(node);
1052      break;
1053    case kMathPow:
1054      reduction = ReduceMathPow(node);
1055      break;
1056    case kMathRound:
1057      reduction = ReduceMathRound(node);
1058      break;
1059    case kMathSign:
1060      reduction = ReduceMathSign(node);
1061      break;
1062    case kMathSin:
1063      reduction = ReduceMathSin(node);
1064      break;
1065    case kMathSinh:
1066      reduction = ReduceMathSinh(node);
1067      break;
1068    case kMathSqrt:
1069      reduction = ReduceMathSqrt(node);
1070      break;
1071    case kMathTan:
1072      reduction = ReduceMathTan(node);
1073      break;
1074    case kMathTanh:
1075      reduction = ReduceMathTanh(node);
1076      break;
1077    case kMathTrunc:
1078      reduction = ReduceMathTrunc(node);
1079      break;
1080    case kNumberParseInt:
1081      reduction = ReduceNumberParseInt(node);
1082      break;
1083    case kStringFromCharCode:
1084      reduction = ReduceStringFromCharCode(node);
1085      break;
1086    case kStringCharAt:
1087      return ReduceStringCharAt(node);
1088    case kStringCharCodeAt:
1089      return ReduceStringCharCodeAt(node);
1090    case kDataViewByteLength:
1091      return ReduceArrayBufferViewAccessor(
1092          node, JS_DATA_VIEW_TYPE,
1093          AccessBuilder::ForJSArrayBufferViewByteLength());
1094    case kDataViewByteOffset:
1095      return ReduceArrayBufferViewAccessor(
1096          node, JS_DATA_VIEW_TYPE,
1097          AccessBuilder::ForJSArrayBufferViewByteOffset());
1098    case kTypedArrayByteLength:
1099      return ReduceArrayBufferViewAccessor(
1100          node, JS_TYPED_ARRAY_TYPE,
1101          AccessBuilder::ForJSArrayBufferViewByteLength());
1102    case kTypedArrayByteOffset:
1103      return ReduceArrayBufferViewAccessor(
1104          node, JS_TYPED_ARRAY_TYPE,
1105          AccessBuilder::ForJSArrayBufferViewByteOffset());
1106    case kTypedArrayLength:
1107      return ReduceArrayBufferViewAccessor(
1108          node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
1109    default:
1110      break;
1111  }
1112
1113  // Replace builtin call assuming replacement nodes are pure values that don't
1114  // produce an effect. Replaces {node} with {reduction} and relaxes effects.
1115  if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement());
1116
1117  return reduction;
1118}
1119
1120Node* JSBuiltinReducer::ToNumber(Node* input) {
1121  Type* input_type = NodeProperties::GetType(input);
1122  if (input_type->Is(Type::Number())) return input;
1123  return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), input);
1124}
1125
1126Node* JSBuiltinReducer::ToUint32(Node* input) {
1127  input = ToNumber(input);
1128  Type* input_type = NodeProperties::GetType(input);
1129  if (input_type->Is(Type::Unsigned32())) return input;
1130  return graph()->NewNode(simplified()->NumberToUint32(), input);
1131}
1132
1133Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); }
1134
1135Factory* JSBuiltinReducer::factory() const { return isolate()->factory(); }
1136
1137Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); }
1138
1139
1140CommonOperatorBuilder* JSBuiltinReducer::common() const {
1141  return jsgraph()->common();
1142}
1143
1144
1145SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const {
1146  return jsgraph()->simplified();
1147}
1148
1149}  // namespace compiler
1150}  // namespace internal
1151}  // namespace v8
1152