js-builtin-reducer.cc revision f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3
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
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 =
279          graph()->NewNode(simplified()->CheckSmi(), 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
326namespace {
327
328bool HasInstanceTypeWitness(Node* receiver, Node* effect,
329                            InstanceType instance_type) {
330  for (Node* dominator = effect;;) {
331    if (dominator->opcode() == IrOpcode::kCheckMaps &&
332        dominator->InputAt(0) == receiver) {
333      // Check if all maps have the given {instance_type}.
334      for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) {
335        Node* const map = NodeProperties::GetValueInput(dominator, i);
336        Type* const map_type = NodeProperties::GetType(map);
337        if (!map_type->IsConstant()) return false;
338        Handle<Map> const map_value =
339            Handle<Map>::cast(map_type->AsConstant()->Value());
340        if (map_value->instance_type() != instance_type) return false;
341      }
342      return true;
343    }
344    switch (dominator->opcode()) {
345      case IrOpcode::kStoreField: {
346        FieldAccess const& access = FieldAccessOf(dominator->op());
347        if (access.base_is_tagged == kTaggedBase &&
348            access.offset == HeapObject::kMapOffset) {
349          return false;
350        }
351        break;
352      }
353      case IrOpcode::kStoreElement:
354      case IrOpcode::kStoreTypedElement:
355        break;
356      default: {
357        DCHECK_EQ(1, dominator->op()->EffectOutputCount());
358        if (dominator->op()->EffectInputCount() != 1 ||
359            !dominator->op()->HasProperty(Operator::kNoWrite)) {
360          // Didn't find any appropriate CheckMaps node.
361          return false;
362        }
363        break;
364      }
365    }
366    dominator = NodeProperties::GetEffectInput(dominator);
367  }
368}
369
370}  // namespace
371
372// ES6 section 20.3.4.10 Date.prototype.getTime ( )
373Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) {
374  Node* receiver = NodeProperties::GetValueInput(node, 1);
375  Node* effect = NodeProperties::GetEffectInput(node);
376  Node* control = NodeProperties::GetControlInput(node);
377  if (HasInstanceTypeWitness(receiver, effect, JS_DATE_TYPE)) {
378    Node* value = effect = graph()->NewNode(
379        simplified()->LoadField(AccessBuilder::ForJSDateValue()), receiver,
380        effect, control);
381    ReplaceWithValue(node, value, effect, control);
382    return Replace(value);
383  }
384  return NoChange();
385}
386
387// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V )
388Reduction JSBuiltinReducer::ReduceFunctionHasInstance(Node* node) {
389  Node* receiver = NodeProperties::GetValueInput(node, 1);
390  Node* object = (node->op()->ValueInputCount() >= 3)
391                     ? NodeProperties::GetValueInput(node, 2)
392                     : jsgraph()->UndefinedConstant();
393  Node* context = NodeProperties::GetContextInput(node);
394  Node* frame_state = NodeProperties::GetFrameStateInput(node);
395  Node* effect = NodeProperties::GetEffectInput(node);
396  Node* control = NodeProperties::GetControlInput(node);
397
398  // TODO(turbofan): If JSOrdinaryToInstance raises an exception, the
399  // stack trace doesn't contain the @@hasInstance call; we have the
400  // corresponding bug in the baseline case. Some massaging of the frame
401  // state would be necessary here.
402
403  // Morph this {node} into a JSOrdinaryHasInstance node.
404  node->ReplaceInput(0, receiver);
405  node->ReplaceInput(1, object);
406  node->ReplaceInput(2, context);
407  node->ReplaceInput(3, frame_state);
408  node->ReplaceInput(4, effect);
409  node->ReplaceInput(5, control);
410  node->TrimInputCount(6);
411  NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
412  return Changed(node);
413}
414
415// ES6 section 18.2.2 isFinite ( number )
416Reduction JSBuiltinReducer::ReduceGlobalIsFinite(Node* node) {
417  JSCallReduction r(node);
418  if (r.InputsMatchOne(Type::PlainPrimitive())) {
419    // isFinite(a:plain-primitive) -> NumberEqual(a', a')
420    // where a' = NumberSubtract(ToNumber(a), ToNumber(a))
421    Node* input = ToNumber(r.GetJSCallInput(0));
422    Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input);
423    Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff);
424    return Replace(value);
425  }
426  return NoChange();
427}
428
429// ES6 section 18.2.3 isNaN ( number )
430Reduction JSBuiltinReducer::ReduceGlobalIsNaN(Node* node) {
431  JSCallReduction r(node);
432  if (r.InputsMatchOne(Type::PlainPrimitive())) {
433    // isNaN(a:plain-primitive) -> BooleanNot(NumberEqual(a', a'))
434    // where a' = ToNumber(a)
435    Node* input = ToNumber(r.GetJSCallInput(0));
436    Node* check = graph()->NewNode(simplified()->NumberEqual(), input, input);
437    Node* value = graph()->NewNode(simplified()->BooleanNot(), check);
438    return Replace(value);
439  }
440  return NoChange();
441}
442
443// ES6 section 20.2.2.1 Math.abs ( x )
444Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) {
445  JSCallReduction r(node);
446  if (r.InputsMatchOne(Type::PlainPrimitive())) {
447    // Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a))
448    Node* input = ToNumber(r.GetJSCallInput(0));
449    Node* value = graph()->NewNode(simplified()->NumberAbs(), input);
450    return Replace(value);
451  }
452  return NoChange();
453}
454
455// ES6 section 20.2.2.2 Math.acos ( x )
456Reduction JSBuiltinReducer::ReduceMathAcos(Node* node) {
457  JSCallReduction r(node);
458  if (r.InputsMatchOne(Type::PlainPrimitive())) {
459    // Math.acos(a:plain-primitive) -> NumberAcos(ToNumber(a))
460    Node* input = ToNumber(r.GetJSCallInput(0));
461    Node* value = graph()->NewNode(simplified()->NumberAcos(), input);
462    return Replace(value);
463  }
464  return NoChange();
465}
466
467// ES6 section 20.2.2.3 Math.acosh ( x )
468Reduction JSBuiltinReducer::ReduceMathAcosh(Node* node) {
469  JSCallReduction r(node);
470  if (r.InputsMatchOne(Type::PlainPrimitive())) {
471    // Math.acosh(a:plain-primitive) -> NumberAcosh(ToNumber(a))
472    Node* input = ToNumber(r.GetJSCallInput(0));
473    Node* value = graph()->NewNode(simplified()->NumberAcosh(), input);
474    return Replace(value);
475  }
476  return NoChange();
477}
478
479// ES6 section 20.2.2.4 Math.asin ( x )
480Reduction JSBuiltinReducer::ReduceMathAsin(Node* node) {
481  JSCallReduction r(node);
482  if (r.InputsMatchOne(Type::PlainPrimitive())) {
483    // Math.asin(a:plain-primitive) -> NumberAsin(ToNumber(a))
484    Node* input = ToNumber(r.GetJSCallInput(0));
485    Node* value = graph()->NewNode(simplified()->NumberAsin(), input);
486    return Replace(value);
487  }
488  return NoChange();
489}
490
491// ES6 section 20.2.2.5 Math.asinh ( x )
492Reduction JSBuiltinReducer::ReduceMathAsinh(Node* node) {
493  JSCallReduction r(node);
494  if (r.InputsMatchOne(Type::PlainPrimitive())) {
495    // Math.asinh(a:plain-primitive) -> NumberAsinh(ToNumber(a))
496    Node* input = ToNumber(r.GetJSCallInput(0));
497    Node* value = graph()->NewNode(simplified()->NumberAsinh(), input);
498    return Replace(value);
499  }
500  return NoChange();
501}
502
503// ES6 section 20.2.2.6 Math.atan ( x )
504Reduction JSBuiltinReducer::ReduceMathAtan(Node* node) {
505  JSCallReduction r(node);
506  if (r.InputsMatchOne(Type::PlainPrimitive())) {
507    // Math.atan(a:plain-primitive) -> NumberAtan(ToNumber(a))
508    Node* input = ToNumber(r.GetJSCallInput(0));
509    Node* value = graph()->NewNode(simplified()->NumberAtan(), input);
510    return Replace(value);
511  }
512  return NoChange();
513}
514
515// ES6 section 20.2.2.7 Math.atanh ( x )
516Reduction JSBuiltinReducer::ReduceMathAtanh(Node* node) {
517  JSCallReduction r(node);
518  if (r.InputsMatchOne(Type::PlainPrimitive())) {
519    // Math.atanh(a:plain-primitive) -> NumberAtanh(ToNumber(a))
520    Node* input = ToNumber(r.GetJSCallInput(0));
521    Node* value = graph()->NewNode(simplified()->NumberAtanh(), input);
522    return Replace(value);
523  }
524  return NoChange();
525}
526
527// ES6 section 20.2.2.8 Math.atan2 ( y, x )
528Reduction JSBuiltinReducer::ReduceMathAtan2(Node* node) {
529  JSCallReduction r(node);
530  if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
531    // Math.atan2(a:plain-primitive,
532    //            b:plain-primitive) -> NumberAtan2(ToNumber(a),
533    //                                              ToNumber(b))
534    Node* left = ToNumber(r.left());
535    Node* right = ToNumber(r.right());
536    Node* value = graph()->NewNode(simplified()->NumberAtan2(), left, right);
537    return Replace(value);
538  }
539  return NoChange();
540}
541
542// ES6 section 20.2.2.10 Math.ceil ( x )
543Reduction JSBuiltinReducer::ReduceMathCeil(Node* node) {
544  JSCallReduction r(node);
545  if (r.InputsMatchOne(Type::PlainPrimitive())) {
546    // Math.ceil(a:plain-primitive) -> NumberCeil(ToNumber(a))
547    Node* input = ToNumber(r.GetJSCallInput(0));
548    Node* value = graph()->NewNode(simplified()->NumberCeil(), input);
549    return Replace(value);
550  }
551  return NoChange();
552}
553
554// ES6 section 20.2.2.11 Math.clz32 ( x )
555Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) {
556  JSCallReduction r(node);
557  if (r.InputsMatchOne(Type::PlainPrimitive())) {
558    // Math.clz32(a:plain-primitive) -> NumberClz32(ToUint32(a))
559    Node* input = ToUint32(r.GetJSCallInput(0));
560    Node* value = graph()->NewNode(simplified()->NumberClz32(), input);
561    return Replace(value);
562  }
563  return NoChange();
564}
565
566// ES6 section 20.2.2.12 Math.cos ( x )
567Reduction JSBuiltinReducer::ReduceMathCos(Node* node) {
568  JSCallReduction r(node);
569  if (r.InputsMatchOne(Type::PlainPrimitive())) {
570    // Math.cos(a:plain-primitive) -> NumberCos(ToNumber(a))
571    Node* input = ToNumber(r.GetJSCallInput(0));
572    Node* value = graph()->NewNode(simplified()->NumberCos(), input);
573    return Replace(value);
574  }
575  return NoChange();
576}
577
578// ES6 section 20.2.2.13 Math.cosh ( x )
579Reduction JSBuiltinReducer::ReduceMathCosh(Node* node) {
580  JSCallReduction r(node);
581  if (r.InputsMatchOne(Type::PlainPrimitive())) {
582    // Math.cosh(a:plain-primitive) -> NumberCosh(ToNumber(a))
583    Node* input = ToNumber(r.GetJSCallInput(0));
584    Node* value = graph()->NewNode(simplified()->NumberCosh(), input);
585    return Replace(value);
586  }
587  return NoChange();
588}
589
590// ES6 section 20.2.2.14 Math.exp ( x )
591Reduction JSBuiltinReducer::ReduceMathExp(Node* node) {
592  JSCallReduction r(node);
593  if (r.InputsMatchOne(Type::PlainPrimitive())) {
594    // Math.exp(a:plain-primitive) -> NumberExp(ToNumber(a))
595    Node* input = ToNumber(r.GetJSCallInput(0));
596    Node* value = graph()->NewNode(simplified()->NumberExp(), input);
597    return Replace(value);
598  }
599  return NoChange();
600}
601
602// ES6 section 20.2.2.15 Math.expm1 ( x )
603Reduction JSBuiltinReducer::ReduceMathExpm1(Node* node) {
604  JSCallReduction r(node);
605  if (r.InputsMatchOne(Type::Number())) {
606    // Math.expm1(a:number) -> NumberExpm1(a)
607    Node* value = graph()->NewNode(simplified()->NumberExpm1(), r.left());
608    return Replace(value);
609  }
610  return NoChange();
611}
612
613// ES6 section 20.2.2.16 Math.floor ( x )
614Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) {
615  JSCallReduction r(node);
616  if (r.InputsMatchOne(Type::PlainPrimitive())) {
617    // Math.floor(a:plain-primitive) -> NumberFloor(ToNumber(a))
618    Node* input = ToNumber(r.GetJSCallInput(0));
619    Node* value = graph()->NewNode(simplified()->NumberFloor(), input);
620    return Replace(value);
621  }
622  return NoChange();
623}
624
625// ES6 section 20.2.2.17 Math.fround ( x )
626Reduction JSBuiltinReducer::ReduceMathFround(Node* node) {
627  JSCallReduction r(node);
628  if (r.InputsMatchOne(Type::PlainPrimitive())) {
629    // Math.fround(a:plain-primitive) -> NumberFround(ToNumber(a))
630    Node* input = ToNumber(r.GetJSCallInput(0));
631    Node* value = graph()->NewNode(simplified()->NumberFround(), input);
632    return Replace(value);
633  }
634  return NoChange();
635}
636
637// ES6 section 20.2.2.19 Math.imul ( x, y )
638Reduction JSBuiltinReducer::ReduceMathImul(Node* node) {
639  JSCallReduction r(node);
640  if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
641    // Math.imul(a:plain-primitive,
642    //           b:plain-primitive) -> NumberImul(ToUint32(a),
643    //                                            ToUint32(b))
644    Node* left = ToUint32(r.left());
645    Node* right = ToUint32(r.right());
646    Node* value = graph()->NewNode(simplified()->NumberImul(), left, right);
647    return Replace(value);
648  }
649  return NoChange();
650}
651
652// ES6 section 20.2.2.20 Math.log ( x )
653Reduction JSBuiltinReducer::ReduceMathLog(Node* node) {
654  JSCallReduction r(node);
655  if (r.InputsMatchOne(Type::PlainPrimitive())) {
656    // Math.log(a:plain-primitive) -> NumberLog(ToNumber(a))
657    Node* input = ToNumber(r.GetJSCallInput(0));
658    Node* value = graph()->NewNode(simplified()->NumberLog(), input);
659    return Replace(value);
660  }
661  return NoChange();
662}
663
664// ES6 section 20.2.2.21 Math.log1p ( x )
665Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) {
666  JSCallReduction r(node);
667  if (r.InputsMatchOne(Type::PlainPrimitive())) {
668    // Math.log1p(a:plain-primitive) -> NumberLog1p(ToNumber(a))
669    Node* input = ToNumber(r.GetJSCallInput(0));
670    Node* value = graph()->NewNode(simplified()->NumberLog1p(), input);
671    return Replace(value);
672  }
673  return NoChange();
674}
675
676// ES6 section 20.2.2.22 Math.log10 ( x )
677Reduction JSBuiltinReducer::ReduceMathLog10(Node* node) {
678  JSCallReduction r(node);
679  if (r.InputsMatchOne(Type::Number())) {
680    // Math.log10(a:number) -> NumberLog10(a)
681    Node* value = graph()->NewNode(simplified()->NumberLog10(), r.left());
682    return Replace(value);
683  }
684  return NoChange();
685}
686
687// ES6 section 20.2.2.23 Math.log2 ( x )
688Reduction JSBuiltinReducer::ReduceMathLog2(Node* node) {
689  JSCallReduction r(node);
690  if (r.InputsMatchOne(Type::Number())) {
691    // Math.log2(a:number) -> NumberLog(a)
692    Node* value = graph()->NewNode(simplified()->NumberLog2(), r.left());
693    return Replace(value);
694  }
695  return NoChange();
696}
697
698// ES6 section 20.2.2.24 Math.max ( value1, value2, ...values )
699Reduction JSBuiltinReducer::ReduceMathMax(Node* node) {
700  JSCallReduction r(node);
701  if (r.InputsMatchZero()) {
702    // Math.max() -> -Infinity
703    return Replace(jsgraph()->Constant(-V8_INFINITY));
704  }
705  if (r.InputsMatchAll(Type::PlainPrimitive())) {
706    // Math.max(a:plain-primitive, b:plain-primitive, ...)
707    Node* value = ToNumber(r.GetJSCallInput(0));
708    for (int i = 1; i < r.GetJSCallArity(); i++) {
709      Node* input = ToNumber(r.GetJSCallInput(i));
710      value = graph()->NewNode(simplified()->NumberMax(), value, input);
711    }
712    return Replace(value);
713  }
714  return NoChange();
715}
716
717// ES6 section 20.2.2.25 Math.min ( value1, value2, ...values )
718Reduction JSBuiltinReducer::ReduceMathMin(Node* node) {
719  JSCallReduction r(node);
720  if (r.InputsMatchZero()) {
721    // Math.min() -> Infinity
722    return Replace(jsgraph()->Constant(V8_INFINITY));
723  }
724  if (r.InputsMatchAll(Type::PlainPrimitive())) {
725    // Math.min(a:plain-primitive, b:plain-primitive, ...)
726    Node* value = ToNumber(r.GetJSCallInput(0));
727    for (int i = 1; i < r.GetJSCallArity(); i++) {
728      Node* input = ToNumber(r.GetJSCallInput(i));
729      value = graph()->NewNode(simplified()->NumberMin(), value, input);
730    }
731    return Replace(value);
732  }
733  return NoChange();
734}
735
736// ES6 section 20.2.2.26 Math.pow ( x, y )
737Reduction JSBuiltinReducer::ReduceMathPow(Node* node) {
738  JSCallReduction r(node);
739  if (r.InputsMatchTwo(Type::PlainPrimitive(), Type::PlainPrimitive())) {
740    // Math.pow(a:plain-primitive,
741    //          b:plain-primitive) -> NumberPow(ToNumber(a), ToNumber(b))
742    Node* left = ToNumber(r.left());
743    Node* right = ToNumber(r.right());
744    Node* value = graph()->NewNode(simplified()->NumberPow(), left, right);
745    return Replace(value);
746  }
747  return NoChange();
748}
749
750// ES6 section 20.2.2.28 Math.round ( x )
751Reduction JSBuiltinReducer::ReduceMathRound(Node* node) {
752  JSCallReduction r(node);
753  if (r.InputsMatchOne(Type::PlainPrimitive())) {
754    // Math.round(a:plain-primitive) -> NumberRound(ToNumber(a))
755    Node* input = ToNumber(r.GetJSCallInput(0));
756    Node* value = graph()->NewNode(simplified()->NumberRound(), input);
757    return Replace(value);
758  }
759  return NoChange();
760}
761
762// ES6 section 20.2.2.9 Math.cbrt ( x )
763Reduction JSBuiltinReducer::ReduceMathCbrt(Node* node) {
764  JSCallReduction r(node);
765  if (r.InputsMatchOne(Type::Number())) {
766    // Math.cbrt(a:number) -> NumberCbrt(a)
767    Node* value = graph()->NewNode(simplified()->NumberCbrt(), r.left());
768    return Replace(value);
769  }
770  return NoChange();
771}
772
773// ES6 section 20.2.2.29 Math.sign ( x )
774Reduction JSBuiltinReducer::ReduceMathSign(Node* node) {
775  JSCallReduction r(node);
776  if (r.InputsMatchOne(Type::PlainPrimitive())) {
777    // Math.sign(a:plain-primitive) -> NumberSign(ToNumber(a))
778    Node* input = ToNumber(r.GetJSCallInput(0));
779    Node* value = graph()->NewNode(simplified()->NumberSign(), input);
780    return Replace(value);
781  }
782  return NoChange();
783}
784
785// ES6 section 20.2.2.30 Math.sin ( x )
786Reduction JSBuiltinReducer::ReduceMathSin(Node* node) {
787  JSCallReduction r(node);
788  if (r.InputsMatchOne(Type::PlainPrimitive())) {
789    // Math.sin(a:plain-primitive) -> NumberSin(ToNumber(a))
790    Node* input = ToNumber(r.GetJSCallInput(0));
791    Node* value = graph()->NewNode(simplified()->NumberSin(), input);
792    return Replace(value);
793  }
794  return NoChange();
795}
796
797// ES6 section 20.2.2.31 Math.sinh ( x )
798Reduction JSBuiltinReducer::ReduceMathSinh(Node* node) {
799  JSCallReduction r(node);
800  if (r.InputsMatchOne(Type::PlainPrimitive())) {
801    // Math.sinh(a:plain-primitive) -> NumberSinh(ToNumber(a))
802    Node* input = ToNumber(r.GetJSCallInput(0));
803    Node* value = graph()->NewNode(simplified()->NumberSinh(), input);
804    return Replace(value);
805  }
806  return NoChange();
807}
808
809// ES6 section 20.2.2.32 Math.sqrt ( x )
810Reduction JSBuiltinReducer::ReduceMathSqrt(Node* node) {
811  JSCallReduction r(node);
812  if (r.InputsMatchOne(Type::PlainPrimitive())) {
813    // Math.sqrt(a:plain-primitive) -> NumberSqrt(ToNumber(a))
814    Node* input = ToNumber(r.GetJSCallInput(0));
815    Node* value = graph()->NewNode(simplified()->NumberSqrt(), input);
816    return Replace(value);
817  }
818  return NoChange();
819}
820
821// ES6 section 20.2.2.33 Math.tan ( x )
822Reduction JSBuiltinReducer::ReduceMathTan(Node* node) {
823  JSCallReduction r(node);
824  if (r.InputsMatchOne(Type::PlainPrimitive())) {
825    // Math.tan(a:plain-primitive) -> NumberTan(ToNumber(a))
826    Node* input = ToNumber(r.GetJSCallInput(0));
827    Node* value = graph()->NewNode(simplified()->NumberTan(), input);
828    return Replace(value);
829  }
830  return NoChange();
831}
832
833// ES6 section 20.2.2.34 Math.tanh ( x )
834Reduction JSBuiltinReducer::ReduceMathTanh(Node* node) {
835  JSCallReduction r(node);
836  if (r.InputsMatchOne(Type::PlainPrimitive())) {
837    // Math.tanh(a:plain-primitive) -> NumberTanh(ToNumber(a))
838    Node* input = ToNumber(r.GetJSCallInput(0));
839    Node* value = graph()->NewNode(simplified()->NumberTanh(), input);
840    return Replace(value);
841  }
842  return NoChange();
843}
844
845// ES6 section 20.2.2.35 Math.trunc ( x )
846Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) {
847  JSCallReduction r(node);
848  if (r.InputsMatchOne(Type::PlainPrimitive())) {
849    // Math.trunc(a:plain-primitive) -> NumberTrunc(ToNumber(a))
850    Node* input = ToNumber(r.GetJSCallInput(0));
851    Node* value = graph()->NewNode(simplified()->NumberTrunc(), input);
852    return Replace(value);
853  }
854  return NoChange();
855}
856
857// ES6 section 20.1.2.2 Number.isFinite ( number )
858Reduction JSBuiltinReducer::ReduceNumberIsFinite(Node* node) {
859  JSCallReduction r(node);
860  if (r.InputsMatchOne(Type::Number())) {
861    // Number.isFinite(a:number) -> NumberEqual(a', a')
862    // where a' = NumberSubtract(a, a)
863    Node* input = r.GetJSCallInput(0);
864    Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input);
865    Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff);
866    return Replace(value);
867  }
868  return NoChange();
869}
870
871// ES6 section 20.1.2.3 Number.isInteger ( number )
872Reduction JSBuiltinReducer::ReduceNumberIsInteger(Node* node) {
873  JSCallReduction r(node);
874  if (r.InputsMatchOne(Type::Number())) {
875    // Number.isInteger(x:number) -> NumberEqual(NumberSubtract(x, x'), #0)
876    // where x' = NumberTrunc(x)
877    Node* input = r.GetJSCallInput(0);
878    Node* trunc = graph()->NewNode(simplified()->NumberTrunc(), input);
879    Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, trunc);
880    Node* value = graph()->NewNode(simplified()->NumberEqual(), diff,
881                                   jsgraph()->ZeroConstant());
882    return Replace(value);
883  }
884  return NoChange();
885}
886
887// ES6 section 20.1.2.4 Number.isNaN ( number )
888Reduction JSBuiltinReducer::ReduceNumberIsNaN(Node* node) {
889  JSCallReduction r(node);
890  if (r.InputsMatchOne(Type::Number())) {
891    // Number.isNaN(a:number) -> BooleanNot(NumberEqual(a, a))
892    Node* input = r.GetJSCallInput(0);
893    Node* check = graph()->NewNode(simplified()->NumberEqual(), input, input);
894    Node* value = graph()->NewNode(simplified()->BooleanNot(), check);
895    return Replace(value);
896  }
897  return NoChange();
898}
899
900// ES6 section 20.1.2.5 Number.isSafeInteger ( number )
901Reduction JSBuiltinReducer::ReduceNumberIsSafeInteger(Node* node) {
902  JSCallReduction r(node);
903  if (r.InputsMatchOne(type_cache_.kSafeInteger)) {
904    // Number.isInteger(x:safe-integer) -> #true
905    Node* value = jsgraph()->TrueConstant();
906    return Replace(value);
907  }
908  return NoChange();
909}
910
911// ES6 section 20.1.2.13 Number.parseInt ( string, radix )
912Reduction JSBuiltinReducer::ReduceNumberParseInt(Node* node) {
913  JSCallReduction r(node);
914  if (r.InputsMatchOne(type_cache_.kSafeInteger) ||
915      r.InputsMatchTwo(type_cache_.kSafeInteger,
916                       type_cache_.kZeroOrUndefined) ||
917      r.InputsMatchTwo(type_cache_.kSafeInteger, type_cache_.kTenOrUndefined)) {
918    // Number.parseInt(a:safe-integer) -> NumberToInt32(a)
919    // Number.parseInt(a:safe-integer,b:#0\/undefined) -> NumberToInt32(a)
920    // Number.parseInt(a:safe-integer,b:#10\/undefined) -> NumberToInt32(a)
921    Node* input = r.GetJSCallInput(0);
922    Node* value = graph()->NewNode(simplified()->NumberToInt32(), input);
923    return Replace(value);
924  }
925  return NoChange();
926}
927
928// ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits )
929Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) {
930  JSCallReduction r(node);
931  if (r.InputsMatchOne(Type::PlainPrimitive())) {
932    // String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a)
933    Node* input = ToNumber(r.GetJSCallInput(0));
934    Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input);
935    return Replace(value);
936  }
937  return NoChange();
938}
939
940namespace {
941
942Node* GetStringWitness(Node* node) {
943  Node* receiver = NodeProperties::GetValueInput(node, 1);
944  Type* receiver_type = NodeProperties::GetType(receiver);
945  Node* effect = NodeProperties::GetEffectInput(node);
946  if (receiver_type->Is(Type::String())) return receiver;
947  // Check if the {node} is dominated by a CheckString renaming for
948  // it's {receiver}, and if so use that renaming as {receiver} for
949  // the lowering below.
950  for (Node* dominator = effect;;) {
951    if (dominator->opcode() == IrOpcode::kCheckString &&
952        dominator->InputAt(0) == receiver) {
953      return dominator;
954    }
955    if (dominator->op()->EffectInputCount() != 1) {
956      // Didn't find any appropriate CheckString node.
957      return nullptr;
958    }
959    dominator = NodeProperties::GetEffectInput(dominator);
960  }
961}
962
963}  // namespace
964
965// ES6 section 21.1.3.1 String.prototype.charAt ( pos )
966Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) {
967  // We need at least target, receiver and index parameters.
968  if (node->op()->ValueInputCount() >= 3) {
969    Node* index = NodeProperties::GetValueInput(node, 2);
970    Type* index_type = NodeProperties::GetType(index);
971    Node* effect = NodeProperties::GetEffectInput(node);
972    Node* control = NodeProperties::GetControlInput(node);
973
974    if (index_type->Is(Type::Unsigned32())) {
975      if (Node* receiver = GetStringWitness(node)) {
976        // Determine the {receiver} length.
977        Node* receiver_length = effect = graph()->NewNode(
978            simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
979            effect, control);
980
981        // Check if {index} is less than {receiver} length.
982        Node* check = graph()->NewNode(simplified()->NumberLessThan(), index,
983                                       receiver_length);
984        Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
985                                        check, control);
986
987        Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
988        Node* vtrue;
989        {
990          // Load the character from the {receiver}.
991          vtrue = graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
992                                   index, if_true);
993
994          // Return it as single character string.
995          vtrue = graph()->NewNode(simplified()->StringFromCharCode(), vtrue);
996        }
997
998        // Return the empty string otherwise.
999        Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1000        Node* vfalse = jsgraph()->EmptyStringConstant();
1001
1002        control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1003        Node* value =
1004            graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1005                             vtrue, vfalse, control);
1006
1007        ReplaceWithValue(node, value, effect, control);
1008        return Replace(value);
1009      }
1010    }
1011  }
1012
1013  return NoChange();
1014}
1015
1016// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
1017Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) {
1018  // We need at least target, receiver and index parameters.
1019  if (node->op()->ValueInputCount() >= 3) {
1020    Node* index = NodeProperties::GetValueInput(node, 2);
1021    Type* index_type = NodeProperties::GetType(index);
1022    Node* effect = NodeProperties::GetEffectInput(node);
1023    Node* control = NodeProperties::GetControlInput(node);
1024
1025    if (index_type->Is(Type::Unsigned32())) {
1026      if (Node* receiver = GetStringWitness(node)) {
1027        // Determine the {receiver} length.
1028        Node* receiver_length = effect = graph()->NewNode(
1029            simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
1030            effect, control);
1031
1032        // Check if {index} is less than {receiver} length.
1033        Node* check = graph()->NewNode(simplified()->NumberLessThan(), index,
1034                                       receiver_length);
1035        Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1036                                        check, control);
1037
1038        // Load the character from the {receiver}.
1039        Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1040        Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(),
1041                                       receiver, index, if_true);
1042
1043        // Return NaN otherwise.
1044        Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1045        Node* vfalse = jsgraph()->NaNConstant();
1046
1047        control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1048        Node* value =
1049            graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1050                             vtrue, vfalse, control);
1051
1052        ReplaceWithValue(node, value, effect, control);
1053        return Replace(value);
1054      }
1055    }
1056  }
1057
1058  return NoChange();
1059}
1060
1061Reduction JSBuiltinReducer::ReduceStringIteratorNext(Node* node) {
1062  Node* receiver = NodeProperties::GetValueInput(node, 1);
1063  Node* effect = NodeProperties::GetEffectInput(node);
1064  Node* control = NodeProperties::GetControlInput(node);
1065  Node* context = NodeProperties::GetContextInput(node);
1066  if (HasInstanceTypeWitness(receiver, effect, JS_STRING_ITERATOR_TYPE)) {
1067    Node* string = effect = graph()->NewNode(
1068        simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()),
1069        receiver, effect, control);
1070    Node* index = effect = graph()->NewNode(
1071        simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()),
1072        receiver, effect, control);
1073    Node* length = effect = graph()->NewNode(
1074        simplified()->LoadField(AccessBuilder::ForStringLength()), string,
1075        effect, control);
1076
1077    // branch0: if (index < length)
1078    Node* check0 =
1079        graph()->NewNode(simplified()->NumberLessThan(), index, length);
1080    Node* branch0 =
1081        graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
1082
1083    Node* etrue0 = effect;
1084    Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1085    Node* done_true;
1086    Node* vtrue0;
1087    {
1088      done_true = jsgraph()->FalseConstant();
1089      Node* lead = graph()->NewNode(simplified()->StringCharCodeAt(), string,
1090                                    index, if_true0);
1091
1092      // branch1: if ((lead & 0xFC00) === 0xD800)
1093      Node* check1 = graph()->NewNode(
1094          simplified()->NumberEqual(),
1095          graph()->NewNode(simplified()->NumberBitwiseAnd(), lead,
1096                           jsgraph()->Int32Constant(0xFC00)),
1097          jsgraph()->Int32Constant(0xD800));
1098      Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1099                                       check1, if_true0);
1100      Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1101      Node* vtrue1;
1102      {
1103        Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
1104                                            jsgraph()->OneConstant());
1105        // branch2: if ((index + 1) < length)
1106        Node* check2 = graph()->NewNode(simplified()->NumberLessThan(),
1107                                        next_index, length);
1108        Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1109                                         check2, if_true1);
1110        Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1111        Node* vtrue2;
1112        {
1113          Node* trail = graph()->NewNode(simplified()->StringCharCodeAt(),
1114                                         string, next_index, if_true2);
1115          // branch3: if ((trail & 0xFC00) === 0xDC00)
1116          Node* check3 = graph()->NewNode(
1117              simplified()->NumberEqual(),
1118              graph()->NewNode(simplified()->NumberBitwiseAnd(), trail,
1119                               jsgraph()->Int32Constant(0xFC00)),
1120              jsgraph()->Int32Constant(0xDC00));
1121          Node* branch3 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1122                                           check3, if_true2);
1123          Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
1124          Node* vtrue3;
1125          {
1126            vtrue3 = graph()->NewNode(
1127                simplified()->NumberBitwiseOr(),
1128// Need to swap the order for big-endian platforms
1129#if V8_TARGET_BIG_ENDIAN
1130                graph()->NewNode(simplified()->NumberShiftLeft(), lead,
1131                                 jsgraph()->Int32Constant(16)),
1132                trail);
1133#else
1134                graph()->NewNode(simplified()->NumberShiftLeft(), trail,
1135                                 jsgraph()->Int32Constant(16)),
1136                lead);
1137#endif
1138          }
1139
1140          Node* if_false3 = graph()->NewNode(common()->IfFalse(), branch3);
1141          Node* vfalse3 = lead;
1142          if_true2 = graph()->NewNode(common()->Merge(2), if_true3, if_false3);
1143          vtrue2 =
1144              graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
1145                               vtrue3, vfalse3, if_true2);
1146        }
1147
1148        Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
1149        Node* vfalse2 = lead;
1150        if_true1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
1151        vtrue1 =
1152            graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
1153                             vtrue2, vfalse2, if_true1);
1154      }
1155
1156      Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1157      Node* vfalse1 = lead;
1158      if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
1159      vtrue0 =
1160          graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
1161                           vtrue1, vfalse1, if_true0);
1162      vtrue0 = graph()->NewNode(
1163          simplified()->StringFromCodePoint(UnicodeEncoding::UTF16), vtrue0);
1164
1165      // Update iterator.[[NextIndex]]
1166      Node* char_length = etrue0 = graph()->NewNode(
1167          simplified()->LoadField(AccessBuilder::ForStringLength()), vtrue0,
1168          etrue0, if_true0);
1169      index = graph()->NewNode(simplified()->NumberAdd(), index, char_length);
1170      etrue0 = graph()->NewNode(
1171          simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()),
1172          receiver, index, etrue0, if_true0);
1173    }
1174
1175    Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1176    Node* done_false;
1177    Node* vfalse0;
1178    {
1179      vfalse0 = jsgraph()->UndefinedConstant();
1180      done_false = jsgraph()->TrueConstant();
1181    }
1182
1183    control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
1184    effect = graph()->NewNode(common()->EffectPhi(2), etrue0, effect, control);
1185    Node* value =
1186        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1187                         vtrue0, vfalse0, control);
1188    Node* done =
1189        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1190                         done_true, done_false, control);
1191
1192    value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
1193                                      value, done, context, effect);
1194
1195    ReplaceWithValue(node, value, effect, control);
1196    return Replace(value);
1197  }
1198  return NoChange();
1199}
1200
1201Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor(
1202    Node* node, InstanceType instance_type, FieldAccess const& access) {
1203  Node* receiver = NodeProperties::GetValueInput(node, 1);
1204  Node* effect = NodeProperties::GetEffectInput(node);
1205  Node* control = NodeProperties::GetControlInput(node);
1206  if (HasInstanceTypeWitness(receiver, effect, instance_type)) {
1207    // Load the {receiver}s field.
1208    Node* receiver_value = effect = graph()->NewNode(
1209        simplified()->LoadField(access), receiver, effect, control);
1210
1211    // Check if the {receiver}s buffer was neutered.
1212    Node* receiver_buffer = effect = graph()->NewNode(
1213        simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
1214        receiver, effect, control);
1215    Node* check = effect =
1216        graph()->NewNode(simplified()->ArrayBufferWasNeutered(),
1217                         receiver_buffer, effect, control);
1218
1219    // Default to zero if the {receiver}s buffer was neutered.
1220    Node* value = graph()->NewNode(
1221        common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
1222        check, jsgraph()->ZeroConstant(), receiver_value);
1223
1224    ReplaceWithValue(node, value, effect, control);
1225    return Replace(value);
1226  }
1227  return NoChange();
1228}
1229
1230Reduction JSBuiltinReducer::Reduce(Node* node) {
1231  Reduction reduction = NoChange();
1232  JSCallReduction r(node);
1233
1234  // Dispatch according to the BuiltinFunctionId if present.
1235  if (!r.HasBuiltinFunctionId()) return NoChange();
1236  switch (r.GetBuiltinFunctionId()) {
1237    case kArrayPop:
1238      return ReduceArrayPop(node);
1239    case kArrayPush:
1240      return ReduceArrayPush(node);
1241    case kDateGetTime:
1242      return ReduceDateGetTime(node);
1243    case kFunctionHasInstance:
1244      return ReduceFunctionHasInstance(node);
1245      break;
1246    case kGlobalIsFinite:
1247      reduction = ReduceGlobalIsFinite(node);
1248      break;
1249    case kGlobalIsNaN:
1250      reduction = ReduceGlobalIsNaN(node);
1251      break;
1252    case kMathAbs:
1253      reduction = ReduceMathAbs(node);
1254      break;
1255    case kMathAcos:
1256      reduction = ReduceMathAcos(node);
1257      break;
1258    case kMathAcosh:
1259      reduction = ReduceMathAcosh(node);
1260      break;
1261    case kMathAsin:
1262      reduction = ReduceMathAsin(node);
1263      break;
1264    case kMathAsinh:
1265      reduction = ReduceMathAsinh(node);
1266      break;
1267    case kMathAtan:
1268      reduction = ReduceMathAtan(node);
1269      break;
1270    case kMathAtanh:
1271      reduction = ReduceMathAtanh(node);
1272      break;
1273    case kMathAtan2:
1274      reduction = ReduceMathAtan2(node);
1275      break;
1276    case kMathCbrt:
1277      reduction = ReduceMathCbrt(node);
1278      break;
1279    case kMathCeil:
1280      reduction = ReduceMathCeil(node);
1281      break;
1282    case kMathClz32:
1283      reduction = ReduceMathClz32(node);
1284      break;
1285    case kMathCos:
1286      reduction = ReduceMathCos(node);
1287      break;
1288    case kMathCosh:
1289      reduction = ReduceMathCosh(node);
1290      break;
1291    case kMathExp:
1292      reduction = ReduceMathExp(node);
1293      break;
1294    case kMathExpm1:
1295      reduction = ReduceMathExpm1(node);
1296      break;
1297    case kMathFloor:
1298      reduction = ReduceMathFloor(node);
1299      break;
1300    case kMathFround:
1301      reduction = ReduceMathFround(node);
1302      break;
1303    case kMathImul:
1304      reduction = ReduceMathImul(node);
1305      break;
1306    case kMathLog:
1307      reduction = ReduceMathLog(node);
1308      break;
1309    case kMathLog1p:
1310      reduction = ReduceMathLog1p(node);
1311      break;
1312    case kMathLog10:
1313      reduction = ReduceMathLog10(node);
1314      break;
1315    case kMathLog2:
1316      reduction = ReduceMathLog2(node);
1317      break;
1318    case kMathMax:
1319      reduction = ReduceMathMax(node);
1320      break;
1321    case kMathMin:
1322      reduction = ReduceMathMin(node);
1323      break;
1324    case kMathPow:
1325      reduction = ReduceMathPow(node);
1326      break;
1327    case kMathRound:
1328      reduction = ReduceMathRound(node);
1329      break;
1330    case kMathSign:
1331      reduction = ReduceMathSign(node);
1332      break;
1333    case kMathSin:
1334      reduction = ReduceMathSin(node);
1335      break;
1336    case kMathSinh:
1337      reduction = ReduceMathSinh(node);
1338      break;
1339    case kMathSqrt:
1340      reduction = ReduceMathSqrt(node);
1341      break;
1342    case kMathTan:
1343      reduction = ReduceMathTan(node);
1344      break;
1345    case kMathTanh:
1346      reduction = ReduceMathTanh(node);
1347      break;
1348    case kMathTrunc:
1349      reduction = ReduceMathTrunc(node);
1350      break;
1351    case kNumberIsFinite:
1352      reduction = ReduceNumberIsFinite(node);
1353      break;
1354    case kNumberIsInteger:
1355      reduction = ReduceNumberIsInteger(node);
1356      break;
1357    case kNumberIsNaN:
1358      reduction = ReduceNumberIsNaN(node);
1359      break;
1360    case kNumberIsSafeInteger:
1361      reduction = ReduceNumberIsSafeInteger(node);
1362      break;
1363    case kNumberParseInt:
1364      reduction = ReduceNumberParseInt(node);
1365      break;
1366    case kStringFromCharCode:
1367      reduction = ReduceStringFromCharCode(node);
1368      break;
1369    case kStringCharAt:
1370      return ReduceStringCharAt(node);
1371    case kStringCharCodeAt:
1372      return ReduceStringCharCodeAt(node);
1373    case kStringIteratorNext:
1374      return ReduceStringIteratorNext(node);
1375    case kDataViewByteLength:
1376      return ReduceArrayBufferViewAccessor(
1377          node, JS_DATA_VIEW_TYPE,
1378          AccessBuilder::ForJSArrayBufferViewByteLength());
1379    case kDataViewByteOffset:
1380      return ReduceArrayBufferViewAccessor(
1381          node, JS_DATA_VIEW_TYPE,
1382          AccessBuilder::ForJSArrayBufferViewByteOffset());
1383    case kTypedArrayByteLength:
1384      return ReduceArrayBufferViewAccessor(
1385          node, JS_TYPED_ARRAY_TYPE,
1386          AccessBuilder::ForJSArrayBufferViewByteLength());
1387    case kTypedArrayByteOffset:
1388      return ReduceArrayBufferViewAccessor(
1389          node, JS_TYPED_ARRAY_TYPE,
1390          AccessBuilder::ForJSArrayBufferViewByteOffset());
1391    case kTypedArrayLength:
1392      return ReduceArrayBufferViewAccessor(
1393          node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
1394    default:
1395      break;
1396  }
1397
1398  // Replace builtin call assuming replacement nodes are pure values that don't
1399  // produce an effect. Replaces {node} with {reduction} and relaxes effects.
1400  if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement());
1401
1402  return reduction;
1403}
1404
1405Node* JSBuiltinReducer::ToNumber(Node* input) {
1406  Type* input_type = NodeProperties::GetType(input);
1407  if (input_type->Is(Type::Number())) return input;
1408  return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), input);
1409}
1410
1411Node* JSBuiltinReducer::ToUint32(Node* input) {
1412  input = ToNumber(input);
1413  Type* input_type = NodeProperties::GetType(input);
1414  if (input_type->Is(Type::Unsigned32())) return input;
1415  return graph()->NewNode(simplified()->NumberToUint32(), input);
1416}
1417
1418Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); }
1419
1420Factory* JSBuiltinReducer::factory() const { return isolate()->factory(); }
1421
1422Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); }
1423
1424
1425CommonOperatorBuilder* JSBuiltinReducer::common() const {
1426  return jsgraph()->common();
1427}
1428
1429
1430SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const {
1431  return jsgraph()->simplified();
1432}
1433
1434JSOperatorBuilder* JSBuiltinReducer::javascript() const {
1435  return jsgraph()->javascript();
1436}
1437
1438}  // namespace compiler
1439}  // namespace internal
1440}  // namespace v8
1441