1// Copyright 2015 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-call-reducer.h"
6
7#include <functional>
8
9#include "src/api/api-inl.h"
10#include "src/base/small-vector.h"
11#include "src/builtins/builtins-promise.h"
12#include "src/builtins/builtins-utils.h"
13#include "src/codegen/code-factory.h"
14#include "src/codegen/tnode.h"
15#include "src/compiler/access-builder.h"
16#include "src/compiler/access-info.h"
17#include "src/compiler/allocation-builder-inl.h"
18#include "src/compiler/allocation-builder.h"
19#include "src/compiler/common-operator.h"
20#include "src/compiler/compilation-dependencies.h"
21#include "src/compiler/fast-api-calls.h"
22#include "src/compiler/feedback-source.h"
23#include "src/compiler/graph-assembler.h"
24#include "src/compiler/js-graph.h"
25#include "src/compiler/linkage.h"
26#include "src/compiler/map-inference.h"
27#include "src/compiler/node-matchers.h"
28#include "src/compiler/opcodes.h"
29#include "src/compiler/property-access-builder.h"
30#include "src/compiler/simplified-operator.h"
31#include "src/compiler/state-values-utils.h"
32#include "src/compiler/type-cache.h"
33#include "src/ic/call-optimization.h"
34#include "src/logging/counters.h"
35#include "src/objects/arguments-inl.h"
36#include "src/objects/feedback-vector-inl.h"
37#include "src/objects/js-array-buffer-inl.h"
38#include "src/objects/js-array-inl.h"
39#include "src/objects/js-function.h"
40#include "src/objects/objects-inl.h"
41#include "src/objects/ordered-hash-table.h"
42#include "src/objects/string-inl.h"
43
44#ifdef V8_INTL_SUPPORT
45#include "src/objects/intl-objects.h"
46#endif
47
48namespace v8 {
49namespace internal {
50namespace compiler {
51
52// Shorter lambda declarations with less visual clutter.
53#define _ [&]()
54
55class JSCallReducerAssembler : public JSGraphAssembler {
56 protected:
57  class CatchScope;
58
59 private:
60  static constexpr bool kMarkLoopExits = true;
61
62 public:
63  JSCallReducerAssembler(JSCallReducer* reducer, Node* node)
64      : JSGraphAssembler(
65            reducer->JSGraphForGraphAssembler(),
66            reducer->ZoneForGraphAssembler(),
67            [reducer](Node* n) { reducer->RevisitForGraphAssembler(n); },
68            kMarkLoopExits),
69        dependencies_(reducer->dependencies()),
70        node_(node),
71        outermost_catch_scope_(
72            CatchScope::Outermost(reducer->ZoneForGraphAssembler())),
73        catch_scope_(&outermost_catch_scope_) {
74    InitializeEffectControl(NodeProperties::GetEffectInput(node),
75                            NodeProperties::GetControlInput(node));
76
77    // Finish initializing the outermost catch scope.
78    bool has_handler =
79        NodeProperties::IsExceptionalCall(node, &outermost_handler_);
80    outermost_catch_scope_.set_has_handler(has_handler);
81    outermost_catch_scope_.set_gasm(this);
82  }
83
84  TNode<Object> ReduceJSCallWithArrayLikeOrSpreadOfEmpty(
85      std::unordered_set<Node*>* generated_calls_with_array_like_or_spread);
86  TNode<Object> ReduceMathUnary(const Operator* op);
87  TNode<Object> ReduceMathBinary(const Operator* op);
88  TNode<String> ReduceStringPrototypeSubstring();
89  TNode<Boolean> ReduceStringPrototypeStartsWith();
90  TNode<Boolean> ReduceStringPrototypeStartsWith(
91      const StringRef& search_element_string);
92  TNode<String> ReduceStringPrototypeSlice();
93
94  TNode<Object> TargetInput() const { return JSCallNode{node_ptr()}.target(); }
95
96  template <typename T>
97  TNode<T> ReceiverInputAs() const {
98    return TNode<T>::UncheckedCast(JSCallNode{node_ptr()}.receiver());
99  }
100
101  TNode<Object> ReceiverInput() const { return ReceiverInputAs<Object>(); }
102
103  CatchScope* catch_scope() const { return catch_scope_; }
104  Node* outermost_handler() const { return outermost_handler_; }
105
106  Node* node_ptr() const { return node_; }
107
108 protected:
109  using NodeGenerator0 = std::function<TNode<Object>()>;
110  using VoidGenerator0 = std::function<void()>;
111
112  // TODO(jgruber): Currently IfBuilder0 and IfBuilder1 are implemented as
113  // separate classes. If, in the future, we encounter additional use cases that
114  // return more than 1 value, we should merge these back into a single variadic
115  // implementation.
116  class IfBuilder0 final {
117   public:
118    IfBuilder0(JSGraphAssembler* gasm, TNode<Boolean> cond, bool negate_cond)
119        : gasm_(gasm),
120          cond_(cond),
121          negate_cond_(negate_cond),
122          initial_effect_(gasm->effect()),
123          initial_control_(gasm->control()) {}
124
125    IfBuilder0& ExpectTrue() {
126      DCHECK_EQ(hint_, BranchHint::kNone);
127      hint_ = BranchHint::kTrue;
128      return *this;
129    }
130    IfBuilder0& ExpectFalse() {
131      DCHECK_EQ(hint_, BranchHint::kNone);
132      hint_ = BranchHint::kFalse;
133      return *this;
134    }
135
136    IfBuilder0& Then(const VoidGenerator0& body) {
137      then_body_ = body;
138      return *this;
139    }
140    IfBuilder0& Else(const VoidGenerator0& body) {
141      else_body_ = body;
142      return *this;
143    }
144
145    ~IfBuilder0() {
146      // Ensure correct usage: effect/control must not have been modified while
147      // the IfBuilder0 instance is alive.
148      DCHECK_EQ(gasm_->effect(), initial_effect_);
149      DCHECK_EQ(gasm_->control(), initial_control_);
150
151      // Unlike IfBuilder1, this supports an empty then or else body. This is
152      // possible since the merge does not take any value inputs.
153      DCHECK(then_body_ || else_body_);
154
155      if (negate_cond_) std::swap(then_body_, else_body_);
156
157      auto if_true = (hint_ == BranchHint::kFalse) ? gasm_->MakeDeferredLabel()
158                                                   : gasm_->MakeLabel();
159      auto if_false = (hint_ == BranchHint::kTrue) ? gasm_->MakeDeferredLabel()
160                                                   : gasm_->MakeLabel();
161      auto merge = gasm_->MakeLabel();
162      gasm_->Branch(cond_, &if_true, &if_false);
163
164      gasm_->Bind(&if_true);
165      if (then_body_) then_body_();
166      if (gasm_->HasActiveBlock()) gasm_->Goto(&merge);
167
168      gasm_->Bind(&if_false);
169      if (else_body_) else_body_();
170      if (gasm_->HasActiveBlock()) gasm_->Goto(&merge);
171
172      gasm_->Bind(&merge);
173    }
174
175    IfBuilder0(const IfBuilder0&) = delete;
176    IfBuilder0& operator=(const IfBuilder0&) = delete;
177
178   private:
179    JSGraphAssembler* const gasm_;
180    const TNode<Boolean> cond_;
181    const bool negate_cond_;
182    const Effect initial_effect_;
183    const Control initial_control_;
184    BranchHint hint_ = BranchHint::kNone;
185    VoidGenerator0 then_body_;
186    VoidGenerator0 else_body_;
187  };
188
189  IfBuilder0 If(TNode<Boolean> cond) { return {this, cond, false}; }
190  IfBuilder0 IfNot(TNode<Boolean> cond) { return {this, cond, true}; }
191
192  template <typename T>
193  class IfBuilder1 {
194    using If1BodyFunction = std::function<TNode<T>()>;
195
196   public:
197    IfBuilder1(JSGraphAssembler* gasm, TNode<Boolean> cond)
198        : gasm_(gasm), cond_(cond) {}
199
200    V8_WARN_UNUSED_RESULT IfBuilder1& ExpectTrue() {
201      DCHECK_EQ(hint_, BranchHint::kNone);
202      hint_ = BranchHint::kTrue;
203      return *this;
204    }
205
206    V8_WARN_UNUSED_RESULT IfBuilder1& ExpectFalse() {
207      DCHECK_EQ(hint_, BranchHint::kNone);
208      hint_ = BranchHint::kFalse;
209      return *this;
210    }
211
212    V8_WARN_UNUSED_RESULT IfBuilder1& Then(const If1BodyFunction& body) {
213      then_body_ = body;
214      return *this;
215    }
216    V8_WARN_UNUSED_RESULT IfBuilder1& Else(const If1BodyFunction& body) {
217      else_body_ = body;
218      return *this;
219    }
220
221    V8_WARN_UNUSED_RESULT TNode<T> Value() {
222      DCHECK(then_body_);
223      DCHECK(else_body_);
224      auto if_true = (hint_ == BranchHint::kFalse) ? gasm_->MakeDeferredLabel()
225                                                   : gasm_->MakeLabel();
226      auto if_false = (hint_ == BranchHint::kTrue) ? gasm_->MakeDeferredLabel()
227                                                   : gasm_->MakeLabel();
228      auto merge = gasm_->MakeLabel(kPhiRepresentation);
229      gasm_->Branch(cond_, &if_true, &if_false);
230
231      gasm_->Bind(&if_true);
232      TNode<T> then_result = then_body_();
233      if (gasm_->HasActiveBlock()) gasm_->Goto(&merge, then_result);
234
235      gasm_->Bind(&if_false);
236      TNode<T> else_result = else_body_();
237      if (gasm_->HasActiveBlock()) {
238        gasm_->Goto(&merge, else_result);
239      }
240
241      gasm_->Bind(&merge);
242      return merge.PhiAt<T>(0);
243    }
244
245   private:
246    static constexpr MachineRepresentation kPhiRepresentation =
247        MachineRepresentation::kTagged;
248
249    JSGraphAssembler* const gasm_;
250    const TNode<Boolean> cond_;
251    BranchHint hint_ = BranchHint::kNone;
252    If1BodyFunction then_body_;
253    If1BodyFunction else_body_;
254  };
255
256  template <typename T>
257  IfBuilder1<T> SelectIf(TNode<Boolean> cond) {
258    return {this, cond};
259  }
260
261  // Simplified operators.
262  TNode<Number> SpeculativeToNumber(
263      TNode<Object> value,
264      NumberOperationHint hint = NumberOperationHint::kNumberOrOddball);
265  TNode<Smi> CheckSmi(TNode<Object> value);
266  TNode<String> CheckString(TNode<Object> value);
267  TNode<Number> CheckBounds(TNode<Number> value, TNode<Number> limit);
268
269  // Common operators.
270  TNode<Smi> TypeGuardUnsignedSmall(TNode<Object> value);
271  TNode<Object> TypeGuardNonInternal(TNode<Object> value);
272  TNode<Number> TypeGuardFixedArrayLength(TNode<Object> value);
273  TNode<Object> Call4(const Callable& callable, TNode<Context> context,
274                      TNode<Object> arg0, TNode<Object> arg1,
275                      TNode<Object> arg2, TNode<Object> arg3);
276
277  // Javascript operators.
278  TNode<Object> JSCall3(TNode<Object> function, TNode<Object> this_arg,
279                        TNode<Object> arg0, TNode<Object> arg1,
280                        TNode<Object> arg2, FrameState frame_state);
281  TNode<Object> JSCall4(TNode<Object> function, TNode<Object> this_arg,
282                        TNode<Object> arg0, TNode<Object> arg1,
283                        TNode<Object> arg2, TNode<Object> arg3,
284                        FrameState frame_state);
285  TNode<Object> JSCallRuntime2(Runtime::FunctionId function_id,
286                               TNode<Object> arg0, TNode<Object> arg1,
287                               FrameState frame_state);
288
289  // Emplace a copy of the call node into the graph at current effect/control.
290  TNode<Object> CopyNode();
291
292  // Used in special cases in which we are certain CreateArray does not throw.
293  TNode<JSArray> CreateArrayNoThrow(TNode<Object> ctor, TNode<Number> size,
294                                    FrameState frame_state);
295
296  TNode<JSArray> AllocateEmptyJSArray(ElementsKind kind,
297                                      const NativeContextRef& native_context);
298
299  TNode<Number> NumberInc(TNode<Number> value) {
300    return NumberAdd(value, OneConstant());
301  }
302
303  void MaybeInsertMapChecks(MapInference* inference,
304                            bool has_stability_dependency) {
305    // TODO(jgruber): Implement MapInference::InsertMapChecks in graph
306    // assembler.
307    if (!has_stability_dependency) {
308      Effect e = effect();
309      inference->InsertMapChecks(jsgraph(), &e, Control{control()}, feedback());
310      InitializeEffectControl(e, control());
311    }
312  }
313
314  // TODO(jgruber): Currently, it's the responsibility of the developer to note
315  // which operations may throw and appropriately wrap these in a call to
316  // MayThrow (see e.g. JSCall3 and CallRuntime2). A more methodical approach
317  // would be good.
318  TNode<Object> MayThrow(const NodeGenerator0& body) {
319    TNode<Object> result = body();
320
321    if (catch_scope()->has_handler()) {
322      // The IfException node is later merged into the outer graph.
323      // Note: AddNode is intentionally not called since effect and control
324      // should not be updated.
325      Node* if_exception =
326          graph()->NewNode(common()->IfException(), effect(), control());
327      catch_scope()->RegisterIfExceptionNode(if_exception);
328
329      // Control resumes here.
330      AddNode(graph()->NewNode(common()->IfSuccess(), control()));
331    }
332
333    return result;
334  }
335
336  // A catch scope represents a single catch handler. The handler can be
337  // custom catch logic within the reduction itself; or a catch handler in the
338  // outside graph into which the reduction will be integrated (in this case
339  // the scope is called 'outermost').
340  class V8_NODISCARD CatchScope {
341   private:
342    // Only used to partially construct the outermost scope.
343    explicit CatchScope(Zone* zone) : if_exception_nodes_(zone) {}
344
345    // For all inner scopes.
346    CatchScope(Zone* zone, JSCallReducerAssembler* gasm)
347        : gasm_(gasm),
348          parent_(gasm->catch_scope_),
349          has_handler_(true),
350          if_exception_nodes_(zone) {
351      gasm_->catch_scope_ = this;
352    }
353
354   public:
355    ~CatchScope() { gasm_->catch_scope_ = parent_; }
356
357    static CatchScope Outermost(Zone* zone) { return CatchScope{zone}; }
358    static CatchScope Inner(Zone* zone, JSCallReducerAssembler* gasm) {
359      return {zone, gasm};
360    }
361
362    bool has_handler() const { return has_handler_; }
363    bool is_outermost() const { return parent_ == nullptr; }
364    CatchScope* parent() const { return parent_; }
365
366    // Should only be used to initialize the outermost scope (inner scopes
367    // always have a handler and are passed the gasm pointer at construction).
368    void set_has_handler(bool v) {
369      DCHECK(is_outermost());
370      has_handler_ = v;
371    }
372    void set_gasm(JSCallReducerAssembler* v) {
373      DCHECK(is_outermost());
374      gasm_ = v;
375    }
376
377    bool has_exceptional_control_flow() const {
378      return !if_exception_nodes_.empty();
379    }
380
381    void RegisterIfExceptionNode(Node* if_exception) {
382      DCHECK(has_handler());
383      if_exception_nodes_.push_back(if_exception);
384    }
385
386    void MergeExceptionalPaths(TNode<Object>* exception_out, Effect* effect_out,
387                               Control* control_out) {
388      DCHECK(has_handler());
389      DCHECK(has_exceptional_control_flow());
390
391      const int size = static_cast<int>(if_exception_nodes_.size());
392
393      if (size == 1) {
394        // No merge needed.
395        Node* e = if_exception_nodes_.at(0);
396        *exception_out = TNode<Object>::UncheckedCast(e);
397        *effect_out = Effect(e);
398        *control_out = Control(e);
399      } else {
400        DCHECK_GT(size, 1);
401
402        Node* merge = gasm_->graph()->NewNode(gasm_->common()->Merge(size),
403                                              size, if_exception_nodes_.data());
404
405        // These phis additionally take {merge} as an input. Temporarily add
406        // it to the list.
407        if_exception_nodes_.push_back(merge);
408        const int size_with_merge =
409            static_cast<int>(if_exception_nodes_.size());
410
411        Node* ephi = gasm_->graph()->NewNode(gasm_->common()->EffectPhi(size),
412                                             size_with_merge,
413                                             if_exception_nodes_.data());
414        Node* phi = gasm_->graph()->NewNode(
415            gasm_->common()->Phi(MachineRepresentation::kTagged, size),
416            size_with_merge, if_exception_nodes_.data());
417        if_exception_nodes_.pop_back();
418
419        *exception_out = TNode<Object>::UncheckedCast(phi);
420        *effect_out = Effect(ephi);
421        *control_out = Control(merge);
422      }
423    }
424
425   private:
426    JSCallReducerAssembler* gasm_ = nullptr;
427    CatchScope* const parent_ = nullptr;
428    bool has_handler_ = false;
429    NodeVector if_exception_nodes_;
430  };
431
432  class TryCatchBuilder0 {
433   public:
434    using TryFunction = VoidGenerator0;
435    using CatchFunction = std::function<void(TNode<Object>)>;
436
437    TryCatchBuilder0(JSCallReducerAssembler* gasm, const TryFunction& try_body)
438        : gasm_(gasm), try_body_(try_body) {}
439
440    void Catch(const CatchFunction& catch_body) {
441      TNode<Object> handler_exception;
442      Effect handler_effect{nullptr};
443      Control handler_control{nullptr};
444
445      auto continuation = gasm_->MakeLabel();
446
447      // Try.
448      {
449        CatchScope catch_scope = CatchScope::Inner(gasm_->temp_zone(), gasm_);
450        try_body_();
451        gasm_->Goto(&continuation);
452
453        catch_scope.MergeExceptionalPaths(&handler_exception, &handler_effect,
454                                          &handler_control);
455      }
456
457      // Catch.
458      {
459        gasm_->InitializeEffectControl(handler_effect, handler_control);
460        catch_body(handler_exception);
461        gasm_->Goto(&continuation);
462      }
463
464      gasm_->Bind(&continuation);
465    }
466
467   private:
468    JSCallReducerAssembler* const gasm_;
469    const VoidGenerator0 try_body_;
470  };
471
472  TryCatchBuilder0 Try(const VoidGenerator0& try_body) {
473    return {this, try_body};
474  }
475
476  using ConditionFunction1 = std::function<TNode<Boolean>(TNode<Number>)>;
477  using StepFunction1 = std::function<TNode<Number>(TNode<Number>)>;
478  class ForBuilder0 {
479    using For0BodyFunction = std::function<void(TNode<Number>)>;
480
481   public:
482    ForBuilder0(JSGraphAssembler* gasm, TNode<Number> initial_value,
483                const ConditionFunction1& cond, const StepFunction1& step)
484        : gasm_(gasm),
485          initial_value_(initial_value),
486          cond_(cond),
487          step_(step) {}
488
489    void Do(const For0BodyFunction& body) {
490      auto loop_exit = gasm_->MakeLabel();
491
492      {
493        GraphAssembler::LoopScope<kPhiRepresentation> loop_scope(gasm_);
494
495        auto loop_header = loop_scope.loop_header_label();
496        auto loop_body = gasm_->MakeLabel();
497
498        gasm_->Goto(loop_header, initial_value_);
499
500        gasm_->Bind(loop_header);
501        TNode<Number> i = loop_header->PhiAt<Number>(0);
502
503        gasm_->BranchWithHint(cond_(i), &loop_body, &loop_exit,
504                              BranchHint::kTrue);
505
506        gasm_->Bind(&loop_body);
507        body(i);
508        gasm_->Goto(loop_header, step_(i));
509      }
510
511      gasm_->Bind(&loop_exit);
512    }
513
514   private:
515    static constexpr MachineRepresentation kPhiRepresentation =
516        MachineRepresentation::kTagged;
517
518    JSGraphAssembler* const gasm_;
519    const TNode<Number> initial_value_;
520    const ConditionFunction1 cond_;
521    const StepFunction1 step_;
522  };
523
524  ForBuilder0 ForZeroUntil(TNode<Number> excluded_limit) {
525    TNode<Number> initial_value = ZeroConstant();
526    auto cond = [=](TNode<Number> i) {
527      return NumberLessThan(i, excluded_limit);
528    };
529    auto step = [=](TNode<Number> i) { return NumberAdd(i, OneConstant()); };
530    return {this, initial_value, cond, step};
531  }
532
533  ForBuilder0 Forever(TNode<Number> initial_value, const StepFunction1& step) {
534    return {this, initial_value, [=](TNode<Number>) { return TrueConstant(); },
535            step};
536  }
537
538  using For1BodyFunction = std::function<void(TNode<Number>, TNode<Object>*)>;
539  class ForBuilder1 {
540   public:
541    ForBuilder1(JSGraphAssembler* gasm, TNode<Number> initial_value,
542                const ConditionFunction1& cond, const StepFunction1& step,
543                TNode<Object> initial_arg0)
544        : gasm_(gasm),
545          initial_value_(initial_value),
546          cond_(cond),
547          step_(step),
548          initial_arg0_(initial_arg0) {}
549
550    V8_WARN_UNUSED_RESULT ForBuilder1& Do(const For1BodyFunction& body) {
551      body_ = body;
552      return *this;
553    }
554
555    V8_WARN_UNUSED_RESULT TNode<Object> Value() {
556      DCHECK(body_);
557      TNode<Object> arg0 = initial_arg0_;
558
559      auto loop_exit = gasm_->MakeDeferredLabel(kPhiRepresentation);
560
561      {
562        GraphAssembler::LoopScope<kPhiRepresentation, kPhiRepresentation>
563            loop_scope(gasm_);
564
565        auto loop_header = loop_scope.loop_header_label();
566        auto loop_body = gasm_->MakeDeferredLabel(kPhiRepresentation);
567
568        gasm_->Goto(loop_header, initial_value_, initial_arg0_);
569
570        gasm_->Bind(loop_header);
571        TNode<Number> i = loop_header->PhiAt<Number>(0);
572        arg0 = loop_header->PhiAt<Object>(1);
573
574        gasm_->BranchWithHint(cond_(i), &loop_body, &loop_exit,
575                              BranchHint::kTrue, arg0);
576
577        gasm_->Bind(&loop_body);
578        body_(i, &arg0);
579        gasm_->Goto(loop_header, step_(i), arg0);
580      }
581
582      gasm_->Bind(&loop_exit);
583      return TNode<Object>::UncheckedCast(loop_exit.PhiAt<Object>(0));
584    }
585
586    void ValueIsUnused() { USE(Value()); }
587
588   private:
589    static constexpr MachineRepresentation kPhiRepresentation =
590        MachineRepresentation::kTagged;
591
592    JSGraphAssembler* const gasm_;
593    const TNode<Number> initial_value_;
594    const ConditionFunction1 cond_;
595    const StepFunction1 step_;
596    For1BodyFunction body_;
597    const TNode<Object> initial_arg0_;
598  };
599
600  ForBuilder1 For1(TNode<Number> initial_value, const ConditionFunction1& cond,
601                   const StepFunction1& step, TNode<Object> initial_arg0) {
602    return {this, initial_value, cond, step, initial_arg0};
603  }
604
605  ForBuilder1 For1ZeroUntil(TNode<Number> excluded_limit,
606                            TNode<Object> initial_arg0) {
607    TNode<Number> initial_value = ZeroConstant();
608    auto cond = [=](TNode<Number> i) {
609      return NumberLessThan(i, excluded_limit);
610    };
611    auto step = [=](TNode<Number> i) { return NumberAdd(i, OneConstant()); };
612    return {this, initial_value, cond, step, initial_arg0};
613  }
614
615  void ThrowIfNotCallable(TNode<Object> maybe_callable,
616                          FrameState frame_state) {
617    IfNot(ObjectIsCallable(maybe_callable))
618        .Then(_ {
619          JSCallRuntime2(Runtime::kThrowTypeError,
620                         NumberConstant(static_cast<double>(
621                             MessageTemplate::kCalledNonCallable)),
622                         maybe_callable, frame_state);
623          Unreachable();  // The runtime call throws unconditionally.
624        })
625        .ExpectTrue();
626  }
627
628  const FeedbackSource& feedback() const {
629    CallParameters const& p = CallParametersOf(node_ptr()->op());
630    return p.feedback();
631  }
632
633  int ArgumentCount() const { return JSCallNode{node_ptr()}.ArgumentCount(); }
634
635  TNode<Object> Argument(int index) const {
636    return TNode<Object>::UncheckedCast(JSCallNode{node_ptr()}.Argument(index));
637  }
638
639  template <typename T>
640  TNode<T> ArgumentAs(int index) const {
641    return TNode<T>::UncheckedCast(Argument(index));
642  }
643
644  TNode<Object> ArgumentOrNaN(int index) {
645    return TNode<Object>::UncheckedCast(
646        ArgumentCount() > index ? Argument(index) : NaNConstant());
647  }
648
649  TNode<Object> ArgumentOrUndefined(int index) {
650    return TNode<Object>::UncheckedCast(
651        ArgumentCount() > index ? Argument(index) : UndefinedConstant());
652  }
653
654  TNode<Number> ArgumentOrZero(int index) {
655    return TNode<Number>::UncheckedCast(
656        ArgumentCount() > index ? Argument(index) : ZeroConstant());
657  }
658
659  TNode<Context> ContextInput() const {
660    return TNode<Context>::UncheckedCast(
661        NodeProperties::GetContextInput(node_));
662  }
663
664  FrameState FrameStateInput() const {
665    return FrameState(NodeProperties::GetFrameStateInput(node_));
666  }
667
668  JSOperatorBuilder* javascript() const { return jsgraph()->javascript(); }
669
670  CompilationDependencies* dependencies() const { return dependencies_; }
671
672 private:
673  CompilationDependencies* const dependencies_;
674  Node* const node_;
675  CatchScope outermost_catch_scope_;
676  Node* outermost_handler_;
677  CatchScope* catch_scope_;
678  friend class CatchScope;
679};
680
681enum class ArrayReduceDirection { kLeft, kRight };
682enum class ArrayFindVariant { kFind, kFindIndex };
683enum class ArrayEverySomeVariant { kEvery, kSome };
684enum class ArrayIndexOfIncludesVariant { kIncludes, kIndexOf };
685
686// This subclass bundles functionality specific to reducing iterating array
687// builtins.
688class IteratingArrayBuiltinReducerAssembler : public JSCallReducerAssembler {
689 public:
690  IteratingArrayBuiltinReducerAssembler(JSCallReducer* reducer, Node* node)
691      : JSCallReducerAssembler(reducer, node) {
692    DCHECK(FLAG_turbo_inline_array_builtins);
693  }
694
695  TNode<Object> ReduceArrayPrototypeForEach(
696      MapInference* inference, const bool has_stability_dependency,
697      ElementsKind kind, const SharedFunctionInfoRef& shared);
698  TNode<Object> ReduceArrayPrototypeReduce(MapInference* inference,
699                                           const bool has_stability_dependency,
700                                           ElementsKind kind,
701                                           ArrayReduceDirection direction,
702                                           const SharedFunctionInfoRef& shared);
703  TNode<JSArray> ReduceArrayPrototypeMap(
704      MapInference* inference, const bool has_stability_dependency,
705      ElementsKind kind, const SharedFunctionInfoRef& shared,
706      const NativeContextRef& native_context);
707  TNode<JSArray> ReduceArrayPrototypeFilter(
708      MapInference* inference, const bool has_stability_dependency,
709      ElementsKind kind, const SharedFunctionInfoRef& shared,
710      const NativeContextRef& native_context);
711  TNode<Object> ReduceArrayPrototypeFind(MapInference* inference,
712                                         const bool has_stability_dependency,
713                                         ElementsKind kind,
714                                         const SharedFunctionInfoRef& shared,
715                                         const NativeContextRef& native_context,
716                                         ArrayFindVariant variant);
717  TNode<Boolean> ReduceArrayPrototypeEverySome(
718      MapInference* inference, const bool has_stability_dependency,
719      ElementsKind kind, const SharedFunctionInfoRef& shared,
720      const NativeContextRef& native_context, ArrayEverySomeVariant variant);
721  TNode<Object> ReduceArrayPrototypeIndexOfIncludes(
722      ElementsKind kind, ArrayIndexOfIncludesVariant variant);
723
724 private:
725  // Returns {index,value}. Assumes that the map has not changed, but possibly
726  // the length and backing store.
727  std::pair<TNode<Number>, TNode<Object>> SafeLoadElement(ElementsKind kind,
728                                                          TNode<JSArray> o,
729                                                          TNode<Number> index) {
730    // Make sure that the access is still in bounds, since the callback could
731    // have changed the array's size.
732    TNode<Number> length = LoadJSArrayLength(o, kind);
733    index = CheckBounds(index, length);
734
735    // Reload the elements pointer before calling the callback, since the
736    // previous callback might have resized the array causing the elements
737    // buffer to be re-allocated.
738    TNode<HeapObject> elements =
739        LoadField<HeapObject>(AccessBuilder::ForJSObjectElements(), o);
740    TNode<Object> value = LoadElement<Object>(
741        AccessBuilder::ForFixedArrayElement(kind), elements, index);
742    return std::make_pair(index, value);
743  }
744
745  template <typename... Vars>
746  TNode<Object> MaybeSkipHole(
747      TNode<Object> o, ElementsKind kind,
748      GraphAssemblerLabel<sizeof...(Vars)>* continue_label,
749      TNode<Vars>... vars) {
750    if (!IsHoleyElementsKind(kind)) return o;
751
752    std::array<MachineRepresentation, sizeof...(Vars)> reps = {
753        MachineRepresentationOf<Vars>::value...};
754    auto if_not_hole =
755        MakeLabel<sizeof...(Vars)>(reps, GraphAssemblerLabelType::kNonDeferred);
756    BranchWithHint(HoleCheck(kind, o), continue_label, &if_not_hole,
757                   BranchHint::kFalse, vars...);
758
759    // The contract is that we don't leak "the hole" into "user JavaScript",
760    // so we must rename the {element} here to explicitly exclude "the hole"
761    // from the type of {element}.
762    Bind(&if_not_hole);
763    return TypeGuardNonInternal(o);
764  }
765
766  TNode<Smi> LoadJSArrayLength(TNode<JSArray> array, ElementsKind kind) {
767    return LoadField<Smi>(AccessBuilder::ForJSArrayLength(kind), array);
768  }
769  void StoreJSArrayLength(TNode<JSArray> array, TNode<Number> value,
770                          ElementsKind kind) {
771    StoreField(AccessBuilder::ForJSArrayLength(kind), array, value);
772  }
773  void StoreFixedArrayBaseElement(TNode<FixedArrayBase> o, TNode<Number> index,
774                                  TNode<Object> v, ElementsKind kind) {
775    StoreElement(AccessBuilder::ForFixedArrayElement(kind), o, index, v);
776  }
777
778  TNode<FixedArrayBase> LoadElements(TNode<JSObject> o) {
779    return LoadField<FixedArrayBase>(AccessBuilder::ForJSObjectElements(), o);
780  }
781  TNode<Smi> LoadFixedArrayBaseLength(TNode<FixedArrayBase> o) {
782    return LoadField<Smi>(AccessBuilder::ForFixedArrayLength(), o);
783  }
784
785  TNode<Boolean> HoleCheck(ElementsKind kind, TNode<Object> v) {
786    return IsDoubleElementsKind(kind)
787               ? NumberIsFloat64Hole(TNode<Number>::UncheckedCast(v))
788               : IsTheHole(v);
789  }
790
791  TNode<Number> CheckFloat64Hole(TNode<Number> value,
792                                 CheckFloat64HoleMode mode) {
793    return AddNode<Number>(
794        graph()->NewNode(simplified()->CheckFloat64Hole(mode, feedback()),
795                         value, effect(), control()));
796  }
797
798  // May deopt for holey double elements.
799  TNode<Object> TryConvertHoleToUndefined(TNode<Object> value,
800                                          ElementsKind kind) {
801    DCHECK(IsHoleyElementsKind(kind));
802    if (kind == HOLEY_DOUBLE_ELEMENTS) {
803      // TODO(7409): avoid deopt if not all uses of value are truncated.
804      TNode<Number> number = TNode<Number>::UncheckedCast(value);
805      return CheckFloat64Hole(number, CheckFloat64HoleMode::kAllowReturnHole);
806    }
807
808    return ConvertTaggedHoleToUndefined(value);
809  }
810};
811
812class PromiseBuiltinReducerAssembler : public JSCallReducerAssembler {
813 public:
814  PromiseBuiltinReducerAssembler(JSCallReducer* reducer, Node* node,
815                                 JSHeapBroker* broker)
816      : JSCallReducerAssembler(reducer, node), broker_(broker) {
817    DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
818  }
819
820  TNode<Object> ReducePromiseConstructor(
821      const NativeContextRef& native_context);
822
823  int ConstructArity() const {
824    return JSConstructNode{node_ptr()}.ArgumentCount();
825  }
826
827  TNode<Object> TargetInput() const {
828    return JSConstructNode{node_ptr()}.target();
829  }
830
831  TNode<Object> NewTargetInput() const {
832    return JSConstructNode{node_ptr()}.new_target();
833  }
834
835 private:
836  TNode<JSPromise> CreatePromise(TNode<Context> context) {
837    return AddNode<JSPromise>(
838        graph()->NewNode(javascript()->CreatePromise(), context, effect()));
839  }
840
841  TNode<Context> CreateFunctionContext(const NativeContextRef& native_context,
842                                       TNode<Context> outer_context,
843                                       int slot_count) {
844    return AddNode<Context>(graph()->NewNode(
845        javascript()->CreateFunctionContext(
846            native_context.scope_info(),
847            slot_count - Context::MIN_CONTEXT_SLOTS, FUNCTION_SCOPE),
848        outer_context, effect(), control()));
849  }
850
851  void StoreContextSlot(TNode<Context> context, size_t slot_index,
852                        TNode<Object> value) {
853    StoreField(AccessBuilder::ForContextSlot(slot_index), context, value);
854  }
855
856  TNode<JSFunction> CreateClosureFromBuiltinSharedFunctionInfo(
857      SharedFunctionInfoRef shared, TNode<Context> context) {
858    DCHECK(shared.HasBuiltinId());
859    Handle<FeedbackCell> feedback_cell =
860        isolate()->factory()->many_closures_cell();
861    Callable const callable =
862        Builtins::CallableFor(isolate(), shared.builtin_id());
863    CodeTRef code = MakeRef(broker_, *callable.code());
864    return AddNode<JSFunction>(graph()->NewNode(
865        javascript()->CreateClosure(shared, code), HeapConstant(feedback_cell),
866        context, effect(), control()));
867  }
868
869  void CallPromiseExecutor(TNode<Object> executor, TNode<JSFunction> resolve,
870                           TNode<JSFunction> reject, FrameState frame_state) {
871    JSConstructNode n(node_ptr());
872    const ConstructParameters& p = n.Parameters();
873    FeedbackSource no_feedback_source{};
874    Node* no_feedback = UndefinedConstant();
875    MayThrow(_ {
876      return AddNode<Object>(graph()->NewNode(
877          javascript()->Call(JSCallNode::ArityForArgc(2), p.frequency(),
878                             no_feedback_source,
879                             ConvertReceiverMode::kNullOrUndefined),
880          executor, UndefinedConstant(), resolve, reject, no_feedback,
881          n.context(), frame_state, effect(), control()));
882    });
883  }
884
885  void CallPromiseReject(TNode<JSFunction> reject, TNode<Object> exception,
886                         FrameState frame_state) {
887    JSConstructNode n(node_ptr());
888    const ConstructParameters& p = n.Parameters();
889    FeedbackSource no_feedback_source{};
890    Node* no_feedback = UndefinedConstant();
891    MayThrow(_ {
892      return AddNode<Object>(graph()->NewNode(
893          javascript()->Call(JSCallNode::ArityForArgc(1), p.frequency(),
894                             no_feedback_source,
895                             ConvertReceiverMode::kNullOrUndefined),
896          reject, UndefinedConstant(), exception, no_feedback, n.context(),
897          frame_state, effect(), control()));
898    });
899  }
900
901  JSHeapBroker* const broker_;
902};
903
904class FastApiCallReducerAssembler : public JSCallReducerAssembler {
905 public:
906  FastApiCallReducerAssembler(
907      JSCallReducer* reducer, Node* node,
908      const FunctionTemplateInfoRef function_template_info,
909      const FastApiCallFunctionVector& c_candidate_functions, Node* receiver,
910      Node* holder, const SharedFunctionInfoRef shared, Node* target,
911      const int arity, Node* effect)
912      : JSCallReducerAssembler(reducer, node),
913        c_candidate_functions_(c_candidate_functions),
914        function_template_info_(function_template_info),
915        receiver_(receiver),
916        holder_(holder),
917        shared_(shared),
918        target_(target),
919        arity_(arity) {
920    DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
921    CHECK_GT(c_candidate_functions.size(), 0);
922    InitializeEffectControl(effect, NodeProperties::GetControlInput(node));
923  }
924
925  TNode<Object> ReduceFastApiCall() {
926    JSCallNode n(node_ptr());
927
928    // C arguments include the receiver at index 0. Thus C index 1 corresponds
929    // to the JS argument 0, etc.
930    // All functions in c_candidate_functions_ have the same number of
931    // arguments, so extract c_argument_count from the first function.
932    const int c_argument_count =
933        static_cast<int>(c_candidate_functions_[0].signature->ArgumentCount());
934    CHECK_GE(c_argument_count, kReceiver);
935
936    int cursor = 0;
937    base::SmallVector<Node*, kInlineSize> inputs(c_argument_count + arity_ +
938                                                 kExtraInputsCount);
939    inputs[cursor++] = n.receiver();
940
941    // TODO(turbofan): Consider refactoring CFunctionInfo to distinguish
942    // between receiver and arguments, simplifying this (and related) spots.
943    int js_args_count = c_argument_count - kReceiver;
944    for (int i = 0; i < js_args_count; ++i) {
945      if (i < n.ArgumentCount()) {
946        inputs[cursor++] = n.Argument(i);
947      } else {
948        inputs[cursor++] = UndefinedConstant();
949      }
950    }
951
952    // Here we add the arguments for the slow call, which will be
953    // reconstructed at a later phase. Those are effectively the same
954    // arguments as for the fast call, but we want to have them as
955    // separate inputs, so that SimplifiedLowering can provide the best
956    // possible UseInfos for each of them. The inputs to FastApiCall
957    // look like:
958    // [fast callee, receiver, ... C arguments,
959    // call code, external constant for function, argc, call handler info data,
960    // holder, receiver, ... JS arguments, context, new frame state]
961    CallHandlerInfoRef call_handler_info = *function_template_info_.call_code();
962    Callable call_api_callback = CodeFactory::CallApiCallback(isolate());
963    CallInterfaceDescriptor cid = call_api_callback.descriptor();
964    CallDescriptor* call_descriptor =
965        Linkage::GetStubCallDescriptor(graph()->zone(), cid, arity_ + kReceiver,
966                                       CallDescriptor::kNeedsFrameState);
967    ApiFunction api_function(call_handler_info.callback());
968    ExternalReference function_reference = ExternalReference::Create(
969        isolate(), &api_function, ExternalReference::DIRECT_API_CALL,
970        function_template_info_.c_functions().data(),
971        function_template_info_.c_signatures().data(),
972        static_cast<unsigned>(function_template_info_.c_functions().size()));
973
974    Node* continuation_frame_state =
975        CreateGenericLazyDeoptContinuationFrameState(
976            jsgraph(), shared_, target_, ContextInput(), receiver_,
977            FrameStateInput());
978
979    inputs[cursor++] = HeapConstant(call_api_callback.code());
980    inputs[cursor++] = ExternalConstant(function_reference);
981    inputs[cursor++] = NumberConstant(arity_);
982    inputs[cursor++] = Constant(call_handler_info.data());
983    inputs[cursor++] = holder_;
984    inputs[cursor++] = receiver_;
985    for (int i = 0; i < arity_; ++i) {
986      inputs[cursor++] = Argument(i);
987    }
988    inputs[cursor++] = ContextInput();
989    inputs[cursor++] = continuation_frame_state;
990    inputs[cursor++] = effect();
991    inputs[cursor++] = control();
992
993    DCHECK_EQ(cursor, c_argument_count + arity_ + kExtraInputsCount);
994
995    return FastApiCall(call_descriptor, inputs.begin(), inputs.size());
996  }
997
998 private:
999  static constexpr int kSlowTarget = 1;
1000  static constexpr int kEffectAndControl = 2;
1001  static constexpr int kContextAndFrameState = 2;
1002  static constexpr int kCallCodeDataAndArgc = 3;
1003  static constexpr int kHolder = 1, kReceiver = 1;
1004  static constexpr int kExtraInputsCount =
1005      kSlowTarget + kEffectAndControl + kContextAndFrameState +
1006      kCallCodeDataAndArgc + kHolder + kReceiver;
1007  static constexpr int kInlineSize = 12;
1008
1009  TNode<Object> FastApiCall(CallDescriptor* descriptor, Node** inputs,
1010                            size_t inputs_size) {
1011    return AddNode<Object>(
1012        graph()->NewNode(simplified()->FastApiCall(c_candidate_functions_,
1013                                                   feedback(), descriptor),
1014                         static_cast<int>(inputs_size), inputs));
1015  }
1016
1017  const FastApiCallFunctionVector c_candidate_functions_;
1018  const FunctionTemplateInfoRef function_template_info_;
1019  Node* const receiver_;
1020  Node* const holder_;
1021  const SharedFunctionInfoRef shared_;
1022  Node* const target_;
1023  const int arity_;
1024};
1025
1026TNode<Number> JSCallReducerAssembler::SpeculativeToNumber(
1027    TNode<Object> value, NumberOperationHint hint) {
1028  return AddNode<Number>(
1029      graph()->NewNode(simplified()->SpeculativeToNumber(hint, feedback()),
1030                       value, effect(), control()));
1031}
1032
1033TNode<Smi> JSCallReducerAssembler::CheckSmi(TNode<Object> value) {
1034  return AddNode<Smi>(graph()->NewNode(simplified()->CheckSmi(feedback()),
1035                                       value, effect(), control()));
1036}
1037
1038TNode<String> JSCallReducerAssembler::CheckString(TNode<Object> value) {
1039  return AddNode<String>(graph()->NewNode(simplified()->CheckString(feedback()),
1040                                          value, effect(), control()));
1041}
1042
1043TNode<Number> JSCallReducerAssembler::CheckBounds(TNode<Number> value,
1044                                                  TNode<Number> limit) {
1045  return AddNode<Number>(graph()->NewNode(simplified()->CheckBounds(feedback()),
1046                                          value, limit, effect(), control()));
1047}
1048
1049TNode<Smi> JSCallReducerAssembler::TypeGuardUnsignedSmall(TNode<Object> value) {
1050  return TNode<Smi>::UncheckedCast(TypeGuard(Type::UnsignedSmall(), value));
1051}
1052
1053TNode<Object> JSCallReducerAssembler::TypeGuardNonInternal(
1054    TNode<Object> value) {
1055  return TNode<Object>::UncheckedCast(TypeGuard(Type::NonInternal(), value));
1056}
1057
1058TNode<Number> JSCallReducerAssembler::TypeGuardFixedArrayLength(
1059    TNode<Object> value) {
1060  DCHECK(TypeCache::Get()->kFixedDoubleArrayLengthType.Is(
1061      TypeCache::Get()->kFixedArrayLengthType));
1062  return TNode<Number>::UncheckedCast(
1063      TypeGuard(TypeCache::Get()->kFixedArrayLengthType, value));
1064}
1065
1066TNode<Object> JSCallReducerAssembler::Call4(
1067    const Callable& callable, TNode<Context> context, TNode<Object> arg0,
1068    TNode<Object> arg1, TNode<Object> arg2, TNode<Object> arg3) {
1069  // TODO(jgruber): Make this more generic. Currently it's fitted to its single
1070  // callsite.
1071  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1072      graph()->zone(), callable.descriptor(),
1073      callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags,
1074      Operator::kEliminatable);
1075
1076  return TNode<Object>::UncheckedCast(Call(desc, HeapConstant(callable.code()),
1077                                           arg0, arg1, arg2, arg3, context));
1078}
1079
1080TNode<Object> JSCallReducerAssembler::JSCall3(
1081    TNode<Object> function, TNode<Object> this_arg, TNode<Object> arg0,
1082    TNode<Object> arg1, TNode<Object> arg2, FrameState frame_state) {
1083  JSCallNode n(node_ptr());
1084  CallParameters const& p = n.Parameters();
1085  return MayThrow(_ {
1086    return AddNode<Object>(graph()->NewNode(
1087        javascript()->Call(JSCallNode::ArityForArgc(3), p.frequency(),
1088                           p.feedback(), ConvertReceiverMode::kAny,
1089                           p.speculation_mode(),
1090                           CallFeedbackRelation::kUnrelated),
1091        function, this_arg, arg0, arg1, arg2, n.feedback_vector(),
1092        ContextInput(), frame_state, effect(), control()));
1093  });
1094}
1095
1096TNode<Object> JSCallReducerAssembler::JSCall4(
1097    TNode<Object> function, TNode<Object> this_arg, TNode<Object> arg0,
1098    TNode<Object> arg1, TNode<Object> arg2, TNode<Object> arg3,
1099    FrameState frame_state) {
1100  JSCallNode n(node_ptr());
1101  CallParameters const& p = n.Parameters();
1102  return MayThrow(_ {
1103    return AddNode<Object>(graph()->NewNode(
1104        javascript()->Call(JSCallNode::ArityForArgc(4), p.frequency(),
1105                           p.feedback(), ConvertReceiverMode::kAny,
1106                           p.speculation_mode(),
1107                           CallFeedbackRelation::kUnrelated),
1108        function, this_arg, arg0, arg1, arg2, arg3, n.feedback_vector(),
1109        ContextInput(), frame_state, effect(), control()));
1110  });
1111}
1112
1113TNode<Object> JSCallReducerAssembler::JSCallRuntime2(
1114    Runtime::FunctionId function_id, TNode<Object> arg0, TNode<Object> arg1,
1115    FrameState frame_state) {
1116  return MayThrow(_ {
1117    return AddNode<Object>(
1118        graph()->NewNode(javascript()->CallRuntime(function_id, 2), arg0, arg1,
1119                         ContextInput(), frame_state, effect(), control()));
1120  });
1121}
1122
1123TNode<Object> JSCallReducerAssembler::CopyNode() {
1124  return MayThrow(_ {
1125    Node* copy = graph()->CloneNode(node_ptr());
1126    NodeProperties::ReplaceEffectInput(copy, effect());
1127    NodeProperties::ReplaceControlInput(copy, control());
1128    return AddNode<Object>(copy);
1129  });
1130}
1131
1132TNode<JSArray> JSCallReducerAssembler::CreateArrayNoThrow(
1133    TNode<Object> ctor, TNode<Number> size, FrameState frame_state) {
1134  return AddNode<JSArray>(
1135      graph()->NewNode(javascript()->CreateArray(1, base::nullopt), ctor, ctor,
1136                       size, ContextInput(), frame_state, effect(), control()));
1137}
1138TNode<JSArray> JSCallReducerAssembler::AllocateEmptyJSArray(
1139    ElementsKind kind, const NativeContextRef& native_context) {
1140  // TODO(jgruber): Port AllocationBuilder to JSGraphAssembler.
1141  MapRef map = native_context.GetInitialJSArrayMap(kind);
1142
1143  AllocationBuilder ab(jsgraph(), effect(), control());
1144  ab.Allocate(map.instance_size(), AllocationType::kYoung, Type::Array());
1145  ab.Store(AccessBuilder::ForMap(), map);
1146  Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
1147  ab.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
1148           empty_fixed_array);
1149  ab.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
1150  ab.Store(AccessBuilder::ForJSArrayLength(kind), jsgraph()->ZeroConstant());
1151  for (int i = 0; i < map.GetInObjectProperties(); ++i) {
1152    ab.Store(AccessBuilder::ForJSObjectInObjectProperty(map, i),
1153             jsgraph()->UndefinedConstant());
1154  }
1155  Node* result = ab.Finish();
1156  InitializeEffectControl(result, control());
1157  return TNode<JSArray>::UncheckedCast(result);
1158}
1159
1160TNode<Object> JSCallReducerAssembler::ReduceMathUnary(const Operator* op) {
1161  TNode<Object> input = Argument(0);
1162  TNode<Number> input_as_number = SpeculativeToNumber(input);
1163  return TNode<Object>::UncheckedCast(graph()->NewNode(op, input_as_number));
1164}
1165
1166TNode<Object> JSCallReducerAssembler::ReduceMathBinary(const Operator* op) {
1167  TNode<Object> left = Argument(0);
1168  TNode<Object> right = ArgumentOrNaN(1);
1169  TNode<Number> left_number = SpeculativeToNumber(left);
1170  TNode<Number> right_number = SpeculativeToNumber(right);
1171  return TNode<Object>::UncheckedCast(
1172      graph()->NewNode(op, left_number, right_number));
1173}
1174
1175TNode<String> JSCallReducerAssembler::ReduceStringPrototypeSubstring() {
1176  TNode<Object> receiver = ReceiverInput();
1177  TNode<Object> start = Argument(0);
1178  TNode<Object> end = ArgumentOrUndefined(1);
1179
1180  TNode<String> receiver_string = CheckString(receiver);
1181  TNode<Number> start_smi = CheckSmi(start);
1182
1183  TNode<Number> length = StringLength(receiver_string);
1184
1185  TNode<Number> end_smi = SelectIf<Number>(IsUndefined(end))
1186                              .Then(_ { return length; })
1187                              .Else(_ { return CheckSmi(end); })
1188                              .ExpectFalse()
1189                              .Value();
1190
1191  TNode<Number> zero = TNode<Number>::UncheckedCast(ZeroConstant());
1192  TNode<Number> finalStart = NumberMin(NumberMax(start_smi, zero), length);
1193  TNode<Number> finalEnd = NumberMin(NumberMax(end_smi, zero), length);
1194  TNode<Number> from = NumberMin(finalStart, finalEnd);
1195  TNode<Number> to = NumberMax(finalStart, finalEnd);
1196
1197  return StringSubstring(receiver_string, from, to);
1198}
1199
1200TNode<Boolean> JSCallReducerAssembler::ReduceStringPrototypeStartsWith(
1201    const StringRef& search_element_string) {
1202  TNode<Object> receiver = ReceiverInput();
1203  TNode<Object> start = ArgumentOrZero(1);
1204
1205  TNode<String> receiver_string = CheckString(receiver);
1206  TNode<Smi> start_smi = CheckSmi(start);
1207  TNode<Number> length = StringLength(receiver_string);
1208
1209  TNode<Number> zero = ZeroConstant();
1210  TNode<Number> clamped_start = NumberMin(NumberMax(start_smi, zero), length);
1211
1212  int search_string_length = search_element_string.length().value();
1213  DCHECK(search_string_length <= JSCallReducer::kMaxInlineMatchSequence);
1214
1215  auto out = MakeLabel(MachineRepresentation::kTagged);
1216
1217  auto search_string_too_long =
1218      NumberLessThan(NumberSubtract(length, clamped_start),
1219                     NumberConstant(search_string_length));
1220
1221  GotoIf(search_string_too_long, &out, BranchHint::kFalse, FalseConstant());
1222
1223  STATIC_ASSERT(String::kMaxLength <= kSmiMaxValue);
1224
1225  for (int i = 0; i < search_string_length; i++) {
1226    TNode<Number> k = NumberConstant(i);
1227    TNode<Number> receiver_string_position = TNode<Number>::UncheckedCast(
1228        TypeGuard(Type::UnsignedSmall(), NumberAdd(k, clamped_start)));
1229    Node* receiver_string_char =
1230        StringCharCodeAt(receiver_string, receiver_string_position);
1231    Node* search_string_char =
1232        jsgraph()->Constant(search_element_string.GetChar(i).value());
1233    auto is_equal = graph()->NewNode(simplified()->NumberEqual(),
1234                                     search_string_char, receiver_string_char);
1235    GotoIfNot(is_equal, &out, FalseConstant());
1236  }
1237
1238  Goto(&out, TrueConstant());
1239
1240  Bind(&out);
1241  return out.PhiAt<Boolean>(0);
1242}
1243
1244TNode<Boolean> JSCallReducerAssembler::ReduceStringPrototypeStartsWith() {
1245  TNode<Object> receiver = ReceiverInput();
1246  TNode<Object> search_element = ArgumentOrUndefined(0);
1247  TNode<Object> start = ArgumentOrZero(1);
1248
1249  TNode<String> receiver_string = CheckString(receiver);
1250  TNode<String> search_string = CheckString(search_element);
1251  TNode<Smi> start_smi = CheckSmi(start);
1252  TNode<Number> length = StringLength(receiver_string);
1253
1254  TNode<Number> zero = ZeroConstant();
1255  TNode<Number> clamped_start = NumberMin(NumberMax(start_smi, zero), length);
1256
1257  TNode<Number> search_string_length = StringLength(search_string);
1258
1259  auto out = MakeLabel(MachineRepresentation::kTagged);
1260
1261  auto search_string_too_long = NumberLessThan(
1262      NumberSubtract(length, clamped_start), search_string_length);
1263
1264  GotoIf(search_string_too_long, &out, BranchHint::kFalse, FalseConstant());
1265
1266  STATIC_ASSERT(String::kMaxLength <= kSmiMaxValue);
1267
1268  ForZeroUntil(search_string_length).Do([&](TNode<Number> k) {
1269    TNode<Number> receiver_string_position = TNode<Number>::UncheckedCast(
1270        TypeGuard(Type::UnsignedSmall(), NumberAdd(k, clamped_start)));
1271    Node* receiver_string_char =
1272        StringCharCodeAt(receiver_string, receiver_string_position);
1273    Node* search_string_char = StringCharCodeAt(search_string, k);
1274    auto is_equal = graph()->NewNode(simplified()->NumberEqual(),
1275                                     receiver_string_char, search_string_char);
1276    GotoIfNot(is_equal, &out, FalseConstant());
1277  });
1278
1279  Goto(&out, TrueConstant());
1280
1281  Bind(&out);
1282  return out.PhiAt<Boolean>(0);
1283}
1284
1285TNode<String> JSCallReducerAssembler::ReduceStringPrototypeSlice() {
1286  TNode<Object> receiver = ReceiverInput();
1287  TNode<Object> start = Argument(0);
1288  TNode<Object> end = ArgumentOrUndefined(1);
1289
1290  TNode<String> receiver_string = CheckString(receiver);
1291  TNode<Number> start_smi = CheckSmi(start);
1292
1293  TNode<Number> length = StringLength(receiver_string);
1294
1295  TNode<Number> end_smi = SelectIf<Number>(IsUndefined(end))
1296                              .Then(_ { return length; })
1297                              .Else(_ { return CheckSmi(end); })
1298                              .ExpectFalse()
1299                              .Value();
1300
1301  TNode<Number> zero = TNode<Number>::UncheckedCast(ZeroConstant());
1302  TNode<Number> from_untyped =
1303      SelectIf<Number>(NumberLessThan(start_smi, zero))
1304          .Then(_ { return NumberMax(NumberAdd(length, start_smi), zero); })
1305          .Else(_ { return NumberMin(start_smi, length); })
1306          .ExpectFalse()
1307          .Value();
1308  // {from} is always in non-negative Smi range, but our typer cannot figure
1309  // that out yet.
1310  TNode<Smi> from = TypeGuardUnsignedSmall(from_untyped);
1311
1312  TNode<Number> to_untyped =
1313      SelectIf<Number>(NumberLessThan(end_smi, zero))
1314          .Then(_ { return NumberMax(NumberAdd(length, end_smi), zero); })
1315          .Else(_ { return NumberMin(end_smi, length); })
1316          .ExpectFalse()
1317          .Value();
1318  // {to} is always in non-negative Smi range, but our typer cannot figure that
1319  // out yet.
1320  TNode<Smi> to = TypeGuardUnsignedSmall(to_untyped);
1321
1322  return SelectIf<String>(NumberLessThan(from, to))
1323      .Then(_ { return StringSubstring(receiver_string, from, to); })
1324      .Else(_ { return EmptyStringConstant(); })
1325      .ExpectTrue()
1326      .Value();
1327}
1328
1329namespace {
1330
1331struct ForEachFrameStateParams {
1332  JSGraph* jsgraph;
1333  SharedFunctionInfoRef shared;
1334  TNode<Context> context;
1335  TNode<Object> target;
1336  FrameState outer_frame_state;
1337  TNode<Object> receiver;
1338  TNode<Object> callback;
1339  TNode<Object> this_arg;
1340  TNode<Object> original_length;
1341};
1342
1343FrameState ForEachLoopLazyFrameState(const ForEachFrameStateParams& params,
1344                                     TNode<Object> k) {
1345  Builtin builtin = Builtin::kArrayForEachLoopLazyDeoptContinuation;
1346  Node* checkpoint_params[] = {params.receiver, params.callback,
1347                               params.this_arg, k, params.original_length};
1348  return CreateJavaScriptBuiltinContinuationFrameState(
1349      params.jsgraph, params.shared, builtin, params.target, params.context,
1350      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1351      ContinuationFrameStateMode::LAZY);
1352}
1353
1354FrameState ForEachLoopEagerFrameState(const ForEachFrameStateParams& params,
1355                                      TNode<Object> k) {
1356  Builtin builtin = Builtin::kArrayForEachLoopEagerDeoptContinuation;
1357  Node* checkpoint_params[] = {params.receiver, params.callback,
1358                               params.this_arg, k, params.original_length};
1359  return CreateJavaScriptBuiltinContinuationFrameState(
1360      params.jsgraph, params.shared, builtin, params.target, params.context,
1361      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1362      ContinuationFrameStateMode::EAGER);
1363}
1364
1365}  // namespace
1366
1367TNode<Object>
1368IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeForEach(
1369    MapInference* inference, const bool has_stability_dependency,
1370    ElementsKind kind, const SharedFunctionInfoRef& shared) {
1371  FrameState outer_frame_state = FrameStateInput();
1372  TNode<Context> context = ContextInput();
1373  TNode<Object> target = TargetInput();
1374  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
1375  TNode<Object> fncallback = ArgumentOrUndefined(0);
1376  TNode<Object> this_arg = ArgumentOrUndefined(1);
1377
1378  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);
1379
1380  ForEachFrameStateParams frame_state_params{
1381      jsgraph(), shared,     context,  target,         outer_frame_state,
1382      receiver,  fncallback, this_arg, original_length};
1383
1384  ThrowIfNotCallable(fncallback, ForEachLoopLazyFrameState(frame_state_params,
1385                                                           ZeroConstant()));
1386
1387  ForZeroUntil(original_length).Do([&](TNode<Number> k) {
1388    Checkpoint(ForEachLoopEagerFrameState(frame_state_params, k));
1389
1390    // Deopt if the map has changed during the iteration.
1391    MaybeInsertMapChecks(inference, has_stability_dependency);
1392
1393    TNode<Object> element;
1394    std::tie(k, element) = SafeLoadElement(kind, receiver, k);
1395
1396    auto continue_label = MakeLabel();
1397    element = MaybeSkipHole(element, kind, &continue_label);
1398
1399    TNode<Number> next_k = NumberAdd(k, OneConstant());
1400    JSCall3(fncallback, this_arg, element, k, receiver,
1401            ForEachLoopLazyFrameState(frame_state_params, next_k));
1402
1403    Goto(&continue_label);
1404    Bind(&continue_label);
1405  });
1406
1407  return UndefinedConstant();
1408}
1409
1410namespace {
1411
1412struct ReduceFrameStateParams {
1413  JSGraph* jsgraph;
1414  SharedFunctionInfoRef shared;
1415  ArrayReduceDirection direction;
1416  TNode<Context> context;
1417  TNode<Object> target;
1418  FrameState outer_frame_state;
1419};
1420
1421FrameState ReducePreLoopLazyFrameState(const ReduceFrameStateParams& params,
1422                                       TNode<Object> receiver,
1423                                       TNode<Object> callback, TNode<Object> k,
1424                                       TNode<Number> original_length) {
1425  Builtin builtin = (params.direction == ArrayReduceDirection::kLeft)
1426                        ? Builtin::kArrayReduceLoopLazyDeoptContinuation
1427                        : Builtin::kArrayReduceRightLoopLazyDeoptContinuation;
1428  Node* checkpoint_params[] = {receiver, callback, k, original_length};
1429  return CreateJavaScriptBuiltinContinuationFrameState(
1430      params.jsgraph, params.shared, builtin, params.target, params.context,
1431      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1432      ContinuationFrameStateMode::LAZY);
1433}
1434
1435FrameState ReducePreLoopEagerFrameState(const ReduceFrameStateParams& params,
1436                                        TNode<Object> receiver,
1437                                        TNode<Object> callback,
1438                                        TNode<Number> original_length) {
1439  Builtin builtin =
1440      (params.direction == ArrayReduceDirection::kLeft)
1441          ? Builtin::kArrayReducePreLoopEagerDeoptContinuation
1442          : Builtin::kArrayReduceRightPreLoopEagerDeoptContinuation;
1443  Node* checkpoint_params[] = {receiver, callback, original_length};
1444  return CreateJavaScriptBuiltinContinuationFrameState(
1445      params.jsgraph, params.shared, builtin, params.target, params.context,
1446      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1447      ContinuationFrameStateMode::EAGER);
1448}
1449
1450FrameState ReduceLoopLazyFrameState(const ReduceFrameStateParams& params,
1451                                    TNode<Object> receiver,
1452                                    TNode<Object> callback, TNode<Object> k,
1453                                    TNode<Number> original_length) {
1454  Builtin builtin = (params.direction == ArrayReduceDirection::kLeft)
1455                        ? Builtin::kArrayReduceLoopLazyDeoptContinuation
1456                        : Builtin::kArrayReduceRightLoopLazyDeoptContinuation;
1457  Node* checkpoint_params[] = {receiver, callback, k, original_length};
1458  return CreateJavaScriptBuiltinContinuationFrameState(
1459      params.jsgraph, params.shared, builtin, params.target, params.context,
1460      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1461      ContinuationFrameStateMode::LAZY);
1462}
1463
1464FrameState ReduceLoopEagerFrameState(const ReduceFrameStateParams& params,
1465                                     TNode<Object> receiver,
1466                                     TNode<Object> callback, TNode<Object> k,
1467                                     TNode<Number> original_length,
1468                                     TNode<Object> accumulator) {
1469  Builtin builtin = (params.direction == ArrayReduceDirection::kLeft)
1470                        ? Builtin::kArrayReduceLoopEagerDeoptContinuation
1471                        : Builtin::kArrayReduceRightLoopEagerDeoptContinuation;
1472  Node* checkpoint_params[] = {receiver, callback, k, original_length,
1473                               accumulator};
1474  return CreateJavaScriptBuiltinContinuationFrameState(
1475      params.jsgraph, params.shared, builtin, params.target, params.context,
1476      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1477      ContinuationFrameStateMode::EAGER);
1478}
1479
1480}  // namespace
1481
1482TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce(
1483    MapInference* inference, const bool has_stability_dependency,
1484    ElementsKind kind, ArrayReduceDirection direction,
1485    const SharedFunctionInfoRef& shared) {
1486  FrameState outer_frame_state = FrameStateInput();
1487  TNode<Context> context = ContextInput();
1488  TNode<Object> target = TargetInput();
1489  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
1490  TNode<Object> fncallback = ArgumentOrUndefined(0);
1491
1492  ReduceFrameStateParams frame_state_params{
1493      jsgraph(), shared, direction, context, target, outer_frame_state};
1494
1495  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);
1496
1497  // Set up variable behavior depending on the reduction kind (left/right).
1498  TNode<Number> k;
1499  StepFunction1 step;
1500  ConditionFunction1 cond;
1501  TNode<Number> zero = ZeroConstant();
1502  TNode<Number> one = OneConstant();
1503  if (direction == ArrayReduceDirection::kLeft) {
1504    k = zero;
1505    step = [&](TNode<Number> i) { return NumberAdd(i, one); };
1506    cond = [&](TNode<Number> i) { return NumberLessThan(i, original_length); };
1507  } else {
1508    k = NumberSubtract(original_length, one);
1509    step = [&](TNode<Number> i) { return NumberSubtract(i, one); };
1510    cond = [&](TNode<Number> i) { return NumberLessThanOrEqual(zero, i); };
1511  }
1512
1513  ThrowIfNotCallable(
1514      fncallback, ReducePreLoopLazyFrameState(frame_state_params, receiver,
1515                                              fncallback, k, original_length));
1516
1517  // Set initial accumulator value.
1518  TNode<Object> accumulator;
1519  if (ArgumentCount() > 1) {
1520    accumulator = Argument(1);  // Initial value specified by the user.
1521  } else {
1522    // The initial value was not specified by the user. In this case, the first
1523    // (or last in the case of reduceRight) non-holey value of the array is
1524    // used. Loop until we find it. If not found, trigger a deopt.
1525    // TODO(jgruber): The deopt does not seem necessary. Instead we could simply
1526    // throw the TypeError here from optimized code.
1527    auto found_initial_element = MakeLabel(MachineRepresentation::kTagged,
1528                                           MachineRepresentation::kTagged);
1529    Forever(k, step).Do([&](TNode<Number> k) {
1530      Checkpoint(ReducePreLoopEagerFrameState(frame_state_params, receiver,
1531                                              fncallback, original_length));
1532      CheckIf(cond(k), DeoptimizeReason::kNoInitialElement);
1533
1534      TNode<Object> element;
1535      std::tie(k, element) = SafeLoadElement(kind, receiver, k);
1536
1537      auto continue_label = MakeLabel();
1538      GotoIf(HoleCheck(kind, element), &continue_label);
1539      Goto(&found_initial_element, k, TypeGuardNonInternal(element));
1540
1541      Bind(&continue_label);
1542    });
1543    Unreachable();  // The loop is exited either by deopt or a jump to below.
1544
1545    // TODO(jgruber): This manual fiddling with blocks could be avoided by
1546    // implementing a `break` mechanic for loop builders.
1547    Bind(&found_initial_element);
1548    k = step(found_initial_element.PhiAt<Number>(0));
1549    accumulator = found_initial_element.PhiAt<Object>(1);
1550  }
1551
1552  TNode<Object> result =
1553      For1(k, cond, step, accumulator)
1554          .Do([&](TNode<Number> k, TNode<Object>* accumulator) {
1555            Checkpoint(ReduceLoopEagerFrameState(frame_state_params, receiver,
1556                                                 fncallback, k, original_length,
1557                                                 *accumulator));
1558
1559            // Deopt if the map has changed during the iteration.
1560            MaybeInsertMapChecks(inference, has_stability_dependency);
1561
1562            TNode<Object> element;
1563            std::tie(k, element) = SafeLoadElement(kind, receiver, k);
1564
1565            auto continue_label = MakeLabel(MachineRepresentation::kTagged);
1566            element =
1567                MaybeSkipHole(element, kind, &continue_label, *accumulator);
1568
1569            TNode<Number> next_k = step(k);
1570            TNode<Object> next_accumulator = JSCall4(
1571                fncallback, UndefinedConstant(), *accumulator, element, k,
1572                receiver,
1573                ReduceLoopLazyFrameState(frame_state_params, receiver,
1574                                         fncallback, next_k, original_length));
1575            Goto(&continue_label, next_accumulator);
1576
1577            Bind(&continue_label);
1578            *accumulator = continue_label.PhiAt<Object>(0);
1579          })
1580          .Value();
1581
1582  return result;
1583}
1584
1585namespace {
1586
1587struct MapFrameStateParams {
1588  JSGraph* jsgraph;
1589  SharedFunctionInfoRef shared;
1590  TNode<Context> context;
1591  TNode<Object> target;
1592  FrameState outer_frame_state;
1593  TNode<Object> receiver;
1594  TNode<Object> callback;
1595  TNode<Object> this_arg;
1596  base::Optional<TNode<JSArray>> a;
1597  TNode<Object> original_length;
1598};
1599
1600FrameState MapPreLoopLazyFrameState(const MapFrameStateParams& params) {
1601  DCHECK(!params.a);
1602  Node* checkpoint_params[] = {params.receiver, params.callback,
1603                               params.this_arg, params.original_length};
1604  return CreateJavaScriptBuiltinContinuationFrameState(
1605      params.jsgraph, params.shared,
1606      Builtin::kArrayMapPreLoopLazyDeoptContinuation, params.target,
1607      params.context, checkpoint_params, arraysize(checkpoint_params),
1608      params.outer_frame_state, ContinuationFrameStateMode::LAZY);
1609}
1610
1611FrameState MapLoopLazyFrameState(const MapFrameStateParams& params,
1612                                 TNode<Number> k) {
1613  Node* checkpoint_params[] = {
1614      params.receiver,       params.callback, params.this_arg, *params.a, k,
1615      params.original_length};
1616  return CreateJavaScriptBuiltinContinuationFrameState(
1617      params.jsgraph, params.shared,
1618      Builtin::kArrayMapLoopLazyDeoptContinuation, params.target,
1619      params.context, checkpoint_params, arraysize(checkpoint_params),
1620      params.outer_frame_state, ContinuationFrameStateMode::LAZY);
1621}
1622
1623FrameState MapLoopEagerFrameState(const MapFrameStateParams& params,
1624                                  TNode<Number> k) {
1625  Node* checkpoint_params[] = {
1626      params.receiver,       params.callback, params.this_arg, *params.a, k,
1627      params.original_length};
1628  return CreateJavaScriptBuiltinContinuationFrameState(
1629      params.jsgraph, params.shared,
1630      Builtin::kArrayMapLoopEagerDeoptContinuation, params.target,
1631      params.context, checkpoint_params, arraysize(checkpoint_params),
1632      params.outer_frame_state, ContinuationFrameStateMode::EAGER);
1633}
1634
1635}  // namespace
1636
1637TNode<JSArray> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeMap(
1638    MapInference* inference, const bool has_stability_dependency,
1639    ElementsKind kind, const SharedFunctionInfoRef& shared,
1640    const NativeContextRef& native_context) {
1641  FrameState outer_frame_state = FrameStateInput();
1642  TNode<Context> context = ContextInput();
1643  TNode<Object> target = TargetInput();
1644  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
1645  TNode<Object> fncallback = ArgumentOrUndefined(0);
1646  TNode<Object> this_arg = ArgumentOrUndefined(1);
1647
1648  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);
1649
1650  // If the array length >= kMaxFastArrayLength, then CreateArray
1651  // will create a dictionary. We should deopt in this case, and make sure
1652  // not to attempt inlining again.
1653  original_length = CheckBounds(original_length,
1654                                NumberConstant(JSArray::kMaxFastArrayLength));
1655
1656  // Even though {JSCreateArray} is not marked as {kNoThrow}, we can elide the
1657  // exceptional projections because it cannot throw with the given
1658  // parameters.
1659  TNode<Object> array_ctor =
1660      Constant(native_context.GetInitialJSArrayMap(kind).GetConstructor());
1661
1662  MapFrameStateParams frame_state_params{
1663      jsgraph(), shared,     context,  target,       outer_frame_state,
1664      receiver,  fncallback, this_arg, {} /* TBD */, original_length};
1665
1666  TNode<JSArray> a =
1667      CreateArrayNoThrow(array_ctor, original_length,
1668                         MapPreLoopLazyFrameState(frame_state_params));
1669  frame_state_params.a = a;
1670
1671  ThrowIfNotCallable(fncallback,
1672                     MapLoopLazyFrameState(frame_state_params, ZeroConstant()));
1673
1674  ForZeroUntil(original_length).Do([&](TNode<Number> k) {
1675    Checkpoint(MapLoopEagerFrameState(frame_state_params, k));
1676    MaybeInsertMapChecks(inference, has_stability_dependency);
1677
1678    TNode<Object> element;
1679    std::tie(k, element) = SafeLoadElement(kind, receiver, k);
1680
1681    auto continue_label = MakeLabel();
1682    element = MaybeSkipHole(element, kind, &continue_label);
1683
1684    TNode<Object> v = JSCall3(fncallback, this_arg, element, k, receiver,
1685                              MapLoopLazyFrameState(frame_state_params, k));
1686
1687    // The array {a} should be HOLEY_SMI_ELEMENTS because we'd only come into
1688    // this loop if the input array length is non-zero, and "new Array({x > 0})"
1689    // always produces a HOLEY array.
1690    MapRef holey_double_map =
1691        native_context.GetInitialJSArrayMap(HOLEY_DOUBLE_ELEMENTS);
1692    MapRef holey_map = native_context.GetInitialJSArrayMap(HOLEY_ELEMENTS);
1693    TransitionAndStoreElement(holey_double_map, holey_map, a, k, v);
1694
1695    Goto(&continue_label);
1696    Bind(&continue_label);
1697  });
1698
1699  return a;
1700}
1701
1702namespace {
1703
1704struct FilterFrameStateParams {
1705  JSGraph* jsgraph;
1706  SharedFunctionInfoRef shared;
1707  TNode<Context> context;
1708  TNode<Object> target;
1709  FrameState outer_frame_state;
1710  TNode<Object> receiver;
1711  TNode<Object> callback;
1712  TNode<Object> this_arg;
1713  TNode<JSArray> a;
1714  TNode<Object> original_length;
1715};
1716
1717FrameState FilterLoopLazyFrameState(const FilterFrameStateParams& params,
1718                                    TNode<Number> k, TNode<Number> to,
1719                                    TNode<Object> element) {
1720  Node* checkpoint_params[] = {params.receiver,
1721                               params.callback,
1722                               params.this_arg,
1723                               params.a,
1724                               k,
1725                               params.original_length,
1726                               element,
1727                               to};
1728  return CreateJavaScriptBuiltinContinuationFrameState(
1729      params.jsgraph, params.shared,
1730      Builtin::kArrayFilterLoopLazyDeoptContinuation, params.target,
1731      params.context, checkpoint_params, arraysize(checkpoint_params),
1732      params.outer_frame_state, ContinuationFrameStateMode::LAZY);
1733}
1734
1735FrameState FilterLoopEagerPostCallbackFrameState(
1736    const FilterFrameStateParams& params, TNode<Number> k, TNode<Number> to,
1737    TNode<Object> element, TNode<Object> callback_value) {
1738  // Note that we are intentionally reusing the
1739  // Builtin::kArrayFilterLoopLazyDeoptContinuation as an *eager* entry
1740  // point in this case. This is safe, because re-evaluating a [ToBoolean]
1741  // coercion is safe.
1742  Node* checkpoint_params[] = {params.receiver,
1743                               params.callback,
1744                               params.this_arg,
1745                               params.a,
1746                               k,
1747                               params.original_length,
1748                               element,
1749                               to,
1750                               callback_value};
1751  return CreateJavaScriptBuiltinContinuationFrameState(
1752      params.jsgraph, params.shared,
1753      Builtin::kArrayFilterLoopLazyDeoptContinuation, params.target,
1754      params.context, checkpoint_params, arraysize(checkpoint_params),
1755      params.outer_frame_state, ContinuationFrameStateMode::EAGER);
1756}
1757
1758FrameState FilterLoopEagerFrameState(const FilterFrameStateParams& params,
1759                                     TNode<Number> k, TNode<Number> to) {
1760  Node* checkpoint_params[] = {params.receiver,
1761                               params.callback,
1762                               params.this_arg,
1763                               params.a,
1764                               k,
1765                               params.original_length,
1766                               to};
1767  return CreateJavaScriptBuiltinContinuationFrameState(
1768      params.jsgraph, params.shared,
1769      Builtin::kArrayFilterLoopEagerDeoptContinuation, params.target,
1770      params.context, checkpoint_params, arraysize(checkpoint_params),
1771      params.outer_frame_state, ContinuationFrameStateMode::EAGER);
1772}
1773
1774}  // namespace
1775
1776TNode<JSArray>
1777IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeFilter(
1778    MapInference* inference, const bool has_stability_dependency,
1779    ElementsKind kind, const SharedFunctionInfoRef& shared,
1780    const NativeContextRef& native_context) {
1781  FrameState outer_frame_state = FrameStateInput();
1782  TNode<Context> context = ContextInput();
1783  TNode<Object> target = TargetInput();
1784  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
1785  TNode<Object> fncallback = ArgumentOrUndefined(0);
1786  TNode<Object> this_arg = ArgumentOrUndefined(1);
1787
1788  // The output array is packed (filter doesn't visit holes).
1789  const ElementsKind packed_kind = GetPackedElementsKind(kind);
1790  TNode<JSArray> a = AllocateEmptyJSArray(packed_kind, native_context);
1791
1792  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);
1793
1794  FilterFrameStateParams frame_state_params{
1795      jsgraph(), shared,     context,  target, outer_frame_state,
1796      receiver,  fncallback, this_arg, a,      original_length};
1797
1798  // This frame state doesn't ever call the deopt continuation, it's only
1799  // necessary to specify a continuation in order to handle the exceptional
1800  // case. We don't have all the values available to completely fill out
1801  // the checkpoint parameters yet, but that's okay because it'll never be
1802  // called.
1803  TNode<Number> zero = ZeroConstant();
1804  ThrowIfNotCallable(fncallback, FilterLoopLazyFrameState(frame_state_params,
1805                                                          zero, zero, zero));
1806
1807  TNode<Number> initial_a_length = zero;
1808  For1ZeroUntil(original_length, initial_a_length)
1809      .Do([&](TNode<Number> k, TNode<Object>* a_length_object) {
1810        TNode<Number> a_length = TNode<Number>::UncheckedCast(*a_length_object);
1811        Checkpoint(FilterLoopEagerFrameState(frame_state_params, k, a_length));
1812        MaybeInsertMapChecks(inference, has_stability_dependency);
1813
1814        TNode<Object> element;
1815        std::tie(k, element) = SafeLoadElement(kind, receiver, k);
1816
1817        auto continue_label = MakeLabel(MachineRepresentation::kTaggedSigned);
1818        element = MaybeSkipHole(element, kind, &continue_label, a_length);
1819
1820        TNode<Object> v = JSCall3(
1821            fncallback, this_arg, element, k, receiver,
1822            FilterLoopLazyFrameState(frame_state_params, k, a_length, element));
1823
1824        // We need an eager frame state for right after the callback function
1825        // returned, just in case an attempt to grow the output array fails.
1826        Checkpoint(FilterLoopEagerPostCallbackFrameState(frame_state_params, k,
1827                                                         a_length, element, v));
1828
1829        GotoIfNot(ToBoolean(v), &continue_label, a_length);
1830
1831        // Since the callback returned a trueish value, store the element in a.
1832        {
1833          TNode<Number> a_length1 = TypeGuardFixedArrayLength(a_length);
1834          TNode<FixedArrayBase> elements = LoadElements(a);
1835          elements = MaybeGrowFastElements(kind, FeedbackSource{}, a, elements,
1836                                           a_length1,
1837                                           LoadFixedArrayBaseLength(elements));
1838
1839          TNode<Number> new_a_length = NumberInc(a_length1);
1840          StoreJSArrayLength(a, new_a_length, kind);
1841          StoreFixedArrayBaseElement(elements, a_length1, element, kind);
1842
1843          Goto(&continue_label, new_a_length);
1844        }
1845
1846        Bind(&continue_label);
1847        *a_length_object =
1848            TNode<Object>::UncheckedCast(continue_label.PhiAt(0));
1849      })
1850      .ValueIsUnused();
1851
1852  return a;
1853}
1854
1855namespace {
1856
1857struct FindFrameStateParams {
1858  JSGraph* jsgraph;
1859  SharedFunctionInfoRef shared;
1860  TNode<Context> context;
1861  TNode<Object> target;
1862  FrameState outer_frame_state;
1863  TNode<Object> receiver;
1864  TNode<Object> callback;
1865  TNode<Object> this_arg;
1866  TNode<Object> original_length;
1867};
1868
1869FrameState FindLoopLazyFrameState(const FindFrameStateParams& params,
1870                                  TNode<Number> k, ArrayFindVariant variant) {
1871  Builtin builtin = (variant == ArrayFindVariant::kFind)
1872                        ? Builtin::kArrayFindLoopLazyDeoptContinuation
1873                        : Builtin::kArrayFindIndexLoopLazyDeoptContinuation;
1874  Node* checkpoint_params[] = {params.receiver, params.callback,
1875                               params.this_arg, k, params.original_length};
1876  return CreateJavaScriptBuiltinContinuationFrameState(
1877      params.jsgraph, params.shared, builtin, params.target, params.context,
1878      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1879      ContinuationFrameStateMode::LAZY);
1880}
1881
1882FrameState FindLoopEagerFrameState(const FindFrameStateParams& params,
1883                                   TNode<Number> k, ArrayFindVariant variant) {
1884  Builtin builtin = (variant == ArrayFindVariant::kFind)
1885                        ? Builtin::kArrayFindLoopEagerDeoptContinuation
1886                        : Builtin::kArrayFindIndexLoopEagerDeoptContinuation;
1887  Node* checkpoint_params[] = {params.receiver, params.callback,
1888                               params.this_arg, k, params.original_length};
1889  return CreateJavaScriptBuiltinContinuationFrameState(
1890      params.jsgraph, params.shared, builtin, params.target, params.context,
1891      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1892      ContinuationFrameStateMode::EAGER);
1893}
1894
1895FrameState FindLoopAfterCallbackLazyFrameState(
1896    const FindFrameStateParams& params, TNode<Number> next_k,
1897    TNode<Object> if_found_value, ArrayFindVariant variant) {
1898  Builtin builtin =
1899      (variant == ArrayFindVariant::kFind)
1900          ? Builtin::kArrayFindLoopAfterCallbackLazyDeoptContinuation
1901          : Builtin::kArrayFindIndexLoopAfterCallbackLazyDeoptContinuation;
1902  Node* checkpoint_params[] = {params.receiver,        params.callback,
1903                               params.this_arg,        next_k,
1904                               params.original_length, if_found_value};
1905  return CreateJavaScriptBuiltinContinuationFrameState(
1906      params.jsgraph, params.shared, builtin, params.target, params.context,
1907      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1908      ContinuationFrameStateMode::LAZY);
1909}
1910
1911}  // namespace
1912
1913TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeFind(
1914    MapInference* inference, const bool has_stability_dependency,
1915    ElementsKind kind, const SharedFunctionInfoRef& shared,
1916    const NativeContextRef& native_context, ArrayFindVariant variant) {
1917  FrameState outer_frame_state = FrameStateInput();
1918  TNode<Context> context = ContextInput();
1919  TNode<Object> target = TargetInput();
1920  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
1921  TNode<Object> fncallback = ArgumentOrUndefined(0);
1922  TNode<Object> this_arg = ArgumentOrUndefined(1);
1923
1924  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);
1925
1926  FindFrameStateParams frame_state_params{
1927      jsgraph(), shared,     context,  target,         outer_frame_state,
1928      receiver,  fncallback, this_arg, original_length};
1929
1930  ThrowIfNotCallable(
1931      fncallback,
1932      FindLoopLazyFrameState(frame_state_params, ZeroConstant(), variant));
1933
1934  const bool is_find_variant = (variant == ArrayFindVariant::kFind);
1935  auto out = MakeLabel(MachineRepresentation::kTagged);
1936
1937  ForZeroUntil(original_length).Do([&](TNode<Number> k) {
1938    Checkpoint(FindLoopEagerFrameState(frame_state_params, k, variant));
1939    MaybeInsertMapChecks(inference, has_stability_dependency);
1940
1941    TNode<Object> element;
1942    std::tie(k, element) = SafeLoadElement(kind, receiver, k);
1943
1944    if (IsHoleyElementsKind(kind)) {
1945      element = TryConvertHoleToUndefined(element, kind);
1946    }
1947
1948    TNode<Object> if_found_value = is_find_variant ? element : k;
1949    TNode<Number> next_k = NumberInc(k);
1950
1951    // The callback result states whether the desired element was found.
1952    TNode<Object> v =
1953        JSCall3(fncallback, this_arg, element, k, receiver,
1954                FindLoopAfterCallbackLazyFrameState(frame_state_params, next_k,
1955                                                    if_found_value, variant));
1956
1957    GotoIf(ToBoolean(v), &out, if_found_value);
1958  });
1959
1960  // If the loop completed, the element was not found.
1961  TNode<Object> if_not_found_value =
1962      is_find_variant ? TNode<Object>::UncheckedCast(UndefinedConstant())
1963                      : TNode<Object>::UncheckedCast(MinusOneConstant());
1964  Goto(&out, if_not_found_value);
1965
1966  Bind(&out);
1967  return out.PhiAt<Object>(0);
1968}
1969
1970namespace {
1971
1972struct EverySomeFrameStateParams {
1973  JSGraph* jsgraph;
1974  SharedFunctionInfoRef shared;
1975  TNode<Context> context;
1976  TNode<Object> target;
1977  FrameState outer_frame_state;
1978  TNode<Object> receiver;
1979  TNode<Object> callback;
1980  TNode<Object> this_arg;
1981  TNode<Object> original_length;
1982};
1983
1984FrameState EverySomeLoopLazyFrameState(const EverySomeFrameStateParams& params,
1985                                       TNode<Number> k,
1986                                       ArrayEverySomeVariant variant) {
1987  Builtin builtin = (variant == ArrayEverySomeVariant::kEvery)
1988                        ? Builtin::kArrayEveryLoopLazyDeoptContinuation
1989                        : Builtin::kArraySomeLoopLazyDeoptContinuation;
1990  Node* checkpoint_params[] = {params.receiver, params.callback,
1991                               params.this_arg, k, params.original_length};
1992  return CreateJavaScriptBuiltinContinuationFrameState(
1993      params.jsgraph, params.shared, builtin, params.target, params.context,
1994      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1995      ContinuationFrameStateMode::LAZY);
1996}
1997
1998FrameState EverySomeLoopEagerFrameState(const EverySomeFrameStateParams& params,
1999                                        TNode<Number> k,
2000                                        ArrayEverySomeVariant variant) {
2001  Builtin builtin = (variant == ArrayEverySomeVariant::kEvery)
2002                        ? Builtin::kArrayEveryLoopEagerDeoptContinuation
2003                        : Builtin::kArraySomeLoopEagerDeoptContinuation;
2004  Node* checkpoint_params[] = {params.receiver, params.callback,
2005                               params.this_arg, k, params.original_length};
2006  return CreateJavaScriptBuiltinContinuationFrameState(
2007      params.jsgraph, params.shared, builtin, params.target, params.context,
2008      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
2009      ContinuationFrameStateMode::EAGER);
2010}
2011
2012}  // namespace
2013
2014TNode<Boolean>
2015IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeEverySome(
2016    MapInference* inference, const bool has_stability_dependency,
2017    ElementsKind kind, const SharedFunctionInfoRef& shared,
2018    const NativeContextRef& native_context, ArrayEverySomeVariant variant) {
2019  FrameState outer_frame_state = FrameStateInput();
2020  TNode<Context> context = ContextInput();
2021  TNode<Object> target = TargetInput();
2022  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
2023  TNode<Object> fncallback = ArgumentOrUndefined(0);
2024  TNode<Object> this_arg = ArgumentOrUndefined(1);
2025
2026  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);
2027
2028  EverySomeFrameStateParams frame_state_params{
2029      jsgraph(), shared,     context,  target,         outer_frame_state,
2030      receiver,  fncallback, this_arg, original_length};
2031
2032  ThrowIfNotCallable(
2033      fncallback,
2034      EverySomeLoopLazyFrameState(frame_state_params, ZeroConstant(), variant));
2035
2036  auto out = MakeLabel(MachineRepresentation::kTagged);
2037
2038  ForZeroUntil(original_length).Do([&](TNode<Number> k) {
2039    Checkpoint(EverySomeLoopEagerFrameState(frame_state_params, k, variant));
2040    MaybeInsertMapChecks(inference, has_stability_dependency);
2041
2042    TNode<Object> element;
2043    std::tie(k, element) = SafeLoadElement(kind, receiver, k);
2044
2045    auto continue_label = MakeLabel();
2046    element = MaybeSkipHole(element, kind, &continue_label);
2047
2048    TNode<Object> v =
2049        JSCall3(fncallback, this_arg, element, k, receiver,
2050                EverySomeLoopLazyFrameState(frame_state_params, k, variant));
2051
2052    if (variant == ArrayEverySomeVariant::kEvery) {
2053      GotoIfNot(ToBoolean(v), &out, FalseConstant());
2054    } else {
2055      DCHECK_EQ(variant, ArrayEverySomeVariant::kSome);
2056      GotoIf(ToBoolean(v), &out, TrueConstant());
2057    }
2058    Goto(&continue_label);
2059    Bind(&continue_label);
2060  });
2061
2062  Goto(&out, (variant == ArrayEverySomeVariant::kEvery) ? TrueConstant()
2063                                                        : FalseConstant());
2064
2065  Bind(&out);
2066  return out.PhiAt<Boolean>(0);
2067}
2068
2069namespace {
2070
2071Callable GetCallableForArrayIndexOfIncludes(ArrayIndexOfIncludesVariant variant,
2072                                            ElementsKind elements_kind,
2073                                            Isolate* isolate) {
2074  if (variant == ArrayIndexOfIncludesVariant::kIndexOf) {
2075    switch (elements_kind) {
2076      case PACKED_SMI_ELEMENTS:
2077      case HOLEY_SMI_ELEMENTS:
2078      case PACKED_ELEMENTS:
2079      case HOLEY_ELEMENTS:
2080        return Builtins::CallableFor(isolate,
2081                                     Builtin::kArrayIndexOfSmiOrObject);
2082      case PACKED_DOUBLE_ELEMENTS:
2083        return Builtins::CallableFor(isolate,
2084                                     Builtin::kArrayIndexOfPackedDoubles);
2085      default:
2086        DCHECK_EQ(HOLEY_DOUBLE_ELEMENTS, elements_kind);
2087        return Builtins::CallableFor(isolate,
2088                                     Builtin::kArrayIndexOfHoleyDoubles);
2089    }
2090  } else {
2091    DCHECK_EQ(variant, ArrayIndexOfIncludesVariant::kIncludes);
2092    switch (elements_kind) {
2093      case PACKED_SMI_ELEMENTS:
2094      case HOLEY_SMI_ELEMENTS:
2095      case PACKED_ELEMENTS:
2096      case HOLEY_ELEMENTS:
2097        return Builtins::CallableFor(isolate,
2098                                     Builtin::kArrayIncludesSmiOrObject);
2099      case PACKED_DOUBLE_ELEMENTS:
2100        return Builtins::CallableFor(isolate,
2101                                     Builtin::kArrayIncludesPackedDoubles);
2102      default:
2103        DCHECK_EQ(HOLEY_DOUBLE_ELEMENTS, elements_kind);
2104        return Builtins::CallableFor(isolate,
2105                                     Builtin::kArrayIncludesHoleyDoubles);
2106    }
2107  }
2108  UNREACHABLE();
2109}
2110
2111}  // namespace
2112
2113TNode<Object>
2114IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeIndexOfIncludes(
2115    ElementsKind kind, ArrayIndexOfIncludesVariant variant) {
2116  TNode<Context> context = ContextInput();
2117  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
2118  TNode<Object> search_element = ArgumentOrUndefined(0);
2119  TNode<Object> from_index = ArgumentOrZero(1);
2120
2121  // TODO(jgruber): This currently only reduces to a stub call. Create a full
2122  // reduction (similar to other higher-order array builtins) instead of
2123  // lowering to a builtin call. E.g. Array.p.every and Array.p.some have almost
2124  // identical functionality.
2125
2126  TNode<Number> length = LoadJSArrayLength(receiver, kind);
2127  TNode<FixedArrayBase> elements = LoadElements(receiver);
2128
2129  const bool have_from_index = ArgumentCount() > 1;
2130  if (have_from_index) {
2131    TNode<Smi> from_index_smi = CheckSmi(from_index);
2132
2133    // If the index is negative, it means the offset from the end and
2134    // therefore needs to be added to the length. If the result is still
2135    // negative, it needs to be clamped to 0.
2136    TNode<Boolean> cond = NumberLessThan(from_index_smi, ZeroConstant());
2137    from_index = SelectIf<Number>(cond)
2138                     .Then(_ {
2139                       return NumberMax(NumberAdd(length, from_index_smi),
2140                                        ZeroConstant());
2141                     })
2142                     .Else(_ { return from_index_smi; })
2143                     .ExpectFalse()
2144                     .Value();
2145  }
2146
2147  return Call4(GetCallableForArrayIndexOfIncludes(variant, kind, isolate()),
2148               context, elements, search_element, length, from_index);
2149}
2150
2151namespace {
2152
2153struct PromiseCtorFrameStateParams {
2154  JSGraph* jsgraph;
2155  SharedFunctionInfoRef shared;
2156  Node* node_ptr;
2157  TNode<Context> context;
2158  TNode<Object> target;
2159  FrameState outer_frame_state;
2160};
2161
2162// Remnant of old-style JSCallReducer code. Could be ported to graph assembler,
2163// but probably not worth the effort.
2164FrameState CreateArtificialFrameState(
2165    Node* node, Node* outer_frame_state, int parameter_count,
2166    BytecodeOffset bailout_id, FrameStateType frame_state_type,
2167    const SharedFunctionInfoRef& shared, Node* context,
2168    CommonOperatorBuilder* common, Graph* graph) {
2169  const FrameStateFunctionInfo* state_info =
2170      common->CreateFrameStateFunctionInfo(
2171          frame_state_type, parameter_count + 1, 0, shared.object());
2172
2173  const Operator* op = common->FrameState(
2174      bailout_id, OutputFrameStateCombine::Ignore(), state_info);
2175  const Operator* op0 = common->StateValues(0, SparseInputMask::Dense());
2176  Node* node0 = graph->NewNode(op0);
2177
2178  static constexpr int kTargetInputIndex = 0;
2179  static constexpr int kReceiverInputIndex = 1;
2180  const int parameter_count_with_receiver = parameter_count + 1;
2181  std::vector<Node*> params;
2182  params.reserve(parameter_count_with_receiver);
2183  for (int i = 0; i < parameter_count_with_receiver; i++) {
2184    params.push_back(node->InputAt(kReceiverInputIndex + i));
2185  }
2186  const Operator* op_param = common->StateValues(
2187      static_cast<int>(params.size()), SparseInputMask::Dense());
2188  Node* params_node = graph->NewNode(op_param, static_cast<int>(params.size()),
2189                                     &params.front());
2190  DCHECK(context);
2191  return FrameState(graph->NewNode(op, params_node, node0, node0, context,
2192                                   node->InputAt(kTargetInputIndex),
2193                                   outer_frame_state));
2194}
2195
2196FrameState PromiseConstructorFrameState(
2197    const PromiseCtorFrameStateParams& params, CommonOperatorBuilder* common,
2198    Graph* graph) {
2199  DCHECK_EQ(1,
2200            params.shared.internal_formal_parameter_count_without_receiver());
2201  return CreateArtificialFrameState(
2202      params.node_ptr, params.outer_frame_state, 1,
2203      BytecodeOffset::ConstructStubInvoke(), FrameStateType::kConstructStub,
2204      params.shared, params.context, common, graph);
2205}
2206
2207FrameState PromiseConstructorLazyFrameState(
2208    const PromiseCtorFrameStateParams& params,
2209    FrameState constructor_frame_state) {
2210  // The deopt continuation of this frame state is never called; the frame state
2211  // is only necessary to obtain the right stack trace.
2212  JSGraph* jsgraph = params.jsgraph;
2213  Node* checkpoint_params[] = {
2214      jsgraph->UndefinedConstant(), /* receiver */
2215      jsgraph->UndefinedConstant(), /* promise */
2216      jsgraph->UndefinedConstant(), /* reject function */
2217      jsgraph->TheHoleConstant()    /* exception */
2218  };
2219  return CreateJavaScriptBuiltinContinuationFrameState(
2220      jsgraph, params.shared, Builtin::kPromiseConstructorLazyDeoptContinuation,
2221      params.target, params.context, checkpoint_params,
2222      arraysize(checkpoint_params), constructor_frame_state,
2223      ContinuationFrameStateMode::LAZY);
2224}
2225
2226FrameState PromiseConstructorLazyWithCatchFrameState(
2227    const PromiseCtorFrameStateParams& params,
2228    FrameState constructor_frame_state, TNode<JSPromise> promise,
2229    TNode<JSFunction> reject) {
2230  // This continuation just returns the created promise and takes care of
2231  // exceptions thrown by the executor.
2232  Node* checkpoint_params[] = {
2233      params.jsgraph->UndefinedConstant(), /* receiver */
2234      promise, reject};
2235  return CreateJavaScriptBuiltinContinuationFrameState(
2236      params.jsgraph, params.shared,
2237      Builtin::kPromiseConstructorLazyDeoptContinuation, params.target,
2238      params.context, checkpoint_params, arraysize(checkpoint_params),
2239      constructor_frame_state, ContinuationFrameStateMode::LAZY_WITH_CATCH);
2240}
2241
2242}  // namespace
2243
2244TNode<Object> PromiseBuiltinReducerAssembler::ReducePromiseConstructor(
2245    const NativeContextRef& native_context) {
2246  DCHECK_GE(ConstructArity(), 1);
2247
2248  JSConstructNode n(node_ptr());
2249  FrameState outer_frame_state = FrameStateInput();
2250  TNode<Context> context = ContextInput();
2251  TNode<Object> target = TargetInput();
2252  TNode<Object> executor = n.Argument(0);
2253  DCHECK_EQ(target, NewTargetInput());
2254
2255  SharedFunctionInfoRef promise_shared =
2256      native_context.promise_function().shared();
2257
2258  PromiseCtorFrameStateParams frame_state_params{jsgraph(),  promise_shared,
2259                                                 node_ptr(), context,
2260                                                 target,     outer_frame_state};
2261
2262  // Insert a construct stub frame into the chain of frame states. This will
2263  // reconstruct the proper frame when deoptimizing within the constructor.
2264  // For the frame state, we only provide the executor parameter, even if more
2265  // arguments were passed. This is not observable from JS.
2266  FrameState constructor_frame_state =
2267      PromiseConstructorFrameState(frame_state_params, common(), graph());
2268
2269  ThrowIfNotCallable(executor,
2270                     PromiseConstructorLazyFrameState(frame_state_params,
2271                                                      constructor_frame_state));
2272
2273  TNode<JSPromise> promise = CreatePromise(context);
2274
2275  // 8. CreatePromiseResolvingFunctions
2276  // Allocate a promise context for the closures below.
2277  TNode<Context> promise_context = CreateFunctionContext(
2278      native_context, context, PromiseBuiltins::kPromiseContextLength);
2279  StoreContextSlot(promise_context, PromiseBuiltins::kPromiseSlot, promise);
2280  StoreContextSlot(promise_context, PromiseBuiltins::kAlreadyResolvedSlot,
2281                   FalseConstant());
2282  StoreContextSlot(promise_context, PromiseBuiltins::kDebugEventSlot,
2283                   TrueConstant());
2284
2285  // Allocate closures for the resolve and reject cases.
2286  SharedFunctionInfoRef resolve_sfi =
2287      MakeRef(broker_, broker_->isolate()
2288                           ->factory()
2289                           ->promise_capability_default_resolve_shared_fun());
2290  TNode<JSFunction> resolve =
2291      CreateClosureFromBuiltinSharedFunctionInfo(resolve_sfi, promise_context);
2292
2293  SharedFunctionInfoRef reject_sfi =
2294      MakeRef(broker_, broker_->isolate()
2295                           ->factory()
2296                           ->promise_capability_default_reject_shared_fun());
2297  TNode<JSFunction> reject =
2298      CreateClosureFromBuiltinSharedFunctionInfo(reject_sfi, promise_context);
2299
2300  FrameState lazy_with_catch_frame_state =
2301      PromiseConstructorLazyWithCatchFrameState(
2302          frame_state_params, constructor_frame_state, promise, reject);
2303
2304  // 9. Call executor with both resolving functions.
2305  // 10a. Call reject if the call to executor threw.
2306  Try(_ {
2307    CallPromiseExecutor(executor, resolve, reject, lazy_with_catch_frame_state);
2308  }).Catch([&](TNode<Object> exception) {
2309    CallPromiseReject(reject, exception, lazy_with_catch_frame_state);
2310  });
2311
2312  return promise;
2313}
2314
2315#undef _
2316
2317Reduction JSCallReducer::ReplaceWithSubgraph(JSCallReducerAssembler* gasm,
2318                                             Node* subgraph) {
2319  // TODO(jgruber): Consider a less fiddly way of integrating the new subgraph
2320  // into the outer graph. For instance, the subgraph could be created in
2321  // complete isolation, and then plugged into the outer graph in one go.
2322  // Instead of manually tracking IfException nodes, we could iterate the
2323  // subgraph.
2324
2325  // Replace the Call node with the newly-produced subgraph.
2326  ReplaceWithValue(gasm->node_ptr(), subgraph, gasm->effect(), gasm->control());
2327
2328  // Wire exception edges contained in the newly-produced subgraph into the
2329  // outer graph.
2330  auto catch_scope = gasm->catch_scope();
2331  DCHECK(catch_scope->is_outermost());
2332
2333  if (catch_scope->has_handler() &&
2334      catch_scope->has_exceptional_control_flow()) {
2335    TNode<Object> handler_exception;
2336    Effect handler_effect{nullptr};
2337    Control handler_control{nullptr};
2338    gasm->catch_scope()->MergeExceptionalPaths(
2339        &handler_exception, &handler_effect, &handler_control);
2340
2341    ReplaceWithValue(gasm->outermost_handler(), handler_exception,
2342                     handler_effect, handler_control);
2343  }
2344
2345  return Replace(subgraph);
2346}
2347
2348Reduction JSCallReducer::ReduceMathUnary(Node* node, const Operator* op) {
2349  JSCallNode n(node);
2350  CallParameters const& p = n.Parameters();
2351  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
2352    return NoChange();
2353  }
2354  if (n.ArgumentCount() < 1) {
2355    Node* value = jsgraph()->NaNConstant();
2356    ReplaceWithValue(node, value);
2357    return Replace(value);
2358  }
2359
2360  JSCallReducerAssembler a(this, node);
2361  Node* subgraph = a.ReduceMathUnary(op);
2362  return ReplaceWithSubgraph(&a, subgraph);
2363}
2364
2365Reduction JSCallReducer::ReduceMathBinary(Node* node, const Operator* op) {
2366  JSCallNode n(node);
2367  CallParameters const& p = n.Parameters();
2368  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
2369    return NoChange();
2370  }
2371  if (n.ArgumentCount() < 1) {
2372    Node* value = jsgraph()->NaNConstant();
2373    ReplaceWithValue(node, value);
2374    return Replace(value);
2375  }
2376
2377  JSCallReducerAssembler a(this, node);
2378  Node* subgraph = a.ReduceMathBinary(op);
2379  return ReplaceWithSubgraph(&a, subgraph);
2380}
2381
2382// ES6 section 20.2.2.19 Math.imul ( x, y )
2383Reduction JSCallReducer::ReduceMathImul(Node* node) {
2384  JSCallNode n(node);
2385  CallParameters const& p = n.Parameters();
2386  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
2387    return NoChange();
2388  }
2389  if (n.ArgumentCount() < 1) {
2390    Node* value = jsgraph()->ZeroConstant();
2391    ReplaceWithValue(node, value);
2392    return Replace(value);
2393  }
2394  Node* left = n.Argument(0);
2395  Node* right = n.ArgumentOr(1, jsgraph()->ZeroConstant());
2396  Effect effect = n.effect();
2397  Control control = n.control();
2398
2399  left = effect =
2400      graph()->NewNode(simplified()->SpeculativeToNumber(
2401                           NumberOperationHint::kNumberOrOddball, p.feedback()),
2402                       left, effect, control);
2403  right = effect =
2404      graph()->NewNode(simplified()->SpeculativeToNumber(
2405                           NumberOperationHint::kNumberOrOddball, p.feedback()),
2406                       right, effect, control);
2407  left = graph()->NewNode(simplified()->NumberToUint32(), left);
2408  right = graph()->NewNode(simplified()->NumberToUint32(), right);
2409  Node* value = graph()->NewNode(simplified()->NumberImul(), left, right);
2410  ReplaceWithValue(node, value, effect);
2411  return Replace(value);
2412}
2413
2414// ES6 section 20.2.2.11 Math.clz32 ( x )
2415Reduction JSCallReducer::ReduceMathClz32(Node* node) {
2416  JSCallNode n(node);
2417  CallParameters const& p = n.Parameters();
2418  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
2419    return NoChange();
2420  }
2421  if (n.ArgumentCount() < 1) {
2422    Node* value = jsgraph()->Constant(32);
2423    ReplaceWithValue(node, value);
2424    return Replace(value);
2425  }
2426  Node* input = n.Argument(0);
2427  Effect effect = n.effect();
2428  Control control = n.control();
2429
2430  input = effect =
2431      graph()->NewNode(simplified()->SpeculativeToNumber(
2432                           NumberOperationHint::kNumberOrOddball, p.feedback()),
2433                       input, effect, control);
2434  input = graph()->NewNode(simplified()->NumberToUint32(), input);
2435  Node* value = graph()->NewNode(simplified()->NumberClz32(), input);
2436  ReplaceWithValue(node, value, effect);
2437  return Replace(value);
2438}
2439
2440// ES6 section 20.2.2.24 Math.max ( value1, value2, ...values )
2441// ES6 section 20.2.2.25 Math.min ( value1, value2, ...values )
2442Reduction JSCallReducer::ReduceMathMinMax(Node* node, const Operator* op,
2443                                          Node* empty_value) {
2444  JSCallNode n(node);
2445  CallParameters const& p = n.Parameters();
2446  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
2447    return NoChange();
2448  }
2449  if (n.ArgumentCount() < 1) {
2450    ReplaceWithValue(node, empty_value);
2451    return Replace(empty_value);
2452  }
2453  Node* effect = NodeProperties::GetEffectInput(node);
2454  Node* control = NodeProperties::GetControlInput(node);
2455
2456  Node* value = effect =
2457      graph()->NewNode(simplified()->SpeculativeToNumber(
2458                           NumberOperationHint::kNumberOrOddball, p.feedback()),
2459                       n.Argument(0), effect, control);
2460  for (int i = 1; i < n.ArgumentCount(); i++) {
2461    Node* input = effect = graph()->NewNode(
2462        simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
2463                                          p.feedback()),
2464        n.Argument(i), effect, control);
2465    value = graph()->NewNode(op, value, input);
2466  }
2467
2468  ReplaceWithValue(node, value, effect);
2469  return Replace(value);
2470}
2471
2472Reduction JSCallReducer::Reduce(Node* node) {
2473  switch (node->opcode()) {
2474    case IrOpcode::kJSConstruct:
2475      return ReduceJSConstruct(node);
2476    case IrOpcode::kJSConstructWithArrayLike:
2477      return ReduceJSConstructWithArrayLike(node);
2478    case IrOpcode::kJSConstructWithSpread:
2479      return ReduceJSConstructWithSpread(node);
2480    case IrOpcode::kJSCall:
2481      return ReduceJSCall(node);
2482    case IrOpcode::kJSCallWithArrayLike:
2483      return ReduceJSCallWithArrayLike(node);
2484    case IrOpcode::kJSCallWithSpread:
2485      return ReduceJSCallWithSpread(node);
2486    default:
2487      break;
2488  }
2489  return NoChange();
2490}
2491
2492void JSCallReducer::Finalize() {
2493  // TODO(turbofan): This is not the best solution; ideally we would be able
2494  // to teach the GraphReducer about arbitrary dependencies between different
2495  // nodes, even if they don't show up in the use list of the other node.
2496  std::set<Node*> const waitlist = std::move(waitlist_);
2497  for (Node* node : waitlist) {
2498    if (!node->IsDead()) {
2499      Reduction const reduction = Reduce(node);
2500      if (reduction.Changed()) {
2501        Node* replacement = reduction.replacement();
2502        if (replacement != node) {
2503          Replace(node, replacement);
2504        }
2505      }
2506    }
2507  }
2508}
2509
2510// ES6 section 22.1.1 The Array Constructor
2511Reduction JSCallReducer::ReduceArrayConstructor(Node* node) {
2512  JSCallNode n(node);
2513  Node* target = n.target();
2514  CallParameters const& p = n.Parameters();
2515
2516  // Turn the {node} into a {JSCreateArray} call.
2517  size_t const arity = p.arity_without_implicit_args();
2518  node->RemoveInput(n.FeedbackVectorIndex());
2519  NodeProperties::ReplaceValueInput(node, target, 0);
2520  NodeProperties::ReplaceValueInput(node, target, 1);
2521  NodeProperties::ChangeOp(node,
2522                           javascript()->CreateArray(arity, base::nullopt));
2523  return Changed(node);
2524}
2525
2526// ES6 section 19.3.1.1 Boolean ( value )
2527Reduction JSCallReducer::ReduceBooleanConstructor(Node* node) {
2528  // Replace the {node} with a proper {ToBoolean} operator.
2529  JSCallNode n(node);
2530  Node* value = n.ArgumentOrUndefined(0, jsgraph());
2531  value = graph()->NewNode(simplified()->ToBoolean(), value);
2532  ReplaceWithValue(node, value);
2533  return Replace(value);
2534}
2535
2536// ES section #sec-object-constructor
2537Reduction JSCallReducer::ReduceObjectConstructor(Node* node) {
2538  JSCallNode n(node);
2539  if (n.ArgumentCount() < 1) return NoChange();
2540  Node* value = n.Argument(0);
2541  Effect effect = n.effect();
2542
2543  // We can fold away the Object(x) call if |x| is definitely not a primitive.
2544  if (NodeProperties::CanBePrimitive(broker(), value, effect)) {
2545    if (!NodeProperties::CanBeNullOrUndefined(broker(), value, effect)) {
2546      // Turn the {node} into a {JSToObject} call if we know that
2547      // the {value} cannot be null or undefined.
2548      NodeProperties::ReplaceValueInputs(node, value);
2549      NodeProperties::ChangeOp(node, javascript()->ToObject());
2550      return Changed(node);
2551    }
2552  } else {
2553    ReplaceWithValue(node, value);
2554    return Replace(value);
2555  }
2556  return NoChange();
2557}
2558
2559// ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray )
2560Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
2561  JSCallNode n(node);
2562  CallParameters const& p = n.Parameters();
2563  CallFeedbackRelation new_feedback_relation =
2564      p.feedback_relation() == CallFeedbackRelation::kReceiver
2565          ? CallFeedbackRelation::kTarget
2566          : CallFeedbackRelation::kUnrelated;
2567  int arity = p.arity_without_implicit_args();
2568
2569  if (arity < 2) {
2570    // Degenerate cases.
2571    ConvertReceiverMode convert_mode;
2572    if (arity == 0) {
2573      // Neither thisArg nor argArray was provided.
2574      convert_mode = ConvertReceiverMode::kNullOrUndefined;
2575      node->ReplaceInput(n.TargetIndex(), n.receiver());
2576      node->ReplaceInput(n.ReceiverIndex(), jsgraph()->UndefinedConstant());
2577    } else {
2578      DCHECK_EQ(arity, 1);
2579      // The argArray was not provided, just remove the {target}.
2580      convert_mode = ConvertReceiverMode::kAny;
2581      node->RemoveInput(n.TargetIndex());
2582      --arity;
2583    }
2584    // Change {node} to a {JSCall} and try to reduce further.
2585    NodeProperties::ChangeOp(
2586        node, javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(),
2587                                 p.feedback(), convert_mode,
2588                                 p.speculation_mode(), new_feedback_relation));
2589    return Changed(node).FollowedBy(ReduceJSCall(node));
2590  }
2591
2592  // Turn the JSCall into a JSCallWithArrayLike.
2593  // If {argArray} can be null or undefined, we have to generate branches since
2594  // JSCallWithArrayLike would throw for null or undefined.
2595
2596  Node* target = n.receiver();
2597  Node* this_argument = n.Argument(0);
2598  Node* arguments_list = n.Argument(1);
2599  Node* context = n.context();
2600  FrameState frame_state = n.frame_state();
2601  Effect effect = n.effect();
2602  Control control = n.control();
2603
2604  // If {arguments_list} cannot be null or undefined, we don't need
2605  // to expand this {node} to control-flow.
2606  if (!NodeProperties::CanBeNullOrUndefined(broker(), arguments_list, effect)) {
2607    // Massage the value inputs appropriately.
2608    node->ReplaceInput(n.TargetIndex(), target);
2609    node->ReplaceInput(n.ReceiverIndex(), this_argument);
2610    node->ReplaceInput(n.ArgumentIndex(0), arguments_list);
2611    while (arity-- > 1) node->RemoveInput(n.ArgumentIndex(1));
2612
2613    // Morph the {node} to a {JSCallWithArrayLike}.
2614    NodeProperties::ChangeOp(
2615        node, javascript()->CallWithArrayLike(p.frequency(), p.feedback(),
2616                                              p.speculation_mode(),
2617                                              new_feedback_relation));
2618    return Changed(node).FollowedBy(ReduceJSCallWithArrayLike(node));
2619  }
2620
2621  // Check whether {arguments_list} is null.
2622  Node* check_null =
2623      graph()->NewNode(simplified()->ReferenceEqual(), arguments_list,
2624                       jsgraph()->NullConstant());
2625  control = graph()->NewNode(common()->Branch(BranchHint::kFalse), check_null,
2626                             control);
2627  Node* if_null = graph()->NewNode(common()->IfTrue(), control);
2628  control = graph()->NewNode(common()->IfFalse(), control);
2629
2630  // Check whether {arguments_list} is undefined.
2631  Node* check_undefined =
2632      graph()->NewNode(simplified()->ReferenceEqual(), arguments_list,
2633                       jsgraph()->UndefinedConstant());
2634  control = graph()->NewNode(common()->Branch(BranchHint::kFalse),
2635                             check_undefined, control);
2636  Node* if_undefined = graph()->NewNode(common()->IfTrue(), control);
2637  control = graph()->NewNode(common()->IfFalse(), control);
2638
2639  // Lower to {JSCallWithArrayLike} if {arguments_list} is neither null
2640  // nor undefined.
2641  Node* effect0 = effect;
2642  Node* control0 = control;
2643  Node* value0 = effect0 = control0 = graph()->NewNode(
2644      javascript()->CallWithArrayLike(p.frequency(), p.feedback(),
2645                                      p.speculation_mode(),
2646                                      new_feedback_relation),
2647      target, this_argument, arguments_list, n.feedback_vector(), context,
2648      frame_state, effect0, control0);
2649
2650  // Lower to {JSCall} if {arguments_list} is either null or undefined.
2651  Node* effect1 = effect;
2652  Node* control1 = graph()->NewNode(common()->Merge(2), if_null, if_undefined);
2653  Node* value1 = effect1 = control1 = graph()->NewNode(
2654      javascript()->Call(JSCallNode::ArityForArgc(0)), target, this_argument,
2655      n.feedback_vector(), context, frame_state, effect1, control1);
2656
2657  // Rewire potential exception edges.
2658  Node* if_exception = nullptr;
2659  if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
2660    // Create appropriate {IfException} and {IfSuccess} nodes.
2661    Node* if_exception0 =
2662        graph()->NewNode(common()->IfException(), control0, effect0);
2663    control0 = graph()->NewNode(common()->IfSuccess(), control0);
2664    Node* if_exception1 =
2665        graph()->NewNode(common()->IfException(), control1, effect1);
2666    control1 = graph()->NewNode(common()->IfSuccess(), control1);
2667
2668    // Join the exception edges.
2669    Node* merge =
2670        graph()->NewNode(common()->Merge(2), if_exception0, if_exception1);
2671    Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception0,
2672                                  if_exception1, merge);
2673    Node* phi =
2674        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2675                         if_exception0, if_exception1, merge);
2676    ReplaceWithValue(if_exception, phi, ephi, merge);
2677  }
2678
2679  // Join control paths.
2680  control = graph()->NewNode(common()->Merge(2), control0, control1);
2681  effect = graph()->NewNode(common()->EffectPhi(2), effect0, effect1, control);
2682  Node* value =
2683      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), value0,
2684                       value1, control);
2685  ReplaceWithValue(node, value, effect, control);
2686  return Replace(value);
2687}
2688
2689// ES section #sec-function.prototype.bind
2690Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
2691  JSCallNode n(node);
2692  CallParameters const& p = n.Parameters();
2693  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
2694    return NoChange();
2695  }
2696
2697  // Value inputs to the {node} are as follows:
2698  //
2699  //  - target, which is Function.prototype.bind JSFunction
2700  //  - receiver, which is the [[BoundTargetFunction]]
2701  //  - bound_this (optional), which is the [[BoundThis]]
2702  //  - and all the remaining value inputs are [[BoundArguments]]
2703  Node* receiver = n.receiver();
2704  Node* context = n.context();
2705  Effect effect = n.effect();
2706  Control control = n.control();
2707
2708  // Ensure that the {receiver} is known to be a JSBoundFunction or
2709  // a JSFunction with the same [[Prototype]], and all maps we've
2710  // seen for the {receiver} so far indicate that {receiver} is
2711  // definitely a constructor or not a constructor.
2712  MapInference inference(broker(), receiver, effect);
2713  if (!inference.HaveMaps()) return NoChange();
2714  ZoneVector<MapRef> const& receiver_maps = inference.GetMaps();
2715
2716  MapRef first_receiver_map = receiver_maps[0];
2717  bool const is_constructor = first_receiver_map.is_constructor();
2718
2719  HeapObjectRef prototype = first_receiver_map.prototype();
2720
2721  for (const MapRef& receiver_map : receiver_maps) {
2722    HeapObjectRef map_prototype = receiver_map.prototype();
2723
2724    // Check for consistency among the {receiver_maps}.
2725    if (!map_prototype.equals(prototype) ||
2726        receiver_map.is_constructor() != is_constructor ||
2727        !InstanceTypeChecker::IsJSFunctionOrBoundFunctionOrWrappedFunction(
2728            receiver_map.instance_type())) {
2729      return inference.NoChange();
2730    }
2731
2732    // Disallow binding of slow-mode functions. We need to figure out
2733    // whether the length and name property are in the original state.
2734    if (receiver_map.is_dictionary_map()) return inference.NoChange();
2735
2736    // Check whether the length and name properties are still present
2737    // as AccessorInfo objects. In that case, their values can be
2738    // recomputed even if the actual value of the object changes.
2739    // This mirrors the checks done in builtins-function-gen.cc at
2740    // runtime otherwise.
2741    int minimum_nof_descriptors =
2742        std::max(
2743            {JSFunctionOrBoundFunctionOrWrappedFunction::kLengthDescriptorIndex,
2744             JSFunctionOrBoundFunctionOrWrappedFunction::
2745                 kNameDescriptorIndex}) +
2746        1;
2747    if (receiver_map.NumberOfOwnDescriptors() < minimum_nof_descriptors) {
2748      return inference.NoChange();
2749    }
2750    const InternalIndex kLengthIndex(
2751        JSFunctionOrBoundFunctionOrWrappedFunction::kLengthDescriptorIndex);
2752    const InternalIndex kNameIndex(
2753        JSFunctionOrBoundFunctionOrWrappedFunction::kNameDescriptorIndex);
2754    ReadOnlyRoots roots(isolate());
2755    StringRef length_string = MakeRef(broker(), roots.length_string_handle());
2756    StringRef name_string = MakeRef(broker(), roots.name_string_handle());
2757
2758    base::Optional<ObjectRef> length_value(
2759        receiver_map.GetStrongValue(kLengthIndex));
2760    base::Optional<ObjectRef> name_value(
2761        receiver_map.GetStrongValue(kNameIndex));
2762    if (!length_value || !name_value) {
2763      TRACE_BROKER_MISSING(
2764          broker(), "name or length descriptors on map " << receiver_map);
2765      return inference.NoChange();
2766    }
2767    if (!receiver_map.GetPropertyKey(kLengthIndex).equals(length_string) ||
2768        !length_value->IsAccessorInfo() ||
2769        !receiver_map.GetPropertyKey(kNameIndex).equals(name_string) ||
2770        !name_value->IsAccessorInfo()) {
2771      return inference.NoChange();
2772    }
2773  }
2774
2775  // Choose the map for the resulting JSBoundFunction (but bail out in case of a
2776  // custom prototype).
2777  MapRef map = is_constructor
2778                   ? native_context().bound_function_with_constructor_map()
2779                   : native_context().bound_function_without_constructor_map();
2780  if (!map.prototype().equals(prototype)) return inference.NoChange();
2781
2782  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
2783                                      control, p.feedback());
2784
2785  // Replace the {node} with a JSCreateBoundFunction.
2786  static constexpr int kBoundThis = 1;
2787  static constexpr int kReceiverContextEffectAndControl = 4;
2788  int const arity = n.ArgumentCount();
2789
2790  if (arity > 0) {
2791    MapRef fixed_array_map = MakeRef(broker(), factory()->fixed_array_map());
2792    AllocationBuilder ab(jsgraph(), effect, control);
2793    if (!ab.CanAllocateArray(arity, fixed_array_map)) {
2794      return NoChange();
2795    }
2796  }
2797
2798  int const arity_with_bound_this = std::max(arity, kBoundThis);
2799  int const input_count =
2800      arity_with_bound_this + kReceiverContextEffectAndControl;
2801  Node** inputs = graph()->zone()->NewArray<Node*>(input_count);
2802  int cursor = 0;
2803  inputs[cursor++] = receiver;
2804  inputs[cursor++] = n.ArgumentOrUndefined(0, jsgraph());  // bound_this.
2805  for (int i = 1; i < arity; ++i) {
2806    inputs[cursor++] = n.Argument(i);
2807  }
2808  inputs[cursor++] = context;
2809  inputs[cursor++] = effect;
2810  inputs[cursor++] = control;
2811  DCHECK_EQ(cursor, input_count);
2812  Node* value = effect =
2813      graph()->NewNode(javascript()->CreateBoundFunction(
2814                           arity_with_bound_this - kBoundThis, map),
2815                       input_count, inputs);
2816  ReplaceWithValue(node, value, effect, control);
2817  return Replace(value);
2818}
2819
2820// ES6 section 19.2.3.3 Function.prototype.call (thisArg, ...args)
2821Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
2822  JSCallNode n(node);
2823  CallParameters const& p = n.Parameters();
2824  Node* target = n.target();
2825  Effect effect = n.effect();
2826  Control control = n.control();
2827
2828  // Change context of {node} to the Function.prototype.call context,
2829  // to ensure any exception is thrown in the correct context.
2830  Node* context;
2831  HeapObjectMatcher m(target);
2832  if (m.HasResolvedValue() && m.Ref(broker()).IsJSFunction()) {
2833    JSFunctionRef function = m.Ref(broker()).AsJSFunction();
2834    context = jsgraph()->Constant(function.context());
2835  } else {
2836    context = effect = graph()->NewNode(
2837        simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
2838        effect, control);
2839  }
2840  NodeProperties::ReplaceContextInput(node, context);
2841  NodeProperties::ReplaceEffectInput(node, effect);
2842
2843  // Remove the target from {node} and use the receiver as target instead, and
2844  // the thisArg becomes the new target.  If thisArg was not provided, insert
2845  // undefined instead.
2846  int arity = p.arity_without_implicit_args();
2847  ConvertReceiverMode convert_mode;
2848  if (arity == 0) {
2849    // The thisArg was not provided, use undefined as receiver.
2850    convert_mode = ConvertReceiverMode::kNullOrUndefined;
2851    node->ReplaceInput(n.TargetIndex(), n.receiver());
2852    node->ReplaceInput(n.ReceiverIndex(), jsgraph()->UndefinedConstant());
2853  } else {
2854    // Just remove the target, which is the first value input.
2855    convert_mode = ConvertReceiverMode::kAny;
2856    node->RemoveInput(n.TargetIndex());
2857    --arity;
2858  }
2859  NodeProperties::ChangeOp(
2860      node, javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(),
2861                               p.feedback(), convert_mode, p.speculation_mode(),
2862                               CallFeedbackRelation::kUnrelated));
2863  // Try to further reduce the JSCall {node}.
2864  return Changed(node).FollowedBy(ReduceJSCall(node));
2865}
2866
2867// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] (V)
2868Reduction JSCallReducer::ReduceFunctionPrototypeHasInstance(Node* node) {
2869  JSCallNode n(node);
2870  Node* receiver = n.receiver();
2871  Node* object = n.ArgumentOrUndefined(0, jsgraph());
2872  Node* context = n.context();
2873  FrameState frame_state = n.frame_state();
2874  Effect effect = n.effect();
2875  Control control = n.control();
2876
2877  // TODO(turbofan): If JSOrdinaryToInstance raises an exception, the
2878  // stack trace doesn't contain the @@hasInstance call; we have the
2879  // corresponding bug in the baseline case. Some massaging of the frame
2880  // state would be necessary here.
2881
2882  // Morph this {node} into a JSOrdinaryHasInstance node.
2883  node->ReplaceInput(0, receiver);
2884  node->ReplaceInput(1, object);
2885  node->ReplaceInput(2, context);
2886  node->ReplaceInput(3, frame_state);
2887  node->ReplaceInput(4, effect);
2888  node->ReplaceInput(5, control);
2889  node->TrimInputCount(6);
2890  NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
2891  return Changed(node);
2892}
2893
2894Reduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) {
2895  Effect effect{NodeProperties::GetEffectInput(node)};
2896
2897  // Try to determine the {object} map.
2898  MapInference inference(broker(), object, effect);
2899  if (!inference.HaveMaps()) return NoChange();
2900  ZoneVector<MapRef> const& object_maps = inference.GetMaps();
2901
2902  MapRef candidate_map = object_maps[0];
2903  HeapObjectRef candidate_prototype = candidate_map.prototype();
2904
2905  // Check if we can constant-fold the {candidate_prototype}.
2906  for (size_t i = 0; i < object_maps.size(); ++i) {
2907    MapRef object_map = object_maps[i];
2908    HeapObjectRef map_prototype = object_map.prototype();
2909    if (IsSpecialReceiverInstanceType(object_map.instance_type()) ||
2910        !map_prototype.equals(candidate_prototype)) {
2911      // We exclude special receivers, like JSProxy or API objects that
2912      // might require access checks here; we also don't want to deal
2913      // with hidden prototypes at this point.
2914      return inference.NoChange();
2915    }
2916    // The above check also excludes maps for primitive values, which is
2917    // important because we are not applying [[ToObject]] here as expected.
2918    DCHECK(!object_map.IsPrimitiveMap() && object_map.IsJSReceiverMap());
2919  }
2920  if (!inference.RelyOnMapsViaStability(dependencies())) {
2921    return inference.NoChange();
2922  }
2923  Node* value = jsgraph()->Constant(candidate_prototype);
2924  ReplaceWithValue(node, value);
2925  return Replace(value);
2926}
2927
2928// ES6 section 19.1.2.11 Object.getPrototypeOf ( O )
2929Reduction JSCallReducer::ReduceObjectGetPrototypeOf(Node* node) {
2930  JSCallNode n(node);
2931  Node* object = n.ArgumentOrUndefined(0, jsgraph());
2932  return ReduceObjectGetPrototype(node, object);
2933}
2934
2935// ES section #sec-object.is
2936Reduction JSCallReducer::ReduceObjectIs(Node* node) {
2937  JSCallNode n(node);
2938  Node* lhs = n.ArgumentOrUndefined(0, jsgraph());
2939  Node* rhs = n.ArgumentOrUndefined(1, jsgraph());
2940  Node* value = graph()->NewNode(simplified()->SameValue(), lhs, rhs);
2941  ReplaceWithValue(node, value);
2942  return Replace(value);
2943}
2944
2945// ES6 section B.2.2.1.1 get Object.prototype.__proto__
2946Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) {
2947  JSCallNode n(node);
2948  return ReduceObjectGetPrototype(node, n.receiver());
2949}
2950
2951// ES #sec-object.prototype.hasownproperty
2952Reduction JSCallReducer::ReduceObjectPrototypeHasOwnProperty(Node* node) {
2953  JSCallNode call_node(node);
2954  Node* receiver = call_node.receiver();
2955  Node* name = call_node.ArgumentOrUndefined(0, jsgraph());
2956  Effect effect = call_node.effect();
2957  Control control = call_node.control();
2958
2959  // We can optimize a call to Object.prototype.hasOwnProperty if it's being
2960  // used inside a fast-mode for..in, so for code like this:
2961  //
2962  //   for (name in receiver) {
2963  //     if (receiver.hasOwnProperty(name)) {
2964  //        ...
2965  //     }
2966  //   }
2967  //
2968  // If the for..in is in fast-mode, we know that the {receiver} has {name}
2969  // as own property, otherwise the enumeration wouldn't include it. The graph
2970  // constructed by the BytecodeGraphBuilder in this case looks like this:
2971
2972  // receiver
2973  //  ^    ^
2974  //  |    |
2975  //  |    +-+
2976  //  |      |
2977  //  |   JSToObject
2978  //  |      ^
2979  //  |      |
2980  //  |   JSForInNext
2981  //  |      ^
2982  //  +----+ |
2983  //       | |
2984  //  JSCall[hasOwnProperty]
2985
2986  // We can constant-fold the {node} to True in this case, and insert
2987  // a (potentially redundant) map check to guard the fact that the
2988  // {receiver} map didn't change since the dominating JSForInNext. This
2989  // map check is only necessary when TurboFan cannot prove that there
2990  // is no observable side effect between the {JSForInNext} and the
2991  // {JSCall} to Object.prototype.hasOwnProperty.
2992  //
2993  // Also note that it's safe to look through the {JSToObject}, since the
2994  // Object.prototype.hasOwnProperty does an implicit ToObject anyway, and
2995  // these operations are not observable.
2996  if (name->opcode() == IrOpcode::kJSForInNext) {
2997    JSForInNextNode n(name);
2998    if (n.Parameters().mode() != ForInMode::kGeneric) {
2999      Node* object = n.receiver();
3000      Node* cache_type = n.cache_type();
3001      if (object->opcode() == IrOpcode::kJSToObject) {
3002        object = NodeProperties::GetValueInput(object, 0);
3003      }
3004      if (object == receiver) {
3005        // No need to repeat the map check if we can prove that there's no
3006        // observable side effect between {effect} and {name].
3007        if (!NodeProperties::NoObservableSideEffectBetween(effect, name)) {
3008          Node* receiver_map = effect =
3009              graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
3010                               receiver, effect, control);
3011          Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
3012                                         receiver_map, cache_type);
3013          effect = graph()->NewNode(
3014              simplified()->CheckIf(DeoptimizeReason::kWrongMap), check, effect,
3015              control);
3016        }
3017        Node* value = jsgraph()->TrueConstant();
3018        ReplaceWithValue(node, value, effect, control);
3019        return Replace(value);
3020      }
3021    }
3022  }
3023
3024  return NoChange();
3025}
3026
3027// ES #sec-object.prototype.isprototypeof
3028Reduction JSCallReducer::ReduceObjectPrototypeIsPrototypeOf(Node* node) {
3029  JSCallNode n(node);
3030  Node* receiver = n.receiver();
3031  Node* value = n.ArgumentOrUndefined(0, jsgraph());
3032  Effect effect = n.effect();
3033
3034  // Ensure that the {receiver} is known to be a JSReceiver (so that
3035  // the ToObject step of Object.prototype.isPrototypeOf is a no-op).
3036  MapInference inference(broker(), receiver, effect);
3037  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAreJSReceiver()) {
3038    return NoChange();
3039  }
3040
3041  // We don't check whether {value} is a proper JSReceiver here explicitly,
3042  // and don't explicitly rule out Primitive {value}s, since all of them
3043  // have null as their prototype, so the prototype chain walk inside the
3044  // JSHasInPrototypeChain operator immediately aborts and yields false.
3045  NodeProperties::ReplaceValueInput(node, value, n.TargetIndex());
3046  for (int i = node->op()->ValueInputCount(); i > 2; i--) {
3047    node->RemoveInput(2);
3048  }
3049  NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain());
3050  return Changed(node);
3051}
3052
3053// ES6 section 26.1.1 Reflect.apply ( target, thisArgument, argumentsList )
3054Reduction JSCallReducer::ReduceReflectApply(Node* node) {
3055  JSCallNode n(node);
3056  CallParameters const& p = n.Parameters();
3057  int arity = p.arity_without_implicit_args();
3058  // Massage value inputs appropriately.
3059  STATIC_ASSERT(n.ReceiverIndex() > n.TargetIndex());
3060  node->RemoveInput(n.ReceiverIndex());
3061  node->RemoveInput(n.TargetIndex());
3062  while (arity < 3) {
3063    node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant());
3064  }
3065  while (arity-- > 3) {
3066    node->RemoveInput(arity);
3067  }
3068  NodeProperties::ChangeOp(
3069      node, javascript()->CallWithArrayLike(p.frequency(), p.feedback(),
3070                                            p.speculation_mode(),
3071                                            CallFeedbackRelation::kUnrelated));
3072  return Changed(node).FollowedBy(ReduceJSCallWithArrayLike(node));
3073}
3074
3075// ES6 section 26.1.2 Reflect.construct ( target, argumentsList [, newTarget] )
3076Reduction JSCallReducer::ReduceReflectConstruct(Node* node) {
3077  JSCallNode n(node);
3078  CallParameters const& p = n.Parameters();
3079  int arity = p.arity_without_implicit_args();
3080  // Massage value inputs appropriately.
3081  Node* arg_target = n.ArgumentOrUndefined(0, jsgraph());
3082  Node* arg_argument_list = n.ArgumentOrUndefined(1, jsgraph());
3083  Node* arg_new_target = n.ArgumentOr(2, arg_target);
3084
3085  STATIC_ASSERT(n.ReceiverIndex() > n.TargetIndex());
3086  node->RemoveInput(n.ReceiverIndex());
3087  node->RemoveInput(n.TargetIndex());
3088
3089  // TODO(jgruber): This pattern essentially ensures that we have the correct
3090  // number of inputs for a given argument count. Wrap it in a helper function.
3091  STATIC_ASSERT(JSConstructNode::FirstArgumentIndex() == 2);
3092  while (arity < 3) {
3093    node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant());
3094  }
3095  while (arity-- > 3) {
3096    node->RemoveInput(arity);
3097  }
3098
3099  STATIC_ASSERT(JSConstructNode::TargetIndex() == 0);
3100  STATIC_ASSERT(JSConstructNode::NewTargetIndex() == 1);
3101  STATIC_ASSERT(JSConstructNode::kFeedbackVectorIsLastInput);
3102  node->ReplaceInput(JSConstructNode::TargetIndex(), arg_target);
3103  node->ReplaceInput(JSConstructNode::NewTargetIndex(), arg_new_target);
3104  node->ReplaceInput(JSConstructNode::ArgumentIndex(0), arg_argument_list);
3105
3106  NodeProperties::ChangeOp(
3107      node, javascript()->ConstructWithArrayLike(p.frequency(), p.feedback()));
3108  return Changed(node).FollowedBy(ReduceJSConstructWithArrayLike(node));
3109}
3110
3111// ES6 section 26.1.7 Reflect.getPrototypeOf ( target )
3112Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) {
3113  JSCallNode n(node);
3114  Node* target = n.ArgumentOrUndefined(0, jsgraph());
3115  return ReduceObjectGetPrototype(node, target);
3116}
3117
3118// ES6 section #sec-object.create Object.create(proto, properties)
3119Reduction JSCallReducer::ReduceObjectCreate(Node* node) {
3120  JSCallNode n(node);
3121  Node* properties = n.ArgumentOrUndefined(1, jsgraph());
3122  if (properties != jsgraph()->UndefinedConstant()) return NoChange();
3123
3124  Node* context = n.context();
3125  FrameState frame_state = n.frame_state();
3126  Effect effect = n.effect();
3127  Control control = n.control();
3128  Node* prototype = n.ArgumentOrUndefined(0, jsgraph());
3129  node->ReplaceInput(0, prototype);
3130  node->ReplaceInput(1, context);
3131  node->ReplaceInput(2, frame_state);
3132  node->ReplaceInput(3, effect);
3133  node->ReplaceInput(4, control);
3134  node->TrimInputCount(5);
3135  NodeProperties::ChangeOp(node, javascript()->CreateObject());
3136  return Changed(node);
3137}
3138
3139// ES section #sec-reflect.get
3140Reduction JSCallReducer::ReduceReflectGet(Node* node) {
3141  JSCallNode n(node);
3142  CallParameters const& p = n.Parameters();
3143  int arity = p.arity_without_implicit_args();
3144  if (arity != 2) return NoChange();
3145  Node* target = n.Argument(0);
3146  Node* key = n.Argument(1);
3147  Node* context = n.context();
3148  FrameState frame_state = n.frame_state();
3149  Effect effect = n.effect();
3150  Control control = n.control();
3151
3152  // Check whether {target} is a JSReceiver.
3153  Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), target);
3154  Node* branch =
3155      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
3156
3157  // Throw an appropriate TypeError if the {target} is not a JSReceiver.
3158  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
3159  Node* efalse = effect;
3160  {
3161    if_false = efalse = graph()->NewNode(
3162        javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
3163        jsgraph()->Constant(
3164            static_cast<int>(MessageTemplate::kCalledOnNonObject)),
3165        jsgraph()->HeapConstant(factory()->ReflectGet_string()), context,
3166        frame_state, efalse, if_false);
3167  }
3168
3169  // Otherwise just use the existing GetPropertyStub.
3170  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
3171  Node* etrue = effect;
3172  Node* vtrue;
3173  {
3174    Callable callable = Builtins::CallableFor(isolate(), Builtin::kGetProperty);
3175    auto call_descriptor = Linkage::GetStubCallDescriptor(
3176        graph()->zone(), callable.descriptor(),
3177        callable.descriptor().GetStackParameterCount(),
3178        CallDescriptor::kNeedsFrameState, Operator::kNoProperties);
3179    Node* stub_code = jsgraph()->HeapConstant(callable.code());
3180    vtrue = etrue = if_true =
3181        graph()->NewNode(common()->Call(call_descriptor), stub_code, target,
3182                         key, context, frame_state, etrue, if_true);
3183  }
3184
3185  // Rewire potential exception edges.
3186  Node* on_exception = nullptr;
3187  if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
3188    // Create appropriate {IfException} and {IfSuccess} nodes.
3189    Node* extrue = graph()->NewNode(common()->IfException(), etrue, if_true);
3190    if_true = graph()->NewNode(common()->IfSuccess(), if_true);
3191    Node* exfalse = graph()->NewNode(common()->IfException(), efalse, if_false);
3192    if_false = graph()->NewNode(common()->IfSuccess(), if_false);
3193
3194    // Join the exception edges.
3195    Node* merge = graph()->NewNode(common()->Merge(2), extrue, exfalse);
3196    Node* ephi =
3197        graph()->NewNode(common()->EffectPhi(2), extrue, exfalse, merge);
3198    Node* phi =
3199        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
3200                         extrue, exfalse, merge);
3201    ReplaceWithValue(on_exception, phi, ephi, merge);
3202  }
3203
3204  // Connect the throwing path to end.
3205  if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
3206  NodeProperties::MergeControlToEnd(graph(), common(), if_false);
3207
3208  // Continue on the regular path.
3209  ReplaceWithValue(node, vtrue, etrue, if_true);
3210  return Changed(vtrue);
3211}
3212
3213// ES section #sec-reflect.has
3214Reduction JSCallReducer::ReduceReflectHas(Node* node) {
3215  JSCallNode n(node);
3216  Node* target = n.ArgumentOrUndefined(0, jsgraph());
3217  Node* key = n.ArgumentOrUndefined(1, jsgraph());
3218  Node* context = n.context();
3219  Effect effect = n.effect();
3220  Control control = n.control();
3221  FrameState frame_state = n.frame_state();
3222
3223  // Check whether {target} is a JSReceiver.
3224  Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), target);
3225  Node* branch =
3226      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
3227
3228  // Throw an appropriate TypeError if the {target} is not a JSReceiver.
3229  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
3230  Node* efalse = effect;
3231  {
3232    if_false = efalse = graph()->NewNode(
3233        javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
3234        jsgraph()->Constant(
3235            static_cast<int>(MessageTemplate::kCalledOnNonObject)),
3236        jsgraph()->HeapConstant(factory()->ReflectHas_string()), context,
3237        frame_state, efalse, if_false);
3238  }
3239
3240  // Otherwise just use the existing {JSHasProperty} logic.
3241  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
3242  Node* etrue = effect;
3243  Node* vtrue;
3244  {
3245    // TODO(magardn): collect feedback so this can be optimized
3246    vtrue = etrue = if_true = graph()->NewNode(
3247        javascript()->HasProperty(FeedbackSource()), target, key,
3248        jsgraph()->UndefinedConstant(), context, frame_state, etrue, if_true);
3249  }
3250
3251  // Rewire potential exception edges.
3252  Node* on_exception = nullptr;
3253  if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
3254    // Create appropriate {IfException} and {IfSuccess} nodes.
3255    Node* extrue = graph()->NewNode(common()->IfException(), etrue, if_true);
3256    if_true = graph()->NewNode(common()->IfSuccess(), if_true);
3257    Node* exfalse = graph()->NewNode(common()->IfException(), efalse, if_false);
3258    if_false = graph()->NewNode(common()->IfSuccess(), if_false);
3259
3260    // Join the exception edges.
3261    Node* merge = graph()->NewNode(common()->Merge(2), extrue, exfalse);
3262    Node* ephi =
3263        graph()->NewNode(common()->EffectPhi(2), extrue, exfalse, merge);
3264    Node* phi =
3265        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
3266                         extrue, exfalse, merge);
3267    ReplaceWithValue(on_exception, phi, ephi, merge);
3268  }
3269
3270  // Connect the throwing path to end.
3271  if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
3272  NodeProperties::MergeControlToEnd(graph(), common(), if_false);
3273
3274  // Continue on the regular path.
3275  ReplaceWithValue(node, vtrue, etrue, if_true);
3276  return Changed(vtrue);
3277}
3278
3279namespace {
3280
3281bool CanInlineArrayIteratingBuiltin(JSHeapBroker* broker,
3282                                    ZoneVector<MapRef> const& receiver_maps,
3283                                    ElementsKind* kind_return) {
3284  DCHECK_NE(0, receiver_maps.size());
3285  *kind_return = receiver_maps[0].elements_kind();
3286  for (const MapRef& map : receiver_maps) {
3287    if (!map.supports_fast_array_iteration() ||
3288        !UnionElementsKindUptoSize(kind_return, map.elements_kind())) {
3289      return false;
3290    }
3291  }
3292  return true;
3293}
3294
3295bool CanInlineArrayResizingBuiltin(JSHeapBroker* broker,
3296                                   ZoneVector<MapRef> const& receiver_maps,
3297                                   std::vector<ElementsKind>* kinds,
3298                                   bool builtin_is_push = false) {
3299  DCHECK_NE(0, receiver_maps.size());
3300  for (const MapRef& map : receiver_maps) {
3301    if (!map.supports_fast_array_resize()) return false;
3302    // TODO(turbofan): We should also handle fast holey double elements once
3303    // we got the hole NaN mess sorted out in TurboFan/V8.
3304    if (map.elements_kind() == HOLEY_DOUBLE_ELEMENTS && !builtin_is_push) {
3305      return false;
3306    }
3307    ElementsKind current_kind = map.elements_kind();
3308    auto kind_ptr = kinds->data();
3309    size_t i;
3310    for (i = 0; i < kinds->size(); i++, kind_ptr++) {
3311      if (UnionElementsKindUptoPackedness(kind_ptr, current_kind)) {
3312        break;
3313      }
3314    }
3315    if (i == kinds->size()) kinds->push_back(current_kind);
3316  }
3317  return true;
3318}
3319
3320// Wraps common setup code for iterating array builtins.
3321class IteratingArrayBuiltinHelper {
3322 public:
3323  IteratingArrayBuiltinHelper(Node* node, JSHeapBroker* broker,
3324                              JSGraph* jsgraph,
3325                              CompilationDependencies* dependencies)
3326      : receiver_(NodeProperties::GetValueInput(node, 1)),
3327        effect_(NodeProperties::GetEffectInput(node)),
3328        control_(NodeProperties::GetControlInput(node)),
3329        inference_(broker, receiver_, effect_) {
3330    if (!FLAG_turbo_inline_array_builtins) return;
3331
3332    DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
3333    const CallParameters& p = CallParametersOf(node->op());
3334    if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
3335      return;
3336    }
3337
3338    // Try to determine the {receiver} map.
3339    if (!inference_.HaveMaps()) return;
3340    ZoneVector<MapRef> const& receiver_maps = inference_.GetMaps();
3341
3342    if (!CanInlineArrayIteratingBuiltin(broker, receiver_maps,
3343                                        &elements_kind_)) {
3344      return;
3345    }
3346
3347    // TODO(jgruber): May only be needed for holey elements kinds.
3348    if (!dependencies->DependOnNoElementsProtector()) return;
3349
3350    has_stability_dependency_ = inference_.RelyOnMapsPreferStability(
3351        dependencies, jsgraph, &effect_, control_, p.feedback());
3352
3353    can_reduce_ = true;
3354  }
3355
3356  bool can_reduce() const { return can_reduce_; }
3357  bool has_stability_dependency() const { return has_stability_dependency_; }
3358  Effect effect() const { return effect_; }
3359  Control control() const { return control_; }
3360  MapInference* inference() { return &inference_; }
3361  ElementsKind elements_kind() const { return elements_kind_; }
3362
3363 private:
3364  bool can_reduce_ = false;
3365  bool has_stability_dependency_ = false;
3366  Node* receiver_;
3367  Effect effect_;
3368  Control control_;
3369  MapInference inference_;
3370  ElementsKind elements_kind_;
3371};
3372
3373}  // namespace
3374
3375Reduction JSCallReducer::ReduceArrayForEach(
3376    Node* node, const SharedFunctionInfoRef& shared) {
3377  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
3378  if (!h.can_reduce()) return h.inference()->NoChange();
3379
3380  IteratingArrayBuiltinReducerAssembler a(this, node);
3381  a.InitializeEffectControl(h.effect(), h.control());
3382  TNode<Object> subgraph = a.ReduceArrayPrototypeForEach(
3383      h.inference(), h.has_stability_dependency(), h.elements_kind(), shared);
3384  return ReplaceWithSubgraph(&a, subgraph);
3385}
3386
3387Reduction JSCallReducer::ReduceArrayReduce(
3388    Node* node, const SharedFunctionInfoRef& shared) {
3389  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
3390  if (!h.can_reduce()) return h.inference()->NoChange();
3391
3392  IteratingArrayBuiltinReducerAssembler a(this, node);
3393  a.InitializeEffectControl(h.effect(), h.control());
3394  TNode<Object> subgraph = a.ReduceArrayPrototypeReduce(
3395      h.inference(), h.has_stability_dependency(), h.elements_kind(),
3396      ArrayReduceDirection::kLeft, shared);
3397  return ReplaceWithSubgraph(&a, subgraph);
3398}
3399
3400Reduction JSCallReducer::ReduceArrayReduceRight(
3401    Node* node, const SharedFunctionInfoRef& shared) {
3402  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
3403  if (!h.can_reduce()) return h.inference()->NoChange();
3404
3405  IteratingArrayBuiltinReducerAssembler a(this, node);
3406  a.InitializeEffectControl(h.effect(), h.control());
3407  TNode<Object> subgraph = a.ReduceArrayPrototypeReduce(
3408      h.inference(), h.has_stability_dependency(), h.elements_kind(),
3409      ArrayReduceDirection::kRight, shared);
3410  return ReplaceWithSubgraph(&a, subgraph);
3411}
3412
3413Reduction JSCallReducer::ReduceArrayMap(Node* node,
3414                                        const SharedFunctionInfoRef& shared) {
3415  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
3416  if (!h.can_reduce()) return h.inference()->NoChange();
3417
3418  // Calls CreateArray and thus requires this additional protector dependency.
3419  if (!dependencies()->DependOnArraySpeciesProtector()) {
3420    return h.inference()->NoChange();
3421  }
3422
3423  IteratingArrayBuiltinReducerAssembler a(this, node);
3424  a.InitializeEffectControl(h.effect(), h.control());
3425
3426  TNode<Object> subgraph =
3427      a.ReduceArrayPrototypeMap(h.inference(), h.has_stability_dependency(),
3428                                h.elements_kind(), shared, native_context());
3429  return ReplaceWithSubgraph(&a, subgraph);
3430}
3431
3432Reduction JSCallReducer::ReduceArrayFilter(
3433    Node* node, const SharedFunctionInfoRef& shared) {
3434  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
3435  if (!h.can_reduce()) return h.inference()->NoChange();
3436
3437  // Calls CreateArray and thus requires this additional protector dependency.
3438  if (!dependencies()->DependOnArraySpeciesProtector()) {
3439    return h.inference()->NoChange();
3440  }
3441
3442  IteratingArrayBuiltinReducerAssembler a(this, node);
3443  a.InitializeEffectControl(h.effect(), h.control());
3444
3445  TNode<Object> subgraph =
3446      a.ReduceArrayPrototypeFilter(h.inference(), h.has_stability_dependency(),
3447                                   h.elements_kind(), shared, native_context());
3448  return ReplaceWithSubgraph(&a, subgraph);
3449}
3450
3451Reduction JSCallReducer::ReduceArrayFind(Node* node,
3452                                         const SharedFunctionInfoRef& shared) {
3453  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
3454  if (!h.can_reduce()) return h.inference()->NoChange();
3455
3456  IteratingArrayBuiltinReducerAssembler a(this, node);
3457  a.InitializeEffectControl(h.effect(), h.control());
3458
3459  TNode<Object> subgraph = a.ReduceArrayPrototypeFind(
3460      h.inference(), h.has_stability_dependency(), h.elements_kind(), shared,
3461      native_context(), ArrayFindVariant::kFind);
3462  return ReplaceWithSubgraph(&a, subgraph);
3463}
3464
3465Reduction JSCallReducer::ReduceArrayFindIndex(
3466    Node* node, const SharedFunctionInfoRef& shared) {
3467  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
3468  if (!h.can_reduce()) return h.inference()->NoChange();
3469
3470  IteratingArrayBuiltinReducerAssembler a(this, node);
3471  a.InitializeEffectControl(h.effect(), h.control());
3472
3473  TNode<Object> subgraph = a.ReduceArrayPrototypeFind(
3474      h.inference(), h.has_stability_dependency(), h.elements_kind(), shared,
3475      native_context(), ArrayFindVariant::kFindIndex);
3476  return ReplaceWithSubgraph(&a, subgraph);
3477}
3478
3479Reduction JSCallReducer::ReduceArrayEvery(Node* node,
3480                                          const SharedFunctionInfoRef& shared) {
3481  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
3482  if (!h.can_reduce()) return h.inference()->NoChange();
3483
3484  IteratingArrayBuiltinReducerAssembler a(this, node);
3485  a.InitializeEffectControl(h.effect(), h.control());
3486
3487  TNode<Object> subgraph = a.ReduceArrayPrototypeEverySome(
3488      h.inference(), h.has_stability_dependency(), h.elements_kind(), shared,
3489      native_context(), ArrayEverySomeVariant::kEvery);
3490  return ReplaceWithSubgraph(&a, subgraph);
3491}
3492
3493// ES7 Array.prototype.inludes(searchElement[, fromIndex])
3494// #sec-array.prototype.includes
3495Reduction JSCallReducer::ReduceArrayIncludes(Node* node) {
3496  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
3497  if (!h.can_reduce()) return h.inference()->NoChange();
3498
3499  IteratingArrayBuiltinReducerAssembler a(this, node);
3500  a.InitializeEffectControl(h.effect(), h.control());
3501
3502  TNode<Object> subgraph = a.ReduceArrayPrototypeIndexOfIncludes(
3503      h.elements_kind(), ArrayIndexOfIncludesVariant::kIncludes);
3504  return ReplaceWithSubgraph(&a, subgraph);
3505}
3506
3507// ES6 Array.prototype.indexOf(searchElement[, fromIndex])
3508// #sec-array.prototype.indexof
3509Reduction JSCallReducer::ReduceArrayIndexOf(Node* node) {
3510  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
3511  if (!h.can_reduce()) return h.inference()->NoChange();
3512
3513  IteratingArrayBuiltinReducerAssembler a(this, node);
3514  a.InitializeEffectControl(h.effect(), h.control());
3515
3516  TNode<Object> subgraph = a.ReduceArrayPrototypeIndexOfIncludes(
3517      h.elements_kind(), ArrayIndexOfIncludesVariant::kIndexOf);
3518  return ReplaceWithSubgraph(&a, subgraph);
3519}
3520
3521Reduction JSCallReducer::ReduceArraySome(Node* node,
3522                                         const SharedFunctionInfoRef& shared) {
3523  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
3524  if (!h.can_reduce()) return h.inference()->NoChange();
3525
3526  IteratingArrayBuiltinReducerAssembler a(this, node);
3527  a.InitializeEffectControl(h.effect(), h.control());
3528
3529  TNode<Object> subgraph = a.ReduceArrayPrototypeEverySome(
3530      h.inference(), h.has_stability_dependency(), h.elements_kind(), shared,
3531      native_context(), ArrayEverySomeVariant::kSome);
3532  return ReplaceWithSubgraph(&a, subgraph);
3533}
3534
3535#if V8_ENABLE_WEBASSEMBLY
3536
3537namespace {
3538
3539bool CanInlineJSToWasmCall(const wasm::FunctionSig* wasm_signature) {
3540  if (wasm_signature->return_count() > 1) {
3541    return false;
3542  }
3543
3544  for (auto type : wasm_signature->all()) {
3545#if defined(V8_TARGET_ARCH_32_BIT)
3546    if (type == wasm::kWasmI64) return false;
3547#endif
3548    if (type != wasm::kWasmI32 && type != wasm::kWasmI64 &&
3549        type != wasm::kWasmF32 && type != wasm::kWasmF64) {
3550      return false;
3551    }
3552  }
3553
3554  return true;
3555}
3556
3557}  // namespace
3558
3559Reduction JSCallReducer::ReduceCallWasmFunction(
3560    Node* node, const SharedFunctionInfoRef& shared) {
3561  DCHECK(flags() & kInlineJSToWasmCalls);
3562
3563  JSCallNode n(node);
3564  const CallParameters& p = n.Parameters();
3565
3566  // Avoid deoptimization loops
3567  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
3568    return NoChange();
3569  }
3570
3571  const wasm::FunctionSig* wasm_signature = shared.wasm_function_signature();
3572  if (!CanInlineJSToWasmCall(wasm_signature)) {
3573    return NoChange();
3574  }
3575
3576  // Signal TurboFan that it should run the 'wasm-inlining' phase.
3577  has_wasm_calls_ = true;
3578
3579  const wasm::WasmModule* wasm_module = shared.wasm_module();
3580  const Operator* op =
3581      javascript()->CallWasm(wasm_module, wasm_signature, p.feedback());
3582
3583  // Remove additional inputs
3584  size_t actual_arity = n.ArgumentCount();
3585  DCHECK(JSCallNode::kFeedbackVectorIsLastInput);
3586  DCHECK_EQ(actual_arity + JSWasmCallNode::kExtraInputCount - 1,
3587            n.FeedbackVectorIndex());
3588  size_t expected_arity = wasm_signature->parameter_count();
3589
3590  while (actual_arity > expected_arity) {
3591    int removal_index =
3592        static_cast<int>(n.FirstArgumentIndex() + expected_arity);
3593    DCHECK_LT(removal_index, static_cast<int>(node->InputCount()));
3594    node->RemoveInput(removal_index);
3595    actual_arity--;
3596  }
3597
3598  // Add missing inputs
3599  while (actual_arity < expected_arity) {
3600    int insertion_index = n.ArgumentIndex(n.ArgumentCount());
3601    node->InsertInput(graph()->zone(), insertion_index,
3602                      jsgraph()->UndefinedConstant());
3603    actual_arity++;
3604  }
3605
3606  NodeProperties::ChangeOp(node, op);
3607  return Changed(node);
3608}
3609#endif  // V8_ENABLE_WEBASSEMBLY
3610
3611// Given a FunctionTemplateInfo, checks whether the fast API call can be
3612// optimized, applying the initial step of the overload resolution algorithm:
3613// Given an overload set function_template_info.c_signatures, and a list of
3614// arguments of size argc:
3615// 1. Let max_arg be the length of the longest type list of the entries in
3616//    function_template_info.c_signatures.
3617// 2. Let argc be the size of the arguments list.
3618// 3. Initialize arg_count = min(max_arg, argc).
3619// 4. Remove from the set all entries whose type list is not of length
3620//    arg_count.
3621// Returns an array with the indexes of the remaining entries in S, which
3622// represents the set of "optimizable" function overloads.
3623
3624FastApiCallFunctionVector CanOptimizeFastCall(
3625    Zone* zone, const FunctionTemplateInfoRef& function_template_info,
3626    size_t argc) {
3627  FastApiCallFunctionVector result(zone);
3628  if (!FLAG_turbo_fast_api_calls) return result;
3629
3630  static constexpr int kReceiver = 1;
3631
3632  ZoneVector<Address> functions = function_template_info.c_functions();
3633  ZoneVector<const CFunctionInfo*> signatures =
3634      function_template_info.c_signatures();
3635  const size_t overloads_count = signatures.size();
3636
3637  // Calculates the length of the longest type list of the entries in
3638  // function_template_info.
3639  size_t max_arg = 0;
3640  for (size_t i = 0; i < overloads_count; i++) {
3641    const CFunctionInfo* c_signature = signatures[i];
3642    // C arguments should include the receiver at index 0.
3643    DCHECK_GE(c_signature->ArgumentCount(), kReceiver);
3644    const size_t len = c_signature->ArgumentCount() - kReceiver;
3645    if (len > max_arg) max_arg = len;
3646  }
3647  const size_t arg_count = std::min(max_arg, argc);
3648
3649  // Only considers entries whose type list length matches arg_count.
3650  for (size_t i = 0; i < overloads_count; i++) {
3651    const CFunctionInfo* c_signature = signatures[i];
3652    const size_t len = c_signature->ArgumentCount() - kReceiver;
3653    bool optimize_to_fast_call = (len == arg_count);
3654
3655    optimize_to_fast_call =
3656        optimize_to_fast_call &&
3657        fast_api_call::CanOptimizeFastSignature(c_signature);
3658
3659    if (optimize_to_fast_call) {
3660      result.push_back({functions[i], c_signature});
3661    }
3662  }
3663
3664  return result;
3665}
3666
3667Reduction JSCallReducer::ReduceCallApiFunction(
3668    Node* node, const SharedFunctionInfoRef& shared) {
3669  JSCallNode n(node);
3670  CallParameters const& p = n.Parameters();
3671  int const argc = p.arity_without_implicit_args();
3672  Node* target = n.target();
3673  Node* global_proxy =
3674      jsgraph()->Constant(native_context().global_proxy_object());
3675  Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined)
3676                       ? global_proxy
3677                       : n.receiver();
3678  Node* holder;
3679  Node* context = n.context();
3680  Effect effect = n.effect();
3681  Control control = n.control();
3682  FrameState frame_state = n.frame_state();
3683
3684  if (!shared.function_template_info().has_value()) {
3685    TRACE_BROKER_MISSING(
3686        broker(), "FunctionTemplateInfo for function with SFI " << shared);
3687    return NoChange();
3688  }
3689
3690  // See if we can optimize this API call to {shared}.
3691  FunctionTemplateInfoRef function_template_info(
3692      shared.function_template_info().value());
3693
3694  if (function_template_info.accept_any_receiver() &&
3695      function_template_info.is_signature_undefined()) {
3696    // We might be able to
3697    // optimize the API call depending on the {function_template_info}.
3698    // If the API function accepts any kind of {receiver}, we only need to
3699    // ensure that the {receiver} is actually a JSReceiver at this point,
3700    // and also pass that as the {holder}. There are two independent bits
3701    // here:
3702    //
3703    //  a. When the "accept any receiver" bit is set, it means we don't
3704    //     need to perform access checks, even if the {receiver}'s map
3705    //     has the "needs access check" bit set.
3706    //  b. When the {function_template_info} has no signature, we don't
3707    //     need to do the compatible receiver check, since all receivers
3708    //     are considered compatible at that point, and the {receiver}
3709    //     will be pass as the {holder}.
3710    //
3711    receiver = holder = effect =
3712        graph()->NewNode(simplified()->ConvertReceiver(p.convert_mode()),
3713                         receiver, global_proxy, effect, control);
3714  } else {
3715    // Try to infer the {receiver} maps from the graph.
3716    MapInference inference(broker(), receiver, effect);
3717    if (inference.HaveMaps()) {
3718      ZoneVector<MapRef> const& receiver_maps = inference.GetMaps();
3719      MapRef first_receiver_map = receiver_maps[0];
3720
3721      // See if we can constant-fold the compatible receiver checks.
3722      HolderLookupResult api_holder =
3723          function_template_info.LookupHolderOfExpectedType(first_receiver_map);
3724      if (api_holder.lookup == CallOptimization::kHolderNotFound) {
3725        return inference.NoChange();
3726      }
3727
3728      // Check that all {receiver_maps} are actually JSReceiver maps and
3729      // that the {function_template_info} accepts them without access
3730      // checks (even if "access check needed" is set for {receiver}).
3731      //
3732      // Note that we don't need to know the concrete {receiver} maps here,
3733      // meaning it's fine if the {receiver_maps} are unreliable, and we also
3734      // don't need to install any stability dependencies, since the only
3735      // relevant information regarding the {receiver} is the Map::constructor
3736      // field on the root map (which is different from the JavaScript exposed
3737      // "constructor" property) and that field cannot change.
3738      //
3739      // So if we know that {receiver} had a certain constructor at some point
3740      // in the past (i.e. it had a certain map), then this constructor is going
3741      // to be the same later, since this information cannot change with map
3742      // transitions.
3743      //
3744      // The same is true for the instance type, e.g. we still know that the
3745      // instance type is JSObject even if that information is unreliable, and
3746      // the "access check needed" bit, which also cannot change later.
3747      CHECK(first_receiver_map.IsJSReceiverMap());
3748      CHECK(!first_receiver_map.is_access_check_needed() ||
3749            function_template_info.accept_any_receiver());
3750
3751      for (size_t i = 1; i < receiver_maps.size(); ++i) {
3752        MapRef receiver_map = receiver_maps[i];
3753        HolderLookupResult holder_i =
3754            function_template_info.LookupHolderOfExpectedType(receiver_map);
3755
3756        if (api_holder.lookup != holder_i.lookup) return inference.NoChange();
3757        DCHECK(holder_i.lookup == CallOptimization::kHolderFound ||
3758               holder_i.lookup == CallOptimization::kHolderIsReceiver);
3759        if (holder_i.lookup == CallOptimization::kHolderFound) {
3760          DCHECK(api_holder.holder.has_value() && holder_i.holder.has_value());
3761          if (!api_holder.holder->equals(*holder_i.holder)) {
3762            return inference.NoChange();
3763          }
3764        }
3765
3766        CHECK(receiver_map.IsJSReceiverMap());
3767        CHECK(!receiver_map.is_access_check_needed() ||
3768              function_template_info.accept_any_receiver());
3769      }
3770
3771      if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation &&
3772          !inference.RelyOnMapsViaStability(dependencies())) {
3773        // We were not able to make the receiver maps reliable without map
3774        // checks but doing map checks would lead to deopt loops, so give up.
3775        return inference.NoChange();
3776      }
3777
3778      // TODO(neis): The maps were used in a way that does not actually require
3779      // map checks or stability dependencies.
3780      inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
3781                                          control, p.feedback());
3782
3783      // Determine the appropriate holder for the {lookup}.
3784      holder = api_holder.lookup == CallOptimization::kHolderFound
3785                   ? jsgraph()->Constant(*api_holder.holder)
3786                   : receiver;
3787    } else {
3788      // We don't have enough information to eliminate the access check
3789      // and/or the compatible receiver check, so use the generic builtin
3790      // that does those checks dynamically. This is still significantly
3791      // faster than the generic call sequence.
3792      Builtin builtin_name;
3793      if (function_template_info.accept_any_receiver()) {
3794        builtin_name = Builtin::kCallFunctionTemplate_CheckCompatibleReceiver;
3795      } else if (function_template_info.is_signature_undefined()) {
3796        builtin_name = Builtin::kCallFunctionTemplate_CheckAccess;
3797      } else {
3798        builtin_name =
3799            Builtin::kCallFunctionTemplate_CheckAccessAndCompatibleReceiver;
3800      }
3801
3802      // The CallFunctionTemplate builtin requires the {receiver} to be
3803      // an actual JSReceiver, so make sure we do the proper conversion
3804      // first if necessary.
3805      receiver = holder = effect =
3806          graph()->NewNode(simplified()->ConvertReceiver(p.convert_mode()),
3807                           receiver, global_proxy, effect, control);
3808
3809      Callable callable = Builtins::CallableFor(isolate(), builtin_name);
3810      auto call_descriptor = Linkage::GetStubCallDescriptor(
3811          graph()->zone(), callable.descriptor(),
3812          argc + 1 /* implicit receiver */, CallDescriptor::kNeedsFrameState);
3813      node->RemoveInput(n.FeedbackVectorIndex());
3814      node->InsertInput(graph()->zone(), 0,
3815                        jsgraph()->HeapConstant(callable.code()));
3816      node->ReplaceInput(1, jsgraph()->Constant(function_template_info));
3817      node->InsertInput(graph()->zone(), 2,
3818                        jsgraph()->Constant(JSParameterCount(argc)));
3819      node->ReplaceInput(3, receiver);       // Update receiver input.
3820      node->ReplaceInput(6 + argc, effect);  // Update effect input.
3821      NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
3822      return Changed(node);
3823    }
3824  }
3825
3826  // TODO(turbofan): Consider introducing a JSCallApiCallback operator for
3827  // this and lower it during JSGenericLowering, and unify this with the
3828  // JSNativeContextSpecialization::InlineApiCall method a bit.
3829  if (!function_template_info.call_code().has_value()) {
3830    TRACE_BROKER_MISSING(broker(), "call code for function template info "
3831                                       << function_template_info);
3832    return NoChange();
3833  }
3834
3835  // Handles overloaded functions.
3836
3837  FastApiCallFunctionVector c_candidate_functions =
3838      CanOptimizeFastCall(graph()->zone(), function_template_info, argc);
3839  DCHECK_LE(c_candidate_functions.size(), 2);
3840
3841  if (!c_candidate_functions.empty()) {
3842    FastApiCallReducerAssembler a(this, node, function_template_info,
3843                                  c_candidate_functions, receiver, holder,
3844                                  shared, target, argc, effect);
3845    Node* fast_call_subgraph = a.ReduceFastApiCall();
3846    ReplaceWithSubgraph(&a, fast_call_subgraph);
3847
3848    return Replace(fast_call_subgraph);
3849  }
3850
3851  // Slow call
3852
3853  CallHandlerInfoRef call_handler_info = *function_template_info.call_code();
3854  Callable call_api_callback = CodeFactory::CallApiCallback(isolate());
3855  CallInterfaceDescriptor cid = call_api_callback.descriptor();
3856  auto call_descriptor =
3857      Linkage::GetStubCallDescriptor(graph()->zone(), cid, argc + 1 /*
3858     implicit receiver */, CallDescriptor::kNeedsFrameState);
3859  ApiFunction api_function(call_handler_info.callback());
3860  ExternalReference function_reference = ExternalReference::Create(
3861      &api_function, ExternalReference::DIRECT_API_CALL);
3862
3863  Node* continuation_frame_state = CreateGenericLazyDeoptContinuationFrameState(
3864      jsgraph(), shared, target, context, receiver, frame_state);
3865
3866  node->RemoveInput(n.FeedbackVectorIndex());
3867  node->InsertInput(graph()->zone(), 0,
3868                    jsgraph()->HeapConstant(call_api_callback.code()));
3869  node->ReplaceInput(1, jsgraph()->ExternalConstant(function_reference));
3870  node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(argc));
3871  node->InsertInput(graph()->zone(), 3,
3872                    jsgraph()->Constant(call_handler_info.data()));
3873  node->InsertInput(graph()->zone(), 4, holder);
3874  node->ReplaceInput(5, receiver);  // Update receiver input.
3875  // 6 + argc is context input.
3876  node->ReplaceInput(6 + argc + 1, continuation_frame_state);
3877  node->ReplaceInput(6 + argc + 2, effect);
3878  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
3879  return Changed(node);
3880}
3881
3882namespace {
3883
3884// Check whether elements aren't mutated; we play it extremely safe here by
3885// explicitly checking that {node} is only used by {LoadField} or
3886// {LoadElement}.
3887bool IsSafeArgumentsElements(Node* node) {
3888  for (Edge const edge : node->use_edges()) {
3889    if (!NodeProperties::IsValueEdge(edge)) continue;
3890    if (edge.from()->opcode() != IrOpcode::kLoadField &&
3891        edge.from()->opcode() != IrOpcode::kLoadElement) {
3892      return false;
3893    }
3894  }
3895  return true;
3896}
3897
3898#ifdef DEBUG
3899bool IsCallOrConstructWithArrayLike(Node* node) {
3900  return node->opcode() == IrOpcode::kJSCallWithArrayLike ||
3901         node->opcode() == IrOpcode::kJSConstructWithArrayLike;
3902}
3903#endif
3904
3905bool IsCallOrConstructWithSpread(Node* node) {
3906  return node->opcode() == IrOpcode::kJSCallWithSpread ||
3907         node->opcode() == IrOpcode::kJSConstructWithSpread;
3908}
3909
3910bool IsCallWithArrayLikeOrSpread(Node* node) {
3911  return node->opcode() == IrOpcode::kJSCallWithArrayLike ||
3912         node->opcode() == IrOpcode::kJSCallWithSpread;
3913}
3914
3915}  // namespace
3916
3917void JSCallReducer::CheckIfConstructor(Node* construct) {
3918  JSConstructNode n(construct);
3919  Node* new_target = n.new_target();
3920  Control control = n.control();
3921
3922  Node* check =
3923      graph()->NewNode(simplified()->ObjectIsConstructor(), new_target);
3924  Node* check_branch =
3925      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
3926  Node* check_fail = graph()->NewNode(common()->IfFalse(), check_branch);
3927  Node* check_throw = check_fail = graph()->NewNode(
3928      javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
3929      jsgraph()->Constant(static_cast<int>(MessageTemplate::kNotConstructor)),
3930      new_target, n.context(), n.frame_state(), n.effect(), check_fail);
3931  control = graph()->NewNode(common()->IfTrue(), check_branch);
3932  NodeProperties::ReplaceControlInput(construct, control);
3933
3934  // Rewire potential exception edges.
3935  Node* on_exception = nullptr;
3936  if (NodeProperties::IsExceptionalCall(construct, &on_exception)) {
3937    // Create appropriate {IfException}  and {IfSuccess} nodes.
3938    Node* if_exception =
3939        graph()->NewNode(common()->IfException(), check_throw, check_fail);
3940    check_fail = graph()->NewNode(common()->IfSuccess(), check_fail);
3941
3942    // Join the exception edges.
3943    Node* merge =
3944        graph()->NewNode(common()->Merge(2), if_exception, on_exception);
3945    Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception,
3946                                  on_exception, merge);
3947    Node* phi =
3948        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
3949                         if_exception, on_exception, merge);
3950    ReplaceWithValue(on_exception, phi, ephi, merge);
3951    merge->ReplaceInput(1, on_exception);
3952    ephi->ReplaceInput(1, on_exception);
3953    phi->ReplaceInput(1, on_exception);
3954  }
3955
3956  // The above %ThrowTypeError runtime call is an unconditional throw,
3957  // making it impossible to return a successful completion in this case. We
3958  // simply connect the successful completion to the graph end.
3959  Node* throw_node =
3960      graph()->NewNode(common()->Throw(), check_throw, check_fail);
3961  NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
3962}
3963
3964namespace {
3965
3966bool ShouldUseCallICFeedback(Node* node) {
3967  HeapObjectMatcher m(node);
3968  if (m.HasResolvedValue() || m.IsCheckClosure() || m.IsJSCreateClosure()) {
3969    // Don't use CallIC feedback when we know the function
3970    // being called, i.e. either know the closure itself or
3971    // at least the SharedFunctionInfo.
3972    return false;
3973  } else if (m.IsPhi()) {
3974    // Protect against endless loops here.
3975    Node* control = NodeProperties::GetControlInput(node);
3976    if (control->opcode() == IrOpcode::kLoop ||
3977        control->opcode() == IrOpcode::kDead)
3978      return false;
3979    // Check if {node} is a Phi of nodes which shouldn't
3980    // use CallIC feedback (not looking through loops).
3981    int const value_input_count = m.node()->op()->ValueInputCount();
3982    for (int n = 0; n < value_input_count; ++n) {
3983      if (ShouldUseCallICFeedback(node->InputAt(n))) return true;
3984    }
3985    return false;
3986  }
3987  return true;
3988}
3989
3990}  // namespace
3991
3992Node* JSCallReducer::CheckArrayLength(Node* array, ElementsKind elements_kind,
3993                                      uint32_t array_length,
3994                                      const FeedbackSource& feedback_source,
3995                                      Effect effect, Control control) {
3996  Node* length = effect = graph()->NewNode(
3997      simplified()->LoadField(AccessBuilder::ForJSArrayLength(elements_kind)),
3998      array, effect, control);
3999  Node* check = graph()->NewNode(simplified()->NumberEqual(), length,
4000                                 jsgraph()->Constant(array_length));
4001  return graph()->NewNode(
4002      simplified()->CheckIf(DeoptimizeReason::kArrayLengthChanged,
4003                            feedback_source),
4004      check, effect, control);
4005}
4006
4007Reduction
4008JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpreadOfCreateArguments(
4009    Node* node, Node* arguments_list, int arraylike_or_spread_index,
4010    CallFrequency const& frequency, FeedbackSource const& feedback,
4011    SpeculationMode speculation_mode, CallFeedbackRelation feedback_relation) {
4012  DCHECK_EQ(arguments_list->opcode(), IrOpcode::kJSCreateArguments);
4013
4014  // Check if {node} is the only value user of {arguments_list} (except for
4015  // value uses in frame states). If not, we give up for now.
4016  for (Edge edge : arguments_list->use_edges()) {
4017    if (!NodeProperties::IsValueEdge(edge)) continue;
4018    Node* const user = edge.from();
4019    switch (user->opcode()) {
4020      case IrOpcode::kCheckMaps:
4021      case IrOpcode::kFrameState:
4022      case IrOpcode::kStateValues:
4023      case IrOpcode::kReferenceEqual:
4024      case IrOpcode::kReturn:
4025        // Ignore safe uses that definitely don't mess with the arguments.
4026        continue;
4027      case IrOpcode::kLoadField: {
4028        DCHECK_EQ(arguments_list, user->InputAt(0));
4029        FieldAccess const& access = FieldAccessOf(user->op());
4030        if (access.offset == JSArray::kLengthOffset) {
4031          // Ignore uses for arguments#length.
4032          STATIC_ASSERT(
4033              static_cast<int>(JSArray::kLengthOffset) ==
4034              static_cast<int>(JSStrictArgumentsObject::kLengthOffset));
4035          STATIC_ASSERT(
4036              static_cast<int>(JSArray::kLengthOffset) ==
4037              static_cast<int>(JSSloppyArgumentsObject::kLengthOffset));
4038          continue;
4039        } else if (access.offset == JSObject::kElementsOffset) {
4040          // Ignore safe uses for arguments#elements.
4041          if (IsSafeArgumentsElements(user)) continue;
4042        }
4043        break;
4044      }
4045      case IrOpcode::kJSCallWithArrayLike: {
4046        // Ignore uses as argumentsList input to calls with array like.
4047        JSCallWithArrayLikeNode n(user);
4048        if (n.Argument(0) == arguments_list) continue;
4049        break;
4050      }
4051      case IrOpcode::kJSConstructWithArrayLike: {
4052        // Ignore uses as argumentsList input to calls with array like.
4053        JSConstructWithArrayLikeNode n(user);
4054        if (n.Argument(0) == arguments_list) continue;
4055        break;
4056      }
4057      case IrOpcode::kJSCallWithSpread: {
4058        // Ignore uses as spread input to calls with spread.
4059        JSCallWithSpreadNode n(user);
4060        if (n.LastArgument() == arguments_list) continue;
4061        break;
4062      }
4063      case IrOpcode::kJSConstructWithSpread: {
4064        // Ignore uses as spread input to construct with spread.
4065        JSConstructWithSpreadNode n(user);
4066        if (n.LastArgument() == arguments_list) continue;
4067        break;
4068      }
4069      default:
4070        break;
4071    }
4072    // We cannot currently reduce the {node} to something better than what
4073    // it already is, but we might be able to do something about the {node}
4074    // later, so put it on the waitlist and try again during finalization.
4075    waitlist_.insert(node);
4076    return NoChange();
4077  }
4078
4079  // Get to the actual frame state from which to extract the arguments;
4080  // we can only optimize this in case the {node} was already inlined into
4081  // some other function (and same for the {arguments_list}).
4082  CreateArgumentsType const type = CreateArgumentsTypeOf(arguments_list->op());
4083  FrameState frame_state =
4084      FrameState{NodeProperties::GetFrameStateInput(arguments_list)};
4085
4086  int formal_parameter_count;
4087  {
4088    Handle<SharedFunctionInfo> shared;
4089    if (!frame_state.frame_state_info().shared_info().ToHandle(&shared)) {
4090      return NoChange();
4091    }
4092    formal_parameter_count =
4093        MakeRef(broker(), shared)
4094            .internal_formal_parameter_count_without_receiver();
4095  }
4096
4097  if (type == CreateArgumentsType::kMappedArguments) {
4098    // Mapped arguments (sloppy mode) that are aliased can only be handled
4099    // here if there's no side-effect between the {node} and the {arg_array}.
4100    // TODO(turbofan): Further relax this constraint.
4101    if (formal_parameter_count != 0) {
4102      Node* effect = NodeProperties::GetEffectInput(node);
4103      if (!NodeProperties::NoObservableSideEffectBetween(effect,
4104                                                         arguments_list)) {
4105        return NoChange();
4106      }
4107    }
4108  }
4109
4110  // For call/construct with spread, we need to also install a code
4111  // dependency on the array iterator lookup protector cell to ensure
4112  // that no one messed with the %ArrayIteratorPrototype%.next method.
4113  if (IsCallOrConstructWithSpread(node)) {
4114    if (!dependencies()->DependOnArrayIteratorProtector()) return NoChange();
4115  }
4116
4117  // Remove the {arguments_list} input from the {node}.
4118  node->RemoveInput(arraylike_or_spread_index);
4119
4120  // The index of the first relevant parameter. Only non-zero when looking at
4121  // rest parameters, in which case it is set to the index of the first rest
4122  // parameter.
4123  const int start_index = (type == CreateArgumentsType::kRestParameter)
4124                              ? formal_parameter_count
4125                              : 0;
4126
4127  // After removing the arraylike or spread object, the argument count is:
4128  int argc =
4129      arraylike_or_spread_index - JSCallOrConstructNode::FirstArgumentIndex();
4130  // Check if are spreading to inlined arguments or to the arguments of
4131  // the outermost function.
4132  if (frame_state.outer_frame_state()->opcode() != IrOpcode::kFrameState) {
4133    Operator const* op;
4134    if (IsCallWithArrayLikeOrSpread(node)) {
4135      static constexpr int kTargetAndReceiver = 2;
4136      op = javascript()->CallForwardVarargs(argc + kTargetAndReceiver,
4137                                            start_index);
4138    } else {
4139      static constexpr int kTargetAndNewTarget = 2;
4140      op = javascript()->ConstructForwardVarargs(argc + kTargetAndNewTarget,
4141                                                 start_index);
4142    }
4143    node->RemoveInput(JSCallOrConstructNode::FeedbackVectorIndexForArgc(argc));
4144    NodeProperties::ChangeOp(node, op);
4145    return Changed(node);
4146  }
4147  // Get to the actual frame state from which to extract the arguments;
4148  // we can only optimize this in case the {node} was already inlined into
4149  // some other function (and same for the {arg_array}).
4150  FrameState outer_state{frame_state.outer_frame_state()};
4151  FrameStateInfo outer_info = outer_state.frame_state_info();
4152  if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
4153    // Need to take the parameters from the arguments adaptor.
4154    frame_state = outer_state;
4155  }
4156  // Add the actual parameters to the {node}, skipping the receiver.
4157  StateValuesAccess parameters_access(frame_state.parameters());
4158  for (auto it = parameters_access.begin_without_receiver_and_skip(start_index);
4159       !it.done(); ++it) {
4160    DCHECK_NOT_NULL(it.node());
4161    node->InsertInput(graph()->zone(),
4162                      JSCallOrConstructNode::ArgumentIndex(argc++), it.node());
4163  }
4164
4165  if (IsCallWithArrayLikeOrSpread(node)) {
4166    NodeProperties::ChangeOp(
4167        node, javascript()->Call(JSCallNode::ArityForArgc(argc), frequency,
4168                                 feedback, ConvertReceiverMode::kAny,
4169                                 speculation_mode, feedback_relation));
4170    return Changed(node).FollowedBy(ReduceJSCall(node));
4171  } else {
4172    NodeProperties::ChangeOp(
4173        node, javascript()->Construct(JSConstructNode::ArityForArgc(argc),
4174                                      frequency, feedback));
4175
4176    // Check whether the given new target value is a constructor function. The
4177    // replacement {JSConstruct} operator only checks the passed target value
4178    // but relies on the new target value to be implicitly valid.
4179    CheckIfConstructor(node);
4180    return Changed(node).FollowedBy(ReduceJSConstruct(node));
4181  }
4182}
4183
4184Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
4185    Node* node, int argument_count, int arraylike_or_spread_index,
4186    CallFrequency const& frequency, FeedbackSource const& feedback_source,
4187    SpeculationMode speculation_mode, CallFeedbackRelation feedback_relation,
4188    Node* target, Effect effect, Control control) {
4189  DCHECK(IsCallOrConstructWithArrayLike(node) ||
4190         IsCallOrConstructWithSpread(node));
4191  DCHECK_IMPLIES(speculation_mode == SpeculationMode::kAllowSpeculation,
4192                 feedback_source.IsValid());
4193
4194  Node* arguments_list =
4195      NodeProperties::GetValueInput(node, arraylike_or_spread_index);
4196
4197  if (arguments_list->opcode() == IrOpcode::kJSCreateArguments) {
4198    return ReduceCallOrConstructWithArrayLikeOrSpreadOfCreateArguments(
4199        node, arguments_list, arraylike_or_spread_index, frequency,
4200        feedback_source, speculation_mode, feedback_relation);
4201  }
4202
4203  if (!FLAG_turbo_optimize_apply) return NoChange();
4204
4205  // Optimization of construct nodes not supported yet.
4206  if (!IsCallWithArrayLikeOrSpread(node)) return NoChange();
4207
4208  // Avoid deoptimization loops.
4209  if (speculation_mode != SpeculationMode::kAllowSpeculation) return NoChange();
4210
4211  // Only optimize with array literals.
4212  if (arguments_list->opcode() != IrOpcode::kJSCreateLiteralArray &&
4213      arguments_list->opcode() != IrOpcode::kJSCreateEmptyLiteralArray) {
4214    return NoChange();
4215  }
4216
4217  // For call/construct with spread, we need to also install a code
4218  // dependency on the array iterator lookup protector cell to ensure
4219  // that no one messed with the %ArrayIteratorPrototype%.next method.
4220  if (IsCallOrConstructWithSpread(node)) {
4221    if (!dependencies()->DependOnArrayIteratorProtector()) return NoChange();
4222  }
4223
4224  if (arguments_list->opcode() == IrOpcode::kJSCreateEmptyLiteralArray) {
4225    if (generated_calls_with_array_like_or_spread_.count(node)) {
4226      return NoChange();  // Avoid infinite recursion.
4227    }
4228    JSCallReducerAssembler a(this, node);
4229    Node* subgraph = a.ReduceJSCallWithArrayLikeOrSpreadOfEmpty(
4230        &generated_calls_with_array_like_or_spread_);
4231    return ReplaceWithSubgraph(&a, subgraph);
4232  }
4233
4234  DCHECK_EQ(arguments_list->opcode(), IrOpcode::kJSCreateLiteralArray);
4235  int new_argument_count;
4236
4237  // Find array length and elements' kind from the feedback's allocation
4238  // site's boilerplate JSArray.
4239  JSCreateLiteralOpNode args_node(arguments_list);
4240  CreateLiteralParameters const& args_params = args_node.Parameters();
4241  const FeedbackSource& array_feedback = args_params.feedback();
4242  const ProcessedFeedback& feedback =
4243      broker()->GetFeedbackForArrayOrObjectLiteral(array_feedback);
4244  if (feedback.IsInsufficient()) return NoChange();
4245
4246  AllocationSiteRef site = feedback.AsLiteral().value();
4247  if (!site.boilerplate().has_value()) return NoChange();
4248
4249  JSArrayRef boilerplate_array = site.boilerplate()->AsJSArray();
4250  int const array_length = boilerplate_array.GetBoilerplateLength().AsSmi();
4251
4252  // We'll replace the arguments_list input with {array_length} element loads.
4253  new_argument_count = argument_count - 1 + array_length;
4254
4255  // Do not optimize calls with a large number of arguments.
4256  // Arbitrarily sets the limit to 32 arguments.
4257  const int kMaxArityForOptimizedFunctionApply = 32;
4258  if (new_argument_count > kMaxArityForOptimizedFunctionApply) {
4259    return NoChange();
4260  }
4261
4262  // Determine the array's map.
4263  MapRef array_map = boilerplate_array.map();
4264  if (!array_map.supports_fast_array_iteration()) {
4265    return NoChange();
4266  }
4267
4268  // Check and depend on NoElementsProtector.
4269  if (!dependencies()->DependOnNoElementsProtector()) {
4270    return NoChange();
4271  }
4272
4273  // Remove the {arguments_list} node which will be replaced by a sequence of
4274  // LoadElement nodes.
4275  node->RemoveInput(arraylike_or_spread_index);
4276
4277  // Speculate on that array's map is still equal to the dynamic map of
4278  // arguments_list; generate a map check.
4279  effect = graph()->NewNode(
4280      simplified()->CheckMaps(CheckMapsFlag::kNone,
4281                              ZoneHandleSet<Map>(array_map.object()),
4282                              feedback_source),
4283      arguments_list, effect, control);
4284
4285  // Speculate on that array's length being equal to the dynamic length of
4286  // arguments_list; generate a deopt check.
4287  ElementsKind elements_kind = array_map.elements_kind();
4288  effect = CheckArrayLength(arguments_list, elements_kind, array_length,
4289                            feedback_source, effect, control);
4290
4291  // Generate N element loads to replace the {arguments_list} node with a set
4292  // of arguments loaded from it.
4293  Node* elements = effect = graph()->NewNode(
4294      simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
4295      arguments_list, effect, control);
4296  for (int i = 0; i < array_length; i++) {
4297    // Load the i-th element from the array.
4298    Node* index = jsgraph()->Constant(i);
4299    Node* load = effect = graph()->NewNode(
4300        simplified()->LoadElement(
4301            AccessBuilder::ForFixedArrayElement(elements_kind)),
4302        elements, index, effect, control);
4303
4304    // In "holey" arrays some arguments might be missing and we pass
4305    // 'undefined' instead.
4306    if (IsHoleyElementsKind(elements_kind)) {
4307      if (elements_kind == HOLEY_DOUBLE_ELEMENTS) {
4308        // May deopt for holey double elements.
4309        load = effect = graph()->NewNode(
4310            simplified()->CheckFloat64Hole(
4311                CheckFloat64HoleMode::kAllowReturnHole, feedback_source),
4312            load, effect, control);
4313      } else {
4314        load = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(),
4315                                load);
4316      }
4317    }
4318
4319    node->InsertInput(graph()->zone(), arraylike_or_spread_index + i, load);
4320  }
4321
4322  NodeProperties::ChangeOp(
4323      node,
4324      javascript()->Call(JSCallNode::ArityForArgc(new_argument_count),
4325                         frequency, feedback_source, ConvertReceiverMode::kAny,
4326                         speculation_mode, CallFeedbackRelation::kUnrelated));
4327  NodeProperties::ReplaceEffectInput(node, effect);
4328  return Changed(node).FollowedBy(ReduceJSCall(node));
4329}
4330
4331bool JSCallReducer::IsBuiltinOrApiFunction(JSFunctionRef function) const {
4332  // TODO(neis): Add a way to check if function template info isn't serialized
4333  // and add a warning in such cases. Currently we can't tell if function
4334  // template info doesn't exist or wasn't serialized.
4335  return function.shared().HasBuiltinId() ||
4336         function.shared().function_template_info().has_value();
4337}
4338
4339Reduction JSCallReducer::ReduceJSCall(Node* node) {
4340  if (broker()->StackHasOverflowed()) return NoChange();
4341
4342  JSCallNode n(node);
4343  CallParameters const& p = n.Parameters();
4344  Node* target = n.target();
4345  Effect effect = n.effect();
4346  Control control = n.control();
4347  int arity = p.arity_without_implicit_args();
4348
4349  // Try to specialize JSCall {node}s with constant {target}s.
4350  HeapObjectMatcher m(target);
4351  if (m.HasResolvedValue()) {
4352    ObjectRef target_ref = m.Ref(broker());
4353    if (target_ref.IsJSFunction()) {
4354      JSFunctionRef function = target_ref.AsJSFunction();
4355
4356      // Don't inline cross native context.
4357      if (!function.native_context().equals(native_context())) {
4358        return NoChange();
4359      }
4360
4361      return ReduceJSCall(node, function.shared());
4362    } else if (target_ref.IsJSBoundFunction()) {
4363      JSBoundFunctionRef function = target_ref.AsJSBoundFunction();
4364      ObjectRef bound_this = function.bound_this();
4365      ConvertReceiverMode const convert_mode =
4366          bound_this.IsNullOrUndefined()
4367              ? ConvertReceiverMode::kNullOrUndefined
4368              : ConvertReceiverMode::kNotNullOrUndefined;
4369
4370      // TODO(jgruber): Inline this block below once TryGet is guaranteed to
4371      // succeed.
4372      FixedArrayRef bound_arguments = function.bound_arguments();
4373      const int bound_arguments_length = bound_arguments.length();
4374      static constexpr int kInlineSize = 16;  // Arbitrary.
4375      base::SmallVector<Node*, kInlineSize> args;
4376      for (int i = 0; i < bound_arguments_length; ++i) {
4377        base::Optional<ObjectRef> maybe_arg = bound_arguments.TryGet(i);
4378        if (!maybe_arg.has_value()) {
4379          TRACE_BROKER_MISSING(broker(), "bound argument");
4380          return NoChange();
4381        }
4382        args.emplace_back(jsgraph()->Constant(maybe_arg.value()));
4383      }
4384
4385      // Patch {node} to use [[BoundTargetFunction]] and [[BoundThis]].
4386      NodeProperties::ReplaceValueInput(
4387          node, jsgraph()->Constant(function.bound_target_function()),
4388          JSCallNode::TargetIndex());
4389      NodeProperties::ReplaceValueInput(node, jsgraph()->Constant(bound_this),
4390                                        JSCallNode::ReceiverIndex());
4391
4392      // Insert the [[BoundArguments]] for {node}.
4393      for (int i = 0; i < bound_arguments_length; ++i) {
4394        node->InsertInput(graph()->zone(), i + 2, args[i]);
4395        arity++;
4396      }
4397
4398      NodeProperties::ChangeOp(
4399          node,
4400          javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(),
4401                             p.feedback(), convert_mode, p.speculation_mode(),
4402                             CallFeedbackRelation::kUnrelated));
4403
4404      // Try to further reduce the JSCall {node}.
4405      return Changed(node).FollowedBy(ReduceJSCall(node));
4406    }
4407
4408    // Don't mess with other {node}s that have a constant {target}.
4409    // TODO(bmeurer): Also support proxies here.
4410    return NoChange();
4411  }
4412
4413  // If {target} is the result of a JSCreateClosure operation, we can
4414  // just immediately try to inline based on the SharedFunctionInfo,
4415  // since TurboFan generally doesn't inline cross-context, and hence
4416  // the {target} must have the same native context as the call site.
4417  // Same if the {target} is the result of a CheckClosure operation.
4418  if (target->opcode() == IrOpcode::kJSCreateClosure) {
4419    CreateClosureParameters const& params =
4420        JSCreateClosureNode{target}.Parameters();
4421    return ReduceJSCall(node, params.shared_info(broker()));
4422  } else if (target->opcode() == IrOpcode::kCheckClosure) {
4423    FeedbackCellRef cell = MakeRef(broker(), FeedbackCellOf(target->op()));
4424    base::Optional<SharedFunctionInfoRef> shared = cell.shared_function_info();
4425    if (!shared.has_value()) {
4426      TRACE_BROKER_MISSING(broker(), "Unable to reduce JSCall. FeedbackCell "
4427                                         << cell << " has no FeedbackVector");
4428      return NoChange();
4429    }
4430    return ReduceJSCall(node, *shared);
4431  }
4432
4433  // If {target} is the result of a JSCreateBoundFunction operation,
4434  // we can just fold the construction and call the bound target
4435  // function directly instead.
4436  if (target->opcode() == IrOpcode::kJSCreateBoundFunction) {
4437    Node* bound_target_function = NodeProperties::GetValueInput(target, 0);
4438    Node* bound_this = NodeProperties::GetValueInput(target, 1);
4439    int const bound_arguments_length =
4440        static_cast<int>(CreateBoundFunctionParametersOf(target->op()).arity());
4441
4442    // Patch the {node} to use [[BoundTargetFunction]] and [[BoundThis]].
4443    NodeProperties::ReplaceValueInput(node, bound_target_function,
4444                                      n.TargetIndex());
4445    NodeProperties::ReplaceValueInput(node, bound_this, n.ReceiverIndex());
4446
4447    // Insert the [[BoundArguments]] for {node}.
4448    for (int i = 0; i < bound_arguments_length; ++i) {
4449      Node* value = NodeProperties::GetValueInput(target, 2 + i);
4450      node->InsertInput(graph()->zone(), n.ArgumentIndex(i), value);
4451      arity++;
4452    }
4453
4454    // Update the JSCall operator on {node}.
4455    ConvertReceiverMode const convert_mode =
4456        NodeProperties::CanBeNullOrUndefined(broker(), bound_this, effect)
4457            ? ConvertReceiverMode::kAny
4458            : ConvertReceiverMode::kNotNullOrUndefined;
4459    NodeProperties::ChangeOp(
4460        node,
4461        javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(),
4462                           p.feedback(), convert_mode, p.speculation_mode(),
4463                           CallFeedbackRelation::kUnrelated));
4464
4465    // Try to further reduce the JSCall {node}.
4466    return Changed(node).FollowedBy(ReduceJSCall(node));
4467  }
4468
4469  if (!ShouldUseCallICFeedback(target) ||
4470      p.feedback_relation() == CallFeedbackRelation::kUnrelated ||
4471      !p.feedback().IsValid()) {
4472    return NoChange();
4473  }
4474
4475  ProcessedFeedback const& feedback =
4476      broker()->GetFeedbackForCall(p.feedback());
4477  if (feedback.IsInsufficient()) {
4478    return ReduceForInsufficientFeedback(
4479        node, DeoptimizeReason::kInsufficientTypeFeedbackForCall);
4480  }
4481
4482  base::Optional<HeapObjectRef> feedback_target;
4483  if (p.feedback_relation() == CallFeedbackRelation::kTarget) {
4484    feedback_target = feedback.AsCall().target();
4485  } else {
4486    DCHECK_EQ(p.feedback_relation(), CallFeedbackRelation::kReceiver);
4487    feedback_target = native_context().function_prototype_apply();
4488  }
4489
4490  if (feedback_target.has_value() && feedback_target->map().is_callable()) {
4491    Node* target_function = jsgraph()->Constant(*feedback_target);
4492
4493    // Check that the {target} is still the {target_function}.
4494    Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
4495                                   target_function);
4496    effect = graph()->NewNode(
4497        simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
4498        effect, control);
4499
4500    // Specialize the JSCall node to the {target_function}.
4501    NodeProperties::ReplaceValueInput(node, target_function, n.TargetIndex());
4502    NodeProperties::ReplaceEffectInput(node, effect);
4503
4504    // Try to further reduce the JSCall {node}.
4505    return Changed(node).FollowedBy(ReduceJSCall(node));
4506  } else if (feedback_target.has_value() && feedback_target->IsFeedbackCell()) {
4507    FeedbackCellRef feedback_cell = feedback_target.value().AsFeedbackCell();
4508    // TODO(neis): This check seems unnecessary.
4509    if (feedback_cell.feedback_vector().has_value()) {
4510      // Check that {target} is a closure with given {feedback_cell},
4511      // which uniquely identifies a given function inside a native context.
4512      Node* target_closure = effect =
4513          graph()->NewNode(simplified()->CheckClosure(feedback_cell.object()),
4514                           target, effect, control);
4515
4516      // Specialize the JSCall node to the {target_closure}.
4517      NodeProperties::ReplaceValueInput(node, target_closure, n.TargetIndex());
4518      NodeProperties::ReplaceEffectInput(node, effect);
4519
4520      // Try to further reduce the JSCall {node}.
4521      return Changed(node).FollowedBy(ReduceJSCall(node));
4522    }
4523  }
4524  return NoChange();
4525}
4526
4527Reduction JSCallReducer::ReduceJSCall(Node* node,
4528                                      const SharedFunctionInfoRef& shared) {
4529  JSCallNode n(node);
4530  Node* target = n.target();
4531
4532  // Do not reduce calls to functions with break points.
4533  // If this state changes during background compilation, the compilation
4534  // job will be aborted from the main thread (see
4535  // Debug::PrepareFunctionForDebugExecution()).
4536  if (shared.HasBreakInfo()) return NoChange();
4537
4538  // Class constructors are callable, but [[Call]] will raise an exception.
4539  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
4540  if (IsClassConstructor(shared.kind())) {
4541    NodeProperties::ReplaceValueInputs(node, target);
4542    NodeProperties::ChangeOp(
4543        node, javascript()->CallRuntime(
4544                  Runtime::kThrowConstructorNonCallableError, 1));
4545    return Changed(node);
4546  }
4547
4548  // Check for known builtin functions.
4549
4550  Builtin builtin =
4551      shared.HasBuiltinId() ? shared.builtin_id() : Builtin::kNoBuiltinId;
4552  switch (builtin) {
4553    case Builtin::kArrayConstructor:
4554      return ReduceArrayConstructor(node);
4555    case Builtin::kBooleanConstructor:
4556      return ReduceBooleanConstructor(node);
4557    case Builtin::kFunctionPrototypeApply:
4558      return ReduceFunctionPrototypeApply(node);
4559    case Builtin::kFastFunctionPrototypeBind:
4560      return ReduceFunctionPrototypeBind(node);
4561    case Builtin::kFunctionPrototypeCall:
4562      return ReduceFunctionPrototypeCall(node);
4563    case Builtin::kFunctionPrototypeHasInstance:
4564      return ReduceFunctionPrototypeHasInstance(node);
4565    case Builtin::kObjectConstructor:
4566      return ReduceObjectConstructor(node);
4567    case Builtin::kObjectCreate:
4568      return ReduceObjectCreate(node);
4569    case Builtin::kObjectGetPrototypeOf:
4570      return ReduceObjectGetPrototypeOf(node);
4571    case Builtin::kObjectIs:
4572      return ReduceObjectIs(node);
4573    case Builtin::kObjectPrototypeGetProto:
4574      return ReduceObjectPrototypeGetProto(node);
4575    case Builtin::kObjectPrototypeHasOwnProperty:
4576      return ReduceObjectPrototypeHasOwnProperty(node);
4577    case Builtin::kObjectPrototypeIsPrototypeOf:
4578      return ReduceObjectPrototypeIsPrototypeOf(node);
4579    case Builtin::kReflectApply:
4580      return ReduceReflectApply(node);
4581    case Builtin::kReflectConstruct:
4582      return ReduceReflectConstruct(node);
4583    case Builtin::kReflectGet:
4584      return ReduceReflectGet(node);
4585    case Builtin::kReflectGetPrototypeOf:
4586      return ReduceReflectGetPrototypeOf(node);
4587    case Builtin::kReflectHas:
4588      return ReduceReflectHas(node);
4589    case Builtin::kArrayForEach:
4590      return ReduceArrayForEach(node, shared);
4591    case Builtin::kArrayMap:
4592      return ReduceArrayMap(node, shared);
4593    case Builtin::kArrayFilter:
4594      return ReduceArrayFilter(node, shared);
4595    case Builtin::kArrayReduce:
4596      return ReduceArrayReduce(node, shared);
4597    case Builtin::kArrayReduceRight:
4598      return ReduceArrayReduceRight(node, shared);
4599    case Builtin::kArrayPrototypeFind:
4600      return ReduceArrayFind(node, shared);
4601    case Builtin::kArrayPrototypeFindIndex:
4602      return ReduceArrayFindIndex(node, shared);
4603    case Builtin::kArrayEvery:
4604      return ReduceArrayEvery(node, shared);
4605    case Builtin::kArrayIndexOf:
4606      return ReduceArrayIndexOf(node);
4607    case Builtin::kArrayIncludes:
4608      return ReduceArrayIncludes(node);
4609    case Builtin::kArraySome:
4610      return ReduceArraySome(node, shared);
4611    case Builtin::kArrayPrototypePush:
4612      return ReduceArrayPrototypePush(node);
4613    case Builtin::kArrayPrototypePop:
4614      return ReduceArrayPrototypePop(node);
4615    case Builtin::kArrayPrototypeShift:
4616      return ReduceArrayPrototypeShift(node);
4617    case Builtin::kArrayPrototypeSlice:
4618      return ReduceArrayPrototypeSlice(node);
4619    case Builtin::kArrayPrototypeEntries:
4620      return ReduceArrayIterator(node, ArrayIteratorKind::kArrayLike,
4621                                 IterationKind::kEntries);
4622    case Builtin::kArrayPrototypeKeys:
4623      return ReduceArrayIterator(node, ArrayIteratorKind::kArrayLike,
4624                                 IterationKind::kKeys);
4625    case Builtin::kArrayPrototypeValues:
4626      return ReduceArrayIterator(node, ArrayIteratorKind::kArrayLike,
4627                                 IterationKind::kValues);
4628    case Builtin::kArrayIteratorPrototypeNext:
4629      return ReduceArrayIteratorPrototypeNext(node);
4630    case Builtin::kArrayIsArray:
4631      return ReduceArrayIsArray(node);
4632    case Builtin::kArrayBufferIsView:
4633      return ReduceArrayBufferIsView(node);
4634    case Builtin::kDataViewPrototypeGetByteLength:
4635      return ReduceArrayBufferViewAccessor(
4636          node, JS_DATA_VIEW_TYPE,
4637          AccessBuilder::ForJSArrayBufferViewByteLength());
4638    case Builtin::kDataViewPrototypeGetByteOffset:
4639      return ReduceArrayBufferViewAccessor(
4640          node, JS_DATA_VIEW_TYPE,
4641          AccessBuilder::ForJSArrayBufferViewByteOffset());
4642    case Builtin::kDataViewPrototypeGetUint8:
4643      return ReduceDataViewAccess(node, DataViewAccess::kGet,
4644                                  ExternalArrayType::kExternalUint8Array);
4645    case Builtin::kDataViewPrototypeGetInt8:
4646      return ReduceDataViewAccess(node, DataViewAccess::kGet,
4647                                  ExternalArrayType::kExternalInt8Array);
4648    case Builtin::kDataViewPrototypeGetUint16:
4649      return ReduceDataViewAccess(node, DataViewAccess::kGet,
4650                                  ExternalArrayType::kExternalUint16Array);
4651    case Builtin::kDataViewPrototypeGetInt16:
4652      return ReduceDataViewAccess(node, DataViewAccess::kGet,
4653                                  ExternalArrayType::kExternalInt16Array);
4654    case Builtin::kDataViewPrototypeGetUint32:
4655      return ReduceDataViewAccess(node, DataViewAccess::kGet,
4656                                  ExternalArrayType::kExternalUint32Array);
4657    case Builtin::kDataViewPrototypeGetInt32:
4658      return ReduceDataViewAccess(node, DataViewAccess::kGet,
4659                                  ExternalArrayType::kExternalInt32Array);
4660    case Builtin::kDataViewPrototypeGetFloat32:
4661      return ReduceDataViewAccess(node, DataViewAccess::kGet,
4662                                  ExternalArrayType::kExternalFloat32Array);
4663    case Builtin::kDataViewPrototypeGetFloat64:
4664      return ReduceDataViewAccess(node, DataViewAccess::kGet,
4665                                  ExternalArrayType::kExternalFloat64Array);
4666    case Builtin::kDataViewPrototypeSetUint8:
4667      return ReduceDataViewAccess(node, DataViewAccess::kSet,
4668                                  ExternalArrayType::kExternalUint8Array);
4669    case Builtin::kDataViewPrototypeSetInt8:
4670      return ReduceDataViewAccess(node, DataViewAccess::kSet,
4671                                  ExternalArrayType::kExternalInt8Array);
4672    case Builtin::kDataViewPrototypeSetUint16:
4673      return ReduceDataViewAccess(node, DataViewAccess::kSet,
4674                                  ExternalArrayType::kExternalUint16Array);
4675    case Builtin::kDataViewPrototypeSetInt16:
4676      return ReduceDataViewAccess(node, DataViewAccess::kSet,
4677                                  ExternalArrayType::kExternalInt16Array);
4678    case Builtin::kDataViewPrototypeSetUint32:
4679      return ReduceDataViewAccess(node, DataViewAccess::kSet,
4680                                  ExternalArrayType::kExternalUint32Array);
4681    case Builtin::kDataViewPrototypeSetInt32:
4682      return ReduceDataViewAccess(node, DataViewAccess::kSet,
4683                                  ExternalArrayType::kExternalInt32Array);
4684    case Builtin::kDataViewPrototypeSetFloat32:
4685      return ReduceDataViewAccess(node, DataViewAccess::kSet,
4686                                  ExternalArrayType::kExternalFloat32Array);
4687    case Builtin::kDataViewPrototypeSetFloat64:
4688      return ReduceDataViewAccess(node, DataViewAccess::kSet,
4689                                  ExternalArrayType::kExternalFloat64Array);
4690    case Builtin::kTypedArrayPrototypeByteLength:
4691      return ReduceArrayBufferViewAccessor(
4692          node, JS_TYPED_ARRAY_TYPE,
4693          AccessBuilder::ForJSArrayBufferViewByteLength());
4694    case Builtin::kTypedArrayPrototypeByteOffset:
4695      return ReduceArrayBufferViewAccessor(
4696          node, JS_TYPED_ARRAY_TYPE,
4697          AccessBuilder::ForJSArrayBufferViewByteOffset());
4698    case Builtin::kTypedArrayPrototypeLength:
4699      return ReduceArrayBufferViewAccessor(
4700          node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
4701    case Builtin::kTypedArrayPrototypeToStringTag:
4702      return ReduceTypedArrayPrototypeToStringTag(node);
4703    case Builtin::kMathAbs:
4704      return ReduceMathUnary(node, simplified()->NumberAbs());
4705    case Builtin::kMathAcos:
4706      return ReduceMathUnary(node, simplified()->NumberAcos());
4707    case Builtin::kMathAcosh:
4708      return ReduceMathUnary(node, simplified()->NumberAcosh());
4709    case Builtin::kMathAsin:
4710      return ReduceMathUnary(node, simplified()->NumberAsin());
4711    case Builtin::kMathAsinh:
4712      return ReduceMathUnary(node, simplified()->NumberAsinh());
4713    case Builtin::kMathAtan:
4714      return ReduceMathUnary(node, simplified()->NumberAtan());
4715    case Builtin::kMathAtanh:
4716      return ReduceMathUnary(node, simplified()->NumberAtanh());
4717    case Builtin::kMathCbrt:
4718      return ReduceMathUnary(node, simplified()->NumberCbrt());
4719    case Builtin::kMathCeil:
4720      return ReduceMathUnary(node, simplified()->NumberCeil());
4721    case Builtin::kMathCos:
4722      return ReduceMathUnary(node, simplified()->NumberCos());
4723    case Builtin::kMathCosh:
4724      return ReduceMathUnary(node, simplified()->NumberCosh());
4725    case Builtin::kMathExp:
4726      return ReduceMathUnary(node, simplified()->NumberExp());
4727    case Builtin::kMathExpm1:
4728      return ReduceMathUnary(node, simplified()->NumberExpm1());
4729    case Builtin::kMathFloor:
4730      return ReduceMathUnary(node, simplified()->NumberFloor());
4731    case Builtin::kMathFround:
4732      return ReduceMathUnary(node, simplified()->NumberFround());
4733    case Builtin::kMathLog:
4734      return ReduceMathUnary(node, simplified()->NumberLog());
4735    case Builtin::kMathLog1p:
4736      return ReduceMathUnary(node, simplified()->NumberLog1p());
4737    case Builtin::kMathLog10:
4738      return ReduceMathUnary(node, simplified()->NumberLog10());
4739    case Builtin::kMathLog2:
4740      return ReduceMathUnary(node, simplified()->NumberLog2());
4741    case Builtin::kMathRound:
4742      return ReduceMathUnary(node, simplified()->NumberRound());
4743    case Builtin::kMathSign:
4744      return ReduceMathUnary(node, simplified()->NumberSign());
4745    case Builtin::kMathSin:
4746      return ReduceMathUnary(node, simplified()->NumberSin());
4747    case Builtin::kMathSinh:
4748      return ReduceMathUnary(node, simplified()->NumberSinh());
4749    case Builtin::kMathSqrt:
4750      return ReduceMathUnary(node, simplified()->NumberSqrt());
4751    case Builtin::kMathTan:
4752      return ReduceMathUnary(node, simplified()->NumberTan());
4753    case Builtin::kMathTanh:
4754      return ReduceMathUnary(node, simplified()->NumberTanh());
4755    case Builtin::kMathTrunc:
4756      return ReduceMathUnary(node, simplified()->NumberTrunc());
4757    case Builtin::kMathAtan2:
4758      return ReduceMathBinary(node, simplified()->NumberAtan2());
4759    case Builtin::kMathPow:
4760      return ReduceMathBinary(node, simplified()->NumberPow());
4761    case Builtin::kMathClz32:
4762      return ReduceMathClz32(node);
4763    case Builtin::kMathImul:
4764      return ReduceMathImul(node);
4765    case Builtin::kMathMax:
4766      return ReduceMathMinMax(node, simplified()->NumberMax(),
4767                              jsgraph()->Constant(-V8_INFINITY));
4768    case Builtin::kMathMin:
4769      return ReduceMathMinMax(node, simplified()->NumberMin(),
4770                              jsgraph()->Constant(V8_INFINITY));
4771    case Builtin::kNumberIsFinite:
4772      return ReduceNumberIsFinite(node);
4773    case Builtin::kNumberIsInteger:
4774      return ReduceNumberIsInteger(node);
4775    case Builtin::kNumberIsSafeInteger:
4776      return ReduceNumberIsSafeInteger(node);
4777    case Builtin::kNumberIsNaN:
4778      return ReduceNumberIsNaN(node);
4779    case Builtin::kNumberParseInt:
4780      return ReduceNumberParseInt(node);
4781    case Builtin::kGlobalIsFinite:
4782      return ReduceGlobalIsFinite(node);
4783    case Builtin::kGlobalIsNaN:
4784      return ReduceGlobalIsNaN(node);
4785    case Builtin::kMapPrototypeGet:
4786      return ReduceMapPrototypeGet(node);
4787    case Builtin::kMapPrototypeHas:
4788      return ReduceMapPrototypeHas(node);
4789    case Builtin::kRegExpPrototypeTest:
4790      return ReduceRegExpPrototypeTest(node);
4791    case Builtin::kReturnReceiver:
4792      return ReduceReturnReceiver(node);
4793    case Builtin::kStringPrototypeIndexOf:
4794      return ReduceStringPrototypeIndexOfIncludes(
4795          node, StringIndexOfIncludesVariant::kIndexOf);
4796    case Builtin::kStringPrototypeIncludes:
4797      return ReduceStringPrototypeIndexOfIncludes(
4798          node, StringIndexOfIncludesVariant::kIncludes);
4799    case Builtin::kStringPrototypeCharAt:
4800      return ReduceStringPrototypeCharAt(node);
4801    case Builtin::kStringPrototypeCharCodeAt:
4802      return ReduceStringPrototypeStringAt(simplified()->StringCharCodeAt(),
4803                                           node);
4804    case Builtin::kStringPrototypeCodePointAt:
4805      return ReduceStringPrototypeStringAt(simplified()->StringCodePointAt(),
4806                                           node);
4807    case Builtin::kStringPrototypeSubstring:
4808      return ReduceStringPrototypeSubstring(node);
4809    case Builtin::kStringPrototypeSlice:
4810      return ReduceStringPrototypeSlice(node);
4811    case Builtin::kStringPrototypeSubstr:
4812      return ReduceStringPrototypeSubstr(node);
4813    case Builtin::kStringPrototypeStartsWith:
4814      return ReduceStringPrototypeStartsWith(node);
4815#ifdef V8_INTL_SUPPORT
4816    case Builtin::kStringPrototypeToLowerCaseIntl:
4817      return ReduceStringPrototypeToLowerCaseIntl(node);
4818    case Builtin::kStringPrototypeToUpperCaseIntl:
4819      return ReduceStringPrototypeToUpperCaseIntl(node);
4820#endif  // V8_INTL_SUPPORT
4821    case Builtin::kStringFromCharCode:
4822      return ReduceStringFromCharCode(node);
4823    case Builtin::kStringFromCodePoint:
4824      return ReduceStringFromCodePoint(node);
4825    case Builtin::kStringPrototypeIterator:
4826      return ReduceStringPrototypeIterator(node);
4827    case Builtin::kStringPrototypeLocaleCompare:
4828      return ReduceStringPrototypeLocaleCompare(node);
4829    case Builtin::kStringIteratorPrototypeNext:
4830      return ReduceStringIteratorPrototypeNext(node);
4831    case Builtin::kStringPrototypeConcat:
4832      return ReduceStringPrototypeConcat(node);
4833    case Builtin::kTypedArrayPrototypeEntries:
4834      return ReduceArrayIterator(node, ArrayIteratorKind::kTypedArray,
4835                                 IterationKind::kEntries);
4836    case Builtin::kTypedArrayPrototypeKeys:
4837      return ReduceArrayIterator(node, ArrayIteratorKind::kTypedArray,
4838                                 IterationKind::kKeys);
4839    case Builtin::kTypedArrayPrototypeValues:
4840      return ReduceArrayIterator(node, ArrayIteratorKind::kTypedArray,
4841                                 IterationKind::kValues);
4842    case Builtin::kPromisePrototypeCatch:
4843      return ReducePromisePrototypeCatch(node);
4844    case Builtin::kPromisePrototypeFinally:
4845      return ReducePromisePrototypeFinally(node);
4846    case Builtin::kPromisePrototypeThen:
4847      return ReducePromisePrototypeThen(node);
4848    case Builtin::kPromiseResolveTrampoline:
4849      return ReducePromiseResolveTrampoline(node);
4850    case Builtin::kMapPrototypeEntries:
4851      return ReduceCollectionIteration(node, CollectionKind::kMap,
4852                                       IterationKind::kEntries);
4853    case Builtin::kMapPrototypeKeys:
4854      return ReduceCollectionIteration(node, CollectionKind::kMap,
4855                                       IterationKind::kKeys);
4856    case Builtin::kMapPrototypeGetSize:
4857      return ReduceCollectionPrototypeSize(node, CollectionKind::kMap);
4858    case Builtin::kMapPrototypeValues:
4859      return ReduceCollectionIteration(node, CollectionKind::kMap,
4860                                       IterationKind::kValues);
4861    case Builtin::kMapIteratorPrototypeNext:
4862      return ReduceCollectionIteratorPrototypeNext(
4863          node, OrderedHashMap::kEntrySize, factory()->empty_ordered_hash_map(),
4864          FIRST_JS_MAP_ITERATOR_TYPE, LAST_JS_MAP_ITERATOR_TYPE);
4865    case Builtin::kSetPrototypeEntries:
4866      return ReduceCollectionIteration(node, CollectionKind::kSet,
4867                                       IterationKind::kEntries);
4868    case Builtin::kSetPrototypeGetSize:
4869      return ReduceCollectionPrototypeSize(node, CollectionKind::kSet);
4870    case Builtin::kSetPrototypeValues:
4871      return ReduceCollectionIteration(node, CollectionKind::kSet,
4872                                       IterationKind::kValues);
4873    case Builtin::kSetIteratorPrototypeNext:
4874      return ReduceCollectionIteratorPrototypeNext(
4875          node, OrderedHashSet::kEntrySize, factory()->empty_ordered_hash_set(),
4876          FIRST_JS_SET_ITERATOR_TYPE, LAST_JS_SET_ITERATOR_TYPE);
4877    case Builtin::kDatePrototypeGetTime:
4878      return ReduceDatePrototypeGetTime(node);
4879    case Builtin::kDateNow:
4880      return ReduceDateNow(node);
4881    case Builtin::kNumberConstructor:
4882      return ReduceNumberConstructor(node);
4883    case Builtin::kBigIntAsIntN:
4884    case Builtin::kBigIntAsUintN:
4885      return ReduceBigIntAsN(node, builtin);
4886    default:
4887      break;
4888  }
4889
4890  if (shared.function_template_info().has_value()) {
4891    return ReduceCallApiFunction(node, shared);
4892  }
4893
4894#if V8_ENABLE_WEBASSEMBLY
4895  if ((flags() & kInlineJSToWasmCalls) && shared.wasm_function_signature()) {
4896    return ReduceCallWasmFunction(node, shared);
4897  }
4898#endif  // V8_ENABLE_WEBASSEMBLY
4899
4900  return NoChange();
4901}
4902
4903TNode<Object> JSCallReducerAssembler::ReduceJSCallWithArrayLikeOrSpreadOfEmpty(
4904    std::unordered_set<Node*>* generated_calls_with_array_like_or_spread) {
4905  DCHECK_EQ(generated_calls_with_array_like_or_spread->count(node_ptr()), 0);
4906  JSCallWithArrayLikeOrSpreadNode n(node_ptr());
4907  CallParameters const& p = n.Parameters();
4908  TNode<Object> arguments_list = n.LastArgument();
4909  DCHECK_EQ(static_cast<Node*>(arguments_list)->opcode(),
4910            IrOpcode::kJSCreateEmptyLiteralArray);
4911
4912  // Turn the JSCallWithArrayLike or JSCallWithSpread roughly into:
4913  //
4914  //      "arguments_list array is still empty?"
4915  //               |
4916  //               |
4917  //            Branch
4918  //           /      \
4919  //          /        \
4920  //      IfTrue      IfFalse
4921  //         |          |
4922  //         |          |
4923  //      JSCall    JSCallWithArrayLike/JSCallWithSpread
4924  //          \        /
4925  //           \      /
4926  //            Merge
4927
4928  TNode<Number> length = TNode<Number>::UncheckedCast(
4929      LoadField(AccessBuilder::ForJSArrayLength(NO_ELEMENTS), arguments_list));
4930  return SelectIf<Object>(NumberEqual(length, ZeroConstant()))
4931      .Then([&]() {
4932        TNode<Object> call = CopyNode();
4933        static_cast<Node*>(call)->RemoveInput(n.LastArgumentIndex());
4934        NodeProperties::ChangeOp(
4935            call, javascript()->Call(p.arity() - 1, p.frequency(), p.feedback(),
4936                                     p.convert_mode(), p.speculation_mode(),
4937                                     p.feedback_relation()));
4938        return call;
4939      })
4940      .Else([&]() {
4941        TNode<Object> call = CopyNode();
4942        generated_calls_with_array_like_or_spread->insert(call);
4943        return call;
4944      })
4945      .ExpectFalse()
4946      .Value();
4947}
4948
4949namespace {
4950
4951// Check if the target is a class constructor.
4952// We need to check all cases where the target will be typed as Function
4953// to prevent later optimizations from using the CallFunction trampoline,
4954// skipping the instance type check.
4955bool TargetIsClassConstructor(Node* node, JSHeapBroker* broker) {
4956  Node* target = NodeProperties::GetValueInput(node, 0);
4957  base::Optional<SharedFunctionInfoRef> shared;
4958  HeapObjectMatcher m(target);
4959  if (m.HasResolvedValue()) {
4960    ObjectRef target_ref = m.Ref(broker);
4961    if (target_ref.IsJSFunction()) {
4962      JSFunctionRef function = target_ref.AsJSFunction();
4963      shared = function.shared();
4964    }
4965  } else if (target->opcode() == IrOpcode::kJSCreateClosure) {
4966    CreateClosureParameters const& ccp =
4967        JSCreateClosureNode{target}.Parameters();
4968    shared = ccp.shared_info(broker);
4969  } else if (target->opcode() == IrOpcode::kCheckClosure) {
4970    FeedbackCellRef cell = MakeRef(broker, FeedbackCellOf(target->op()));
4971    shared = cell.shared_function_info();
4972  }
4973
4974  if (shared.has_value() && IsClassConstructor(shared->kind())) return true;
4975
4976  return false;
4977}
4978
4979}  // namespace
4980
4981Reduction JSCallReducer::ReduceJSCallWithArrayLike(Node* node) {
4982  JSCallWithArrayLikeNode n(node);
4983  CallParameters const& p = n.Parameters();
4984  DCHECK_EQ(p.arity_without_implicit_args(), 1);  // The arraylike object.
4985  // Class constructors are callable, but [[Call]] will raise an exception.
4986  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
4987  if (TargetIsClassConstructor(node, broker())) {
4988    return NoChange();
4989  }
4990  return ReduceCallOrConstructWithArrayLikeOrSpread(
4991      node, n.ArgumentCount(), n.LastArgumentIndex(), p.frequency(),
4992      p.feedback(), p.speculation_mode(), p.feedback_relation(), n.target(),
4993      n.effect(), n.control());
4994}
4995
4996Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) {
4997  JSCallWithSpreadNode n(node);
4998  CallParameters const& p = n.Parameters();
4999  DCHECK_GE(p.arity_without_implicit_args(), 1);  // At least the spread.
5000  // Class constructors are callable, but [[Call]] will raise an exception.
5001  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
5002  if (TargetIsClassConstructor(node, broker())) {
5003    return NoChange();
5004  }
5005  return ReduceCallOrConstructWithArrayLikeOrSpread(
5006      node, n.ArgumentCount(), n.LastArgumentIndex(), p.frequency(),
5007      p.feedback(), p.speculation_mode(), p.feedback_relation(), n.target(),
5008      n.effect(), n.control());
5009}
5010
5011Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
5012  if (broker()->StackHasOverflowed()) return NoChange();
5013
5014  JSConstructNode n(node);
5015  ConstructParameters const& p = n.Parameters();
5016  int arity = p.arity_without_implicit_args();
5017  Node* target = n.target();
5018  Node* new_target = n.new_target();
5019  Effect effect = n.effect();
5020  Control control = n.control();
5021
5022  if (p.feedback().IsValid()) {
5023    ProcessedFeedback const& feedback =
5024        broker()->GetFeedbackForCall(p.feedback());
5025    if (feedback.IsInsufficient()) {
5026      return ReduceForInsufficientFeedback(
5027          node, DeoptimizeReason::kInsufficientTypeFeedbackForConstruct);
5028    }
5029
5030    base::Optional<HeapObjectRef> feedback_target = feedback.AsCall().target();
5031    if (feedback_target.has_value() && feedback_target->IsAllocationSite()) {
5032      // The feedback is an AllocationSite, which means we have called the
5033      // Array function and collected transition (and pretenuring) feedback
5034      // for the resulting arrays.  This has to be kept in sync with the
5035      // implementation in Ignition.
5036
5037      Node* array_function =
5038          jsgraph()->Constant(native_context().array_function());
5039
5040      // Check that the {target} is still the {array_function}.
5041      Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
5042                                     array_function);
5043      effect = graph()->NewNode(
5044          simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
5045          effect, control);
5046
5047      // Turn the {node} into a {JSCreateArray} call.
5048      NodeProperties::ReplaceEffectInput(node, effect);
5049      STATIC_ASSERT(JSConstructNode::NewTargetIndex() == 1);
5050      node->ReplaceInput(n.NewTargetIndex(), array_function);
5051      node->RemoveInput(n.FeedbackVectorIndex());
5052      NodeProperties::ChangeOp(
5053          node, javascript()->CreateArray(arity,
5054                                          feedback_target->AsAllocationSite()));
5055      return Changed(node);
5056    } else if (feedback_target.has_value() &&
5057               !HeapObjectMatcher(new_target).HasResolvedValue() &&
5058               feedback_target->map().is_constructor()) {
5059      Node* new_target_feedback = jsgraph()->Constant(*feedback_target);
5060
5061      // Check that the {new_target} is still the {new_target_feedback}.
5062      Node* check = graph()->NewNode(simplified()->ReferenceEqual(), new_target,
5063                                     new_target_feedback);
5064      effect = graph()->NewNode(
5065          simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
5066          effect, control);
5067
5068      // Specialize the JSConstruct node to the {new_target_feedback}.
5069      node->ReplaceInput(n.NewTargetIndex(), new_target_feedback);
5070      NodeProperties::ReplaceEffectInput(node, effect);
5071      if (target == new_target) {
5072        node->ReplaceInput(n.TargetIndex(), new_target_feedback);
5073      }
5074
5075      // Try to further reduce the JSConstruct {node}.
5076      return Changed(node).FollowedBy(ReduceJSConstruct(node));
5077    }
5078  }
5079
5080  // Try to specialize JSConstruct {node}s with constant {target}s.
5081  HeapObjectMatcher m(target);
5082  if (m.HasResolvedValue()) {
5083    HeapObjectRef target_ref = m.Ref(broker());
5084
5085    // Raise a TypeError if the {target} is not a constructor.
5086    if (!target_ref.map().is_constructor()) {
5087      NodeProperties::ReplaceValueInputs(node, target);
5088      NodeProperties::ChangeOp(node,
5089                               javascript()->CallRuntime(
5090                                   Runtime::kThrowConstructedNonConstructable));
5091      return Changed(node);
5092    }
5093
5094    if (target_ref.IsJSFunction()) {
5095      JSFunctionRef function = target_ref.AsJSFunction();
5096
5097      // Do not reduce constructors with break points.
5098      // If this state changes during background compilation, the compilation
5099      // job will be aborted from the main thread (see
5100      // Debug::PrepareFunctionForDebugExecution()).
5101      SharedFunctionInfoRef sfi = function.shared();
5102      if (sfi.HasBreakInfo()) return NoChange();
5103
5104      // Don't inline cross native context.
5105      if (!function.native_context().equals(native_context())) {
5106        return NoChange();
5107      }
5108
5109      // Check for known builtin functions.
5110      Builtin builtin =
5111          sfi.HasBuiltinId() ? sfi.builtin_id() : Builtin::kNoBuiltinId;
5112      switch (builtin) {
5113        case Builtin::kArrayConstructor: {
5114          // TODO(bmeurer): Deal with Array subclasses here.
5115          // Turn the {node} into a {JSCreateArray} call.
5116          STATIC_ASSERT(JSConstructNode::NewTargetIndex() == 1);
5117          node->ReplaceInput(n.NewTargetIndex(), new_target);
5118          node->RemoveInput(n.FeedbackVectorIndex());
5119          NodeProperties::ChangeOp(
5120              node, javascript()->CreateArray(arity, base::nullopt));
5121          return Changed(node);
5122        }
5123        case Builtin::kObjectConstructor: {
5124          // If no value is passed, we can immediately lower to a simple
5125          // JSCreate and don't need to do any massaging of the {node}.
5126          if (arity == 0) {
5127            node->RemoveInput(n.FeedbackVectorIndex());
5128            NodeProperties::ChangeOp(node, javascript()->Create());
5129            return Changed(node);
5130          }
5131
5132          // If {target} is not the same as {new_target} (i.e. the Object
5133          // constructor), {value} will be ignored and therefore we can lower
5134          // to {JSCreate}. See https://tc39.es/ecma262/#sec-object-value.
5135          HeapObjectMatcher mnew_target(new_target);
5136          if (mnew_target.HasResolvedValue() &&
5137              !mnew_target.Ref(broker()).equals(function)) {
5138            // Drop the value inputs.
5139            node->RemoveInput(n.FeedbackVectorIndex());
5140            for (int i = n.ArgumentCount() - 1; i >= 0; i--) {
5141              node->RemoveInput(n.ArgumentIndex(i));
5142            }
5143            NodeProperties::ChangeOp(node, javascript()->Create());
5144            return Changed(node);
5145          }
5146          break;
5147        }
5148        case Builtin::kPromiseConstructor:
5149          return ReducePromiseConstructor(node);
5150        case Builtin::kTypedArrayConstructor:
5151          return ReduceTypedArrayConstructor(node, function.shared());
5152        default:
5153          break;
5154      }
5155    } else if (target_ref.IsJSBoundFunction()) {
5156      JSBoundFunctionRef function = target_ref.AsJSBoundFunction();
5157      JSReceiverRef bound_target_function = function.bound_target_function();
5158      FixedArrayRef bound_arguments = function.bound_arguments();
5159      const int bound_arguments_length = bound_arguments.length();
5160
5161      // TODO(jgruber): Inline this block below once TryGet is guaranteed to
5162      // succeed.
5163      static constexpr int kInlineSize = 16;  // Arbitrary.
5164      base::SmallVector<Node*, kInlineSize> args;
5165      for (int i = 0; i < bound_arguments_length; ++i) {
5166        base::Optional<ObjectRef> maybe_arg = bound_arguments.TryGet(i);
5167        if (!maybe_arg.has_value()) {
5168          TRACE_BROKER_MISSING(broker(), "bound argument");
5169          return NoChange();
5170        }
5171        args.emplace_back(jsgraph()->Constant(maybe_arg.value()));
5172      }
5173
5174      // Patch {node} to use [[BoundTargetFunction]].
5175      node->ReplaceInput(n.TargetIndex(),
5176                         jsgraph()->Constant(bound_target_function));
5177
5178      // Patch {node} to use [[BoundTargetFunction]]
5179      // as new.target if {new_target} equals {target}.
5180      if (target == new_target) {
5181        node->ReplaceInput(n.NewTargetIndex(),
5182                           jsgraph()->Constant(bound_target_function));
5183      } else {
5184        node->ReplaceInput(
5185            n.NewTargetIndex(),
5186            graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
5187                             graph()->NewNode(simplified()->ReferenceEqual(),
5188                                              target, new_target),
5189                             jsgraph()->Constant(bound_target_function),
5190                             new_target));
5191      }
5192
5193      // Insert the [[BoundArguments]] for {node}.
5194      for (int i = 0; i < bound_arguments_length; ++i) {
5195        node->InsertInput(graph()->zone(), n.ArgumentIndex(i), args[i]);
5196        arity++;
5197      }
5198
5199      // Update the JSConstruct operator on {node}.
5200      NodeProperties::ChangeOp(
5201          node, javascript()->Construct(JSConstructNode::ArityForArgc(arity),
5202                                        p.frequency(), FeedbackSource()));
5203
5204      // Try to further reduce the JSConstruct {node}.
5205      return Changed(node).FollowedBy(ReduceJSConstruct(node));
5206    }
5207
5208    // TODO(bmeurer): Also support optimizing proxies here.
5209  }
5210
5211  // If {target} is the result of a JSCreateBoundFunction operation,
5212  // we can just fold the construction and construct the bound target
5213  // function directly instead.
5214  if (target->opcode() == IrOpcode::kJSCreateBoundFunction) {
5215    Node* bound_target_function = NodeProperties::GetValueInput(target, 0);
5216    int const bound_arguments_length =
5217        static_cast<int>(CreateBoundFunctionParametersOf(target->op()).arity());
5218
5219    // Patch the {node} to use [[BoundTargetFunction]].
5220    node->ReplaceInput(n.TargetIndex(), bound_target_function);
5221
5222    // Patch {node} to use [[BoundTargetFunction]]
5223    // as new.target if {new_target} equals {target}.
5224    if (target == new_target) {
5225      node->ReplaceInput(n.NewTargetIndex(), bound_target_function);
5226    } else {
5227      node->ReplaceInput(
5228          n.NewTargetIndex(),
5229          graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
5230                           graph()->NewNode(simplified()->ReferenceEqual(),
5231                                            target, new_target),
5232                           bound_target_function, new_target));
5233    }
5234
5235    // Insert the [[BoundArguments]] for {node}.
5236    for (int i = 0; i < bound_arguments_length; ++i) {
5237      Node* value = NodeProperties::GetValueInput(target, 2 + i);
5238      node->InsertInput(graph()->zone(), n.ArgumentIndex(i), value);
5239      arity++;
5240    }
5241
5242    // Update the JSConstruct operator on {node}.
5243    NodeProperties::ChangeOp(
5244        node, javascript()->Construct(JSConstructNode::ArityForArgc(arity),
5245                                      p.frequency(), FeedbackSource()));
5246
5247    // Try to further reduce the JSConstruct {node}.
5248    return Changed(node).FollowedBy(ReduceJSConstruct(node));
5249  }
5250
5251  return NoChange();
5252}
5253
5254// ES #sec-string.prototype.indexof
5255// ES #sec-string.prototype.includes
5256Reduction JSCallReducer::ReduceStringPrototypeIndexOfIncludes(
5257    Node* node, StringIndexOfIncludesVariant variant) {
5258  JSCallNode n(node);
5259  CallParameters const& p = n.Parameters();
5260  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5261    return NoChange();
5262  }
5263
5264  Effect effect = n.effect();
5265  Control control = n.control();
5266  if (n.ArgumentCount() > 0) {
5267    Node* receiver = n.receiver();
5268    Node* new_receiver = effect = graph()->NewNode(
5269        simplified()->CheckString(p.feedback()), receiver, effect, control);
5270
5271    Node* search_string = n.Argument(0);
5272    Node* new_search_string = effect =
5273        graph()->NewNode(simplified()->CheckString(p.feedback()), search_string,
5274                         effect, control);
5275
5276    Node* new_position = jsgraph()->ZeroConstant();
5277    if (n.ArgumentCount() > 1) {
5278      Node* position = n.Argument(1);
5279      new_position = effect = graph()->NewNode(
5280          simplified()->CheckSmi(p.feedback()), position, effect, control);
5281
5282      Node* receiver_length =
5283          graph()->NewNode(simplified()->StringLength(), new_receiver);
5284      new_position = graph()->NewNode(
5285          simplified()->NumberMin(),
5286          graph()->NewNode(simplified()->NumberMax(), new_position,
5287                           jsgraph()->ZeroConstant()),
5288          receiver_length);
5289    }
5290
5291    NodeProperties::ReplaceEffectInput(node, effect);
5292    RelaxEffectsAndControls(node);
5293    node->ReplaceInput(0, new_receiver);
5294    node->ReplaceInput(1, new_search_string);
5295    node->ReplaceInput(2, new_position);
5296    node->TrimInputCount(3);
5297    NodeProperties::ChangeOp(node, simplified()->StringIndexOf());
5298
5299    if (variant == StringIndexOfIncludesVariant::kIndexOf) {
5300      return Changed(node);
5301    } else {
5302      DCHECK(variant == StringIndexOfIncludesVariant::kIncludes);
5303      Node* result =
5304          graph()->NewNode(simplified()->BooleanNot(),
5305                           graph()->NewNode(simplified()->NumberEqual(), node,
5306                                            jsgraph()->SmiConstant(-1)));
5307      return Replace(result);
5308    }
5309  }
5310  return NoChange();
5311}
5312
5313// ES #sec-string.prototype.substring
5314Reduction JSCallReducer::ReduceStringPrototypeSubstring(Node* node) {
5315  JSCallNode n(node);
5316  CallParameters const& p = n.Parameters();
5317  if (n.ArgumentCount() < 1) return NoChange();
5318  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5319    return NoChange();
5320  }
5321
5322  JSCallReducerAssembler a(this, node);
5323  Node* subgraph = a.ReduceStringPrototypeSubstring();
5324  return ReplaceWithSubgraph(&a, subgraph);
5325}
5326
5327// ES #sec-string.prototype.slice
5328Reduction JSCallReducer::ReduceStringPrototypeSlice(Node* node) {
5329  JSCallNode n(node);
5330  CallParameters const& p = n.Parameters();
5331  if (n.ArgumentCount() < 1) return NoChange();
5332  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5333    return NoChange();
5334  }
5335
5336  JSCallReducerAssembler a(this, node);
5337  Node* subgraph = a.ReduceStringPrototypeSlice();
5338  return ReplaceWithSubgraph(&a, subgraph);
5339}
5340
5341// ES #sec-string.prototype.substr
5342Reduction JSCallReducer::ReduceStringPrototypeSubstr(Node* node) {
5343  JSCallNode n(node);
5344  CallParameters const& p = n.Parameters();
5345  if (n.ArgumentCount() < 1) return NoChange();
5346  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5347    return NoChange();
5348  }
5349
5350  Effect effect = n.effect();
5351  Control control = n.control();
5352  Node* receiver = n.receiver();
5353  Node* start = n.Argument(0);
5354  Node* end = n.ArgumentOrUndefined(1, jsgraph());
5355
5356  receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
5357                                       receiver, effect, control);
5358
5359  start = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()), start,
5360                                    effect, control);
5361
5362  Node* length = graph()->NewNode(simplified()->StringLength(), receiver);
5363
5364  // Replace {end} argument with {length} if it is undefined.
5365  {
5366    Node* check = graph()->NewNode(simplified()->ReferenceEqual(), end,
5367                                   jsgraph()->UndefinedConstant());
5368    Node* branch =
5369        graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
5370
5371    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
5372    Node* etrue = effect;
5373    Node* vtrue = length;
5374
5375    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
5376    Node* efalse = effect;
5377    Node* vfalse = efalse = graph()->NewNode(
5378        simplified()->CheckSmi(p.feedback()), end, efalse, if_false);
5379
5380    control = graph()->NewNode(common()->Merge(2), if_true, if_false);
5381    effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
5382    end = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
5383                           vtrue, vfalse, control);
5384  }
5385
5386  Node* initStart = graph()->NewNode(
5387      common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
5388      graph()->NewNode(simplified()->NumberLessThan(), start,
5389                       jsgraph()->ZeroConstant()),
5390      graph()->NewNode(
5391          simplified()->NumberMax(),
5392          graph()->NewNode(simplified()->NumberAdd(), length, start),
5393          jsgraph()->ZeroConstant()),
5394      start);
5395  // The select above guarantees that initStart is non-negative, but
5396  // our typer can't figure that out yet.
5397  initStart = effect = graph()->NewNode(
5398      common()->TypeGuard(Type::UnsignedSmall()), initStart, effect, control);
5399
5400  Node* resultLength = graph()->NewNode(
5401      simplified()->NumberMin(),
5402      graph()->NewNode(simplified()->NumberMax(), end,
5403                       jsgraph()->ZeroConstant()),
5404      graph()->NewNode(simplified()->NumberSubtract(), length, initStart));
5405
5406  // The the select below uses {resultLength} only if {resultLength > 0},
5407  // but our typer can't figure that out yet.
5408  Node* to = effect = graph()->NewNode(
5409      common()->TypeGuard(Type::UnsignedSmall()),
5410      graph()->NewNode(simplified()->NumberAdd(), initStart, resultLength),
5411      effect, control);
5412
5413  Node* result_string = nullptr;
5414  // Return empty string if {from} is smaller than {to}.
5415  {
5416    Node* check = graph()->NewNode(simplified()->NumberLessThan(),
5417                                   jsgraph()->ZeroConstant(), resultLength);
5418
5419    Node* branch =
5420        graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
5421
5422    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
5423    Node* etrue = effect;
5424    Node* vtrue = etrue =
5425        graph()->NewNode(simplified()->StringSubstring(), receiver, initStart,
5426                         to, etrue, if_true);
5427
5428    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
5429    Node* efalse = effect;
5430    Node* vfalse = jsgraph()->EmptyStringConstant();
5431
5432    control = graph()->NewNode(common()->Merge(2), if_true, if_false);
5433    effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
5434    result_string =
5435        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
5436                         vtrue, vfalse, control);
5437  }
5438
5439  ReplaceWithValue(node, result_string, effect, control);
5440  return Replace(result_string);
5441}
5442
5443Reduction JSCallReducer::ReduceJSConstructWithArrayLike(Node* node) {
5444  JSConstructWithArrayLikeNode n(node);
5445  ConstructParameters const& p = n.Parameters();
5446  const int arraylike_index = n.LastArgumentIndex();
5447  DCHECK_EQ(n.ArgumentCount(), 1);  // The arraylike object.
5448  return ReduceCallOrConstructWithArrayLikeOrSpread(
5449      node, n.ArgumentCount(), arraylike_index, p.frequency(), p.feedback(),
5450      SpeculationMode::kDisallowSpeculation, CallFeedbackRelation::kTarget,
5451      n.target(), n.effect(), n.control());
5452}
5453
5454Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) {
5455  JSConstructWithSpreadNode n(node);
5456  ConstructParameters const& p = n.Parameters();
5457  const int spread_index = n.LastArgumentIndex();
5458  DCHECK_GE(n.ArgumentCount(), 1);  // At least the spread.
5459  return ReduceCallOrConstructWithArrayLikeOrSpread(
5460      node, n.ArgumentCount(), spread_index, p.frequency(), p.feedback(),
5461      SpeculationMode::kDisallowSpeculation, CallFeedbackRelation::kTarget,
5462      n.target(), n.effect(), n.control());
5463}
5464
5465Reduction JSCallReducer::ReduceReturnReceiver(Node* node) {
5466  JSCallNode n(node);
5467  Node* receiver = n.receiver();
5468  ReplaceWithValue(node, receiver);
5469  return Replace(receiver);
5470}
5471
5472Reduction JSCallReducer::ReduceForInsufficientFeedback(
5473    Node* node, DeoptimizeReason reason) {
5474  DCHECK(node->opcode() == IrOpcode::kJSCall ||
5475         node->opcode() == IrOpcode::kJSConstruct);
5476  if (!(flags() & kBailoutOnUninitialized)) return NoChange();
5477
5478  Node* effect = NodeProperties::GetEffectInput(node);
5479  Node* control = NodeProperties::GetControlInput(node);
5480  Node* frame_state =
5481      NodeProperties::FindFrameStateBefore(node, jsgraph()->Dead());
5482  Node* deoptimize =
5483      graph()->NewNode(common()->Deoptimize(reason, FeedbackSource()),
5484                       frame_state, effect, control);
5485  // TODO(bmeurer): This should be on the AdvancedReducer somehow.
5486  NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
5487  Revisit(graph()->end());
5488  node->TrimInputCount(0);
5489  NodeProperties::ChangeOp(node, common()->Dead());
5490  return Changed(node);
5491}
5492
5493Node* JSCallReducer::LoadReceiverElementsKind(Node* receiver, Effect* effect,
5494                                              Control control) {
5495  Node* effect_node = *effect;
5496  Node* receiver_map = effect_node =
5497      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
5498                       receiver, effect_node, control);
5499  Node* receiver_bit_field2 = effect_node = graph()->NewNode(
5500      simplified()->LoadField(AccessBuilder::ForMapBitField2()), receiver_map,
5501      effect_node, control);
5502  Node* receiver_elements_kind = graph()->NewNode(
5503      simplified()->NumberShiftRightLogical(),
5504      graph()->NewNode(
5505          simplified()->NumberBitwiseAnd(), receiver_bit_field2,
5506          jsgraph()->Constant(Map::Bits2::ElementsKindBits::kMask)),
5507      jsgraph()->Constant(Map::Bits2::ElementsKindBits::kShift));
5508  *effect = effect_node;
5509  return receiver_elements_kind;
5510}
5511
5512void JSCallReducer::CheckIfElementsKind(Node* receiver_elements_kind,
5513                                        ElementsKind kind, Node* control,
5514                                        Node** if_true, Node** if_false) {
5515  Node* is_packed_kind =
5516      graph()->NewNode(simplified()->NumberEqual(), receiver_elements_kind,
5517                       jsgraph()->Constant(GetPackedElementsKind(kind)));
5518  Node* packed_branch =
5519      graph()->NewNode(common()->Branch(), is_packed_kind, control);
5520  Node* if_packed = graph()->NewNode(common()->IfTrue(), packed_branch);
5521
5522  if (IsHoleyElementsKind(kind)) {
5523    Node* if_not_packed = graph()->NewNode(common()->IfFalse(), packed_branch);
5524    Node* is_holey_kind =
5525        graph()->NewNode(simplified()->NumberEqual(), receiver_elements_kind,
5526                         jsgraph()->Constant(GetHoleyElementsKind(kind)));
5527    Node* holey_branch =
5528        graph()->NewNode(common()->Branch(), is_holey_kind, if_not_packed);
5529    Node* if_holey = graph()->NewNode(common()->IfTrue(), holey_branch);
5530
5531    Node* if_not_packed_not_holey =
5532        graph()->NewNode(common()->IfFalse(), holey_branch);
5533
5534    *if_true = graph()->NewNode(common()->Merge(2), if_packed, if_holey);
5535    *if_false = if_not_packed_not_holey;
5536  } else {
5537    *if_true = if_packed;
5538    *if_false = graph()->NewNode(common()->IfFalse(), packed_branch);
5539  }
5540}
5541
5542// ES6 section 22.1.3.18 Array.prototype.push ( )
5543Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
5544  JSCallNode n(node);
5545  CallParameters const& p = n.Parameters();
5546  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5547    return NoChange();
5548  }
5549
5550  int const num_values = n.ArgumentCount();
5551  Node* receiver = n.receiver();
5552  Effect effect = n.effect();
5553  Control control = n.control();
5554
5555  MapInference inference(broker(), receiver, effect);
5556  if (!inference.HaveMaps()) return NoChange();
5557  ZoneVector<MapRef> const& receiver_maps = inference.GetMaps();
5558
5559  std::vector<ElementsKind> kinds;
5560  if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds, true)) {
5561    return inference.NoChange();
5562  }
5563  if (!dependencies()->DependOnNoElementsProtector()) {
5564    return inference.NoChange();
5565  }
5566  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
5567                                      control, p.feedback());
5568
5569  std::vector<Node*> controls_to_merge;
5570  std::vector<Node*> effects_to_merge;
5571  std::vector<Node*> values_to_merge;
5572  Node* return_value = jsgraph()->UndefinedConstant();
5573
5574  Node* receiver_elements_kind =
5575      LoadReceiverElementsKind(receiver, &effect, control);
5576  Node* next_control = control;
5577  Node* next_effect = effect;
5578  for (size_t i = 0; i < kinds.size(); i++) {
5579    ElementsKind kind = kinds[i];
5580    control = next_control;
5581    effect = next_effect;
5582    // We do not need branch for the last elements kind.
5583    if (i != kinds.size() - 1) {
5584      Node* control_node = control;
5585      CheckIfElementsKind(receiver_elements_kind, kind, control_node,
5586                          &control_node, &next_control);
5587      control = control_node;
5588    }
5589
5590    // Collect the value inputs to push.
5591    std::vector<Node*> values(num_values);
5592    for (int j = 0; j < num_values; ++j) {
5593      values[j] = n.Argument(j);
5594    }
5595
5596    for (auto& value : values) {
5597      if (IsSmiElementsKind(kind)) {
5598        value = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
5599                                          value, effect, control);
5600      } else if (IsDoubleElementsKind(kind)) {
5601        value = effect = graph()->NewNode(
5602            simplified()->CheckNumber(p.feedback()), value, effect, control);
5603        // Make sure we do not store signaling NaNs into double arrays.
5604        value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
5605      }
5606    }
5607
5608    // Load the "length" property of the {receiver}.
5609    Node* length = effect = graph()->NewNode(
5610        simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)),
5611        receiver, effect, control);
5612    return_value = length;
5613
5614    // Check if we have any {values} to push.
5615    if (num_values > 0) {
5616      // Compute the resulting "length" of the {receiver}.
5617      Node* new_length = return_value = graph()->NewNode(
5618          simplified()->NumberAdd(), length, jsgraph()->Constant(num_values));
5619
5620      // Load the elements backing store of the {receiver}.
5621      Node* elements = effect = graph()->NewNode(
5622          simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
5623          receiver, effect, control);
5624      Node* elements_length = effect = graph()->NewNode(
5625          simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
5626          elements, effect, control);
5627
5628      GrowFastElementsMode mode =
5629          IsDoubleElementsKind(kind)
5630              ? GrowFastElementsMode::kDoubleElements
5631              : GrowFastElementsMode::kSmiOrObjectElements;
5632      elements = effect = graph()->NewNode(
5633          simplified()->MaybeGrowFastElements(mode, p.feedback()), receiver,
5634          elements,
5635          graph()->NewNode(simplified()->NumberAdd(), length,
5636                           jsgraph()->Constant(num_values - 1)),
5637          elements_length, effect, control);
5638
5639      // Update the JSArray::length field. Since this is observable,
5640      // there must be no other check after this.
5641      effect = graph()->NewNode(
5642          simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
5643          receiver, new_length, effect, control);
5644
5645      // Append the {values} to the {elements}.
5646      for (int j = 0; j < num_values; ++j) {
5647        Node* value = values[j];
5648        Node* index = graph()->NewNode(simplified()->NumberAdd(), length,
5649                                       jsgraph()->Constant(j));
5650        effect =
5651            graph()->NewNode(simplified()->StoreElement(
5652                                 AccessBuilder::ForFixedArrayElement(kind)),
5653                             elements, index, value, effect, control);
5654      }
5655    }
5656
5657    controls_to_merge.push_back(control);
5658    effects_to_merge.push_back(effect);
5659    values_to_merge.push_back(return_value);
5660  }
5661
5662  if (controls_to_merge.size() > 1) {
5663    int const count = static_cast<int>(controls_to_merge.size());
5664
5665    control = graph()->NewNode(common()->Merge(count), count,
5666                               &controls_to_merge.front());
5667    effects_to_merge.push_back(control);
5668    effect = graph()->NewNode(common()->EffectPhi(count), count + 1,
5669                              &effects_to_merge.front());
5670    values_to_merge.push_back(control);
5671    return_value =
5672        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
5673                         count + 1, &values_to_merge.front());
5674  }
5675
5676  ReplaceWithValue(node, return_value, effect, control);
5677  return Replace(return_value);
5678}
5679
5680// ES6 section 22.1.3.17 Array.prototype.pop ( )
5681Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
5682  JSCallNode n(node);
5683  CallParameters const& p = n.Parameters();
5684  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5685    return NoChange();
5686  }
5687
5688  Effect effect = n.effect();
5689  Control control = n.control();
5690  Node* receiver = n.receiver();
5691
5692  MapInference inference(broker(), receiver, effect);
5693  if (!inference.HaveMaps()) return NoChange();
5694  ZoneVector<MapRef> const& receiver_maps = inference.GetMaps();
5695
5696  std::vector<ElementsKind> kinds;
5697  if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds)) {
5698    return inference.NoChange();
5699  }
5700  if (!dependencies()->DependOnNoElementsProtector()) {
5701    return inference.NoChange();
5702  }
5703  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
5704                                      control, p.feedback());
5705
5706  std::vector<Node*> controls_to_merge;
5707  std::vector<Node*> effects_to_merge;
5708  std::vector<Node*> values_to_merge;
5709  Node* value = jsgraph()->UndefinedConstant();
5710
5711  Node* receiver_elements_kind =
5712      LoadReceiverElementsKind(receiver, &effect, control);
5713  Node* next_control = control;
5714  Node* next_effect = effect;
5715  for (size_t i = 0; i < kinds.size(); i++) {
5716    ElementsKind kind = kinds[i];
5717    control = next_control;
5718    effect = next_effect;
5719    // We do not need branch for the last elements kind.
5720    if (i != kinds.size() - 1) {
5721      Node* control_node = control;
5722      CheckIfElementsKind(receiver_elements_kind, kind, control_node,
5723                          &control_node, &next_control);
5724      control = control_node;
5725    }
5726
5727    // Load the "length" property of the {receiver}.
5728    Node* length = effect = graph()->NewNode(
5729        simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)),
5730        receiver, effect, control);
5731
5732    // Check if the {receiver} has any elements.
5733    Node* check = graph()->NewNode(simplified()->NumberEqual(), length,
5734                                   jsgraph()->ZeroConstant());
5735    Node* branch =
5736        graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
5737
5738    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
5739    Node* etrue = effect;
5740    Node* vtrue = jsgraph()->UndefinedConstant();
5741
5742    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
5743    Node* efalse = effect;
5744    Node* vfalse;
5745    {
5746      // TODO(turbofan): We should trim the backing store if the capacity is too
5747      // big, as implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
5748
5749      // Load the elements backing store from the {receiver}.
5750      Node* elements = efalse = graph()->NewNode(
5751          simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
5752          receiver, efalse, if_false);
5753
5754      // Ensure that we aren't popping from a copy-on-write backing store.
5755      if (IsSmiOrObjectElementsKind(kind)) {
5756        elements = efalse =
5757            graph()->NewNode(simplified()->EnsureWritableFastElements(),
5758                             receiver, elements, efalse, if_false);
5759      }
5760
5761      // Compute the new {length}.
5762      Node* new_length = graph()->NewNode(simplified()->NumberSubtract(),
5763                                          length, jsgraph()->OneConstant());
5764
5765      // This extra check exists solely to break an exploitation technique
5766      // that abuses typer mismatches.
5767      new_length = efalse = graph()->NewNode(
5768          simplified()->CheckBounds(p.feedback(),
5769                                    CheckBoundsFlag::kAbortOnOutOfBounds),
5770          new_length, length, efalse, if_false);
5771
5772      // Store the new {length} to the {receiver}.
5773      efalse = graph()->NewNode(
5774          simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
5775          receiver, new_length, efalse, if_false);
5776
5777      // Load the last entry from the {elements}.
5778      vfalse = efalse = graph()->NewNode(
5779          simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(kind)),
5780          elements, new_length, efalse, if_false);
5781
5782      // Store a hole to the element we just removed from the {receiver}.
5783      efalse = graph()->NewNode(
5784          simplified()->StoreElement(
5785              AccessBuilder::ForFixedArrayElement(GetHoleyElementsKind(kind))),
5786          elements, new_length, jsgraph()->TheHoleConstant(), efalse, if_false);
5787    }
5788
5789    control = graph()->NewNode(common()->Merge(2), if_true, if_false);
5790    effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
5791    value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
5792                             vtrue, vfalse, control);
5793
5794    // Convert the hole to undefined. Do this last, so that we can optimize
5795    // conversion operator via some smart strength reduction in many cases.
5796    if (IsHoleyElementsKind(kind)) {
5797      value =
5798          graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
5799    }
5800
5801    controls_to_merge.push_back(control);
5802    effects_to_merge.push_back(effect);
5803    values_to_merge.push_back(value);
5804  }
5805
5806  if (controls_to_merge.size() > 1) {
5807    int const count = static_cast<int>(controls_to_merge.size());
5808
5809    control = graph()->NewNode(common()->Merge(count), count,
5810                               &controls_to_merge.front());
5811    effects_to_merge.push_back(control);
5812    effect = graph()->NewNode(common()->EffectPhi(count), count + 1,
5813                              &effects_to_merge.front());
5814    values_to_merge.push_back(control);
5815    value =
5816        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
5817                         count + 1, &values_to_merge.front());
5818  }
5819
5820  ReplaceWithValue(node, value, effect, control);
5821  return Replace(value);
5822}
5823
5824// ES6 section 22.1.3.22 Array.prototype.shift ( )
5825Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
5826  JSCallNode n(node);
5827  CallParameters const& p = n.Parameters();
5828  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
5829    return NoChange();
5830  }
5831
5832  Node* target = n.target();
5833  Node* receiver = n.receiver();
5834  Node* context = n.context();
5835  FrameState frame_state = n.frame_state();
5836  Effect effect = n.effect();
5837  Control control = n.control();
5838
5839  MapInference inference(broker(), receiver, effect);
5840  if (!inference.HaveMaps()) return NoChange();
5841  ZoneVector<MapRef> const& receiver_maps = inference.GetMaps();
5842
5843  std::vector<ElementsKind> kinds;
5844  if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds)) {
5845    return inference.NoChange();
5846  }
5847  if (!dependencies()->DependOnNoElementsProtector()) {
5848    return inference.NoChange();
5849  }
5850  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
5851                                      control, p.feedback());
5852
5853  std::vector<Node*> controls_to_merge;
5854  std::vector<Node*> effects_to_merge;
5855  std::vector<Node*> values_to_merge;
5856  Node* value = jsgraph()->UndefinedConstant();
5857
5858  Node* receiver_elements_kind =
5859      LoadReceiverElementsKind(receiver, &effect, control);
5860  Node* next_control = control;
5861  Node* next_effect = effect;
5862  for (size_t i = 0; i < kinds.size(); i++) {
5863    ElementsKind kind = kinds[i];
5864    control = next_control;
5865    effect = next_effect;
5866    // We do not need branch for the last elements kind.
5867    if (i != kinds.size() - 1) {
5868      Node* control_node = control;
5869      CheckIfElementsKind(receiver_elements_kind, kind, control_node,
5870                          &control_node, &next_control);
5871      control = control_node;
5872    }
5873
5874    // Load length of the {receiver}.
5875    Node* length = effect = graph()->NewNode(
5876        simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)),
5877        receiver, effect, control);
5878
5879    // Return undefined if {receiver} has no elements.
5880    Node* check0 = graph()->NewNode(simplified()->NumberEqual(), length,
5881                                    jsgraph()->ZeroConstant());
5882    Node* branch0 =
5883        graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
5884
5885    Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
5886    Node* etrue0 = effect;
5887    Node* vtrue0 = jsgraph()->UndefinedConstant();
5888
5889    Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
5890    Node* efalse0 = effect;
5891    Node* vfalse0;
5892    {
5893      // Check if we should take the fast-path.
5894      Node* check1 =
5895          graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
5896                           jsgraph()->Constant(JSArray::kMaxCopyElements));
5897      Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
5898                                       check1, if_false0);
5899
5900      Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
5901      Node* etrue1 = efalse0;
5902      Node* vtrue1;
5903      {
5904        Node* elements = etrue1 = graph()->NewNode(
5905            simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
5906            receiver, etrue1, if_true1);
5907
5908        // Load the first element here, which we return below.
5909        vtrue1 = etrue1 = graph()->NewNode(
5910            simplified()->LoadElement(
5911                AccessBuilder::ForFixedArrayElement(kind)),
5912            elements, jsgraph()->ZeroConstant(), etrue1, if_true1);
5913
5914        // Ensure that we aren't shifting a copy-on-write backing store.
5915        if (IsSmiOrObjectElementsKind(kind)) {
5916          elements = etrue1 =
5917              graph()->NewNode(simplified()->EnsureWritableFastElements(),
5918                               receiver, elements, etrue1, if_true1);
5919        }
5920
5921        // Shift the remaining {elements} by one towards the start.
5922        Node* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1);
5923        Node* eloop =
5924            graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop);
5925        Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
5926        NodeProperties::MergeControlToEnd(graph(), common(), terminate);
5927
5928        Node* index = graph()->NewNode(
5929            common()->Phi(MachineRepresentation::kTagged, 2),
5930            jsgraph()->OneConstant(),
5931            jsgraph()->Constant(JSArray::kMaxCopyElements - 1), loop);
5932
5933        {
5934          Node* check2 =
5935              graph()->NewNode(simplified()->NumberLessThan(), index, length);
5936          Node* branch2 = graph()->NewNode(common()->Branch(), check2, loop);
5937
5938          if_true1 = graph()->NewNode(common()->IfFalse(), branch2);
5939          etrue1 = eloop;
5940
5941          Node* control2 = graph()->NewNode(common()->IfTrue(), branch2);
5942          Node* effect2 = etrue1;
5943
5944          ElementAccess const access =
5945              AccessBuilder::ForFixedArrayElement(kind);
5946
5947          // When disable FLAG_turbo_loop_variable, typer cannot infer index
5948          // is in [1, kMaxCopyElements-1], and will break in representing
5949          // kRepFloat64 (Range(1, inf)) to kRepWord64 when converting
5950          // input for kLoadElement. So we need to add type guard here.
5951          // And we need to use index when using NumberLessThan to check
5952          // terminate and updating index, otherwise which will break inducing
5953          // variables in LoopVariableOptimizer.
5954          STATIC_ASSERT(JSArray::kMaxCopyElements < kSmiMaxValue);
5955          Node* index_retyped = effect2 =
5956              graph()->NewNode(common()->TypeGuard(Type::UnsignedSmall()),
5957                               index, effect2, control2);
5958
5959          Node* value2 = effect2 =
5960              graph()->NewNode(simplified()->LoadElement(access), elements,
5961                               index_retyped, effect2, control2);
5962          effect2 = graph()->NewNode(
5963              simplified()->StoreElement(access), elements,
5964              graph()->NewNode(simplified()->NumberSubtract(), index_retyped,
5965                               jsgraph()->OneConstant()),
5966              value2, effect2, control2);
5967
5968          loop->ReplaceInput(1, control2);
5969          eloop->ReplaceInput(1, effect2);
5970          index->ReplaceInput(1,
5971                              graph()->NewNode(simplified()->NumberAdd(), index,
5972                                               jsgraph()->OneConstant()));
5973        }
5974
5975        // Compute the new {length}.
5976        Node* new_length = graph()->NewNode(simplified()->NumberSubtract(),
5977                                            length, jsgraph()->OneConstant());
5978
5979        // This extra check exists solely to break an exploitation technique
5980        // that abuses typer mismatches.
5981        new_length = etrue1 = graph()->NewNode(
5982            simplified()->CheckBounds(p.feedback(),
5983                                      CheckBoundsFlag::kAbortOnOutOfBounds),
5984            new_length, length, etrue1, if_true1);
5985
5986        // Store the new {length} to the {receiver}.
5987        etrue1 = graph()->NewNode(
5988            simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
5989            receiver, new_length, etrue1, if_true1);
5990
5991        // Store a hole to the element we just removed from the {receiver}.
5992        etrue1 = graph()->NewNode(
5993            simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
5994                GetHoleyElementsKind(kind))),
5995            elements, new_length, jsgraph()->TheHoleConstant(), etrue1,
5996            if_true1);
5997      }
5998
5999      Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
6000      Node* efalse1 = efalse0;
6001      Node* vfalse1;
6002      {
6003        // Call the generic C++ implementation.
6004        const Builtin builtin = Builtin::kArrayShift;
6005        auto call_descriptor = Linkage::GetCEntryStubCallDescriptor(
6006            graph()->zone(), 1, BuiltinArguments::kNumExtraArgsWithReceiver,
6007            Builtins::name(builtin), node->op()->properties(),
6008            CallDescriptor::kNeedsFrameState);
6009        Node* stub_code = jsgraph()->CEntryStubConstant(
6010            1, SaveFPRegsMode::kIgnore, ArgvMode::kStack, true);
6011        Address builtin_entry = Builtins::CppEntryOf(builtin);
6012        Node* entry = jsgraph()->ExternalConstant(
6013            ExternalReference::Create(builtin_entry));
6014        Node* argc =
6015            jsgraph()->Constant(BuiltinArguments::kNumExtraArgsWithReceiver);
6016        if_false1 = efalse1 = vfalse1 =
6017            graph()->NewNode(common()->Call(call_descriptor), stub_code,
6018                             receiver, jsgraph()->PaddingConstant(), argc,
6019                             target, jsgraph()->UndefinedConstant(), entry,
6020                             argc, context, frame_state, efalse1, if_false1);
6021      }
6022
6023      if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
6024      efalse0 =
6025          graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
6026      vfalse0 =
6027          graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
6028                           vtrue1, vfalse1, if_false0);
6029    }
6030
6031    control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
6032    effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
6033    value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
6034                             vtrue0, vfalse0, control);
6035
6036    // Convert the hole to undefined. Do this last, so that we can optimize
6037    // conversion operator via some smart strength reduction in many cases.
6038    if (IsHoleyElementsKind(kind)) {
6039      value =
6040          graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
6041    }
6042
6043    controls_to_merge.push_back(control);
6044    effects_to_merge.push_back(effect);
6045    values_to_merge.push_back(value);
6046  }
6047
6048  if (controls_to_merge.size() > 1) {
6049    int const count = static_cast<int>(controls_to_merge.size());
6050
6051    control = graph()->NewNode(common()->Merge(count), count,
6052                               &controls_to_merge.front());
6053    effects_to_merge.push_back(control);
6054    effect = graph()->NewNode(common()->EffectPhi(count), count + 1,
6055                              &effects_to_merge.front());
6056    values_to_merge.push_back(control);
6057    value =
6058        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
6059                         count + 1, &values_to_merge.front());
6060  }
6061
6062  ReplaceWithValue(node, value, effect, control);
6063  return Replace(value);
6064}
6065
6066// ES6 section 22.1.3.23 Array.prototype.slice ( )
6067Reduction JSCallReducer::ReduceArrayPrototypeSlice(Node* node) {
6068  if (!FLAG_turbo_inline_array_builtins) return NoChange();
6069  JSCallNode n(node);
6070  CallParameters const& p = n.Parameters();
6071  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6072    return NoChange();
6073  }
6074
6075  Node* receiver = n.receiver();
6076  Node* start = n.ArgumentOr(0, jsgraph()->ZeroConstant());
6077  Node* end = n.ArgumentOrUndefined(1, jsgraph());
6078  Node* context = n.context();
6079  Effect effect = n.effect();
6080  Control control = n.control();
6081
6082  // Optimize for the case where we simply clone the {receiver}, i.e. when the
6083  // {start} is zero and the {end} is undefined (meaning it will be set to
6084  // {receiver}s "length" property). This logic should be in sync with
6085  // ReduceArrayPrototypeSlice (to a reasonable degree). This is because
6086  // CloneFastJSArray produces arrays which are potentially COW. If there's a
6087  // discrepancy, TF generates code which produces a COW array and then expects
6088  // it to be non-COW (or the other way around) -> immediate deopt.
6089  if (!NumberMatcher(start).Is(0) ||
6090      !HeapObjectMatcher(end).Is(factory()->undefined_value())) {
6091    return NoChange();
6092  }
6093
6094  MapInference inference(broker(), receiver, effect);
6095  if (!inference.HaveMaps()) return NoChange();
6096  ZoneVector<MapRef> const& receiver_maps = inference.GetMaps();
6097
6098  // Check that the maps are of JSArray (and more).
6099  // TODO(turbofan): Consider adding special case for the common pattern
6100  // `slice.call(arguments)`, for example jQuery makes heavy use of that.
6101  bool can_be_holey = false;
6102  for (const MapRef& receiver_map : receiver_maps) {
6103    if (!receiver_map.supports_fast_array_iteration()) {
6104      return inference.NoChange();
6105    }
6106    if (IsHoleyElementsKind(receiver_map.elements_kind())) {
6107      can_be_holey = true;
6108    }
6109  }
6110
6111  if (!dependencies()->DependOnArraySpeciesProtector()) {
6112    return inference.NoChange();
6113  }
6114  if (can_be_holey && !dependencies()->DependOnNoElementsProtector()) {
6115    return inference.NoChange();
6116  }
6117  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
6118                                      control, p.feedback());
6119
6120  // TODO(turbofan): We can do even better here, either adding a CloneArray
6121  // simplified operator, whose output type indicates that it's an Array,
6122  // saving subsequent checks, or yet better, by introducing new operators
6123  // CopySmiOrObjectElements / CopyDoubleElements and inlining the JSArray
6124  // allocation in here. That way we'd even get escape analysis and scalar
6125  // replacement to help in some cases.
6126  Callable callable =
6127      Builtins::CallableFor(isolate(), Builtin::kCloneFastJSArray);
6128  auto call_descriptor = Linkage::GetStubCallDescriptor(
6129      graph()->zone(), callable.descriptor(),
6130      callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags,
6131      Operator::kNoThrow | Operator::kNoDeopt);
6132
6133  // Calls to Builtin::kCloneFastJSArray produce COW arrays
6134  // if the original array is COW
6135  Node* clone = effect = graph()->NewNode(
6136      common()->Call(call_descriptor), jsgraph()->HeapConstant(callable.code()),
6137      receiver, context, effect, control);
6138
6139  ReplaceWithValue(node, clone, effect, control);
6140  return Replace(clone);
6141}
6142
6143// ES6 section 22.1.2.2 Array.isArray ( arg )
6144Reduction JSCallReducer::ReduceArrayIsArray(Node* node) {
6145  // We certainly know that undefined is not an array.
6146  JSCallNode n(node);
6147  if (n.ArgumentCount() < 1) {
6148    Node* value = jsgraph()->FalseConstant();
6149    ReplaceWithValue(node, value);
6150    return Replace(value);
6151  }
6152
6153  Effect effect = n.effect();
6154  Control control = n.control();
6155  Node* context = n.context();
6156  FrameState frame_state = n.frame_state();
6157  Node* object = n.Argument(0);
6158  node->ReplaceInput(0, object);
6159  node->ReplaceInput(1, context);
6160  node->ReplaceInput(2, frame_state);
6161  node->ReplaceInput(3, effect);
6162  node->ReplaceInput(4, control);
6163  node->TrimInputCount(5);
6164  NodeProperties::ChangeOp(node, javascript()->ObjectIsArray());
6165  return Changed(node);
6166}
6167
6168Reduction JSCallReducer::ReduceArrayIterator(Node* node,
6169                                             ArrayIteratorKind array_kind,
6170                                             IterationKind iteration_kind) {
6171  JSCallNode n(node);
6172  Node* receiver = n.receiver();
6173  Node* context = n.context();
6174  Effect effect = n.effect();
6175  Control control = n.control();
6176
6177  // Check if we know that {receiver} is a valid JSReceiver.
6178  MapInference inference(broker(), receiver, effect);
6179  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAreJSReceiver()) {
6180    return NoChange();
6181  }
6182
6183  // TypedArray iteration is stricter: it throws if the receiver is not a typed
6184  // array. So don't bother optimizing in that case.
6185  if (array_kind == ArrayIteratorKind::kTypedArray &&
6186      !inference.AllOfInstanceTypesAre(InstanceType::JS_TYPED_ARRAY_TYPE)) {
6187    return NoChange();
6188  }
6189
6190  if (array_kind == ArrayIteratorKind::kTypedArray) {
6191    // Make sure we deopt when the JSArrayBuffer is detached.
6192    if (!dependencies()->DependOnArrayBufferDetachingProtector()) {
6193      CallParameters const& p = CallParametersOf(node->op());
6194      if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6195        return NoChange();
6196      }
6197      Node* buffer = effect = graph()->NewNode(
6198          simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
6199          receiver, effect, control);
6200      Node* buffer_bit_field = effect = graph()->NewNode(
6201          simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
6202          buffer, effect, control);
6203      Node* check = graph()->NewNode(
6204          simplified()->NumberEqual(),
6205          graph()->NewNode(
6206              simplified()->NumberBitwiseAnd(), buffer_bit_field,
6207              jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
6208          jsgraph()->ZeroConstant());
6209      effect = graph()->NewNode(
6210          simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached,
6211                                p.feedback()),
6212          check, effect, control);
6213    }
6214  }
6215
6216  // Morph the {node} into a JSCreateArrayIterator with the given {kind}.
6217  RelaxControls(node);
6218  node->ReplaceInput(0, receiver);
6219  node->ReplaceInput(1, context);
6220  node->ReplaceInput(2, effect);
6221  node->ReplaceInput(3, control);
6222  node->TrimInputCount(4);
6223  NodeProperties::ChangeOp(node,
6224                           javascript()->CreateArrayIterator(iteration_kind));
6225  return Changed(node);
6226}
6227
6228// ES #sec-%arrayiteratorprototype%.next
6229Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
6230  JSCallNode n(node);
6231  CallParameters const& p = n.Parameters();
6232  Node* iterator = n.receiver();
6233  Node* context = n.context();
6234  Effect effect = n.effect();
6235  Control control = n.control();
6236
6237  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6238    return NoChange();
6239  }
6240
6241  if (iterator->opcode() != IrOpcode::kJSCreateArrayIterator) return NoChange();
6242
6243  IterationKind const iteration_kind =
6244      CreateArrayIteratorParametersOf(iterator->op()).kind();
6245  Node* iterated_object = NodeProperties::GetValueInput(iterator, 0);
6246  Effect iterator_effect{NodeProperties::GetEffectInput(iterator)};
6247
6248  MapInference inference(broker(), iterated_object, iterator_effect);
6249  if (!inference.HaveMaps()) return NoChange();
6250  ZoneVector<MapRef> const& iterated_object_maps = inference.GetMaps();
6251
6252  // Check that various {iterated_object_maps} have compatible elements kinds.
6253  ElementsKind elements_kind = iterated_object_maps[0].elements_kind();
6254  if (IsTypedArrayElementsKind(elements_kind)) {
6255    // TurboFan doesn't support loading from BigInt typed arrays yet.
6256    if (elements_kind == BIGUINT64_ELEMENTS ||
6257        elements_kind == BIGINT64_ELEMENTS) {
6258      return inference.NoChange();
6259    }
6260    for (const MapRef& iterated_object_map : iterated_object_maps) {
6261      if (iterated_object_map.elements_kind() != elements_kind) {
6262        return inference.NoChange();
6263      }
6264    }
6265  } else {
6266    if (!CanInlineArrayIteratingBuiltin(broker(), iterated_object_maps,
6267                                        &elements_kind)) {
6268      return inference.NoChange();
6269    }
6270  }
6271
6272  if (IsHoleyElementsKind(elements_kind) &&
6273      !dependencies()->DependOnNoElementsProtector()) {
6274    return inference.NoChange();
6275  }
6276
6277  // Since the map inference was done relative to {iterator_effect} rather than
6278  // {effect}, we need to guard the use of the map(s) even when the inference
6279  // was reliable.
6280  inference.InsertMapChecks(jsgraph(), &effect, control, p.feedback());
6281
6282  if (IsTypedArrayElementsKind(elements_kind)) {
6283    // See if we can skip the detaching check.
6284    if (!dependencies()->DependOnArrayBufferDetachingProtector()) {
6285      // Bail out if the {iterated_object}s JSArrayBuffer was detached.
6286      Node* buffer = effect = graph()->NewNode(
6287          simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
6288          iterated_object, effect, control);
6289      Node* buffer_bit_field = effect = graph()->NewNode(
6290          simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
6291          buffer, effect, control);
6292      Node* check = graph()->NewNode(
6293          simplified()->NumberEqual(),
6294          graph()->NewNode(
6295              simplified()->NumberBitwiseAnd(), buffer_bit_field,
6296              jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
6297          jsgraph()->ZeroConstant());
6298      effect = graph()->NewNode(
6299          simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached,
6300                                p.feedback()),
6301          check, effect, control);
6302    }
6303  }
6304
6305  // Load the [[NextIndex]] from the {iterator} and leverage the fact
6306  // that we definitely know that it's in Unsigned32 range since the
6307  // {iterated_object} is either a JSArray or a JSTypedArray. For the
6308  // latter case we even know that it's a Smi in UnsignedSmall range.
6309  FieldAccess index_access = AccessBuilder::ForJSArrayIteratorNextIndex();
6310  if (IsTypedArrayElementsKind(elements_kind)) {
6311    index_access.type = TypeCache::Get()->kJSTypedArrayLengthType;
6312  } else {
6313    index_access.type = TypeCache::Get()->kJSArrayLengthType;
6314  }
6315  Node* index = effect = graph()->NewNode(simplified()->LoadField(index_access),
6316                                          iterator, effect, control);
6317
6318  // Load the elements of the {iterated_object}. While it feels
6319  // counter-intuitive to place the elements pointer load before
6320  // the condition below, as it might not be needed (if the {index}
6321  // is out of bounds for the {iterated_object}), it's better this
6322  // way as it allows the LoadElimination to eliminate redundant
6323  // reloads of the elements pointer.
6324  Node* elements = effect = graph()->NewNode(
6325      simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
6326      iterated_object, effect, control);
6327
6328  // Load the length of the {iterated_object}. Due to the map checks we
6329  // already know something about the length here, which we can leverage
6330  // to generate Word32 operations below without additional checking.
6331  FieldAccess length_access =
6332      IsTypedArrayElementsKind(elements_kind)
6333          ? AccessBuilder::ForJSTypedArrayLength()
6334          : AccessBuilder::ForJSArrayLength(elements_kind);
6335  Node* length = effect = graph()->NewNode(
6336      simplified()->LoadField(length_access), iterated_object, effect, control);
6337
6338  // Check whether {index} is within the valid range for the {iterated_object}.
6339  Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, length);
6340  Node* branch =
6341      graph()->NewNode(common()->Branch(BranchHint::kNone), check, control);
6342
6343  Node* done_true;
6344  Node* value_true;
6345  Node* etrue = effect;
6346  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
6347  {
6348    // This extra check exists to refine the type of {index} but also to break
6349    // an exploitation technique that abuses typer mismatches.
6350    index = etrue = graph()->NewNode(
6351        simplified()->CheckBounds(p.feedback(),
6352                                  CheckBoundsFlag::kAbortOnOutOfBounds),
6353        index, length, etrue, if_true);
6354
6355    done_true = jsgraph()->FalseConstant();
6356    if (iteration_kind == IterationKind::kKeys) {
6357      // Just return the {index}.
6358      value_true = index;
6359    } else {
6360      DCHECK(iteration_kind == IterationKind::kEntries ||
6361             iteration_kind == IterationKind::kValues);
6362
6363      if (IsTypedArrayElementsKind(elements_kind)) {
6364        Node* base_ptr = etrue =
6365            graph()->NewNode(simplified()->LoadField(
6366                                 AccessBuilder::ForJSTypedArrayBasePointer()),
6367                             iterated_object, etrue, if_true);
6368        Node* external_ptr = etrue = graph()->NewNode(
6369            simplified()->LoadField(
6370                AccessBuilder::ForJSTypedArrayExternalPointer()),
6371            iterated_object, etrue, if_true);
6372
6373        ExternalArrayType array_type = kExternalInt8Array;
6374        switch (elements_kind) {
6375#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
6376  case TYPE##_ELEMENTS:                           \
6377    array_type = kExternal##Type##Array;          \
6378    break;
6379          TYPED_ARRAYS(TYPED_ARRAY_CASE)
6380          default:
6381            UNREACHABLE();
6382#undef TYPED_ARRAY_CASE
6383        }
6384
6385        Node* buffer = etrue =
6386            graph()->NewNode(simplified()->LoadField(
6387                                 AccessBuilder::ForJSArrayBufferViewBuffer()),
6388                             iterated_object, etrue, if_true);
6389
6390        value_true = etrue =
6391            graph()->NewNode(simplified()->LoadTypedElement(array_type), buffer,
6392                             base_ptr, external_ptr, index, etrue, if_true);
6393      } else {
6394        value_true = etrue = graph()->NewNode(
6395            simplified()->LoadElement(
6396                AccessBuilder::ForFixedArrayElement(elements_kind)),
6397            elements, index, etrue, if_true);
6398
6399        // Convert hole to undefined if needed.
6400        if (elements_kind == HOLEY_ELEMENTS ||
6401            elements_kind == HOLEY_SMI_ELEMENTS) {
6402          value_true = graph()->NewNode(
6403              simplified()->ConvertTaggedHoleToUndefined(), value_true);
6404        } else if (elements_kind == HOLEY_DOUBLE_ELEMENTS) {
6405          // TODO(6587): avoid deopt if not all uses of value are truncated.
6406          CheckFloat64HoleMode mode = CheckFloat64HoleMode::kAllowReturnHole;
6407          value_true = etrue = graph()->NewNode(
6408              simplified()->CheckFloat64Hole(mode, p.feedback()), value_true,
6409              etrue, if_true);
6410        }
6411      }
6412
6413      if (iteration_kind == IterationKind::kEntries) {
6414        // Allocate elements for key/value pair
6415        value_true = etrue =
6416            graph()->NewNode(javascript()->CreateKeyValueArray(), index,
6417                             value_true, context, etrue);
6418      } else {
6419        DCHECK_EQ(IterationKind::kValues, iteration_kind);
6420      }
6421    }
6422
6423    // Increment the [[NextIndex]] field in the {iterator}. The TypeGuards
6424    // above guarantee that the {next_index} is in the UnsignedSmall range.
6425    Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
6426                                        jsgraph()->OneConstant());
6427    etrue = graph()->NewNode(simplified()->StoreField(index_access), iterator,
6428                             next_index, etrue, if_true);
6429  }
6430
6431  Node* done_false;
6432  Node* value_false;
6433  Node* efalse = effect;
6434  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
6435  {
6436    // iterator.[[NextIndex]] >= array.length, stop iterating.
6437    done_false = jsgraph()->TrueConstant();
6438    value_false = jsgraph()->UndefinedConstant();
6439
6440    if (!IsTypedArrayElementsKind(elements_kind)) {
6441      // Mark the {iterator} as exhausted by setting the [[NextIndex]] to a
6442      // value that will never pass the length check again (aka the maximum
6443      // value possible for the specific iterated object). Note that this is
6444      // different from what the specification says, which is changing the
6445      // [[IteratedObject]] field to undefined, but that makes it difficult
6446      // to eliminate the map checks and "length" accesses in for..of loops.
6447      //
6448      // This is not necessary for JSTypedArray's, since the length of those
6449      // cannot change later and so if we were ever out of bounds for them
6450      // we will stay out-of-bounds forever.
6451      Node* end_index = jsgraph()->Constant(index_access.type.Max());
6452      efalse = graph()->NewNode(simplified()->StoreField(index_access),
6453                                iterator, end_index, efalse, if_false);
6454    }
6455  }
6456
6457  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
6458  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
6459  Node* value =
6460      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
6461                       value_true, value_false, control);
6462  Node* done =
6463      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
6464                       done_true, done_false, control);
6465
6466  // Create IteratorResult object.
6467  value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
6468                                    value, done, context, effect);
6469  ReplaceWithValue(node, value, effect, control);
6470  return Replace(value);
6471}
6472
6473// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
6474// ES6 section 21.1.3.3 String.prototype.codePointAt ( pos )
6475Reduction JSCallReducer::ReduceStringPrototypeStringAt(
6476    const Operator* string_access_operator, Node* node) {
6477  DCHECK(string_access_operator->opcode() == IrOpcode::kStringCharCodeAt ||
6478         string_access_operator->opcode() == IrOpcode::kStringCodePointAt);
6479  JSCallNode n(node);
6480  CallParameters const& p = n.Parameters();
6481  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6482    return NoChange();
6483  }
6484
6485  Node* receiver = n.receiver();
6486  Node* index = n.ArgumentOr(0, jsgraph()->ZeroConstant());
6487  Effect effect = n.effect();
6488  Control control = n.control();
6489
6490  // Ensure that the {receiver} is actually a String.
6491  receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
6492                                       receiver, effect, control);
6493
6494  // Determine the {receiver} length.
6495  Node* receiver_length =
6496      graph()->NewNode(simplified()->StringLength(), receiver);
6497
6498  // Check that the {index} is within range.
6499  index = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
6500                                    index, receiver_length, effect, control);
6501
6502  // Return the character from the {receiver} as single character string.
6503  Node* value = effect = graph()->NewNode(string_access_operator, receiver,
6504                                          index, effect, control);
6505
6506  ReplaceWithValue(node, value, effect, control);
6507  return Replace(value);
6508}
6509
6510// ES section 21.1.3.20
6511// String.prototype.startsWith ( searchString [ , position ] )
6512Reduction JSCallReducer::ReduceStringPrototypeStartsWith(Node* node) {
6513  JSCallNode n(node);
6514  CallParameters const& p = n.Parameters();
6515  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6516    return NoChange();
6517  }
6518
6519  TNode<Object> search_element = n.ArgumentOrUndefined(0, jsgraph());
6520
6521  // Here are three conditions:
6522  // First, If search_element is definitely not a string, we make no change.
6523  // Second, If search_element is definitely a string and its length is less
6524  // or equal than max inline matching sequence threshold, we could inline
6525  // the entire matching sequence.
6526  // Third, we try to inline, and have a runtime deopt if search_element is
6527  // not a string.
6528  HeapObjectMatcher search_element_matcher(search_element);
6529  if (search_element_matcher.HasResolvedValue()) {
6530    ObjectRef target_ref = search_element_matcher.Ref(broker());
6531    if (!target_ref.IsString()) return NoChange();
6532    StringRef search_element_string = target_ref.AsString();
6533    if (search_element_string.length().has_value()) {
6534      int length = search_element_string.length().value();
6535      // If search_element's length is less or equal than
6536      // kMaxInlineMatchSequence, we inline the entire
6537      // matching sequence.
6538      if (length <= kMaxInlineMatchSequence) {
6539        JSCallReducerAssembler a(this, node);
6540        Node* subgraph =
6541            a.ReduceStringPrototypeStartsWith(search_element_string);
6542        return ReplaceWithSubgraph(&a, subgraph);
6543      }
6544    }
6545  }
6546
6547  JSCallReducerAssembler a(this, node);
6548  Node* subgraph = a.ReduceStringPrototypeStartsWith();
6549  return ReplaceWithSubgraph(&a, subgraph);
6550}
6551
6552// ES section 21.1.3.1 String.prototype.charAt ( pos )
6553Reduction JSCallReducer::ReduceStringPrototypeCharAt(Node* node) {
6554  JSCallNode n(node);
6555  CallParameters const& p = n.Parameters();
6556  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6557    return NoChange();
6558  }
6559
6560  Node* receiver = n.receiver();
6561  Node* index = n.ArgumentOr(0, jsgraph()->ZeroConstant());
6562  Effect effect = n.effect();
6563  Control control = n.control();
6564
6565  // Ensure that the {receiver} is actually a String.
6566  receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
6567                                       receiver, effect, control);
6568
6569  // Determine the {receiver} length.
6570  Node* receiver_length =
6571      graph()->NewNode(simplified()->StringLength(), receiver);
6572
6573  // Check that the {index} is within range.
6574  index = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
6575                                    index, receiver_length, effect, control);
6576
6577  // Return the character from the {receiver} as single character string.
6578  Node* value = effect = graph()->NewNode(simplified()->StringCharCodeAt(),
6579                                          receiver, index, effect, control);
6580  value = graph()->NewNode(simplified()->StringFromSingleCharCode(), value);
6581
6582  ReplaceWithValue(node, value, effect, control);
6583  return Replace(value);
6584}
6585
6586#ifdef V8_INTL_SUPPORT
6587
6588Reduction JSCallReducer::ReduceStringPrototypeToLowerCaseIntl(Node* node) {
6589  JSCallNode n(node);
6590  CallParameters const& p = n.Parameters();
6591  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6592    return NoChange();
6593  }
6594  Effect effect = n.effect();
6595  Control control = n.control();
6596
6597  Node* receiver = effect = graph()->NewNode(
6598      simplified()->CheckString(p.feedback()), n.receiver(), effect, control);
6599
6600  NodeProperties::ReplaceEffectInput(node, effect);
6601  RelaxEffectsAndControls(node);
6602  node->ReplaceInput(0, receiver);
6603  node->TrimInputCount(1);
6604  NodeProperties::ChangeOp(node, simplified()->StringToLowerCaseIntl());
6605  NodeProperties::SetType(node, Type::String());
6606  return Changed(node);
6607}
6608
6609Reduction JSCallReducer::ReduceStringPrototypeToUpperCaseIntl(Node* node) {
6610  JSCallNode n(node);
6611  CallParameters const& p = n.Parameters();
6612  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6613    return NoChange();
6614  }
6615  Effect effect = n.effect();
6616  Control control = n.control();
6617
6618  Node* receiver = effect = graph()->NewNode(
6619      simplified()->CheckString(p.feedback()), n.receiver(), effect, control);
6620
6621  NodeProperties::ReplaceEffectInput(node, effect);
6622  RelaxEffectsAndControls(node);
6623  node->ReplaceInput(0, receiver);
6624  node->TrimInputCount(1);
6625  NodeProperties::ChangeOp(node, simplified()->StringToUpperCaseIntl());
6626  NodeProperties::SetType(node, Type::String());
6627  return Changed(node);
6628}
6629
6630#endif  // V8_INTL_SUPPORT
6631
6632// ES #sec-string.fromcharcode
6633Reduction JSCallReducer::ReduceStringFromCharCode(Node* node) {
6634  JSCallNode n(node);
6635  CallParameters const& p = n.Parameters();
6636  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6637    return NoChange();
6638  }
6639  if (n.ArgumentCount() == 1) {
6640    Effect effect = n.effect();
6641    Control control = n.control();
6642    Node* input = n.Argument(0);
6643
6644    input = effect = graph()->NewNode(
6645        simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
6646                                          p.feedback()),
6647        input, effect, control);
6648
6649    Node* value =
6650        graph()->NewNode(simplified()->StringFromSingleCharCode(), input);
6651    ReplaceWithValue(node, value, effect);
6652    return Replace(value);
6653  }
6654  return NoChange();
6655}
6656
6657// ES #sec-string.fromcodepoint
6658Reduction JSCallReducer::ReduceStringFromCodePoint(Node* node) {
6659  JSCallNode n(node);
6660  CallParameters const& p = n.Parameters();
6661  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6662    return NoChange();
6663  }
6664  if (n.ArgumentCount() != 1) return NoChange();
6665
6666  Effect effect = n.effect();
6667  Control control = n.control();
6668  Node* input = n.Argument(0);
6669
6670  input = effect = graph()->NewNode(
6671      simplified()->CheckBounds(p.feedback(),
6672                                CheckBoundsFlag::kConvertStringAndMinusZero),
6673      input, jsgraph()->Constant(0x10FFFF + 1), effect, control);
6674
6675  Node* value =
6676      graph()->NewNode(simplified()->StringFromSingleCodePoint(), input);
6677  ReplaceWithValue(node, value, effect);
6678  return Replace(value);
6679}
6680
6681Reduction JSCallReducer::ReduceStringPrototypeIterator(Node* node) {
6682  JSCallNode n(node);
6683  CallParameters const& p = n.Parameters();
6684  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6685    return NoChange();
6686  }
6687  Node* effect = NodeProperties::GetEffectInput(node);
6688  Node* control = NodeProperties::GetControlInput(node);
6689  Node* receiver = effect = graph()->NewNode(
6690      simplified()->CheckString(p.feedback()), n.receiver(), effect, control);
6691  Node* iterator = effect =
6692      graph()->NewNode(javascript()->CreateStringIterator(), receiver,
6693                       jsgraph()->NoContextConstant(), effect);
6694  ReplaceWithValue(node, iterator, effect, control);
6695  return Replace(iterator);
6696}
6697
6698Reduction JSCallReducer::ReduceStringPrototypeLocaleCompare(Node* node) {
6699#ifdef V8_INTL_SUPPORT
6700  JSCallNode n(node);
6701  // Signature: receiver.localeCompare(compareString, locales, options)
6702  if (n.ArgumentCount() < 1 || n.ArgumentCount() > 3) {
6703    return NoChange();
6704  }
6705
6706  {
6707    Handle<Object> locales;
6708    {
6709      HeapObjectMatcher m(n.ArgumentOrUndefined(1, jsgraph()));
6710      if (!m.HasResolvedValue()) return NoChange();
6711      if (m.Is(factory()->undefined_value())) {
6712        locales = factory()->undefined_value();
6713      } else {
6714        ObjectRef ref = m.Ref(broker());
6715        if (!ref.IsString()) return NoChange();
6716        StringRef sref = ref.AsString();
6717        if (base::Optional<Handle<String>> maybe_locales =
6718                sref.ObjectIfContentAccessible()) {
6719          locales = *maybe_locales;
6720        } else {
6721          return NoChange();
6722        }
6723      }
6724    }
6725
6726    TNode<Object> options = n.ArgumentOrUndefined(2, jsgraph());
6727    {
6728      HeapObjectMatcher m(options);
6729      if (!m.Is(factory()->undefined_value())) {
6730        return NoChange();
6731      }
6732    }
6733
6734    if (Intl::CompareStringsOptionsFor(broker()->local_isolate_or_isolate(),
6735                                       locales, factory()->undefined_value()) !=
6736        Intl::CompareStringsOptions::kTryFastPath) {
6737      return NoChange();
6738    }
6739  }
6740
6741  Callable callable =
6742      Builtins::CallableFor(isolate(), Builtin::kStringFastLocaleCompare);
6743  auto call_descriptor = Linkage::GetStubCallDescriptor(
6744      graph()->zone(), callable.descriptor(),
6745      callable.descriptor().GetStackParameterCount(),
6746      CallDescriptor::kNeedsFrameState);
6747  node->RemoveInput(n.FeedbackVectorIndex());
6748  if (n.ArgumentCount() == 3) {
6749    node->RemoveInput(n.ArgumentIndex(2));
6750  } else if (n.ArgumentCount() == 1) {
6751    node->InsertInput(graph()->zone(), n.LastArgumentIndex() + 1,
6752                      jsgraph()->UndefinedConstant());
6753  } else {
6754    DCHECK_EQ(2, n.ArgumentCount());
6755  }
6756  node->InsertInput(graph()->zone(), 0,
6757                    jsgraph()->HeapConstant(callable.code()));
6758  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
6759  return Changed(node);
6760#else
6761  return NoChange();
6762#endif
6763}
6764
6765Reduction JSCallReducer::ReduceStringIteratorPrototypeNext(Node* node) {
6766  JSCallNode n(node);
6767  Node* receiver = n.receiver();
6768  Effect effect = n.effect();
6769  Control control = n.control();
6770  Node* context = n.context();
6771
6772  MapInference inference(broker(), receiver, effect);
6773  if (!inference.HaveMaps() ||
6774      !inference.AllOfInstanceTypesAre(JS_STRING_ITERATOR_TYPE)) {
6775    return NoChange();
6776  }
6777
6778  Node* string = effect = graph()->NewNode(
6779      simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()),
6780      receiver, effect, control);
6781  Node* index = effect = graph()->NewNode(
6782      simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()),
6783      receiver, effect, control);
6784  Node* length = graph()->NewNode(simplified()->StringLength(), string);
6785
6786  // branch0: if (index < length)
6787  Node* check0 =
6788      graph()->NewNode(simplified()->NumberLessThan(), index, length);
6789  Node* branch0 =
6790      graph()->NewNode(common()->Branch(BranchHint::kNone), check0, control);
6791
6792  Node* etrue0 = effect;
6793  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
6794  Node* done_true;
6795  Node* vtrue0;
6796  {
6797    done_true = jsgraph()->FalseConstant();
6798    vtrue0 = etrue0 = graph()->NewNode(simplified()->StringFromCodePointAt(),
6799                                       string, index, etrue0, if_true0);
6800
6801    // Update iterator.[[NextIndex]]
6802    Node* char_length = graph()->NewNode(simplified()->StringLength(), vtrue0);
6803    index = graph()->NewNode(simplified()->NumberAdd(), index, char_length);
6804    etrue0 = graph()->NewNode(
6805        simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()),
6806        receiver, index, etrue0, if_true0);
6807  }
6808
6809  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
6810  Node* done_false;
6811  Node* vfalse0;
6812  {
6813    vfalse0 = jsgraph()->UndefinedConstant();
6814    done_false = jsgraph()->TrueConstant();
6815  }
6816
6817  control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
6818  effect = graph()->NewNode(common()->EffectPhi(2), etrue0, effect, control);
6819  Node* value =
6820      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), vtrue0,
6821                       vfalse0, control);
6822  Node* done =
6823      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
6824                       done_true, done_false, control);
6825
6826  value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
6827                                    value, done, context, effect);
6828
6829  ReplaceWithValue(node, value, effect, control);
6830  return Replace(value);
6831}
6832
6833// ES #sec-string.prototype.concat
6834Reduction JSCallReducer::ReduceStringPrototypeConcat(Node* node) {
6835  JSCallNode n(node);
6836  CallParameters const& p = n.Parameters();
6837  const int parameter_count = n.ArgumentCount();
6838  if (parameter_count > 1) return NoChange();
6839  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6840    return NoChange();
6841  }
6842
6843  Effect effect = n.effect();
6844  Control control = n.control();
6845  Node* receiver = effect = graph()->NewNode(
6846      simplified()->CheckString(p.feedback()), n.receiver(), effect, control);
6847
6848  if (parameter_count == 0) {
6849    ReplaceWithValue(node, receiver, effect, control);
6850    return Replace(receiver);
6851  }
6852
6853  Node* argument = effect = graph()->NewNode(
6854      simplified()->CheckString(p.feedback()), n.Argument(0), effect, control);
6855  Node* receiver_length =
6856      graph()->NewNode(simplified()->StringLength(), receiver);
6857  Node* argument_length =
6858      graph()->NewNode(simplified()->StringLength(), argument);
6859  Node* length = graph()->NewNode(simplified()->NumberAdd(), receiver_length,
6860                                  argument_length);
6861  length = effect = graph()->NewNode(
6862      simplified()->CheckBounds(p.feedback()), length,
6863      jsgraph()->Constant(String::kMaxLength + 1), effect, control);
6864
6865  Node* value = graph()->NewNode(simplified()->StringConcat(), length, receiver,
6866                                 argument);
6867
6868  ReplaceWithValue(node, value, effect, control);
6869  return Replace(value);
6870}
6871
6872Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
6873  PromiseBuiltinReducerAssembler a(this, node, broker());
6874
6875  // We only inline when we have the executor.
6876  if (a.ConstructArity() < 1) return NoChange();
6877  // Only handle builtins Promises, not subclasses.
6878  if (a.TargetInput() != a.NewTargetInput()) return NoChange();
6879  if (!dependencies()->DependOnPromiseHookProtector()) return NoChange();
6880
6881  TNode<Object> subgraph = a.ReducePromiseConstructor(native_context());
6882  return ReplaceWithSubgraph(&a, subgraph);
6883}
6884
6885bool JSCallReducer::DoPromiseChecks(MapInference* inference) {
6886  if (!inference->HaveMaps()) return false;
6887  ZoneVector<MapRef> const& receiver_maps = inference->GetMaps();
6888
6889  // Check whether all {receiver_maps} are JSPromise maps and
6890  // have the initial Promise.prototype as their [[Prototype]].
6891  for (const MapRef& receiver_map : receiver_maps) {
6892    if (!receiver_map.IsJSPromiseMap()) return false;
6893    HeapObjectRef prototype = receiver_map.prototype();
6894    if (!prototype.equals(native_context().promise_prototype())) {
6895      return false;
6896    }
6897  }
6898
6899  return true;
6900}
6901
6902// ES section #sec-promise.prototype.catch
6903Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
6904  JSCallNode n(node);
6905  CallParameters const& p = n.Parameters();
6906  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6907    return NoChange();
6908  }
6909  int arity = p.arity_without_implicit_args();
6910  Node* receiver = n.receiver();
6911  Effect effect = n.effect();
6912  Control control = n.control();
6913
6914  MapInference inference(broker(), receiver, effect);
6915  if (!DoPromiseChecks(&inference)) return inference.NoChange();
6916
6917  if (!dependencies()->DependOnPromiseThenProtector()) {
6918    return inference.NoChange();
6919  }
6920  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
6921                                      control, p.feedback());
6922
6923  // Massage the {node} to call "then" instead by first removing all inputs
6924  // following the onRejected parameter, and then filling up the parameters
6925  // to two inputs from the left with undefined.
6926  Node* target = jsgraph()->Constant(native_context().promise_then());
6927  NodeProperties::ReplaceValueInput(node, target, 0);
6928  NodeProperties::ReplaceEffectInput(node, effect);
6929  for (; arity > 1; --arity) node->RemoveInput(3);
6930  for (; arity < 2; ++arity) {
6931    node->InsertInput(graph()->zone(), 2, jsgraph()->UndefinedConstant());
6932  }
6933  NodeProperties::ChangeOp(
6934      node, javascript()->Call(
6935                JSCallNode::ArityForArgc(arity), p.frequency(), p.feedback(),
6936                ConvertReceiverMode::kNotNullOrUndefined, p.speculation_mode(),
6937                CallFeedbackRelation::kUnrelated));
6938  return Changed(node).FollowedBy(ReducePromisePrototypeThen(node));
6939}
6940
6941Node* JSCallReducer::CreateClosureFromBuiltinSharedFunctionInfo(
6942    SharedFunctionInfoRef shared, Node* context, Node* effect, Node* control) {
6943  DCHECK(shared.HasBuiltinId());
6944  Handle<FeedbackCell> feedback_cell =
6945      isolate()->factory()->many_closures_cell();
6946  Callable const callable =
6947      Builtins::CallableFor(isolate(), shared.builtin_id());
6948  CodeTRef code = MakeRef(broker(), *callable.code());
6949  return graph()->NewNode(javascript()->CreateClosure(shared, code),
6950                          jsgraph()->HeapConstant(feedback_cell), context,
6951                          effect, control);
6952}
6953
6954// ES section #sec-promise.prototype.finally
6955Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
6956  JSCallNode n(node);
6957  CallParameters const& p = n.Parameters();
6958  int arity = p.arity_without_implicit_args();
6959  Node* receiver = n.receiver();
6960  Node* on_finally = n.ArgumentOrUndefined(0, jsgraph());
6961  Effect effect = n.effect();
6962  Control control = n.control();
6963  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
6964    return NoChange();
6965  }
6966
6967  MapInference inference(broker(), receiver, effect);
6968  if (!DoPromiseChecks(&inference)) return inference.NoChange();
6969  ZoneVector<MapRef> const& receiver_maps = inference.GetMaps();
6970
6971  if (!dependencies()->DependOnPromiseHookProtector()) {
6972    return inference.NoChange();
6973  }
6974  if (!dependencies()->DependOnPromiseThenProtector()) {
6975    return inference.NoChange();
6976  }
6977  if (!dependencies()->DependOnPromiseSpeciesProtector()) {
6978    return inference.NoChange();
6979  }
6980  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
6981                                      control, p.feedback());
6982
6983  // Check if {on_finally} is callable, and if so wrap it into appropriate
6984  // closures that perform the finalization.
6985  Node* check = graph()->NewNode(simplified()->ObjectIsCallable(), on_finally);
6986  Node* branch =
6987      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
6988
6989  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
6990  Node* etrue = effect;
6991  Node* catch_true;
6992  Node* then_true;
6993  {
6994    Node* context = jsgraph()->Constant(native_context());
6995    Node* constructor =
6996        jsgraph()->Constant(native_context().promise_function());
6997
6998    // Allocate shared context for the closures below.
6999    context = etrue =
7000        graph()->NewNode(javascript()->CreateFunctionContext(
7001                             native_context().scope_info(),
7002                             PromiseBuiltins::kPromiseFinallyContextLength -
7003                                 Context::MIN_CONTEXT_SLOTS,
7004                             FUNCTION_SCOPE),
7005                         context, etrue, if_true);
7006    etrue = graph()->NewNode(
7007        simplified()->StoreField(
7008            AccessBuilder::ForContextSlot(PromiseBuiltins::kOnFinallySlot)),
7009        context, on_finally, etrue, if_true);
7010    etrue = graph()->NewNode(
7011        simplified()->StoreField(
7012            AccessBuilder::ForContextSlot(PromiseBuiltins::kConstructorSlot)),
7013        context, constructor, etrue, if_true);
7014
7015    // Allocate the closure for the reject case.
7016    SharedFunctionInfoRef promise_catch_finally =
7017        MakeRef(broker(), factory()->promise_catch_finally_shared_fun());
7018    catch_true = etrue = CreateClosureFromBuiltinSharedFunctionInfo(
7019        promise_catch_finally, context, etrue, if_true);
7020
7021    // Allocate the closure for the fulfill case.
7022    SharedFunctionInfoRef promise_then_finally =
7023        MakeRef(broker(), factory()->promise_then_finally_shared_fun());
7024    then_true = etrue = CreateClosureFromBuiltinSharedFunctionInfo(
7025        promise_then_finally, context, etrue, if_true);
7026  }
7027
7028  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
7029  Node* efalse = effect;
7030  Node* catch_false = on_finally;
7031  Node* then_false = on_finally;
7032
7033  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
7034  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
7035  Node* catch_finally =
7036      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
7037                       catch_true, catch_false, control);
7038  Node* then_finally =
7039      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
7040                       then_true, then_false, control);
7041
7042  // At this point we definitely know that {receiver} has one of the
7043  // {receiver_maps}, so insert a MapGuard as a hint for the lowering
7044  // of the call to "then" below.
7045  {
7046    ZoneHandleSet<Map> maps;
7047    for (const MapRef& map : receiver_maps) {
7048      maps.insert(map.object(), graph()->zone());
7049    }
7050    effect = graph()->NewNode(simplified()->MapGuard(maps), receiver, effect,
7051                              control);
7052  }
7053
7054  // Massage the {node} to call "then" instead by first removing all inputs
7055  // following the onFinally parameter, and then replacing the only parameter
7056  // input with the {on_finally} value.
7057  Node* target = jsgraph()->Constant(native_context().promise_then());
7058  NodeProperties::ReplaceValueInput(node, target, n.TargetIndex());
7059  NodeProperties::ReplaceEffectInput(node, effect);
7060  NodeProperties::ReplaceControlInput(node, control);
7061  for (; arity > 2; --arity) node->RemoveInput(2);
7062  for (; arity < 2; ++arity) {
7063    node->InsertInput(graph()->zone(), 2, then_finally);
7064  }
7065  node->ReplaceInput(2, then_finally);
7066  node->ReplaceInput(3, catch_finally);
7067  NodeProperties::ChangeOp(
7068      node, javascript()->Call(
7069                JSCallNode::ArityForArgc(arity), p.frequency(), p.feedback(),
7070                ConvertReceiverMode::kNotNullOrUndefined, p.speculation_mode(),
7071                CallFeedbackRelation::kUnrelated));
7072  return Changed(node).FollowedBy(ReducePromisePrototypeThen(node));
7073}
7074
7075Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
7076  JSCallNode n(node);
7077  CallParameters const& p = n.Parameters();
7078  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
7079    return NoChange();
7080  }
7081
7082  Node* receiver = n.receiver();
7083  Node* on_fulfilled = n.ArgumentOrUndefined(0, jsgraph());
7084  Node* on_rejected = n.ArgumentOrUndefined(1, jsgraph());
7085  Node* context = n.context();
7086  Effect effect = n.effect();
7087  Control control = n.control();
7088  FrameState frame_state = n.frame_state();
7089
7090  MapInference inference(broker(), receiver, effect);
7091  if (!DoPromiseChecks(&inference)) return inference.NoChange();
7092
7093  if (!dependencies()->DependOnPromiseHookProtector()) {
7094    return inference.NoChange();
7095  }
7096  if (!dependencies()->DependOnPromiseSpeciesProtector()) {
7097    return inference.NoChange();
7098  }
7099  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
7100                                      control, p.feedback());
7101
7102  // Check that {on_fulfilled} is callable.
7103  on_fulfilled = graph()->NewNode(
7104      common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
7105      graph()->NewNode(simplified()->ObjectIsCallable(), on_fulfilled),
7106      on_fulfilled, jsgraph()->UndefinedConstant());
7107
7108  // Check that {on_rejected} is callable.
7109  on_rejected = graph()->NewNode(
7110      common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
7111      graph()->NewNode(simplified()->ObjectIsCallable(), on_rejected),
7112      on_rejected, jsgraph()->UndefinedConstant());
7113
7114  // Create the resulting JSPromise.
7115  Node* promise = effect =
7116      graph()->NewNode(javascript()->CreatePromise(), context, effect);
7117
7118  // Chain {result} onto {receiver}.
7119  promise = effect = graph()->NewNode(
7120      javascript()->PerformPromiseThen(), receiver, on_fulfilled, on_rejected,
7121      promise, context, frame_state, effect, control);
7122
7123  // At this point we know that {promise} is going to have the
7124  // initial Promise map, since even if {PerformPromiseThen}
7125  // above called into the host rejection tracker, the {promise}
7126  // doesn't escape to user JavaScript. So bake this information
7127  // into the graph such that subsequent passes can use the
7128  // information for further optimizations.
7129  MapRef promise_map =
7130      native_context().promise_function().initial_map(dependencies());
7131  effect = graph()->NewNode(
7132      simplified()->MapGuard(ZoneHandleSet<Map>(promise_map.object())), promise,
7133      effect, control);
7134
7135  ReplaceWithValue(node, promise, effect, control);
7136  return Replace(promise);
7137}
7138
7139// ES section #sec-promise.resolve
7140Reduction JSCallReducer::ReducePromiseResolveTrampoline(Node* node) {
7141  JSCallNode n(node);
7142  Node* receiver = n.receiver();
7143  Node* value = n.ArgumentOrUndefined(0, jsgraph());
7144  Node* context = n.context();
7145  Effect effect = n.effect();
7146  Control control = n.control();
7147  FrameState frame_state = n.frame_state();
7148
7149  // Only reduce when the receiver is guaranteed to be a JSReceiver.
7150  MapInference inference(broker(), receiver, effect);
7151  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAreJSReceiver()) {
7152    return NoChange();
7153  }
7154
7155  // Morph the {node} into a JSPromiseResolve operation.
7156  node->ReplaceInput(0, receiver);
7157  node->ReplaceInput(1, value);
7158  node->ReplaceInput(2, context);
7159  node->ReplaceInput(3, frame_state);
7160  node->ReplaceInput(4, effect);
7161  node->ReplaceInput(5, control);
7162  node->TrimInputCount(6);
7163  NodeProperties::ChangeOp(node, javascript()->PromiseResolve());
7164  return Changed(node);
7165}
7166
7167// ES #sec-typedarray-constructors
7168Reduction JSCallReducer::ReduceTypedArrayConstructor(
7169    Node* node, const SharedFunctionInfoRef& shared) {
7170  JSConstructNode n(node);
7171  ConstructParameters const& p = n.Parameters();
7172  int arity = p.arity_without_implicit_args();
7173  Node* target = n.target();
7174  Node* arg0 = n.ArgumentOrUndefined(0, jsgraph());
7175  Node* arg1 = n.ArgumentOrUndefined(1, jsgraph());
7176  Node* arg2 = n.ArgumentOrUndefined(2, jsgraph());
7177  Node* new_target = n.new_target();
7178  Node* context = n.context();
7179  FrameState frame_state = n.frame_state();
7180  Effect effect = n.effect();
7181  Control control = n.control();
7182
7183  // Insert a construct stub frame into the chain of frame states. This will
7184  // reconstruct the proper frame when deoptimizing within the constructor.
7185  frame_state = CreateArtificialFrameState(
7186      node, frame_state, arity, BytecodeOffset::ConstructStubInvoke(),
7187      FrameStateType::kConstructStub, shared, context, common(), graph());
7188
7189  // This continuation just returns the newly created JSTypedArray. We
7190  // pass the_hole as the receiver, just like the builtin construct stub
7191  // does in this case.
7192  Node* const parameters[] = {jsgraph()->TheHoleConstant()};
7193  int const num_parameters = static_cast<int>(arraysize(parameters));
7194  frame_state = CreateJavaScriptBuiltinContinuationFrameState(
7195      jsgraph(), shared, Builtin::kGenericLazyDeoptContinuation, target,
7196      context, parameters, num_parameters, frame_state,
7197      ContinuationFrameStateMode::LAZY);
7198
7199  Node* result =
7200      graph()->NewNode(javascript()->CreateTypedArray(), target, new_target,
7201                       arg0, arg1, arg2, context, frame_state, effect, control);
7202  return Replace(result);
7203}
7204
7205// ES #sec-get-%typedarray%.prototype-@@tostringtag
7206Reduction JSCallReducer::ReduceTypedArrayPrototypeToStringTag(Node* node) {
7207  Node* receiver = NodeProperties::GetValueInput(node, 1);
7208  Node* effect = NodeProperties::GetEffectInput(node);
7209  Node* control = NodeProperties::GetControlInput(node);
7210
7211  NodeVector values(graph()->zone());
7212  NodeVector effects(graph()->zone());
7213  NodeVector controls(graph()->zone());
7214
7215  Node* smi_check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
7216  control = graph()->NewNode(common()->Branch(BranchHint::kFalse), smi_check,
7217                             control);
7218
7219  values.push_back(jsgraph()->UndefinedConstant());
7220  effects.push_back(effect);
7221  controls.push_back(graph()->NewNode(common()->IfTrue(), control));
7222
7223  control = graph()->NewNode(common()->IfFalse(), control);
7224  Node* receiver_map = effect =
7225      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
7226                       receiver, effect, control);
7227  Node* receiver_bit_field2 = effect = graph()->NewNode(
7228      simplified()->LoadField(AccessBuilder::ForMapBitField2()), receiver_map,
7229      effect, control);
7230  Node* receiver_elements_kind = graph()->NewNode(
7231      simplified()->NumberShiftRightLogical(),
7232      graph()->NewNode(
7233          simplified()->NumberBitwiseAnd(), receiver_bit_field2,
7234          jsgraph()->Constant(Map::Bits2::ElementsKindBits::kMask)),
7235      jsgraph()->Constant(Map::Bits2::ElementsKindBits::kShift));
7236
7237  // Offset the elements kind by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
7238  // so that the branch cascade below is turned into a simple table
7239  // switch by the ControlFlowOptimizer later.
7240  receiver_elements_kind = graph()->NewNode(
7241      simplified()->NumberSubtract(), receiver_elements_kind,
7242      jsgraph()->Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
7243
7244#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)                      \
7245  do {                                                                 \
7246    Node* check = graph()->NewNode(                                    \
7247        simplified()->NumberEqual(), receiver_elements_kind,           \
7248        jsgraph()->Constant(TYPE##_ELEMENTS -                          \
7249                            FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));   \
7250    control = graph()->NewNode(common()->Branch(), check, control);    \
7251    values.push_back(jsgraph()->Constant(                              \
7252        broker()->GetTypedArrayStringTag(TYPE##_ELEMENTS)));           \
7253    effects.push_back(effect);                                         \
7254    controls.push_back(graph()->NewNode(common()->IfTrue(), control)); \
7255    control = graph()->NewNode(common()->IfFalse(), control);          \
7256  } while (false);
7257  TYPED_ARRAYS(TYPED_ARRAY_CASE)
7258#undef TYPED_ARRAY_CASE
7259
7260  values.push_back(jsgraph()->UndefinedConstant());
7261  effects.push_back(effect);
7262  controls.push_back(control);
7263
7264  int const count = static_cast<int>(controls.size());
7265  control = graph()->NewNode(common()->Merge(count), count, &controls.front());
7266  effects.push_back(control);
7267  effect =
7268      graph()->NewNode(common()->EffectPhi(count), count + 1, &effects.front());
7269  values.push_back(control);
7270  Node* value =
7271      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
7272                       count + 1, &values.front());
7273  ReplaceWithValue(node, value, effect, control);
7274  return Replace(value);
7275}
7276
7277// ES #sec-number.isfinite
7278Reduction JSCallReducer::ReduceNumberIsFinite(Node* node) {
7279  JSCallNode n(node);
7280  if (n.ArgumentCount() < 1) {
7281    Node* value = jsgraph()->FalseConstant();
7282    ReplaceWithValue(node, value);
7283    return Replace(value);
7284  }
7285  Node* input = n.Argument(0);
7286  Node* value = graph()->NewNode(simplified()->ObjectIsFiniteNumber(), input);
7287  ReplaceWithValue(node, value);
7288  return Replace(value);
7289}
7290
7291// ES #sec-number.isfinite
7292Reduction JSCallReducer::ReduceNumberIsInteger(Node* node) {
7293  JSCallNode n(node);
7294  if (n.ArgumentCount() < 1) {
7295    Node* value = jsgraph()->FalseConstant();
7296    ReplaceWithValue(node, value);
7297    return Replace(value);
7298  }
7299  Node* input = n.Argument(0);
7300  Node* value = graph()->NewNode(simplified()->ObjectIsInteger(), input);
7301  ReplaceWithValue(node, value);
7302  return Replace(value);
7303}
7304
7305// ES #sec-number.issafeinteger
7306Reduction JSCallReducer::ReduceNumberIsSafeInteger(Node* node) {
7307  JSCallNode n(node);
7308  if (n.ArgumentCount() < 1) {
7309    Node* value = jsgraph()->FalseConstant();
7310    ReplaceWithValue(node, value);
7311    return Replace(value);
7312  }
7313  Node* input = n.Argument(0);
7314  Node* value = graph()->NewNode(simplified()->ObjectIsSafeInteger(), input);
7315  ReplaceWithValue(node, value);
7316  return Replace(value);
7317}
7318
7319// ES #sec-number.isnan
7320Reduction JSCallReducer::ReduceNumberIsNaN(Node* node) {
7321  JSCallNode n(node);
7322  if (n.ArgumentCount() < 1) {
7323    Node* value = jsgraph()->FalseConstant();
7324    ReplaceWithValue(node, value);
7325    return Replace(value);
7326  }
7327  Node* input = n.Argument(0);
7328  Node* value = graph()->NewNode(simplified()->ObjectIsNaN(), input);
7329  ReplaceWithValue(node, value);
7330  return Replace(value);
7331}
7332
7333Reduction JSCallReducer::ReduceMapPrototypeGet(Node* node) {
7334  // We only optimize if we have target, receiver and key parameters.
7335  JSCallNode n(node);
7336  if (n.ArgumentCount() != 1) return NoChange();
7337  Node* receiver = NodeProperties::GetValueInput(node, 1);
7338  Effect effect{NodeProperties::GetEffectInput(node)};
7339  Control control{NodeProperties::GetControlInput(node)};
7340  Node* key = NodeProperties::GetValueInput(node, 2);
7341
7342  MapInference inference(broker(), receiver, effect);
7343  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(JS_MAP_TYPE)) {
7344    return NoChange();
7345  }
7346
7347  Node* table = effect = graph()->NewNode(
7348      simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
7349      effect, control);
7350
7351  Node* entry = effect = graph()->NewNode(
7352      simplified()->FindOrderedHashMapEntry(), table, key, effect, control);
7353
7354  Node* check = graph()->NewNode(simplified()->NumberEqual(), entry,
7355                                 jsgraph()->MinusOneConstant());
7356
7357  Node* branch = graph()->NewNode(common()->Branch(), check, control);
7358
7359  // Key not found.
7360  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
7361  Node* etrue = effect;
7362  Node* vtrue = jsgraph()->UndefinedConstant();
7363
7364  // Key found.
7365  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
7366  Node* efalse = effect;
7367  Node* vfalse = efalse = graph()->NewNode(
7368      simplified()->LoadElement(AccessBuilder::ForOrderedHashMapEntryValue()),
7369      table, entry, efalse, if_false);
7370
7371  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
7372  Node* value = graph()->NewNode(
7373      common()->Phi(MachineRepresentation::kTagged, 2), vtrue, vfalse, control);
7374  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
7375
7376  ReplaceWithValue(node, value, effect, control);
7377  return Replace(value);
7378}
7379
7380Reduction JSCallReducer::ReduceMapPrototypeHas(Node* node) {
7381  // We only optimize if we have target, receiver and key parameters.
7382  JSCallNode n(node);
7383  if (n.ArgumentCount() != 1) return NoChange();
7384  Node* receiver = NodeProperties::GetValueInput(node, 1);
7385  Effect effect{NodeProperties::GetEffectInput(node)};
7386  Control control{NodeProperties::GetControlInput(node)};
7387  Node* key = NodeProperties::GetValueInput(node, 2);
7388
7389  MapInference inference(broker(), receiver, effect);
7390  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(JS_MAP_TYPE)) {
7391    return NoChange();
7392  }
7393
7394  Node* table = effect = graph()->NewNode(
7395      simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
7396      effect, control);
7397
7398  Node* index = effect = graph()->NewNode(
7399      simplified()->FindOrderedHashMapEntry(), table, key, effect, control);
7400
7401  Node* value = graph()->NewNode(simplified()->NumberEqual(), index,
7402                                 jsgraph()->MinusOneConstant());
7403  value = graph()->NewNode(simplified()->BooleanNot(), value);
7404
7405  ReplaceWithValue(node, value, effect, control);
7406  return Replace(value);
7407}
7408
7409namespace {
7410
7411InstanceType InstanceTypeForCollectionKind(CollectionKind kind) {
7412  switch (kind) {
7413    case CollectionKind::kMap:
7414      return JS_MAP_TYPE;
7415    case CollectionKind::kSet:
7416      return JS_SET_TYPE;
7417  }
7418  UNREACHABLE();
7419}
7420
7421}  // namespace
7422
7423Reduction JSCallReducer::ReduceCollectionIteration(
7424    Node* node, CollectionKind collection_kind, IterationKind iteration_kind) {
7425  DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
7426  Node* receiver = NodeProperties::GetValueInput(node, 1);
7427  Node* context = NodeProperties::GetContextInput(node);
7428  Effect effect{NodeProperties::GetEffectInput(node)};
7429  Control control{NodeProperties::GetControlInput(node)};
7430
7431  InstanceType type = InstanceTypeForCollectionKind(collection_kind);
7432  MapInference inference(broker(), receiver, effect);
7433  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(type)) {
7434    return NoChange();
7435  }
7436
7437  Node* js_create_iterator = effect = graph()->NewNode(
7438      javascript()->CreateCollectionIterator(collection_kind, iteration_kind),
7439      receiver, context, effect, control);
7440  ReplaceWithValue(node, js_create_iterator, effect);
7441  return Replace(js_create_iterator);
7442}
7443
7444Reduction JSCallReducer::ReduceCollectionPrototypeSize(
7445    Node* node, CollectionKind collection_kind) {
7446  DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
7447  Node* receiver = NodeProperties::GetValueInput(node, 1);
7448  Effect effect{NodeProperties::GetEffectInput(node)};
7449  Control control{NodeProperties::GetControlInput(node)};
7450
7451  InstanceType type = InstanceTypeForCollectionKind(collection_kind);
7452  MapInference inference(broker(), receiver, effect);
7453  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(type)) {
7454    return NoChange();
7455  }
7456
7457  Node* table = effect = graph()->NewNode(
7458      simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
7459      effect, control);
7460  Node* value = effect = graph()->NewNode(
7461      simplified()->LoadField(
7462          AccessBuilder::ForOrderedHashMapOrSetNumberOfElements()),
7463      table, effect, control);
7464  ReplaceWithValue(node, value, effect, control);
7465  return Replace(value);
7466}
7467
7468Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
7469    Node* node, int entry_size, Handle<HeapObject> empty_collection,
7470    InstanceType collection_iterator_instance_type_first,
7471    InstanceType collection_iterator_instance_type_last) {
7472  JSCallNode n(node);
7473  CallParameters const& p = n.Parameters();
7474  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
7475    return NoChange();
7476  }
7477
7478  Node* receiver = n.receiver();
7479  Node* context = n.context();
7480  Effect effect = n.effect();
7481  Control control = n.control();
7482
7483  // A word of warning to begin with: This whole method might look a bit
7484  // strange at times, but that's mostly because it was carefully handcrafted
7485  // to allow for full escape analysis and scalar replacement of both the
7486  // collection iterator object and the iterator results, including the
7487  // key-value arrays in case of Set/Map entry iteration.
7488  //
7489  // TODO(turbofan): Currently the escape analysis (and the store-load
7490  // forwarding) is unable to eliminate the allocations for the key-value
7491  // arrays in case of Set/Map entry iteration, and we should investigate
7492  // how to update the escape analysis / arrange the graph in a way that
7493  // this becomes possible.
7494
7495  InstanceType receiver_instance_type;
7496  {
7497    MapInference inference(broker(), receiver, effect);
7498    if (!inference.HaveMaps()) return NoChange();
7499    ZoneVector<MapRef> const& receiver_maps = inference.GetMaps();
7500    receiver_instance_type = receiver_maps[0].instance_type();
7501    for (size_t i = 1; i < receiver_maps.size(); ++i) {
7502      if (receiver_maps[i].instance_type() != receiver_instance_type) {
7503        return inference.NoChange();
7504      }
7505    }
7506    if (receiver_instance_type < collection_iterator_instance_type_first ||
7507        receiver_instance_type > collection_iterator_instance_type_last) {
7508      return inference.NoChange();
7509    }
7510    inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
7511                                        control, p.feedback());
7512  }
7513
7514  // Transition the JSCollectionIterator {receiver} if necessary
7515  // (i.e. there were certain mutations while we're iterating).
7516  {
7517    Node* done_loop;
7518    Node* done_eloop;
7519    Node* loop = control =
7520        graph()->NewNode(common()->Loop(2), control, control);
7521    Node* eloop = effect =
7522        graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
7523    Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
7524    NodeProperties::MergeControlToEnd(graph(), common(), terminate);
7525
7526    // Check if reached the final table of the {receiver}.
7527    Node* table = effect = graph()->NewNode(
7528        simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorTable()),
7529        receiver, effect, control);
7530    Node* next_table = effect =
7531        graph()->NewNode(simplified()->LoadField(
7532                             AccessBuilder::ForOrderedHashMapOrSetNextTable()),
7533                         table, effect, control);
7534    Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), next_table);
7535    control =
7536        graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
7537
7538    // Abort the {loop} when we reach the final table.
7539    done_loop = graph()->NewNode(common()->IfTrue(), control);
7540    done_eloop = effect;
7541
7542    // Migrate to the {next_table} otherwise.
7543    control = graph()->NewNode(common()->IfFalse(), control);
7544
7545    // Self-heal the {receiver}s index.
7546    Node* index = effect = graph()->NewNode(
7547        simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorIndex()),
7548        receiver, effect, control);
7549    Callable const callable =
7550        Builtins::CallableFor(isolate(), Builtin::kOrderedHashTableHealIndex);
7551    auto call_descriptor = Linkage::GetStubCallDescriptor(
7552        graph()->zone(), callable.descriptor(),
7553        callable.descriptor().GetStackParameterCount(),
7554        CallDescriptor::kNoFlags, Operator::kEliminatable);
7555    index = effect =
7556        graph()->NewNode(common()->Call(call_descriptor),
7557                         jsgraph()->HeapConstant(callable.code()), table, index,
7558                         jsgraph()->NoContextConstant(), effect);
7559
7560    index = effect = graph()->NewNode(
7561        common()->TypeGuard(TypeCache::Get()->kFixedArrayLengthType), index,
7562        effect, control);
7563
7564    // Update the {index} and {table} on the {receiver}.
7565    effect = graph()->NewNode(
7566        simplified()->StoreField(AccessBuilder::ForJSCollectionIteratorIndex()),
7567        receiver, index, effect, control);
7568    effect = graph()->NewNode(
7569        simplified()->StoreField(AccessBuilder::ForJSCollectionIteratorTable()),
7570        receiver, next_table, effect, control);
7571
7572    // Tie the knot.
7573    loop->ReplaceInput(1, control);
7574    eloop->ReplaceInput(1, effect);
7575
7576    control = done_loop;
7577    effect = done_eloop;
7578  }
7579
7580  // Get current index and table from the JSCollectionIterator {receiver}.
7581  Node* index = effect = graph()->NewNode(
7582      simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorIndex()),
7583      receiver, effect, control);
7584  Node* table = effect = graph()->NewNode(
7585      simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorTable()),
7586      receiver, effect, control);
7587
7588  // Create the {JSIteratorResult} first to ensure that we always have
7589  // a dominating Allocate node for the allocation folding phase.
7590  Node* iterator_result = effect = graph()->NewNode(
7591      javascript()->CreateIterResultObject(), jsgraph()->UndefinedConstant(),
7592      jsgraph()->TrueConstant(), context, effect);
7593
7594  // Look for the next non-holey key, starting from {index} in the {table}.
7595  Node* controls[2];
7596  Node* effects[3];
7597  {
7598    // Compute the currently used capacity.
7599    Node* number_of_buckets = effect = graph()->NewNode(
7600        simplified()->LoadField(
7601            AccessBuilder::ForOrderedHashMapOrSetNumberOfBuckets()),
7602        table, effect, control);
7603    Node* number_of_elements = effect = graph()->NewNode(
7604        simplified()->LoadField(
7605            AccessBuilder::ForOrderedHashMapOrSetNumberOfElements()),
7606        table, effect, control);
7607    Node* number_of_deleted_elements = effect = graph()->NewNode(
7608        simplified()->LoadField(
7609            AccessBuilder::ForOrderedHashMapOrSetNumberOfDeletedElements()),
7610        table, effect, control);
7611    Node* used_capacity =
7612        graph()->NewNode(simplified()->NumberAdd(), number_of_elements,
7613                         number_of_deleted_elements);
7614
7615    // Skip holes and update the {index}.
7616    Node* loop = graph()->NewNode(common()->Loop(2), control, control);
7617    Node* eloop =
7618        graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
7619    Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
7620    NodeProperties::MergeControlToEnd(graph(), common(), terminate);
7621    Node* iloop = graph()->NewNode(
7622        common()->Phi(MachineRepresentation::kTagged, 2), index, index, loop);
7623
7624    index = effect = graph()->NewNode(
7625        common()->TypeGuard(TypeCache::Get()->kFixedArrayLengthType), iloop,
7626        eloop, control);
7627    {
7628      Node* check0 = graph()->NewNode(simplified()->NumberLessThan(), index,
7629                                      used_capacity);
7630      Node* branch0 =
7631          graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, loop);
7632
7633      Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
7634      Node* efalse0 = effect;
7635      {
7636        // Mark the {receiver} as exhausted.
7637        efalse0 = graph()->NewNode(
7638            simplified()->StoreField(
7639                AccessBuilder::ForJSCollectionIteratorTable()),
7640            receiver, jsgraph()->HeapConstant(empty_collection), efalse0,
7641            if_false0);
7642
7643        controls[0] = if_false0;
7644        effects[0] = efalse0;
7645      }
7646
7647      Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
7648      Node* etrue0 = effect;
7649      {
7650        // Load the key of the entry.
7651        STATIC_ASSERT(OrderedHashMap::HashTableStartIndex() ==
7652                      OrderedHashSet::HashTableStartIndex());
7653        Node* entry_start_position = graph()->NewNode(
7654            simplified()->NumberAdd(),
7655            graph()->NewNode(
7656                simplified()->NumberAdd(),
7657                graph()->NewNode(simplified()->NumberMultiply(), index,
7658                                 jsgraph()->Constant(entry_size)),
7659                number_of_buckets),
7660            jsgraph()->Constant(OrderedHashMap::HashTableStartIndex()));
7661        Node* entry_key = etrue0 = graph()->NewNode(
7662            simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
7663            table, entry_start_position, etrue0, if_true0);
7664
7665        // Advance the index.
7666        index = graph()->NewNode(simplified()->NumberAdd(), index,
7667                                 jsgraph()->OneConstant());
7668
7669        Node* check1 =
7670            graph()->NewNode(simplified()->ReferenceEqual(), entry_key,
7671                             jsgraph()->TheHoleConstant());
7672        Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
7673                                         check1, if_true0);
7674
7675        {
7676          // Abort loop with resulting value.
7677          control = graph()->NewNode(common()->IfFalse(), branch1);
7678          effect = etrue0;
7679          Node* value = effect =
7680              graph()->NewNode(common()->TypeGuard(Type::NonInternal()),
7681                               entry_key, effect, control);
7682          Node* done = jsgraph()->FalseConstant();
7683
7684          // Advance the index on the {receiver}.
7685          effect = graph()->NewNode(
7686              simplified()->StoreField(
7687                  AccessBuilder::ForJSCollectionIteratorIndex()),
7688              receiver, index, effect, control);
7689
7690          // The actual {value} depends on the {receiver} iteration type.
7691          switch (receiver_instance_type) {
7692            case JS_MAP_KEY_ITERATOR_TYPE:
7693            case JS_SET_VALUE_ITERATOR_TYPE:
7694              break;
7695
7696            case JS_SET_KEY_VALUE_ITERATOR_TYPE:
7697              value = effect =
7698                  graph()->NewNode(javascript()->CreateKeyValueArray(), value,
7699                                   value, context, effect);
7700              break;
7701
7702            case JS_MAP_VALUE_ITERATOR_TYPE:
7703              value = effect = graph()->NewNode(
7704                  simplified()->LoadElement(
7705                      AccessBuilder::ForFixedArrayElement()),
7706                  table,
7707                  graph()->NewNode(
7708                      simplified()->NumberAdd(), entry_start_position,
7709                      jsgraph()->Constant(OrderedHashMap::kValueOffset)),
7710                  effect, control);
7711              break;
7712
7713            case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
7714              value = effect = graph()->NewNode(
7715                  simplified()->LoadElement(
7716                      AccessBuilder::ForFixedArrayElement()),
7717                  table,
7718                  graph()->NewNode(
7719                      simplified()->NumberAdd(), entry_start_position,
7720                      jsgraph()->Constant(OrderedHashMap::kValueOffset)),
7721                  effect, control);
7722              value = effect =
7723                  graph()->NewNode(javascript()->CreateKeyValueArray(),
7724                                   entry_key, value, context, effect);
7725              break;
7726
7727            default:
7728              UNREACHABLE();
7729          }
7730
7731          // Store final {value} and {done} into the {iterator_result}.
7732          effect =
7733              graph()->NewNode(simplified()->StoreField(
7734                                   AccessBuilder::ForJSIteratorResultValue()),
7735                               iterator_result, value, effect, control);
7736          effect =
7737              graph()->NewNode(simplified()->StoreField(
7738                                   AccessBuilder::ForJSIteratorResultDone()),
7739                               iterator_result, done, effect, control);
7740
7741          controls[1] = control;
7742          effects[1] = effect;
7743        }
7744
7745        // Continue with next loop index.
7746        loop->ReplaceInput(1, graph()->NewNode(common()->IfTrue(), branch1));
7747        eloop->ReplaceInput(1, etrue0);
7748        iloop->ReplaceInput(1, index);
7749      }
7750    }
7751
7752    control = effects[2] = graph()->NewNode(common()->Merge(2), 2, controls);
7753    effect = graph()->NewNode(common()->EffectPhi(2), 3, effects);
7754  }
7755
7756  // Yield the final {iterator_result}.
7757  ReplaceWithValue(node, iterator_result, effect, control);
7758  return Replace(iterator_result);
7759}
7760
7761Reduction JSCallReducer::ReduceArrayBufferIsView(Node* node) {
7762  JSCallNode n(node);
7763  Node* value = n.ArgumentOrUndefined(0, jsgraph());
7764  RelaxEffectsAndControls(node);
7765  node->ReplaceInput(0, value);
7766  node->TrimInputCount(1);
7767  NodeProperties::ChangeOp(node, simplified()->ObjectIsArrayBufferView());
7768  return Changed(node);
7769}
7770
7771Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
7772    Node* node, InstanceType instance_type, FieldAccess const& access) {
7773  Node* receiver = NodeProperties::GetValueInput(node, 1);
7774  Effect effect{NodeProperties::GetEffectInput(node)};
7775  Control control{NodeProperties::GetControlInput(node)};
7776
7777  MapInference inference(broker(), receiver, effect);
7778  if (!inference.HaveMaps() ||
7779      !inference.AllOfInstanceTypesAre(instance_type)) {
7780    return NoChange();
7781  }
7782
7783  // Load the {receiver}s field.
7784  Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
7785                                          receiver, effect, control);
7786
7787  // See if we can skip the detaching check.
7788  if (!dependencies()->DependOnArrayBufferDetachingProtector()) {
7789    // Check whether {receiver}s JSArrayBuffer was detached.
7790    Node* buffer = effect = graph()->NewNode(
7791        simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
7792        receiver, effect, control);
7793    Node* buffer_bit_field = effect = graph()->NewNode(
7794        simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
7795        buffer, effect, control);
7796    Node* check = graph()->NewNode(
7797        simplified()->NumberEqual(),
7798        graph()->NewNode(
7799            simplified()->NumberBitwiseAnd(), buffer_bit_field,
7800            jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
7801        jsgraph()->ZeroConstant());
7802
7803    // TODO(turbofan): Ideally we would bail out here if the {receiver}s
7804    // JSArrayBuffer was detached, but there's no way to guard against
7805    // deoptimization loops right now, since the JSCall {node} is usually
7806    // created from a LOAD_IC inlining, and so there's no CALL_IC slot
7807    // from which we could use the speculation bit.
7808    value = graph()->NewNode(
7809        common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
7810        check, value, jsgraph()->ZeroConstant());
7811  }
7812
7813  ReplaceWithValue(node, value, effect, control);
7814  return Replace(value);
7815}
7816
7817namespace {
7818uint32_t ExternalArrayElementSize(const ExternalArrayType element_type) {
7819  switch (element_type) {
7820#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
7821  case kExternal##Type##Array:                    \
7822    DCHECK_LE(sizeof(ctype), 8);                  \
7823    return sizeof(ctype);
7824    TYPED_ARRAYS(TYPED_ARRAY_CASE)
7825    default:
7826      UNREACHABLE();
7827#undef TYPED_ARRAY_CASE
7828  }
7829}
7830}  // namespace
7831
7832Reduction JSCallReducer::ReduceDataViewAccess(Node* node, DataViewAccess access,
7833                                              ExternalArrayType element_type) {
7834  JSCallNode n(node);
7835  CallParameters const& p = n.Parameters();
7836  size_t const element_size = ExternalArrayElementSize(element_type);
7837  Effect effect = n.effect();
7838  Control control = n.control();
7839  Node* receiver = n.receiver();
7840  Node* offset = n.ArgumentOr(0, jsgraph()->ZeroConstant());
7841  Node* value = nullptr;
7842  if (access == DataViewAccess::kSet) {
7843    value = n.ArgumentOrUndefined(1, jsgraph());
7844  }
7845  const int endian_index = (access == DataViewAccess::kGet ? 1 : 2);
7846  Node* is_little_endian =
7847      n.ArgumentOr(endian_index, jsgraph()->FalseConstant());
7848
7849  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
7850    return NoChange();
7851  }
7852
7853  // Only do stuff if the {receiver} is really a DataView.
7854  MapInference inference(broker(), receiver, effect);
7855  if (!inference.HaveMaps() ||
7856      !inference.AllOfInstanceTypesAre(JS_DATA_VIEW_TYPE)) {
7857    return NoChange();
7858  }
7859
7860  // Check that the {offset} is within range for the {receiver}.
7861  HeapObjectMatcher m(receiver);
7862  if (m.HasResolvedValue() && m.Ref(broker()).IsJSDataView()) {
7863    // We only deal with DataViews here whose [[ByteLength]] is at least
7864    // {element_size}, as for all other DataViews it'll be out-of-bounds.
7865    JSDataViewRef dataview = m.Ref(broker()).AsJSDataView();
7866    size_t length = dataview.byte_length();
7867    if (length < element_size) return NoChange();
7868
7869    // Check that the {offset} is within range of the {length}.
7870    Node* byte_length = jsgraph()->Constant(length - (element_size - 1));
7871    offset = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
7872                                       offset, byte_length, effect, control);
7873  } else {
7874    // We only deal with DataViews here that have Smi [[ByteLength]]s.
7875    Node* byte_length = effect =
7876        graph()->NewNode(simplified()->LoadField(
7877                             AccessBuilder::ForJSArrayBufferViewByteLength()),
7878                         receiver, effect, control);
7879
7880    if (element_size > 1) {
7881      // For non-byte accesses we also need to check that the {offset}
7882      // plus the {element_size}-1 fits within the given {byte_length}.
7883      // So to keep this as a single check on the {offset}, we subtract
7884      // the {element_size}-1 from the {byte_length} here (clamped to
7885      // positive safe integer range), and perform a check against that
7886      // with the {offset} below.
7887      byte_length = graph()->NewNode(
7888          simplified()->NumberMax(), jsgraph()->ZeroConstant(),
7889          graph()->NewNode(simplified()->NumberSubtract(), byte_length,
7890                           jsgraph()->Constant(element_size - 1)));
7891    }
7892
7893    // Check that the {offset} is within range of the {byte_length}.
7894    offset = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
7895                                       offset, byte_length, effect, control);
7896  }
7897
7898  // Coerce {is_little_endian} to boolean.
7899  is_little_endian =
7900      graph()->NewNode(simplified()->ToBoolean(), is_little_endian);
7901
7902  // Coerce {value} to Number.
7903  if (access == DataViewAccess::kSet) {
7904    value = effect = graph()->NewNode(
7905        simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
7906                                          p.feedback()),
7907        value, effect, control);
7908  }
7909
7910  // We need to retain either the {receiver} itself or it's backing
7911  // JSArrayBuffer to make sure that the GC doesn't collect the raw
7912  // memory. We default to {receiver} here, and only use the buffer
7913  // if we anyways have to load it (to reduce register pressure).
7914  Node* buffer_or_receiver = receiver;
7915
7916  if (!dependencies()->DependOnArrayBufferDetachingProtector()) {
7917    // Get the underlying buffer and check that it has not been detached.
7918    Node* buffer = effect = graph()->NewNode(
7919        simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
7920        receiver, effect, control);
7921
7922    // Bail out if the {buffer} was detached.
7923    Node* buffer_bit_field = effect = graph()->NewNode(
7924        simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
7925        buffer, effect, control);
7926    Node* check = graph()->NewNode(
7927        simplified()->NumberEqual(),
7928        graph()->NewNode(
7929            simplified()->NumberBitwiseAnd(), buffer_bit_field,
7930            jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
7931        jsgraph()->ZeroConstant());
7932    effect = graph()->NewNode(
7933        simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached,
7934                              p.feedback()),
7935        check, effect, control);
7936
7937    // We can reduce register pressure by holding on to the {buffer}
7938    // now to retain the backing store memory.
7939    buffer_or_receiver = buffer;
7940  }
7941
7942  // Load the {receiver}s data pointer.
7943  Node* data_pointer = effect = graph()->NewNode(
7944      simplified()->LoadField(AccessBuilder::ForJSDataViewDataPointer()),
7945      receiver, effect, control);
7946
7947  switch (access) {
7948    case DataViewAccess::kGet:
7949      // Perform the load.
7950      value = effect = graph()->NewNode(
7951          simplified()->LoadDataViewElement(element_type), buffer_or_receiver,
7952          data_pointer, offset, is_little_endian, effect, control);
7953      break;
7954    case DataViewAccess::kSet:
7955      // Perform the store.
7956      effect = graph()->NewNode(
7957          simplified()->StoreDataViewElement(element_type), buffer_or_receiver,
7958          data_pointer, offset, value, is_little_endian, effect, control);
7959      value = jsgraph()->UndefinedConstant();
7960      break;
7961  }
7962
7963  ReplaceWithValue(node, value, effect, control);
7964  return Changed(value);
7965}
7966
7967// ES6 section 18.2.2 isFinite ( number )
7968Reduction JSCallReducer::ReduceGlobalIsFinite(Node* node) {
7969  JSCallNode n(node);
7970  CallParameters const& p = n.Parameters();
7971  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
7972    return NoChange();
7973  }
7974  if (n.ArgumentCount() < 1) {
7975    Node* value = jsgraph()->FalseConstant();
7976    ReplaceWithValue(node, value);
7977    return Replace(value);
7978  }
7979
7980  Effect effect = n.effect();
7981  Control control = n.control();
7982  Node* input = n.Argument(0);
7983
7984  input = effect =
7985      graph()->NewNode(simplified()->SpeculativeToNumber(
7986                           NumberOperationHint::kNumberOrOddball, p.feedback()),
7987                       input, effect, control);
7988  Node* value = graph()->NewNode(simplified()->NumberIsFinite(), input);
7989  ReplaceWithValue(node, value, effect);
7990  return Replace(value);
7991}
7992
7993// ES6 section 18.2.3 isNaN ( number )
7994Reduction JSCallReducer::ReduceGlobalIsNaN(Node* node) {
7995  JSCallNode n(node);
7996  CallParameters const& p = n.Parameters();
7997  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
7998    return NoChange();
7999  }
8000  if (n.ArgumentCount() < 1) {
8001    Node* value = jsgraph()->TrueConstant();
8002    ReplaceWithValue(node, value);
8003    return Replace(value);
8004  }
8005
8006  Effect effect = n.effect();
8007  Control control = n.control();
8008  Node* input = n.Argument(0);
8009
8010  input = effect =
8011      graph()->NewNode(simplified()->SpeculativeToNumber(
8012                           NumberOperationHint::kNumberOrOddball, p.feedback()),
8013                       input, effect, control);
8014  Node* value = graph()->NewNode(simplified()->NumberIsNaN(), input);
8015  ReplaceWithValue(node, value, effect);
8016  return Replace(value);
8017}
8018
8019// ES6 section 20.3.4.10 Date.prototype.getTime ( )
8020Reduction JSCallReducer::ReduceDatePrototypeGetTime(Node* node) {
8021  Node* receiver = NodeProperties::GetValueInput(node, 1);
8022  Effect effect{NodeProperties::GetEffectInput(node)};
8023  Control control{NodeProperties::GetControlInput(node)};
8024
8025  MapInference inference(broker(), receiver, effect);
8026  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(JS_DATE_TYPE)) {
8027    return NoChange();
8028  }
8029
8030  Node* value = effect =
8031      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForJSDateValue()),
8032                       receiver, effect, control);
8033  ReplaceWithValue(node, value, effect, control);
8034  return Replace(value);
8035}
8036
8037// ES6 section 20.3.3.1 Date.now ( )
8038Reduction JSCallReducer::ReduceDateNow(Node* node) {
8039  Node* effect = NodeProperties::GetEffectInput(node);
8040  Node* control = NodeProperties::GetControlInput(node);
8041  Node* value = effect =
8042      graph()->NewNode(simplified()->DateNow(), effect, control);
8043  ReplaceWithValue(node, value, effect, control);
8044  return Replace(value);
8045}
8046
8047// ES6 section 20.1.2.13 Number.parseInt ( string, radix )
8048Reduction JSCallReducer::ReduceNumberParseInt(Node* node) {
8049  JSCallNode n(node);
8050  if (n.ArgumentCount() < 1) {
8051    Node* value = jsgraph()->NaNConstant();
8052    ReplaceWithValue(node, value);
8053    return Replace(value);
8054  }
8055
8056  Effect effect = n.effect();
8057  Control control = n.control();
8058  Node* context = n.context();
8059  FrameState frame_state = n.frame_state();
8060  Node* object = n.Argument(0);
8061  Node* radix = n.ArgumentOrUndefined(1, jsgraph());
8062  node->ReplaceInput(0, object);
8063  node->ReplaceInput(1, radix);
8064  node->ReplaceInput(2, context);
8065  node->ReplaceInput(3, frame_state);
8066  node->ReplaceInput(4, effect);
8067  node->ReplaceInput(5, control);
8068  node->TrimInputCount(6);
8069  NodeProperties::ChangeOp(node, javascript()->ParseInt());
8070  return Changed(node);
8071}
8072
8073Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
8074  JSCallNode n(node);
8075  CallParameters const& p = n.Parameters();
8076  if (FLAG_force_slow_path) return NoChange();
8077  if (n.ArgumentCount() < 1) return NoChange();
8078
8079  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
8080    return NoChange();
8081  }
8082
8083  Effect effect = n.effect();
8084  Control control = n.control();
8085  Node* regexp = n.receiver();
8086
8087  // Only the initial JSRegExp map is valid here, since the following lastIndex
8088  // check as well as the lowered builtin call rely on a known location of the
8089  // lastIndex field.
8090  MapRef regexp_initial_map =
8091      native_context().regexp_function().initial_map(dependencies());
8092
8093  MapInference inference(broker(), regexp, effect);
8094  if (!inference.Is(regexp_initial_map)) return inference.NoChange();
8095  ZoneVector<MapRef> const& regexp_maps = inference.GetMaps();
8096
8097  ZoneVector<PropertyAccessInfo> access_infos(graph()->zone());
8098  AccessInfoFactory access_info_factory(broker(), dependencies(),
8099                                        graph()->zone());
8100
8101  for (const MapRef& map : regexp_maps) {
8102    access_infos.push_back(broker()->GetPropertyAccessInfo(
8103        map, MakeRef(broker(), isolate()->factory()->exec_string()),
8104        AccessMode::kLoad, dependencies()));
8105  }
8106
8107  PropertyAccessInfo ai_exec =
8108      access_info_factory.FinalizePropertyAccessInfosAsOne(access_infos,
8109                                                           AccessMode::kLoad);
8110  if (ai_exec.IsInvalid()) return inference.NoChange();
8111  if (!ai_exec.IsFastDataConstant()) return inference.NoChange();
8112
8113  // Do not reduce if the exec method is not on the prototype chain.
8114  base::Optional<JSObjectRef> holder = ai_exec.holder();
8115  if (!holder.has_value()) return inference.NoChange();
8116
8117  // Bail out if the exec method is not the original one.
8118  base::Optional<ObjectRef> constant = holder->GetOwnFastDataProperty(
8119      ai_exec.field_representation(), ai_exec.field_index(), dependencies());
8120  if (!constant.has_value() ||
8121      !constant->equals(native_context().regexp_exec_function())) {
8122    return inference.NoChange();
8123  }
8124
8125  // Add proper dependencies on the {regexp}s [[Prototype]]s.
8126  dependencies()->DependOnStablePrototypeChains(
8127      ai_exec.lookup_start_object_maps(), kStartAtPrototype, holder.value());
8128
8129  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
8130                                      control, p.feedback());
8131
8132  Node* context = n.context();
8133  FrameState frame_state = n.frame_state();
8134  Node* search = n.Argument(0);
8135  Node* search_string = effect = graph()->NewNode(
8136      simplified()->CheckString(p.feedback()), search, effect, control);
8137
8138  Node* lastIndex = effect = graph()->NewNode(
8139      simplified()->LoadField(AccessBuilder::ForJSRegExpLastIndex()), regexp,
8140      effect, control);
8141
8142  Node* lastIndexSmi = effect = graph()->NewNode(
8143      simplified()->CheckSmi(p.feedback()), lastIndex, effect, control);
8144
8145  Node* is_positive = graph()->NewNode(simplified()->NumberLessThanOrEqual(),
8146                                       jsgraph()->ZeroConstant(), lastIndexSmi);
8147
8148  effect = graph()->NewNode(
8149      simplified()->CheckIf(DeoptimizeReason::kNotASmi, p.feedback()),
8150      is_positive, effect, control);
8151
8152  node->ReplaceInput(0, regexp);
8153  node->ReplaceInput(1, search_string);
8154  node->ReplaceInput(2, context);
8155  node->ReplaceInput(3, frame_state);
8156  node->ReplaceInput(4, effect);
8157  node->ReplaceInput(5, control);
8158  node->TrimInputCount(6);
8159  NodeProperties::ChangeOp(node, javascript()->RegExpTest());
8160  return Changed(node);
8161}
8162
8163// ES section #sec-number-constructor
8164Reduction JSCallReducer::ReduceNumberConstructor(Node* node) {
8165  JSCallNode n(node);
8166  Node* target = n.target();
8167  Node* receiver = n.receiver();
8168  Node* value = n.ArgumentOr(0, jsgraph()->ZeroConstant());
8169  Node* context = n.context();
8170  FrameState frame_state = n.frame_state();
8171
8172  // Create the artificial frame state in the middle of the Number constructor.
8173  SharedFunctionInfoRef shared_info =
8174      native_context().number_function().shared();
8175  Node* stack_parameters[] = {receiver};
8176  int stack_parameter_count = arraysize(stack_parameters);
8177  Node* continuation_frame_state =
8178      CreateJavaScriptBuiltinContinuationFrameState(
8179          jsgraph(), shared_info, Builtin::kGenericLazyDeoptContinuation,
8180          target, context, stack_parameters, stack_parameter_count, frame_state,
8181          ContinuationFrameStateMode::LAZY);
8182
8183  // Convert the {value} to a Number.
8184  NodeProperties::ReplaceValueInputs(node, value);
8185  NodeProperties::ChangeOp(node, javascript()->ToNumberConvertBigInt());
8186  NodeProperties::ReplaceFrameStateInput(node, continuation_frame_state);
8187  return Changed(node);
8188}
8189
8190Reduction JSCallReducer::ReduceBigIntAsN(Node* node, Builtin builtin) {
8191  DCHECK(builtin == Builtin::kBigIntAsIntN ||
8192         builtin == Builtin::kBigIntAsUintN);
8193
8194  if (!jsgraph()->machine()->Is64()) return NoChange();
8195
8196  JSCallNode n(node);
8197  CallParameters const& p = n.Parameters();
8198  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
8199    return NoChange();
8200  }
8201  if (n.ArgumentCount() < 2) {
8202    return NoChange();
8203  }
8204
8205  Effect effect = n.effect();
8206  Control control = n.control();
8207  Node* bits = n.Argument(0);
8208  Node* value = n.Argument(1);
8209
8210  NumberMatcher matcher(bits);
8211  if (matcher.IsInteger() && matcher.IsInRange(0, 64)) {
8212    const int bits_value = static_cast<int>(matcher.ResolvedValue());
8213    value = effect = graph()->NewNode(
8214        (builtin == Builtin::kBigIntAsIntN
8215             ? simplified()->SpeculativeBigIntAsIntN(bits_value, p.feedback())
8216             : simplified()->SpeculativeBigIntAsUintN(bits_value,
8217                                                      p.feedback())),
8218        value, effect, control);
8219    ReplaceWithValue(node, value, effect);
8220    return Replace(value);
8221  }
8222
8223  return NoChange();
8224}
8225
8226CompilationDependencies* JSCallReducer::dependencies() const {
8227  return broker()->dependencies();
8228}
8229
8230Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
8231
8232Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
8233
8234Factory* JSCallReducer::factory() const { return isolate()->factory(); }
8235
8236NativeContextRef JSCallReducer::native_context() const {
8237  return broker()->target_native_context();
8238}
8239
8240CommonOperatorBuilder* JSCallReducer::common() const {
8241  return jsgraph()->common();
8242}
8243
8244JSOperatorBuilder* JSCallReducer::javascript() const {
8245  return jsgraph()->javascript();
8246}
8247
8248SimplifiedOperatorBuilder* JSCallReducer::simplified() const {
8249  return jsgraph()->simplified();
8250}
8251
8252}  // namespace compiler
8253}  // namespace internal
8254}  // namespace v8
8255