js-call-reducer.cc 309 KB
Newer Older
1 2 3 4 5 6
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/compiler/js-call-reducer.h"

7 8
#include <functional>

9
#include "include/v8-fast-api-calls.h"
10
#include "src/api/api-inl.h"
11
#include "src/base/small-vector.h"
12
#include "src/builtins/builtins-promise.h"
13
#include "src/builtins/builtins-utils.h"
14
#include "src/codegen/code-factory.h"
15
#include "src/codegen/tnode.h"
16
#include "src/compiler/access-builder.h"
17
#include "src/compiler/access-info.h"
18
#include "src/compiler/allocation-builder.h"
19
#include "src/compiler/compilation-dependencies.h"
20
#include "src/compiler/feedback-source.h"
21
#include "src/compiler/graph-assembler.h"
22
#include "src/compiler/js-graph.h"
23
#include "src/compiler/linkage.h"
24
#include "src/compiler/map-inference.h"
25
#include "src/compiler/node-matchers.h"
26
#include "src/compiler/property-access-builder.h"
27
#include "src/compiler/simplified-operator.h"
28
#include "src/compiler/type-cache.h"
29
#include "src/ic/call-optimization.h"
30
#include "src/logging/counters.h"
31
#include "src/objects/arguments-inl.h"
32
#include "src/objects/feedback-vector-inl.h"
33
#include "src/objects/js-array-buffer-inl.h"
34
#include "src/objects/js-array-inl.h"
35
#include "src/objects/js-objects.h"
36
#include "src/objects/objects-inl.h"
37
#include "src/objects/ordered-hash-table.h"
38 39 40 41 42

namespace v8 {
namespace internal {
namespace compiler {

43 44 45
// Shorter lambda declarations with less visual clutter.
#define _ [&]()  // NOLINT(whitespace/braces)

46
class JSCallReducerAssembler : public JSGraphAssembler {
47 48 49
 protected:
  class CatchScope;

50 51 52
 private:
  static constexpr bool kMarkLoopExits = true;

53
 public:
54 55 56 57 58 59
  JSCallReducerAssembler(JSCallReducer* reducer, Node* node)
      : JSGraphAssembler(
            reducer->JSGraphForGraphAssembler(),
            reducer->ZoneForGraphAssembler(),
            [reducer](Node* n) { reducer->RevisitForGraphAssembler(n); },
            nullptr, kMarkLoopExits),
60
        node_(node),
61 62
        outermost_catch_scope_(
            CatchScope::Outermost(reducer->ZoneForGraphAssembler())),
63
        catch_scope_(&outermost_catch_scope_) {
64 65
    InitializeEffectControl(NodeProperties::GetEffectInput(node),
                            NodeProperties::GetControlInput(node));
66

67 68 69 70 71
    // Finish initializing the outermost catch scope.
    bool has_handler =
        NodeProperties::IsExceptionalCall(node, &outermost_handler_);
    outermost_catch_scope_.set_has_handler(has_handler);
    outermost_catch_scope_.set_gasm(this);
72 73 74 75 76 77
  }

  TNode<Object> ReduceMathUnary(const Operator* op);
  TNode<Object> ReduceMathBinary(const Operator* op);
  TNode<String> ReduceStringPrototypeSubstring();
  TNode<String> ReduceStringPrototypeSlice();
78

79 80 81 82 83 84 85 86
  TNode<Object> TargetInput() const { return JSCallNode{node_ptr()}.target(); }

  template <typename T>
  TNode<T> ReceiverInputAs() const {
    return TNode<T>::UncheckedCast(JSCallNode{node_ptr()}.receiver());
  }

  TNode<Object> ReceiverInput() const { return ReceiverInputAs<Object>(); }
87

88 89
  CatchScope* catch_scope() const { return catch_scope_; }
  Node* outermost_handler() const { return outermost_handler_; }
90

91
  Node* node_ptr() const { return node_; }
92

93
 protected:
94 95
  using NodeGenerator0 = std::function<TNode<Object>()>;
  using VoidGenerator0 = std::function<void()>;
96 97 98 99 100

  // TODO(jgruber): Currently IfBuilder0 and IfBuilder1 are implemented as
  // separate classes. If, in the future, we encounter additional use cases that
  // return more than 1 value, we should merge these back into a single variadic
  // implementation.
101
  class IfBuilder0 final {
102
   public:
103
    IfBuilder0(JSGraphAssembler* gasm, TNode<Boolean> cond, bool negate_cond)
104 105 106 107 108
        : gasm_(gasm),
          cond_(cond),
          negate_cond_(negate_cond),
          initial_effect_(gasm->effect()),
          initial_control_(gasm->control()) {}
109

110
    IfBuilder0& ExpectTrue() {
111 112 113 114
      DCHECK_EQ(hint_, BranchHint::kNone);
      hint_ = BranchHint::kTrue;
      return *this;
    }
115
    IfBuilder0& ExpectFalse() {
116 117 118 119 120
      DCHECK_EQ(hint_, BranchHint::kNone);
      hint_ = BranchHint::kFalse;
      return *this;
    }

121
    IfBuilder0& Then(const VoidGenerator0& body) {
122 123 124
      then_body_ = body;
      return *this;
    }
125
    IfBuilder0& Else(const VoidGenerator0& body) {
126 127 128 129
      else_body_ = body;
      return *this;
    }

130 131 132 133 134 135
    ~IfBuilder0() {
      // Ensure correct usage: effect/control must not have been modified while
      // the IfBuilder0 instance is alive.
      DCHECK_EQ(gasm_->effect(), initial_effect_);
      DCHECK_EQ(gasm_->control(), initial_control_);

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
      // Unlike IfBuilder1, this supports an empty then or else body. This is
      // possible since the merge does not take any value inputs.
      DCHECK(then_body_ || else_body_);

      if (negate_cond_) std::swap(then_body_, else_body_);

      auto if_true = (hint_ == BranchHint::kFalse) ? gasm_->MakeDeferredLabel()
                                                   : gasm_->MakeLabel();
      auto if_false = (hint_ == BranchHint::kTrue) ? gasm_->MakeDeferredLabel()
                                                   : gasm_->MakeLabel();
      auto merge = gasm_->MakeLabel();
      gasm_->Branch(cond_, &if_true, &if_false);

      gasm_->Bind(&if_true);
      if (then_body_) then_body_();
151
      if (gasm_->HasActiveBlock()) gasm_->Goto(&merge);
152 153 154

      gasm_->Bind(&if_false);
      if (else_body_) else_body_();
155
      if (gasm_->HasActiveBlock()) gasm_->Goto(&merge);
156 157 158 159

      gasm_->Bind(&merge);
    }

160 161 162
    IfBuilder0(const IfBuilder0&) = delete;
    IfBuilder0& operator=(const IfBuilder0&) = delete;

163
   private:
164
    JSGraphAssembler* const gasm_;
165
    const TNode<Boolean> cond_;
166
    const bool negate_cond_;
167 168
    const Effect initial_effect_;
    const Control initial_control_;
169
    BranchHint hint_ = BranchHint::kNone;
170 171
    VoidGenerator0 then_body_;
    VoidGenerator0 else_body_;
172 173
  };

174 175
  IfBuilder0 If(TNode<Boolean> cond) { return {this, cond, false}; }
  IfBuilder0 IfNot(TNode<Boolean> cond) { return {this, cond, true}; }
176

177
  template <typename T>
178
  class IfBuilder1 {
179 180
    using If1BodyFunction = std::function<TNode<T>()>;

181
   public:
182
    IfBuilder1(JSGraphAssembler* gasm, TNode<Boolean> cond)
183 184
        : gasm_(gasm), cond_(cond) {}

185
    V8_WARN_UNUSED_RESULT IfBuilder1& ExpectTrue() {
186
      DCHECK_EQ(hint_, BranchHint::kNone);
187 188 189 190
      hint_ = BranchHint::kTrue;
      return *this;
    }

191
    V8_WARN_UNUSED_RESULT IfBuilder1& ExpectFalse() {
192
      DCHECK_EQ(hint_, BranchHint::kNone);
193 194 195 196
      hint_ = BranchHint::kFalse;
      return *this;
    }

197
    V8_WARN_UNUSED_RESULT IfBuilder1& Then(const If1BodyFunction& body) {
198 199 200
      then_body_ = body;
      return *this;
    }
201
    V8_WARN_UNUSED_RESULT IfBuilder1& Else(const If1BodyFunction& body) {
202 203 204 205
      else_body_ = body;
      return *this;
    }

206
    V8_WARN_UNUSED_RESULT TNode<T> Value() {
207 208 209 210 211 212 213 214 215 216
      DCHECK(then_body_);
      DCHECK(else_body_);
      auto if_true = (hint_ == BranchHint::kFalse) ? gasm_->MakeDeferredLabel()
                                                   : gasm_->MakeLabel();
      auto if_false = (hint_ == BranchHint::kTrue) ? gasm_->MakeDeferredLabel()
                                                   : gasm_->MakeLabel();
      auto merge = gasm_->MakeLabel(kPhiRepresentation);
      gasm_->Branch(cond_, &if_true, &if_false);

      gasm_->Bind(&if_true);
217
      TNode<T> then_result = then_body_();
218
      if (gasm_->HasActiveBlock()) gasm_->Goto(&merge, then_result);
219 220

      gasm_->Bind(&if_false);
221
      TNode<T> else_result = else_body_();
222 223 224
      if (gasm_->HasActiveBlock()) {
        gasm_->Goto(&merge, else_result);
      }
225 226

      gasm_->Bind(&merge);
227
      return merge.PhiAt<T>(0);
228 229 230 231 232 233
    }

   private:
    static constexpr MachineRepresentation kPhiRepresentation =
        MachineRepresentation::kTagged;

234
    JSGraphAssembler* const gasm_;
235
    const TNode<Boolean> cond_;
236
    BranchHint hint_ = BranchHint::kNone;
237 238
    If1BodyFunction then_body_;
    If1BodyFunction else_body_;
239 240
  };

241 242 243 244
  template <typename T>
  IfBuilder1<T> SelectIf(TNode<Boolean> cond) {
    return {this, cond};
  }
245

246
  // Simplified operators.
247
  TNode<Number> SpeculativeToNumber(
248
      TNode<Object> value,
249
      NumberOperationHint hint = NumberOperationHint::kNumberOrOddball);
250 251
  TNode<Smi> CheckSmi(TNode<Object> value);
  TNode<String> CheckString(TNode<Object> value);
252
  TNode<Number> CheckBounds(TNode<Number> value, TNode<Number> limit);
253

254
  // Common operators.
255 256
  TNode<Smi> TypeGuardUnsignedSmall(TNode<Object> value);
  TNode<Object> TypeGuardNonInternal(TNode<Object> value);
257
  TNode<Number> TypeGuardFixedArrayLength(TNode<Object> value);
258 259 260
  TNode<Object> Call4(const Callable& callable, TNode<Context> context,
                      TNode<Object> arg0, TNode<Object> arg1,
                      TNode<Object> arg2, TNode<Object> arg3);
261

262
  // Javascript operators.
263 264
  TNode<Object> JSCall3(TNode<Object> function, TNode<Object> this_arg,
                        TNode<Object> arg0, TNode<Object> arg1,
265
                        TNode<Object> arg2, FrameState frame_state);
266 267 268
  TNode<Object> JSCall4(TNode<Object> function, TNode<Object> this_arg,
                        TNode<Object> arg0, TNode<Object> arg1,
                        TNode<Object> arg2, TNode<Object> arg3,
269
                        FrameState frame_state);
270
  TNode<Object> JSCallRuntime2(Runtime::FunctionId function_id,
271
                               TNode<Object> arg0, TNode<Object> arg1,
272
                               FrameState frame_state);
273
  // Used in special cases in which we are certain CreateArray does not throw.
274 275
  TNode<JSArray> CreateArrayNoThrow(TNode<Object> ctor, TNode<Number> size,
                                    FrameState frame_state);
276

277 278 279 280 281 282 283
  TNode<JSArray> AllocateEmptyJSArray(ElementsKind kind,
                                      const NativeContextRef& native_context);

  TNode<Number> NumberInc(TNode<Number> value) {
    return NumberAdd(value, OneConstant());
  }

284 285 286 287 288
  void MaybeInsertMapChecks(MapInference* inference,
                            bool has_stability_dependency) {
    // TODO(jgruber): Implement MapInference::InsertMapChecks in graph
    // assembler.
    if (!has_stability_dependency) {
289 290
      Effect e = effect();
      inference->InsertMapChecks(jsgraph(), &e, Control{control()}, feedback());
291 292 293 294
      InitializeEffectControl(e, control());
    }
  }

295 296 297 298
  // TODO(jgruber): Currently, it's the responsibility of the developer to note
  // which operations may throw and appropriately wrap these in a call to
  // MayThrow (see e.g. JSCall3 and CallRuntime2). A more methodical approach
  // would be good.
299 300
  TNode<Object> MayThrow(const NodeGenerator0& body) {
    TNode<Object> result = body();
301

302
    if (catch_scope()->has_handler()) {
303
      // The IfException node is later merged into the outer graph.
304 305
      // Note: AddNode is intentionally not called since effect and control
      // should not be updated.
306
      Node* if_exception =
307 308
          graph()->NewNode(common()->IfException(), effect(), control());
      catch_scope()->RegisterIfExceptionNode(if_exception);
309

310 311
      // Control resumes here.
      AddNode(graph()->NewNode(common()->IfSuccess(), control()));
312 313 314 315 316
    }

    return result;
  }

317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
  // A catch scope represents a single catch handler. The handler can be
  // custom catch logic within the reduction itself; or a catch handler in the
  // outside graph into which the reduction will be integrated (in this case
  // the scope is called 'outermost').
  class CatchScope {
   private:
    // Only used to partially construct the outermost scope.
    explicit CatchScope(Zone* zone) : if_exception_nodes_(zone) {}

    // For all inner scopes.
    CatchScope(Zone* zone, JSCallReducerAssembler* gasm)
        : gasm_(gasm),
          parent_(gasm->catch_scope_),
          has_handler_(true),
          if_exception_nodes_(zone) {
      gasm_->catch_scope_ = this;
    }

   public:
    ~CatchScope() { gasm_->catch_scope_ = parent_; }

    static CatchScope Outermost(Zone* zone) { return CatchScope{zone}; }
    static CatchScope Inner(Zone* zone, JSCallReducerAssembler* gasm) {
      return {zone, gasm};
    }

    bool has_handler() const { return has_handler_; }
    bool is_outermost() const { return parent_ == nullptr; }
    CatchScope* parent() const { return parent_; }

    // Should only be used to initialize the outermost scope (inner scopes
    // always have a handler and are passed the gasm pointer at construction).
    void set_has_handler(bool v) {
      DCHECK(is_outermost());
      has_handler_ = v;
    }
    void set_gasm(JSCallReducerAssembler* v) {
      DCHECK(is_outermost());
      gasm_ = v;
    }

    bool has_exceptional_control_flow() const {
      return !if_exception_nodes_.empty();
    }

    void RegisterIfExceptionNode(Node* if_exception) {
      DCHECK(has_handler());
      if_exception_nodes_.push_back(if_exception);
    }

    void MergeExceptionalPaths(TNode<Object>* exception_out, Effect* effect_out,
                               Control* control_out) {
      DCHECK(has_handler());
      DCHECK(has_exceptional_control_flow());

      const int size = static_cast<int>(if_exception_nodes_.size());

      if (size == 1) {
        // No merge needed.
        Node* e = if_exception_nodes_.at(0);
        *exception_out = TNode<Object>::UncheckedCast(e);
        *effect_out = Effect(e);
        *control_out = Control(e);
      } else {
        DCHECK_GT(size, 1);

        Node* merge = gasm_->graph()->NewNode(gasm_->common()->Merge(size),
                                              size, if_exception_nodes_.data());

        // These phis additionally take {merge} as an input. Temporarily add
        // it to the list.
        if_exception_nodes_.push_back(merge);
        const int size_with_merge =
            static_cast<int>(if_exception_nodes_.size());

        Node* ephi = gasm_->graph()->NewNode(gasm_->common()->EffectPhi(size),
                                             size_with_merge,
                                             if_exception_nodes_.data());
        Node* phi = gasm_->graph()->NewNode(
            gasm_->common()->Phi(MachineRepresentation::kTagged, size),
            size_with_merge, if_exception_nodes_.data());
        if_exception_nodes_.pop_back();

        *exception_out = TNode<Object>::UncheckedCast(phi);
        *effect_out = Effect(ephi);
        *control_out = Control(merge);
      }
    }

   private:
    JSCallReducerAssembler* gasm_ = nullptr;
    CatchScope* const parent_ = nullptr;
    bool has_handler_ = false;
    NodeVector if_exception_nodes_;
  };

  class TryCatchBuilder0 {
   public:
    using TryFunction = VoidGenerator0;
    using CatchFunction = std::function<void(TNode<Object>)>;

    TryCatchBuilder0(JSCallReducerAssembler* gasm, const TryFunction& try_body)
        : gasm_(gasm), try_body_(try_body) {}

    void Catch(const CatchFunction& catch_body) {
      TNode<Object> handler_exception;
      Effect handler_effect{nullptr};
      Control handler_control{nullptr};

      auto continuation = gasm_->MakeLabel();

      // Try.
      {
        CatchScope catch_scope = CatchScope::Inner(gasm_->temp_zone(), gasm_);
        try_body_();
        gasm_->Goto(&continuation);

        catch_scope.MergeExceptionalPaths(&handler_exception, &handler_effect,
                                          &handler_control);
      }

      // Catch.
      {
        gasm_->InitializeEffectControl(handler_effect, handler_control);
        catch_body(handler_exception);
        gasm_->Goto(&continuation);
      }

      gasm_->Bind(&continuation);
    }

   private:
    JSCallReducerAssembler* const gasm_;
    const VoidGenerator0 try_body_;
  };

  TryCatchBuilder0 Try(const VoidGenerator0& try_body) {
    return {this, try_body};
  }

457 458
  using ConditionFunction1 = std::function<TNode<Boolean>(TNode<Number>)>;
  using StepFunction1 = std::function<TNode<Number>(TNode<Number>)>;
459
  class ForBuilder0 {
460 461
    using For0BodyFunction = std::function<void(TNode<Number>)>;

462
   public:
463
    ForBuilder0(JSGraphAssembler* gasm, TNode<Number> initial_value,
464
                const ConditionFunction1& cond, const StepFunction1& step)
465 466 467 468 469
        : gasm_(gasm),
          initial_value_(initial_value),
          cond_(cond),
          step_(step) {}

470
    void Do(const For0BodyFunction& body) {
471 472
      auto loop_exit = gasm_->MakeLabel();

473 474 475 476 477 478 479
      {
        GraphAssembler::LoopScope<kPhiRepresentation> loop_scope(gasm_);

        auto loop_header = loop_scope.loop_header_label();
        auto loop_body = gasm_->MakeLabel();

        gasm_->Goto(loop_header, initial_value_);
480

481 482
        gasm_->Bind(loop_header);
        TNode<Number> i = loop_header->PhiAt<Number>(0);
483

484 485
        gasm_->BranchWithHint(cond_(i), &loop_body, &loop_exit,
                              BranchHint::kTrue);
486

487 488 489 490
        gasm_->Bind(&loop_body);
        body(i);
        gasm_->Goto(loop_header, step_(i));
      }
491 492 493 494 495 496 497 498

      gasm_->Bind(&loop_exit);
    }

   private:
    static constexpr MachineRepresentation kPhiRepresentation =
        MachineRepresentation::kTagged;

499
    JSGraphAssembler* const gasm_;
500 501 502
    const TNode<Number> initial_value_;
    const ConditionFunction1 cond_;
    const StepFunction1 step_;
503 504
  };

505
  ForBuilder0 ForZeroUntil(TNode<Number> excluded_limit) {
506
    TNode<Number> initial_value = ZeroConstant();
507 508 509
    auto cond = [=](TNode<Number> i) {
      return NumberLessThan(i, excluded_limit);
    };
510
    auto step = [=](TNode<Number> i) { return NumberAdd(i, OneConstant()); };
511 512 513
    return {this, initial_value, cond, step};
  }

514
  ForBuilder0 Forever(TNode<Number> initial_value, const StepFunction1& step) {
515
    return {this, initial_value, [=](TNode<Number>) { return TrueConstant(); },
516
            step};
517 518
  }

519
  using For1BodyFunction = std::function<void(TNode<Number>, TNode<Object>*)>;
520 521
  class ForBuilder1 {
   public:
522
    ForBuilder1(JSGraphAssembler* gasm, TNode<Number> initial_value,
523 524
                const ConditionFunction1& cond, const StepFunction1& step,
                TNode<Object> initial_arg0)
525 526 527 528 529 530
        : gasm_(gasm),
          initial_value_(initial_value),
          cond_(cond),
          step_(step),
          initial_arg0_(initial_arg0) {}

531
    V8_WARN_UNUSED_RESULT ForBuilder1& Do(const For1BodyFunction& body) {
532 533 534 535
      body_ = body;
      return *this;
    }

536
    V8_WARN_UNUSED_RESULT TNode<Object> Value() {
537
      DCHECK(body_);
538
      TNode<Object> arg0 = initial_arg0_;
539 540 541

      auto loop_exit = gasm_->MakeDeferredLabel(kPhiRepresentation);

542 543 544
      {
        GraphAssembler::LoopScope<kPhiRepresentation, kPhiRepresentation>
            loop_scope(gasm_);
545

546 547
        auto loop_header = loop_scope.loop_header_label();
        auto loop_body = gasm_->MakeDeferredLabel(kPhiRepresentation);
548

549
        gasm_->Goto(loop_header, initial_value_, initial_arg0_);
550

551 552 553 554 555 556 557 558 559 560 561
        gasm_->Bind(loop_header);
        TNode<Number> i = loop_header->PhiAt<Number>(0);
        arg0 = loop_header->PhiAt<Object>(1);

        gasm_->BranchWithHint(cond_(i), &loop_body, &loop_exit,
                              BranchHint::kTrue, arg0);

        gasm_->Bind(&loop_body);
        body_(i, &arg0);
        gasm_->Goto(loop_header, step_(i), arg0);
      }
562 563

      gasm_->Bind(&loop_exit);
564
      return TNode<Object>::UncheckedCast(loop_exit.PhiAt<Object>(0));
565 566
    }

567 568
    void ValueIsUnused() { USE(Value()); }

569 570 571 572
   private:
    static constexpr MachineRepresentation kPhiRepresentation =
        MachineRepresentation::kTagged;

573
    JSGraphAssembler* const gasm_;
574 575 576 577 578
    const TNode<Number> initial_value_;
    const ConditionFunction1 cond_;
    const StepFunction1 step_;
    For1BodyFunction body_;
    const TNode<Object> initial_arg0_;
579 580
  };

581 582
  ForBuilder1 For1(TNode<Number> initial_value, const ConditionFunction1& cond,
                   const StepFunction1& step, TNode<Object> initial_arg0) {
583 584 585
    return {this, initial_value, cond, step, initial_arg0};
  }

586 587
  ForBuilder1 For1ZeroUntil(TNode<Number> excluded_limit,
                            TNode<Object> initial_arg0) {
588 589 590 591 592 593 594 595
    TNode<Number> initial_value = ZeroConstant();
    auto cond = [=](TNode<Number> i) {
      return NumberLessThan(i, excluded_limit);
    };
    auto step = [=](TNode<Number> i) { return NumberAdd(i, OneConstant()); };
    return {this, initial_value, cond, step, initial_arg0};
  }

596 597 598 599 600 601 602 603 604 605
  void ThrowIfNotCallable(TNode<Object> maybe_callable,
                          FrameState frame_state) {
    IfNot(ObjectIsCallable(maybe_callable))
        .Then(_ {
          JSCallRuntime2(Runtime::kThrowTypeError,
                         NumberConstant(static_cast<double>(
                             MessageTemplate::kCalledNonCallable)),
                         maybe_callable, frame_state);
          Unreachable();  // The runtime call throws unconditionally.
        })
606
        .ExpectTrue();
607 608
  }

609 610 611 612 613
  const FeedbackSource& feedback() const {
    CallParameters const& p = CallParametersOf(node_ptr()->op());
    return p.feedback();
  }

614
  int ArgumentCount() const { return JSCallNode{node_ptr()}.ArgumentCount(); }
615

616 617
  TNode<Object> Argument(int index) const {
    return TNode<Object>::UncheckedCast(JSCallNode{node_ptr()}.Argument(index));
618 619
  }

620
  template <typename T>
621 622
  TNode<T> ArgumentAs(int index) const {
    return TNode<T>::UncheckedCast(Argument(index));
623 624
  }

625
  TNode<Object> ArgumentOrNaN(int index) {
626
    return TNode<Object>::UncheckedCast(
627
        ArgumentCount() > index ? Argument(index) : NaNConstant());
628 629
  }

630
  TNode<Object> ArgumentOrUndefined(int index) {
631
    return TNode<Object>::UncheckedCast(
632
        ArgumentCount() > index ? Argument(index) : UndefinedConstant());
633 634
  }

635
  TNode<Number> ArgumentOrZero(int index) {
636
    return TNode<Number>::UncheckedCast(
637
        ArgumentCount() > index ? Argument(index) : ZeroConstant());
638 639
  }

640
  TNode<Context> ContextInput() const {
641 642
    return TNode<Context>::UncheckedCast(
        NodeProperties::GetContextInput(node_));
643 644
  }

645 646
  FrameState FrameStateInput() const {
    return FrameState(NodeProperties::GetFrameStateInput(node_));
647 648 649
  }

  JSOperatorBuilder* javascript() const { return jsgraph()->javascript(); }
650

651
 private:
652
  Node* const node_;
653

654 655 656 657
  CatchScope outermost_catch_scope_;
  Node* outermost_handler_;
  CatchScope* catch_scope_;
  friend class CatchScope;
658 659
};

660
enum class ArrayReduceDirection { kLeft, kRight };
661
enum class ArrayFindVariant { kFind, kFindIndex };
662
enum class ArrayEverySomeVariant { kEvery, kSome };
663
enum class ArrayIndexOfIncludesVariant { kIncludes, kIndexOf };
664 665 666 667 668

// This subclass bundles functionality specific to reducing iterating array
// builtins.
class IteratingArrayBuiltinReducerAssembler : public JSCallReducerAssembler {
 public:
669 670
  IteratingArrayBuiltinReducerAssembler(JSCallReducer* reducer, Node* node)
      : JSCallReducerAssembler(reducer, node) {
671 672
    DCHECK(FLAG_turbo_inline_array_builtins);
  }
673 674 675 676 677 678 679 680 681

  TNode<Object> ReduceArrayPrototypeForEach(
      MapInference* inference, const bool has_stability_dependency,
      ElementsKind kind, const SharedFunctionInfoRef& shared);
  TNode<Object> ReduceArrayPrototypeReduce(MapInference* inference,
                                           const bool has_stability_dependency,
                                           ElementsKind kind,
                                           ArrayReduceDirection direction,
                                           const SharedFunctionInfoRef& shared);
682 683 684 685
  TNode<JSArray> ReduceArrayPrototypeMap(
      MapInference* inference, const bool has_stability_dependency,
      ElementsKind kind, const SharedFunctionInfoRef& shared,
      const NativeContextRef& native_context);
686 687 688 689
  TNode<JSArray> ReduceArrayPrototypeFilter(
      MapInference* inference, const bool has_stability_dependency,
      ElementsKind kind, const SharedFunctionInfoRef& shared,
      const NativeContextRef& native_context);
690 691 692 693 694 695
  TNode<Object> ReduceArrayPrototypeFind(MapInference* inference,
                                         const bool has_stability_dependency,
                                         ElementsKind kind,
                                         const SharedFunctionInfoRef& shared,
                                         const NativeContextRef& native_context,
                                         ArrayFindVariant variant);
696 697 698 699
  TNode<Boolean> ReduceArrayPrototypeEverySome(
      MapInference* inference, const bool has_stability_dependency,
      ElementsKind kind, const SharedFunctionInfoRef& shared,
      const NativeContextRef& native_context, ArrayEverySomeVariant variant);
700 701
  TNode<Object> ReduceArrayPrototypeIndexOfIncludes(
      ElementsKind kind, ArrayIndexOfIncludesVariant variant);
702

703
 private:
704 705 706
  // Returns {index,value}. Assumes that the map has not changed, but possibly
  // the length and backing store.
  std::pair<TNode<Number>, TNode<Object>> SafeLoadElement(ElementsKind kind,
707
                                                          TNode<JSArray> o,
708 709 710
                                                          TNode<Number> index) {
    // Make sure that the access is still in bounds, since the callback could
    // have changed the array's size.
711
    TNode<Number> length = LoadJSArrayLength(o, kind);
712 713 714 715 716
    index = CheckBounds(index, length);

    // Reload the elements pointer before calling the callback, since the
    // previous callback might have resized the array causing the elements
    // buffer to be re-allocated.
717 718 719
    TNode<HeapObject> elements =
        LoadField<HeapObject>(AccessBuilder::ForJSObjectElements(), o);
    TNode<Object> value = LoadElement<Object>(
720
        AccessBuilder::ForFixedArrayElement(kind, LoadSensitivity::kCritical),
721
        elements, index);
722 723 724
    return std::make_pair(index, value);
  }

725 726 727
  template <typename... Vars>
  TNode<Object> MaybeSkipHole(
      TNode<Object> o, ElementsKind kind,
728 729
      GraphAssemblerLabel<sizeof...(Vars)>* continue_label,
      TNode<Vars>... vars) {
730 731
    if (!IsHoleyElementsKind(kind)) return o;

732 733 734 735
    std::array<MachineRepresentation, sizeof...(Vars)> reps = {
        MachineRepresentationOf<Vars>::value...};
    auto if_not_hole =
        MakeLabel<sizeof...(Vars)>(reps, GraphAssemblerLabelType::kNonDeferred);
736 737 738 739 740 741 742 743 744 745 746 747 748
    BranchWithHint(HoleCheck(kind, o), continue_label, &if_not_hole,
                   BranchHint::kFalse, vars...);

    // The contract is that we don't leak "the hole" into "user JavaScript",
    // so we must rename the {element} here to explicitly exclude "the hole"
    // from the type of {element}.
    Bind(&if_not_hole);
    return TypeGuardNonInternal(o);
  }

  TNode<Smi> LoadJSArrayLength(TNode<JSArray> array, ElementsKind kind) {
    return LoadField<Smi>(AccessBuilder::ForJSArrayLength(kind), array);
  }
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
  void StoreJSArrayLength(TNode<JSArray> array, TNode<Number> value,
                          ElementsKind kind) {
    StoreField(AccessBuilder::ForJSArrayLength(kind), array, value);
  }
  void StoreFixedArrayBaseElement(TNode<FixedArrayBase> o, TNode<Number> index,
                                  TNode<Object> v, ElementsKind kind) {
    StoreElement(AccessBuilder::ForFixedArrayElement(kind), o, index, v);
  }

  TNode<FixedArrayBase> LoadElements(TNode<JSObject> o) {
    return LoadField<FixedArrayBase>(AccessBuilder::ForJSObjectElements(), o);
  }
  TNode<Smi> LoadFixedArrayBaseLength(TNode<FixedArrayBase> o) {
    return LoadField<Smi>(AccessBuilder::ForFixedArrayLength(), o);
  }
764

765
  TNode<Boolean> HoleCheck(ElementsKind kind, TNode<Object> v) {
766 767 768
    return IsDoubleElementsKind(kind)
               ? NumberIsFloat64Hole(TNode<Number>::UncheckedCast(v))
               : IsTheHole(v);
769
  }
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789

  TNode<Number> CheckFloat64Hole(TNode<Number> value,
                                 CheckFloat64HoleMode mode) {
    return AddNode<Number>(
        graph()->NewNode(simplified()->CheckFloat64Hole(mode, feedback()),
                         value, effect(), control()));
  }

  // May deopt for holey double elements.
  TNode<Object> TryConvertHoleToUndefined(TNode<Object> value,
                                          ElementsKind kind) {
    DCHECK(IsHoleyElementsKind(kind));
    if (kind == HOLEY_DOUBLE_ELEMENTS) {
      // TODO(7409): avoid deopt if not all uses of value are truncated.
      TNode<Number> number = TNode<Number>::UncheckedCast(value);
      return CheckFloat64Hole(number, CheckFloat64HoleMode::kAllowReturnHole);
    }

    return ConvertTaggedHoleToUndefined(value);
  }
790 791
};

792 793
class PromiseBuiltinReducerAssembler : public JSCallReducerAssembler {
 public:
794
  PromiseBuiltinReducerAssembler(JSCallReducer* reducer, Node* node,
795
                                 JSHeapBroker* broker)
796
      : JSCallReducerAssembler(reducer, node), broker_(broker) {
797 798 799 800 801 802 803
    DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
  }

  TNode<Object> ReducePromiseConstructor(
      const NativeContextRef& native_context);

  int ConstructArity() const {
804
    return JSConstructNode{node_ptr()}.ArgumentCount();
805 806
  }

807
  TNode<Object> TargetInput() const {
808
    return JSConstructNode{node_ptr()}.target();
809 810
  }

811
  TNode<Object> NewTargetInput() const {
812
    return JSConstructNode{node_ptr()}.new_target();
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
  }

 private:
  TNode<JSPromise> CreatePromise(TNode<Context> context) {
    return AddNode<JSPromise>(
        graph()->NewNode(javascript()->CreatePromise(), context, effect()));
  }

  TNode<Context> CreateFunctionContext(const NativeContextRef& native_context,
                                       TNode<Context> outer_context,
                                       int slot_count) {
    return AddNode<Context>(graph()->NewNode(
        javascript()->CreateFunctionContext(
            native_context.scope_info().object(),
            slot_count - Context::MIN_CONTEXT_SLOTS, FUNCTION_SCOPE),
        outer_context, effect(), control()));
  }

  void StoreContextSlot(TNode<Context> context, size_t slot_index,
                        TNode<Object> value) {
    StoreField(AccessBuilder::ForContextSlot(slot_index), context, value);
  }

  TNode<JSFunction> CreateClosureFromBuiltinSharedFunctionInfo(
      SharedFunctionInfoRef shared, TNode<Context> context) {
    DCHECK(shared.HasBuiltinId());
839 840
    Handle<FeedbackCell> feedback_cell =
        isolate()->factory()->many_closures_cell();
841 842 843
    Callable const callable = Builtins::CallableFor(
        isolate(), static_cast<Builtins::Name>(shared.builtin_id()));
    return AddNode<JSFunction>(graph()->NewNode(
844 845
        javascript()->CreateClosure(shared.object(), callable.code()),
        HeapConstant(feedback_cell), context, effect(), control()));
846 847 848 849
  }

  void CallPromiseExecutor(TNode<Object> executor, TNode<JSFunction> resolve,
                           TNode<JSFunction> reject, FrameState frame_state) {
850 851
    JSConstructNode n(node_ptr());
    const ConstructParameters& p = n.Parameters();
852
    FeedbackSource no_feedback_source{};
853
    Node* no_feedback = UndefinedConstant();
854 855
    MayThrow(_ {
      return AddNode<Object>(graph()->NewNode(
856
          javascript()->Call(JSCallNode::ArityForArgc(2), p.frequency(),
857
                             no_feedback_source,
858
                             ConvertReceiverMode::kNullOrUndefined),
859 860
          executor, UndefinedConstant(), resolve, reject, no_feedback,
          n.context(), frame_state, effect(), control()));
861 862 863 864 865
    });
  }

  void CallPromiseReject(TNode<JSFunction> reject, TNode<Object> exception,
                         FrameState frame_state) {
866 867
    JSConstructNode n(node_ptr());
    const ConstructParameters& p = n.Parameters();
868
    FeedbackSource no_feedback_source{};
869
    Node* no_feedback = UndefinedConstant();
870 871
    MayThrow(_ {
      return AddNode<Object>(graph()->NewNode(
872
          javascript()->Call(JSCallNode::ArityForArgc(1), p.frequency(),
873
                             no_feedback_source,
874
                             ConvertReceiverMode::kNullOrUndefined),
875
          reject, UndefinedConstant(), exception, no_feedback, n.context(),
876
          frame_state, effect(), control()));
877 878
    });
  }
879 880

  JSHeapBroker* const broker_;
881 882
};

883 884
class FastApiCallReducerAssembler : public JSCallReducerAssembler {
 public:
885
  FastApiCallReducerAssembler(
886
      JSCallReducer* reducer, Node* node,
887 888 889
      const FunctionTemplateInfoRef function_template_info, Node* receiver,
      Node* holder, const SharedFunctionInfoRef shared, Node* target,
      const int arity, Node* effect)
890
      : JSCallReducerAssembler(reducer, node),
891 892
        c_function_(function_template_info.c_function()),
        c_signature_(function_template_info.c_signature()),
893 894 895 896 897 898
        function_template_info_(function_template_info),
        receiver_(receiver),
        holder_(holder),
        shared_(shared),
        target_(target),
        arity_(arity) {
899 900 901
    DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
    DCHECK_NE(c_function_, kNullAddress);
    CHECK_NOT_NULL(c_signature_);
902
    InitializeEffectControl(effect, NodeProperties::GetControlInput(node));
903 904 905
  }

  TNode<Object> ReduceFastApiCall() {
906
    JSCallNode n(node_ptr());
907 908 909 910
    // C arguments include the receiver at index 0. Thus C index 1 corresponds
    // to the JS argument 0, etc.
    const int c_argument_count =
        static_cast<int>(c_signature_->ArgumentCount());
911
    CHECK_GE(c_argument_count, kReceiver);
912 913

    int cursor = 0;
914 915
    base::SmallVector<Node*, kInlineSize> inputs(c_argument_count + arity_ +
                                                 kExtraInputsCount);
916 917
    inputs[cursor++] = ExternalConstant(ExternalReference::Create(c_function_));

918
    inputs[cursor++] = n.receiver();
919

920
    // TODO(turbofan): Consider refactoring CFunctionInfo to distinguish
921
    // between receiver and arguments, simplifying this (and related) spots.
922 923 924
    int js_args_count = c_argument_count - kReceiver;
    for (int i = 0; i < js_args_count; ++i) {
      if (i < n.ArgumentCount()) {
925
        inputs[cursor++] = n.Argument(i);
926
      } else {
927
        inputs[cursor++] = UndefinedConstant();
928 929 930
      }
    }

931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
    // Here we add the arguments for the slow call, which will be
    // reconstructed at a later phase. Those are effectively the same
    // arguments as for the fast call, but we want to have them as
    // separate inputs, so that SimplifiedLowering can provide the best
    // possible UseInfos for each of them. The inputs to FastApiCall
    // look like:
    // [fast callee, receiver, ... C arguments,
    // call code, external constant for function, argc, call handler info data,
    // holder, receiver, ... JS arguments, context, new frame state]
    CallHandlerInfoRef call_handler_info = *function_template_info_.call_code();
    Callable call_api_callback = CodeFactory::CallApiCallback(isolate());
    CallInterfaceDescriptor cid = call_api_callback.descriptor();
    CallDescriptor* call_descriptor =
        Linkage::GetStubCallDescriptor(graph()->zone(), cid, arity_ + kReceiver,
                                       CallDescriptor::kNeedsFrameState);
    ApiFunction api_function(call_handler_info.callback());
    ExternalReference function_reference = ExternalReference::Create(
        &api_function, ExternalReference::DIRECT_API_CALL);

    Node* continuation_frame_state =
        CreateGenericLazyDeoptContinuationFrameState(
            jsgraph(), shared_, target_, ContextInput(), receiver_,
            FrameStateInput());

    inputs[cursor++] = HeapConstant(call_api_callback.code());
    inputs[cursor++] = ExternalConstant(function_reference);
    inputs[cursor++] = NumberConstant(arity_);
    inputs[cursor++] = Constant(call_handler_info.data());
    inputs[cursor++] = holder_;
    inputs[cursor++] = receiver_;
    for (int i = 0; i < arity_; ++i) {
      inputs[cursor++] = Argument(i);
    }
    inputs[cursor++] = ContextInput();
    inputs[cursor++] = continuation_frame_state;
966 967 968
    inputs[cursor++] = effect();
    inputs[cursor++] = control();

969 970 971
    DCHECK_EQ(cursor, c_argument_count + arity_ + kExtraInputsCount);

    return FastApiCall(call_descriptor, inputs.begin(), inputs.size());
972 973 974
  }

 private:
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
  static constexpr int kTarget = 1;
  static constexpr int kEffectAndControl = 2;
  static constexpr int kContextAndFrameState = 2;
  static constexpr int kCallCodeDataAndArgc = 3;
  static constexpr int kHolder = 1, kReceiver = 1;
  static constexpr int kExtraInputsCount =
      kTarget * 2 + kEffectAndControl + kContextAndFrameState +
      kCallCodeDataAndArgc + kHolder + kReceiver;
  static constexpr int kInlineSize = 12;

  TNode<Object> FastApiCall(CallDescriptor* descriptor, Node** inputs,
                            size_t inputs_size) {
    return AddNode<Object>(graph()->NewNode(
        simplified()->FastApiCall(c_signature_, feedback(), descriptor),
        static_cast<int>(inputs_size), inputs));
990 991 992 993
  }

  const Address c_function_;
  const CFunctionInfo* const c_signature_;
994 995 996 997 998 999
  const FunctionTemplateInfoRef function_template_info_;
  Node* const receiver_;
  Node* const holder_;
  const SharedFunctionInfoRef shared_;
  Node* const target_;
  const int arity_;
1000 1001
};

1002
TNode<Number> JSCallReducerAssembler::SpeculativeToNumber(
1003 1004
    TNode<Object> value, NumberOperationHint hint) {
  return AddNode<Number>(
1005
      graph()->NewNode(simplified()->SpeculativeToNumber(hint, feedback()),
1006
                       value, effect(), control()));
1007 1008
}

1009 1010 1011
TNode<Smi> JSCallReducerAssembler::CheckSmi(TNode<Object> value) {
  return AddNode<Smi>(graph()->NewNode(simplified()->CheckSmi(feedback()),
                                       value, effect(), control()));
1012 1013
}

1014 1015 1016
TNode<String> JSCallReducerAssembler::CheckString(TNode<Object> value) {
  return AddNode<String>(graph()->NewNode(simplified()->CheckString(feedback()),
                                          value, effect(), control()));
1017 1018
}

1019 1020
TNode<Number> JSCallReducerAssembler::CheckBounds(TNode<Number> value,
                                                  TNode<Number> limit) {
1021 1022
  return AddNode<Number>(graph()->NewNode(simplified()->CheckBounds(feedback()),
                                          value, limit, effect(), control()));
1023 1024
}

1025
TNode<Smi> JSCallReducerAssembler::TypeGuardUnsignedSmall(TNode<Object> value) {
1026
  return TNode<Smi>::UncheckedCast(TypeGuard(Type::UnsignedSmall(), value));
1027 1028
}

1029
TNode<Object> JSCallReducerAssembler::TypeGuardNonInternal(
1030
    TNode<Object> value) {
1031
  return TNode<Object>::UncheckedCast(TypeGuard(Type::NonInternal(), value));
1032 1033
}

1034 1035 1036 1037 1038 1039 1040 1041
TNode<Number> JSCallReducerAssembler::TypeGuardFixedArrayLength(
    TNode<Object> value) {
  DCHECK(TypeCache::Get()->kFixedDoubleArrayLengthType.Is(
      TypeCache::Get()->kFixedArrayLengthType));
  return TNode<Number>::UncheckedCast(
      TypeGuard(TypeCache::Get()->kFixedArrayLengthType, value));
}

1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
TNode<Object> JSCallReducerAssembler::Call4(
    const Callable& callable, TNode<Context> context, TNode<Object> arg0,
    TNode<Object> arg1, TNode<Object> arg2, TNode<Object> arg3) {
  // TODO(jgruber): Make this more generic. Currently it's fitted to its single
  // callsite.
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      graph()->zone(), callable.descriptor(),
      callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags,
      Operator::kEliminatable);

  return TNode<Object>::UncheckedCast(Call(desc, HeapConstant(callable.code()),
                                           arg0, arg1, arg2, arg3, context));
}

1056
TNode<Object> JSCallReducerAssembler::JSCall3(
1057
    TNode<Object> function, TNode<Object> this_arg, TNode<Object> arg0,
1058
    TNode<Object> arg1, TNode<Object> arg2, FrameState frame_state) {
1059 1060
  JSCallNode n(node_ptr());
  CallParameters const& p = n.Parameters();
1061
  return MayThrow(_ {
1062
    return AddNode<Object>(graph()->NewNode(
1063 1064 1065
        javascript()->Call(JSCallNode::ArityForArgc(3), p.frequency(),
                           p.feedback(), ConvertReceiverMode::kAny,
                           p.speculation_mode(),
1066
                           CallFeedbackRelation::kUnrelated),
1067 1068
        function, this_arg, arg0, arg1, arg2, n.feedback_vector(),
        ContextInput(), frame_state, effect(), control()));
1069 1070 1071
  });
}

1072
TNode<Object> JSCallReducerAssembler::JSCall4(
1073 1074
    TNode<Object> function, TNode<Object> this_arg, TNode<Object> arg0,
    TNode<Object> arg1, TNode<Object> arg2, TNode<Object> arg3,
1075
    FrameState frame_state) {
1076 1077
  JSCallNode n(node_ptr());
  CallParameters const& p = n.Parameters();
1078
  return MayThrow(_ {
1079
    return AddNode<Object>(graph()->NewNode(
1080 1081 1082
        javascript()->Call(JSCallNode::ArityForArgc(4), p.frequency(),
                           p.feedback(), ConvertReceiverMode::kAny,
                           p.speculation_mode(),
1083
                           CallFeedbackRelation::kUnrelated),
1084 1085
        function, this_arg, arg0, arg1, arg2, arg3, n.feedback_vector(),
        ContextInput(), frame_state, effect(), control()));
1086 1087 1088
  });
}

1089
TNode<Object> JSCallReducerAssembler::JSCallRuntime2(
1090
    Runtime::FunctionId function_id, TNode<Object> arg0, TNode<Object> arg1,
1091
    FrameState frame_state) {
1092
  return MayThrow(_ {
1093 1094 1095
    return AddNode<Object>(
        graph()->NewNode(javascript()->CallRuntime(function_id, 2), arg0, arg1,
                         ContextInput(), frame_state, effect(), control()));
1096 1097 1098
  });
}

1099 1100
TNode<JSArray> JSCallReducerAssembler::CreateArrayNoThrow(
    TNode<Object> ctor, TNode<Number> size, FrameState frame_state) {
1101 1102
  return AddNode<JSArray>(graph()->NewNode(
      javascript()->CreateArray(1, MaybeHandle<AllocationSite>()), ctor, ctor,
1103
      size, ContextInput(), frame_state, effect(), control()));
1104
}
1105 1106
TNode<JSArray> JSCallReducerAssembler::AllocateEmptyJSArray(
    ElementsKind kind, const NativeContextRef& native_context) {
1107
  // TODO(jgruber): Port AllocationBuilder to JSGraphAssembler.
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
  MapRef map = native_context.GetInitialJSArrayMap(kind);

  AllocationBuilder ab(jsgraph(), effect(), control());
  ab.Allocate(map.instance_size(), AllocationType::kYoung, Type::Array());
  ab.Store(AccessBuilder::ForMap(), map);
  Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
  ab.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
           empty_fixed_array);
  ab.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
  ab.Store(AccessBuilder::ForJSArrayLength(kind), jsgraph()->ZeroConstant());
  for (int i = 0; i < map.GetInObjectProperties(); ++i) {
    ab.Store(AccessBuilder::ForJSObjectInObjectProperty(map, i),
             jsgraph()->UndefinedConstant());
  }
  Node* result = ab.Finish();
  InitializeEffectControl(result, control());
  return TNode<JSArray>::UncheckedCast(result);
}

1127
TNode<Object> JSCallReducerAssembler::ReduceMathUnary(const Operator* op) {
1128
  TNode<Object> input = Argument(0);
1129
  TNode<Number> input_as_number = SpeculativeToNumber(input);
1130
  return TNode<Object>::UncheckedCast(graph()->NewNode(op, input_as_number));
1131 1132 1133
}

TNode<Object> JSCallReducerAssembler::ReduceMathBinary(const Operator* op) {
1134 1135
  TNode<Object> left = Argument(0);
  TNode<Object> right = ArgumentOrNaN(1);
1136 1137
  TNode<Number> left_number = SpeculativeToNumber(left);
  TNode<Number> right_number = SpeculativeToNumber(right);
1138 1139
  return TNode<Object>::UncheckedCast(
      graph()->NewNode(op, left_number, right_number));
1140 1141 1142
}

TNode<String> JSCallReducerAssembler::ReduceStringPrototypeSubstring() {
1143 1144 1145
  TNode<Object> receiver = ReceiverInput();
  TNode<Object> start = Argument(0);
  TNode<Object> end = ArgumentOrUndefined(1);
1146

1147 1148
  TNode<String> receiver_string = CheckString(receiver);
  TNode<Number> start_smi = CheckSmi(start);
1149

1150
  TNode<Number> length = StringLength(receiver_string);
1151

1152 1153 1154 1155 1156
  TNode<Number> end_smi = SelectIf<Number>(IsUndefined(end))
                              .Then(_ { return length; })
                              .Else(_ { return CheckSmi(end); })
                              .ExpectFalse()
                              .Value();
1157

1158 1159 1160 1161 1162
  TNode<Number> zero = TNode<Number>::UncheckedCast(ZeroConstant());
  TNode<Number> finalStart = NumberMin(NumberMax(start_smi, zero), length);
  TNode<Number> finalEnd = NumberMin(NumberMax(end_smi, zero), length);
  TNode<Number> from = NumberMin(finalStart, finalEnd);
  TNode<Number> to = NumberMax(finalStart, finalEnd);
1163

1164
  return StringSubstring(receiver_string, from, to);
1165 1166 1167
}

TNode<String> JSCallReducerAssembler::ReduceStringPrototypeSlice() {
1168 1169 1170
  TNode<Object> receiver = ReceiverInput();
  TNode<Object> start = Argument(0);
  TNode<Object> end = ArgumentOrUndefined(1);
1171

1172 1173
  TNode<String> receiver_string = CheckString(receiver);
  TNode<Number> start_smi = CheckSmi(start);
1174

1175
  TNode<Number> length = StringLength(receiver_string);
1176

1177 1178 1179 1180 1181
  TNode<Number> end_smi = SelectIf<Number>(IsUndefined(end))
                              .Then(_ { return length; })
                              .Else(_ { return CheckSmi(end); })
                              .ExpectFalse()
                              .Value();
1182

1183 1184 1185
  TNode<Number> zero = TNode<Number>::UncheckedCast(ZeroConstant());
  TNode<Number> from_untyped =
      SelectIf<Number>(NumberLessThan(start_smi, zero))
1186 1187 1188 1189 1190 1191
          .Then(_ { return NumberMax(NumberAdd(length, start_smi), zero); })
          .Else(_ { return NumberMin(start_smi, length); })
          .ExpectFalse()
          .Value();
  // {from} is always in non-negative Smi range, but our typer cannot figure
  // that out yet.
1192
  TNode<Smi> from = TypeGuardUnsignedSmall(from_untyped);
1193

1194 1195
  TNode<Number> to_untyped =
      SelectIf<Number>(NumberLessThan(end_smi, zero))
1196 1197 1198
          .Then(_ { return NumberMax(NumberAdd(length, end_smi), zero); })
          .Else(_ { return NumberMin(end_smi, length); })
          .ExpectFalse()
1199
          .Value();
1200 1201
  // {to} is always in non-negative Smi range, but our typer cannot figure that
  // out yet.
1202 1203 1204 1205
  TNode<Smi> to = TypeGuardUnsignedSmall(to_untyped);

  return SelectIf<String>(NumberLessThan(from, to))
      .Then(_ { return StringSubstring(receiver_string, from, to); })
1206
      .Else(_ { return EmptyStringConstant(); })
1207 1208
      .ExpectTrue()
      .Value();
1209 1210
}

1211 1212 1213 1214 1215 1216 1217
namespace {

struct ForEachFrameStateParams {
  JSGraph* jsgraph;
  SharedFunctionInfoRef shared;
  TNode<Context> context;
  TNode<Object> target;
1218
  FrameState outer_frame_state;
1219 1220 1221 1222 1223 1224
  TNode<Object> receiver;
  TNode<Object> callback;
  TNode<Object> this_arg;
  TNode<Object> original_length;
};

1225 1226
FrameState ForEachLoopLazyFrameState(const ForEachFrameStateParams& params,
                                     TNode<Object> k) {
1227 1228 1229
  Builtins::Name builtin = Builtins::kArrayForEachLoopLazyDeoptContinuation;
  Node* checkpoint_params[] = {params.receiver, params.callback,
                               params.this_arg, k, params.original_length};
1230
  return CreateJavaScriptBuiltinContinuationFrameState(
1231 1232
      params.jsgraph, params.shared, builtin, params.target, params.context,
      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1233
      ContinuationFrameStateMode::LAZY);
1234 1235
}

1236 1237
FrameState ForEachLoopEagerFrameState(const ForEachFrameStateParams& params,
                                      TNode<Object> k) {
1238 1239 1240
  Builtins::Name builtin = Builtins::kArrayForEachLoopEagerDeoptContinuation;
  Node* checkpoint_params[] = {params.receiver, params.callback,
                               params.this_arg, k, params.original_length};
1241
  return CreateJavaScriptBuiltinContinuationFrameState(
1242 1243
      params.jsgraph, params.shared, builtin, params.target, params.context,
      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1244
      ContinuationFrameStateMode::EAGER);
1245
}
1246 1247 1248

}  // namespace

1249 1250
TNode<Object>
IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeForEach(
1251 1252
    MapInference* inference, const bool has_stability_dependency,
    ElementsKind kind, const SharedFunctionInfoRef& shared) {
1253
  FrameState outer_frame_state = FrameStateInput();
1254
  TNode<Context> context = ContextInput();
1255
  TNode<Object> target = TargetInput();
1256 1257 1258
  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
  TNode<Object> fncallback = ArgumentOrUndefined(0);
  TNode<Object> this_arg = ArgumentOrUndefined(1);
1259

1260
  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);
1261 1262 1263 1264 1265

  ForEachFrameStateParams frame_state_params{
      jsgraph(), shared,     context,  target,         outer_frame_state,
      receiver,  fncallback, this_arg, original_length};

1266 1267
  ThrowIfNotCallable(fncallback, ForEachLoopLazyFrameState(frame_state_params,
                                                           ZeroConstant()));
1268

1269
  ForZeroUntil(original_length).Do([&](TNode<Number> k) {
1270
    Checkpoint(ForEachLoopEagerFrameState(frame_state_params, k));
1271 1272 1273 1274

    // Deopt if the map has changed during the iteration.
    MaybeInsertMapChecks(inference, has_stability_dependency);

1275
    TNode<Object> element;
1276
    std::tie(k, element) = SafeLoadElement(kind, receiver, k);
1277 1278

    auto continue_label = MakeLabel();
1279
    element = MaybeSkipHole(element, kind, &continue_label);
1280

1281
    TNode<Number> next_k = NumberAdd(k, OneConstant());
1282
    JSCall3(fncallback, this_arg, element, k, receiver,
1283
            ForEachLoopLazyFrameState(frame_state_params, next_k));
1284 1285 1286 1287 1288

    Goto(&continue_label);
    Bind(&continue_label);
  });

1289
  return UndefinedConstant();
1290 1291
}

1292 1293 1294 1295 1296 1297 1298 1299
namespace {

struct ReduceFrameStateParams {
  JSGraph* jsgraph;
  SharedFunctionInfoRef shared;
  ArrayReduceDirection direction;
  TNode<Context> context;
  TNode<Object> target;
1300
  FrameState outer_frame_state;
1301 1302
};

1303 1304 1305 1306
FrameState ReducePreLoopLazyFrameState(const ReduceFrameStateParams& params,
                                       TNode<Object> receiver,
                                       TNode<Object> callback, TNode<Object> k,
                                       TNode<Number> original_length) {
1307 1308 1309 1310 1311
  Builtins::Name builtin =
      (params.direction == ArrayReduceDirection::kLeft)
          ? Builtins::kArrayReduceLoopLazyDeoptContinuation
          : Builtins::kArrayReduceRightLoopLazyDeoptContinuation;
  Node* checkpoint_params[] = {receiver, callback, k, original_length};
1312
  return CreateJavaScriptBuiltinContinuationFrameState(
1313 1314
      params.jsgraph, params.shared, builtin, params.target, params.context,
      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1315
      ContinuationFrameStateMode::LAZY);
1316 1317
}

1318 1319 1320 1321
FrameState ReducePreLoopEagerFrameState(const ReduceFrameStateParams& params,
                                        TNode<Object> receiver,
                                        TNode<Object> callback,
                                        TNode<Number> original_length) {
1322 1323 1324 1325 1326
  Builtins::Name builtin =
      (params.direction == ArrayReduceDirection::kLeft)
          ? Builtins::kArrayReducePreLoopEagerDeoptContinuation
          : Builtins::kArrayReduceRightPreLoopEagerDeoptContinuation;
  Node* checkpoint_params[] = {receiver, callback, original_length};
1327
  return CreateJavaScriptBuiltinContinuationFrameState(
1328 1329
      params.jsgraph, params.shared, builtin, params.target, params.context,
      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1330
      ContinuationFrameStateMode::EAGER);
1331 1332
}

1333 1334 1335 1336
FrameState ReduceLoopLazyFrameState(const ReduceFrameStateParams& params,
                                    TNode<Object> receiver,
                                    TNode<Object> callback, TNode<Object> k,
                                    TNode<Number> original_length) {
1337 1338 1339 1340 1341
  Builtins::Name builtin =
      (params.direction == ArrayReduceDirection::kLeft)
          ? Builtins::kArrayReduceLoopLazyDeoptContinuation
          : Builtins::kArrayReduceRightLoopLazyDeoptContinuation;
  Node* checkpoint_params[] = {receiver, callback, k, original_length};
1342
  return CreateJavaScriptBuiltinContinuationFrameState(
1343 1344
      params.jsgraph, params.shared, builtin, params.target, params.context,
      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1345
      ContinuationFrameStateMode::LAZY);
1346 1347
}

1348 1349 1350 1351 1352
FrameState ReduceLoopEagerFrameState(const ReduceFrameStateParams& params,
                                     TNode<Object> receiver,
                                     TNode<Object> callback, TNode<Object> k,
                                     TNode<Number> original_length,
                                     TNode<Object> accumulator) {
1353 1354 1355 1356 1357 1358
  Builtins::Name builtin =
      (params.direction == ArrayReduceDirection::kLeft)
          ? Builtins::kArrayReduceLoopEagerDeoptContinuation
          : Builtins::kArrayReduceRightLoopEagerDeoptContinuation;
  Node* checkpoint_params[] = {receiver, callback, k, original_length,
                               accumulator};
1359
  return CreateJavaScriptBuiltinContinuationFrameState(
1360 1361
      params.jsgraph, params.shared, builtin, params.target, params.context,
      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1362
      ContinuationFrameStateMode::EAGER);
1363 1364 1365 1366 1367 1368 1369 1370
}

}  // namespace

TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce(
    MapInference* inference, const bool has_stability_dependency,
    ElementsKind kind, ArrayReduceDirection direction,
    const SharedFunctionInfoRef& shared) {
1371
  FrameState outer_frame_state = FrameStateInput();
1372
  TNode<Context> context = ContextInput();
1373
  TNode<Object> target = TargetInput();
1374 1375
  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
  TNode<Object> fncallback = ArgumentOrUndefined(0);
1376 1377 1378 1379

  ReduceFrameStateParams frame_state_params{
      jsgraph(), shared, direction, context, target, outer_frame_state};

1380
  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);
1381 1382 1383

  // Set up variable behavior depending on the reduction kind (left/right).
  TNode<Number> k;
1384 1385
  StepFunction1 step;
  ConditionFunction1 cond;
1386 1387
  TNode<Number> zero = ZeroConstant();
  TNode<Number> one = OneConstant();
1388
  if (direction == ArrayReduceDirection::kLeft) {
1389 1390 1391
    k = zero;
    step = [&](TNode<Number> i) { return NumberAdd(i, one); };
    cond = [&](TNode<Number> i) { return NumberLessThan(i, original_length); };
1392
  } else {
1393 1394 1395
    k = NumberSubtract(original_length, one);
    step = [&](TNode<Number> i) { return NumberSubtract(i, one); };
    cond = [&](TNode<Number> i) { return NumberLessThanOrEqual(zero, i); };
1396 1397 1398 1399 1400 1401 1402 1403
  }

  ThrowIfNotCallable(
      fncallback, ReducePreLoopLazyFrameState(frame_state_params, receiver,
                                              fncallback, k, original_length));

  // Set initial accumulator value.
  TNode<Object> accumulator;
1404 1405
  if (ArgumentCount() > 1) {
    accumulator = Argument(1);  // Initial value specified by the user.
1406 1407 1408 1409 1410 1411 1412 1413
  } else {
    // The initial value was not specified by the user. In this case, the first
    // (or last in the case of reduceRight) non-holey value of the array is
    // used. Loop until we find it. If not found, trigger a deopt.
    // TODO(jgruber): The deopt does not seem necessary. Instead we could simply
    // throw the TypeError here from optimized code.
    auto found_initial_element = MakeLabel(MachineRepresentation::kTagged,
                                           MachineRepresentation::kTagged);
1414
    Forever(k, step).Do([&](TNode<Number> k) {
1415 1416 1417 1418 1419
      Checkpoint(ReducePreLoopEagerFrameState(frame_state_params, receiver,
                                              fncallback, original_length));
      CheckIf(cond(k), DeoptimizeReason::kNoInitialElement);

      TNode<Object> element;
1420
      std::tie(k, element) = SafeLoadElement(kind, receiver, k);
1421

1422 1423 1424 1425 1426
      auto continue_label = MakeLabel();
      GotoIf(HoleCheck(kind, element), &continue_label);
      Goto(&found_initial_element, k, TypeGuardNonInternal(element));

      Bind(&continue_label);
1427 1428 1429 1430 1431 1432
    });
    Unreachable();  // The loop is exited either by deopt or a jump to below.

    // TODO(jgruber): This manual fiddling with blocks could be avoided by
    // implementing a `break` mechanic for loop builders.
    Bind(&found_initial_element);
1433 1434
    k = step(found_initial_element.PhiAt<Number>(0));
    accumulator = found_initial_element.PhiAt<Object>(1);
1435 1436 1437 1438
  }

  TNode<Object> result =
      For1(k, cond, step, accumulator)
1439 1440 1441 1442
          .Do([&](TNode<Number> k, TNode<Object>* accumulator) {
            Checkpoint(ReduceLoopEagerFrameState(frame_state_params, receiver,
                                                 fncallback, k, original_length,
                                                 *accumulator));
1443 1444 1445 1446 1447

            // Deopt if the map has changed during the iteration.
            MaybeInsertMapChecks(inference, has_stability_dependency);

            TNode<Object> element;
1448
            std::tie(k, element) = SafeLoadElement(kind, receiver, k);
1449 1450

            auto continue_label = MakeLabel(MachineRepresentation::kTagged);
1451 1452
            element =
                MaybeSkipHole(element, kind, &continue_label, *accumulator);
1453

1454
            TNode<Number> next_k = step(k);
1455 1456 1457 1458
            TNode<Object> next_accumulator = JSCall4(
                fncallback, UndefinedConstant(), *accumulator, element, k,
                receiver,
                ReduceLoopLazyFrameState(frame_state_params, receiver,
1459
                                         fncallback, next_k, original_length));
1460 1461 1462
            Goto(&continue_label, next_accumulator);

            Bind(&continue_label);
1463
            *accumulator = continue_label.PhiAt<Object>(0);
1464 1465 1466 1467 1468 1469
          })
          .Value();

  return result;
}

1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484
namespace {

struct MapFrameStateParams {
  JSGraph* jsgraph;
  SharedFunctionInfoRef shared;
  TNode<Context> context;
  TNode<Object> target;
  FrameState outer_frame_state;
  TNode<Object> receiver;
  TNode<Object> callback;
  TNode<Object> this_arg;
  TNode<JSArray> a;
  TNode<Object> original_length;
};

1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495
FrameState MapPreLoopLazyFrameState(const MapFrameStateParams& params) {
  DCHECK(params.a.is_null());
  Node* checkpoint_params[] = {params.receiver, params.callback,
                               params.this_arg, params.original_length};
  return CreateJavaScriptBuiltinContinuationFrameState(
      params.jsgraph, params.shared,
      Builtins::kArrayMapPreLoopLazyDeoptContinuation, params.target,
      params.context, checkpoint_params, arraysize(checkpoint_params),
      params.outer_frame_state, ContinuationFrameStateMode::LAZY);
}

1496 1497 1498 1499 1500
FrameState MapLoopLazyFrameState(const MapFrameStateParams& params,
                                 TNode<Number> k) {
  Node* checkpoint_params[] = {
      params.receiver,       params.callback, params.this_arg, params.a, k,
      params.original_length};
1501
  return CreateJavaScriptBuiltinContinuationFrameState(
1502 1503 1504
      params.jsgraph, params.shared,
      Builtins::kArrayMapLoopLazyDeoptContinuation, params.target,
      params.context, checkpoint_params, arraysize(checkpoint_params),
1505
      params.outer_frame_state, ContinuationFrameStateMode::LAZY);
1506 1507 1508 1509 1510 1511 1512
}

FrameState MapLoopEagerFrameState(const MapFrameStateParams& params,
                                  TNode<Number> k) {
  Node* checkpoint_params[] = {
      params.receiver,       params.callback, params.this_arg, params.a, k,
      params.original_length};
1513
  return CreateJavaScriptBuiltinContinuationFrameState(
1514 1515 1516
      params.jsgraph, params.shared,
      Builtins::kArrayMapLoopEagerDeoptContinuation, params.target,
      params.context, checkpoint_params, arraysize(checkpoint_params),
1517
      params.outer_frame_state, ContinuationFrameStateMode::EAGER);
1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
}

}  // namespace

TNode<JSArray> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeMap(
    MapInference* inference, const bool has_stability_dependency,
    ElementsKind kind, const SharedFunctionInfoRef& shared,
    const NativeContextRef& native_context) {
  FrameState outer_frame_state = FrameStateInput();
  TNode<Context> context = ContextInput();
1528
  TNode<Object> target = TargetInput();
1529 1530 1531
  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
  TNode<Object> fncallback = ArgumentOrUndefined(0);
  TNode<Object> this_arg = ArgumentOrUndefined(1);
1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547

  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);

  // If the array length >= kMaxFastArrayLength, then CreateArray
  // will create a dictionary. We should deopt in this case, and make sure
  // not to attempt inlining again.
  original_length = CheckBounds(original_length,
                                NumberConstant(JSArray::kMaxFastArrayLength));

  // Even though {JSCreateArray} is not marked as {kNoThrow}, we can elide the
  // exceptional projections because it cannot throw with the given
  // parameters.
  TNode<Object> array_ctor =
      Constant(native_context.GetInitialJSArrayMap(kind).GetConstructor());

  MapFrameStateParams frame_state_params{
1548 1549 1550 1551 1552 1553 1554
      jsgraph(), shared,     context,  target,       outer_frame_state,
      receiver,  fncallback, this_arg, {} /* TBD */, original_length};

  TNode<JSArray> a =
      CreateArrayNoThrow(array_ctor, original_length,
                         MapPreLoopLazyFrameState(frame_state_params));
  frame_state_params.a = a;
1555 1556 1557 1558

  ThrowIfNotCallable(fncallback,
                     MapLoopLazyFrameState(frame_state_params, ZeroConstant()));

1559
  ForZeroUntil(original_length).Do([&](TNode<Number> k) {
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586
    Checkpoint(MapLoopEagerFrameState(frame_state_params, k));
    MaybeInsertMapChecks(inference, has_stability_dependency);

    TNode<Object> element;
    std::tie(k, element) = SafeLoadElement(kind, receiver, k);

    auto continue_label = MakeLabel();
    element = MaybeSkipHole(element, kind, &continue_label);

    TNode<Object> v = JSCall3(fncallback, this_arg, element, k, receiver,
                              MapLoopLazyFrameState(frame_state_params, k));

    // The array {a} should be HOLEY_SMI_ELEMENTS because we'd only come into
    // this loop if the input array length is non-zero, and "new Array({x > 0})"
    // always produces a HOLEY array.
    MapRef holey_double_map =
        native_context.GetInitialJSArrayMap(HOLEY_DOUBLE_ELEMENTS);
    MapRef holey_map = native_context.GetInitialJSArrayMap(HOLEY_ELEMENTS);
    TransitionAndStoreElement(holey_double_map, holey_map, a, k, v);

    Goto(&continue_label);
    Bind(&continue_label);
  });

  return a;
}

1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
namespace {

struct FilterFrameStateParams {
  JSGraph* jsgraph;
  SharedFunctionInfoRef shared;
  TNode<Context> context;
  TNode<Object> target;
  FrameState outer_frame_state;
  TNode<Object> receiver;
  TNode<Object> callback;
  TNode<Object> this_arg;
  TNode<JSArray> a;
  TNode<Object> original_length;
};

FrameState FilterLoopLazyFrameState(const FilterFrameStateParams& params,
                                    TNode<Number> k, TNode<Number> to,
                                    TNode<Object> element) {
  Node* checkpoint_params[] = {params.receiver,
                               params.callback,
                               params.this_arg,
                               params.a,
                               k,
                               params.original_length,
                               element,
                               to};
1613
  return CreateJavaScriptBuiltinContinuationFrameState(
1614 1615 1616
      params.jsgraph, params.shared,
      Builtins::kArrayFilterLoopLazyDeoptContinuation, params.target,
      params.context, checkpoint_params, arraysize(checkpoint_params),
1617
      params.outer_frame_state, ContinuationFrameStateMode::LAZY);
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
}

FrameState FilterLoopEagerPostCallbackFrameState(
    const FilterFrameStateParams& params, TNode<Number> k, TNode<Number> to,
    TNode<Object> element, TNode<Object> callback_value) {
  // Note that we are intentionally reusing the
  // Builtins::kArrayFilterLoopLazyDeoptContinuation as an *eager* entry point
  // in this case. This is safe, because re-evaluating a [ToBoolean] coercion is
  // safe.
  Node* checkpoint_params[] = {params.receiver,
                               params.callback,
                               params.this_arg,
                               params.a,
                               k,
                               params.original_length,
                               element,
                               to,
                               callback_value};
1636
  return CreateJavaScriptBuiltinContinuationFrameState(
1637 1638 1639
      params.jsgraph, params.shared,
      Builtins::kArrayFilterLoopLazyDeoptContinuation, params.target,
      params.context, checkpoint_params, arraysize(checkpoint_params),
1640
      params.outer_frame_state, ContinuationFrameStateMode::EAGER);
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651
}

FrameState FilterLoopEagerFrameState(const FilterFrameStateParams& params,
                                     TNode<Number> k, TNode<Number> to) {
  Node* checkpoint_params[] = {params.receiver,
                               params.callback,
                               params.this_arg,
                               params.a,
                               k,
                               params.original_length,
                               to};
1652
  return CreateJavaScriptBuiltinContinuationFrameState(
1653 1654 1655
      params.jsgraph, params.shared,
      Builtins::kArrayFilterLoopEagerDeoptContinuation, params.target,
      params.context, checkpoint_params, arraysize(checkpoint_params),
1656
      params.outer_frame_state, ContinuationFrameStateMode::EAGER);
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
}

}  // namespace

TNode<JSArray>
IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeFilter(
    MapInference* inference, const bool has_stability_dependency,
    ElementsKind kind, const SharedFunctionInfoRef& shared,
    const NativeContextRef& native_context) {
  FrameState outer_frame_state = FrameStateInput();
  TNode<Context> context = ContextInput();
1668
  TNode<Object> target = TargetInput();
1669 1670 1671
  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
  TNode<Object> fncallback = ArgumentOrUndefined(0);
  TNode<Object> this_arg = ArgumentOrUndefined(1);
1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692

  // The output array is packed (filter doesn't visit holes).
  const ElementsKind packed_kind = GetPackedElementsKind(kind);
  TNode<JSArray> a = AllocateEmptyJSArray(packed_kind, native_context);

  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);

  FilterFrameStateParams frame_state_params{
      jsgraph(), shared,     context,  target, outer_frame_state,
      receiver,  fncallback, this_arg, a,      original_length};

  // This frame state doesn't ever call the deopt continuation, it's only
  // necessary to specify a continuation in order to handle the exceptional
  // case. We don't have all the values available to completely fill out
  // the checkpoint parameters yet, but that's okay because it'll never be
  // called.
  TNode<Number> zero = ZeroConstant();
  ThrowIfNotCallable(fncallback, FilterLoopLazyFrameState(frame_state_params,
                                                          zero, zero, zero));

  TNode<Number> initial_a_length = zero;
1693
  For1ZeroUntil(original_length, initial_a_length)
1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739
      .Do([&](TNode<Number> k, TNode<Object>* a_length_object) {
        TNode<Number> a_length = TNode<Number>::UncheckedCast(*a_length_object);
        Checkpoint(FilterLoopEagerFrameState(frame_state_params, k, a_length));
        MaybeInsertMapChecks(inference, has_stability_dependency);

        TNode<Object> element;
        std::tie(k, element) = SafeLoadElement(kind, receiver, k);

        auto continue_label = MakeLabel(MachineRepresentation::kTaggedSigned);
        element = MaybeSkipHole(element, kind, &continue_label, a_length);

        TNode<Object> v = JSCall3(
            fncallback, this_arg, element, k, receiver,
            FilterLoopLazyFrameState(frame_state_params, k, a_length, element));

        // We need an eager frame state for right after the callback function
        // returned, just in case an attempt to grow the output array fails.
        Checkpoint(FilterLoopEagerPostCallbackFrameState(frame_state_params, k,
                                                         a_length, element, v));

        GotoIfNot(ToBoolean(v), &continue_label, a_length);

        // Since the callback returned a trueish value, store the element in a.
        {
          TNode<Number> a_length1 = TypeGuardFixedArrayLength(a_length);
          TNode<FixedArrayBase> elements = LoadElements(a);
          elements = MaybeGrowFastElements(kind, FeedbackSource{}, a, elements,
                                           a_length1,
                                           LoadFixedArrayBaseLength(elements));

          TNode<Number> new_a_length = NumberInc(a_length1);
          StoreJSArrayLength(a, new_a_length, kind);
          StoreFixedArrayBaseElement(elements, a_length1, element, kind);

          Goto(&continue_label, new_a_length);
        }

        Bind(&continue_label);
        *a_length_object =
            TNode<Object>::UncheckedCast(continue_label.PhiAt(0));
      })
      .ValueIsUnused();

  return a;
}

1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761
namespace {

struct FindFrameStateParams {
  JSGraph* jsgraph;
  SharedFunctionInfoRef shared;
  TNode<Context> context;
  TNode<Object> target;
  FrameState outer_frame_state;
  TNode<Object> receiver;
  TNode<Object> callback;
  TNode<Object> this_arg;
  TNode<Object> original_length;
};

FrameState FindLoopLazyFrameState(const FindFrameStateParams& params,
                                  TNode<Number> k, ArrayFindVariant variant) {
  Builtins::Name builtin =
      (variant == ArrayFindVariant::kFind)
          ? Builtins::kArrayFindLoopLazyDeoptContinuation
          : Builtins::kArrayFindIndexLoopLazyDeoptContinuation;
  Node* checkpoint_params[] = {params.receiver, params.callback,
                               params.this_arg, k, params.original_length};
1762
  return CreateJavaScriptBuiltinContinuationFrameState(
1763 1764
      params.jsgraph, params.shared, builtin, params.target, params.context,
      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1765
      ContinuationFrameStateMode::LAZY);
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775
}

FrameState FindLoopEagerFrameState(const FindFrameStateParams& params,
                                   TNode<Number> k, ArrayFindVariant variant) {
  Builtins::Name builtin =
      (variant == ArrayFindVariant::kFind)
          ? Builtins::kArrayFindLoopEagerDeoptContinuation
          : Builtins::kArrayFindIndexLoopEagerDeoptContinuation;
  Node* checkpoint_params[] = {params.receiver, params.callback,
                               params.this_arg, k, params.original_length};
1776
  return CreateJavaScriptBuiltinContinuationFrameState(
1777 1778
      params.jsgraph, params.shared, builtin, params.target, params.context,
      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1779
      ContinuationFrameStateMode::EAGER);
1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791
}

FrameState FindLoopAfterCallbackLazyFrameState(
    const FindFrameStateParams& params, TNode<Number> next_k,
    TNode<Object> if_found_value, ArrayFindVariant variant) {
  Builtins::Name builtin =
      (variant == ArrayFindVariant::kFind)
          ? Builtins::kArrayFindLoopAfterCallbackLazyDeoptContinuation
          : Builtins::kArrayFindIndexLoopAfterCallbackLazyDeoptContinuation;
  Node* checkpoint_params[] = {params.receiver,        params.callback,
                               params.this_arg,        next_k,
                               params.original_length, if_found_value};
1792
  return CreateJavaScriptBuiltinContinuationFrameState(
1793 1794
      params.jsgraph, params.shared, builtin, params.target, params.context,
      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1795
      ContinuationFrameStateMode::LAZY);
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805
}

}  // namespace

TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeFind(
    MapInference* inference, const bool has_stability_dependency,
    ElementsKind kind, const SharedFunctionInfoRef& shared,
    const NativeContextRef& native_context, ArrayFindVariant variant) {
  FrameState outer_frame_state = FrameStateInput();
  TNode<Context> context = ContextInput();
1806
  TNode<Object> target = TargetInput();
1807 1808 1809
  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
  TNode<Object> fncallback = ArgumentOrUndefined(0);
  TNode<Object> this_arg = ArgumentOrUndefined(1);
1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823

  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);

  FindFrameStateParams frame_state_params{
      jsgraph(), shared,     context,  target,         outer_frame_state,
      receiver,  fncallback, this_arg, original_length};

  ThrowIfNotCallable(
      fncallback,
      FindLoopLazyFrameState(frame_state_params, ZeroConstant(), variant));

  const bool is_find_variant = (variant == ArrayFindVariant::kFind);
  auto out = MakeLabel(MachineRepresentation::kTagged);

1824
  ForZeroUntil(original_length).Do([&](TNode<Number> k) {
1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856
    Checkpoint(FindLoopEagerFrameState(frame_state_params, k, variant));
    MaybeInsertMapChecks(inference, has_stability_dependency);

    TNode<Object> element;
    std::tie(k, element) = SafeLoadElement(kind, receiver, k);

    if (IsHoleyElementsKind(kind)) {
      element = TryConvertHoleToUndefined(element, kind);
    }

    TNode<Object> if_found_value = is_find_variant ? element : k;
    TNode<Number> next_k = NumberInc(k);

    // The callback result states whether the desired element was found.
    TNode<Object> v =
        JSCall3(fncallback, this_arg, element, k, receiver,
                FindLoopAfterCallbackLazyFrameState(frame_state_params, next_k,
                                                    if_found_value, variant));

    GotoIf(ToBoolean(v), &out, if_found_value);
  });

  // If the loop completed, the element was not found.
  TNode<Object> if_not_found_value =
      is_find_variant ? TNode<Object>::UncheckedCast(UndefinedConstant())
                      : TNode<Object>::UncheckedCast(MinusOneConstant());
  Goto(&out, if_not_found_value);

  Bind(&out);
  return out.PhiAt<Object>(0);
}

1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878
namespace {

struct EverySomeFrameStateParams {
  JSGraph* jsgraph;
  SharedFunctionInfoRef shared;
  TNode<Context> context;
  TNode<Object> target;
  FrameState outer_frame_state;
  TNode<Object> receiver;
  TNode<Object> callback;
  TNode<Object> this_arg;
  TNode<Object> original_length;
};

FrameState EverySomeLoopLazyFrameState(const EverySomeFrameStateParams& params,
                                       TNode<Number> k,
                                       ArrayEverySomeVariant variant) {
  Builtins::Name builtin = (variant == ArrayEverySomeVariant::kEvery)
                               ? Builtins::kArrayEveryLoopLazyDeoptContinuation
                               : Builtins::kArraySomeLoopLazyDeoptContinuation;
  Node* checkpoint_params[] = {params.receiver, params.callback,
                               params.this_arg, k, params.original_length};
1879
  return CreateJavaScriptBuiltinContinuationFrameState(
1880 1881
      params.jsgraph, params.shared, builtin, params.target, params.context,
      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1882
      ContinuationFrameStateMode::LAZY);
1883 1884 1885 1886 1887 1888 1889 1890 1891 1892
}

FrameState EverySomeLoopEagerFrameState(const EverySomeFrameStateParams& params,
                                        TNode<Number> k,
                                        ArrayEverySomeVariant variant) {
  Builtins::Name builtin = (variant == ArrayEverySomeVariant::kEvery)
                               ? Builtins::kArrayEveryLoopEagerDeoptContinuation
                               : Builtins::kArraySomeLoopEagerDeoptContinuation;
  Node* checkpoint_params[] = {params.receiver, params.callback,
                               params.this_arg, k, params.original_length};
1893
  return CreateJavaScriptBuiltinContinuationFrameState(
1894 1895
      params.jsgraph, params.shared, builtin, params.target, params.context,
      checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state,
1896
      ContinuationFrameStateMode::EAGER);
1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907
}

}  // namespace

TNode<Boolean>
IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeEverySome(
    MapInference* inference, const bool has_stability_dependency,
    ElementsKind kind, const SharedFunctionInfoRef& shared,
    const NativeContextRef& native_context, ArrayEverySomeVariant variant) {
  FrameState outer_frame_state = FrameStateInput();
  TNode<Context> context = ContextInput();
1908
  TNode<Object> target = TargetInput();
1909 1910 1911
  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
  TNode<Object> fncallback = ArgumentOrUndefined(0);
  TNode<Object> this_arg = ArgumentOrUndefined(1);
1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924

  TNode<Number> original_length = LoadJSArrayLength(receiver, kind);

  EverySomeFrameStateParams frame_state_params{
      jsgraph(), shared,     context,  target,         outer_frame_state,
      receiver,  fncallback, this_arg, original_length};

  ThrowIfNotCallable(
      fncallback,
      EverySomeLoopLazyFrameState(frame_state_params, ZeroConstant(), variant));

  auto out = MakeLabel(MachineRepresentation::kTagged);

1925
  ForZeroUntil(original_length).Do([&](TNode<Number> k) {
1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955
    Checkpoint(EverySomeLoopEagerFrameState(frame_state_params, k, variant));
    MaybeInsertMapChecks(inference, has_stability_dependency);

    TNode<Object> element;
    std::tie(k, element) = SafeLoadElement(kind, receiver, k);

    auto continue_label = MakeLabel();
    element = MaybeSkipHole(element, kind, &continue_label);

    TNode<Object> v =
        JSCall3(fncallback, this_arg, element, k, receiver,
                EverySomeLoopLazyFrameState(frame_state_params, k, variant));

    if (variant == ArrayEverySomeVariant::kEvery) {
      GotoIfNot(ToBoolean(v), &out, FalseConstant());
    } else {
      DCHECK_EQ(variant, ArrayEverySomeVariant::kSome);
      GotoIf(ToBoolean(v), &out, TrueConstant());
    }
    Goto(&continue_label);
    Bind(&continue_label);
  });

  Goto(&out, (variant == ArrayEverySomeVariant::kEvery) ? TrueConstant()
                                                        : FalseConstant());

  Bind(&out);
  return out.PhiAt<Boolean>(0);
}

1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003
namespace {

Callable GetCallableForArrayIndexOfIncludes(ArrayIndexOfIncludesVariant variant,
                                            ElementsKind elements_kind,
                                            Isolate* isolate) {
  if (variant == ArrayIndexOfIncludesVariant::kIndexOf) {
    switch (elements_kind) {
      case PACKED_SMI_ELEMENTS:
      case HOLEY_SMI_ELEMENTS:
      case PACKED_ELEMENTS:
      case HOLEY_ELEMENTS:
        return Builtins::CallableFor(isolate,
                                     Builtins::kArrayIndexOfSmiOrObject);
      case PACKED_DOUBLE_ELEMENTS:
        return Builtins::CallableFor(isolate,
                                     Builtins::kArrayIndexOfPackedDoubles);
      default:
        DCHECK_EQ(HOLEY_DOUBLE_ELEMENTS, elements_kind);
        return Builtins::CallableFor(isolate,
                                     Builtins::kArrayIndexOfHoleyDoubles);
    }
  } else {
    DCHECK_EQ(variant, ArrayIndexOfIncludesVariant::kIncludes);
    switch (elements_kind) {
      case PACKED_SMI_ELEMENTS:
      case HOLEY_SMI_ELEMENTS:
      case PACKED_ELEMENTS:
      case HOLEY_ELEMENTS:
        return Builtins::CallableFor(isolate,
                                     Builtins::kArrayIncludesSmiOrObject);
      case PACKED_DOUBLE_ELEMENTS:
        return Builtins::CallableFor(isolate,
                                     Builtins::kArrayIncludesPackedDoubles);
      default:
        DCHECK_EQ(HOLEY_DOUBLE_ELEMENTS, elements_kind);
        return Builtins::CallableFor(isolate,
                                     Builtins::kArrayIncludesHoleyDoubles);
    }
  }
  UNREACHABLE();
}

}  // namespace

TNode<Object>
IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeIndexOfIncludes(
    ElementsKind kind, ArrayIndexOfIncludesVariant variant) {
  TNode<Context> context = ContextInput();
2004 2005 2006
  TNode<JSArray> receiver = ReceiverInputAs<JSArray>();
  TNode<Object> search_element = ArgumentOrUndefined(0);
  TNode<Object> from_index = ArgumentOrZero(1);
2007 2008 2009 2010 2011 2012 2013 2014 2015

  // TODO(jgruber): This currently only reduces to a stub call. Create a full
  // reduction (similar to other higher-order array builtins) instead of
  // lowering to a builtin call. E.g. Array.p.every and Array.p.some have almost
  // identical functionality.

  TNode<Number> length = LoadJSArrayLength(receiver, kind);
  TNode<FixedArrayBase> elements = LoadElements(receiver);

2016
  const bool have_from_index = ArgumentCount() > 1;
2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037
  if (have_from_index) {
    TNode<Smi> from_index_smi = CheckSmi(from_index);

    // If the index is negative, it means the offset from the end and
    // therefore needs to be added to the length. If the result is still
    // negative, it needs to be clamped to 0.
    TNode<Boolean> cond = NumberLessThan(from_index_smi, ZeroConstant());
    from_index = SelectIf<Number>(cond)
                     .Then(_ {
                       return NumberMax(NumberAdd(length, from_index_smi),
                                        ZeroConstant());
                     })
                     .Else(_ { return from_index_smi; })
                     .ExpectFalse()
                     .Value();
  }

  return Call4(GetCallableForArrayIndexOfIncludes(variant, kind, isolate()),
               context, elements, search_element, length, from_index);
}

2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050
namespace {

struct PromiseCtorFrameStateParams {
  JSGraph* jsgraph;
  SharedFunctionInfoRef shared;
  Node* node_ptr;
  TNode<Context> context;
  TNode<Object> target;
  FrameState outer_frame_state;
};

// Remnant of old-style JSCallReducer code. Could be ported to graph assembler,
// but probably not worth the effort.
2051 2052 2053 2054 2055 2056 2057
FrameState CreateArtificialFrameState(Node* node, Node* outer_frame_state,
                                      int parameter_count, BailoutId bailout_id,
                                      FrameStateType frame_state_type,
                                      const SharedFunctionInfoRef& shared,
                                      Node* context,
                                      CommonOperatorBuilder* common,
                                      Graph* graph) {
2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079
  const FrameStateFunctionInfo* state_info =
      common->CreateFrameStateFunctionInfo(
          frame_state_type, parameter_count + 1, 0, shared.object());

  const Operator* op = common->FrameState(
      bailout_id, OutputFrameStateCombine::Ignore(), state_info);
  const Operator* op0 = common->StateValues(0, SparseInputMask::Dense());
  Node* node0 = graph->NewNode(op0);

  static constexpr int kTargetInputIndex = 0;
  static constexpr int kReceiverInputIndex = 1;
  const int parameter_count_with_receiver = parameter_count + 1;
  std::vector<Node*> params;
  params.reserve(parameter_count_with_receiver);
  for (int i = 0; i < parameter_count_with_receiver; i++) {
    params.push_back(node->InputAt(kReceiverInputIndex + i));
  }
  const Operator* op_param = common->StateValues(
      static_cast<int>(params.size()), SparseInputMask::Dense());
  Node* params_node = graph->NewNode(op_param, static_cast<int>(params.size()),
                                     &params.front());
  DCHECK(context);
2080 2081 2082
  return FrameState(graph->NewNode(op, params_node, node0, node0, context,
                                   node->InputAt(kTargetInputIndex),
                                   outer_frame_state));
2083 2084 2085 2086 2087 2088
}

FrameState PromiseConstructorFrameState(
    const PromiseCtorFrameStateParams& params, CommonOperatorBuilder* common,
    Graph* graph) {
  DCHECK_EQ(1, params.shared.internal_formal_parameter_count());
2089
  return CreateArtificialFrameState(
2090 2091
      params.node_ptr, params.outer_frame_state, 1,
      BailoutId::ConstructStubInvoke(), FrameStateType::kConstructStub,
2092
      params.shared, params.context, common, graph);
2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106
}

FrameState PromiseConstructorLazyFrameState(
    const PromiseCtorFrameStateParams& params,
    FrameState constructor_frame_state) {
  // The deopt continuation of this frame state is never called; the frame state
  // is only necessary to obtain the right stack trace.
  JSGraph* jsgraph = params.jsgraph;
  Node* checkpoint_params[] = {
      jsgraph->UndefinedConstant(), /* receiver */
      jsgraph->UndefinedConstant(), /* promise */
      jsgraph->UndefinedConstant(), /* reject function */
      jsgraph->TheHoleConstant()    /* exception */
  };
2107
  return CreateJavaScriptBuiltinContinuationFrameState(
2108 2109 2110
      jsgraph, params.shared,
      Builtins::kPromiseConstructorLazyDeoptContinuation, params.target,
      params.context, checkpoint_params, arraysize(checkpoint_params),
2111
      constructor_frame_state, ContinuationFrameStateMode::LAZY);
2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122
}

FrameState PromiseConstructorLazyWithCatchFrameState(
    const PromiseCtorFrameStateParams& params,
    FrameState constructor_frame_state, TNode<JSPromise> promise,
    TNode<JSFunction> reject) {
  // This continuation just returns the created promise and takes care of
  // exceptions thrown by the executor.
  Node* checkpoint_params[] = {
      params.jsgraph->UndefinedConstant(), /* receiver */
      promise, reject};
2123
  return CreateJavaScriptBuiltinContinuationFrameState(
2124 2125 2126
      params.jsgraph, params.shared,
      Builtins::kPromiseConstructorLazyDeoptContinuation, params.target,
      params.context, checkpoint_params, arraysize(checkpoint_params),
2127
      constructor_frame_state, ContinuationFrameStateMode::LAZY_WITH_CATCH);
2128 2129 2130 2131 2132 2133 2134 2135
}

}  // namespace

TNode<Object> PromiseBuiltinReducerAssembler::ReducePromiseConstructor(
    const NativeContextRef& native_context) {
  DCHECK_GE(ConstructArity(), 1);

2136
  JSConstructNode n(node_ptr());
2137 2138 2139
  FrameState outer_frame_state = FrameStateInput();
  TNode<Context> context = ContextInput();
  TNode<Object> target = TargetInput();
2140
  TNode<Object> executor = n.Argument(0);
2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173
  DCHECK_EQ(target, NewTargetInput());

  SharedFunctionInfoRef promise_shared =
      native_context.promise_function().shared();

  PromiseCtorFrameStateParams frame_state_params{jsgraph(),  promise_shared,
                                                 node_ptr(), context,
                                                 target,     outer_frame_state};

  // Insert a construct stub frame into the chain of frame states. This will
  // reconstruct the proper frame when deoptimizing within the constructor.
  // For the frame state, we only provide the executor parameter, even if more
  // arguments were passed. This is not observable from JS.
  FrameState constructor_frame_state =
      PromiseConstructorFrameState(frame_state_params, common(), graph());

  ThrowIfNotCallable(executor,
                     PromiseConstructorLazyFrameState(frame_state_params,
                                                      constructor_frame_state));

  TNode<JSPromise> promise = CreatePromise(context);

  // 8. CreatePromiseResolvingFunctions
  // Allocate a promise context for the closures below.
  TNode<Context> promise_context = CreateFunctionContext(
      native_context, context, PromiseBuiltins::kPromiseContextLength);
  StoreContextSlot(promise_context, PromiseBuiltins::kPromiseSlot, promise);
  StoreContextSlot(promise_context, PromiseBuiltins::kAlreadyResolvedSlot,
                   FalseConstant());
  StoreContextSlot(promise_context, PromiseBuiltins::kDebugEventSlot,
                   TrueConstant());

  // Allocate closures for the resolve and reject cases.
2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186
  SharedFunctionInfoRef resolve_sfi(
      broker_, broker_->isolate()
                   ->factory()
                   ->promise_capability_default_resolve_shared_fun());
  TNode<JSFunction> resolve =
      CreateClosureFromBuiltinSharedFunctionInfo(resolve_sfi, promise_context);

  SharedFunctionInfoRef reject_sfi(
      broker_, broker_->isolate()
                   ->factory()
                   ->promise_capability_default_reject_shared_fun());
  TNode<JSFunction> reject =
      CreateClosureFromBuiltinSharedFunctionInfo(reject_sfi, promise_context);
2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202

  FrameState lazy_with_catch_frame_state =
      PromiseConstructorLazyWithCatchFrameState(
          frame_state_params, constructor_frame_state, promise, reject);

  // 9. Call executor with both resolving functions.
  // 10a. Call reject if the call to executor threw.
  Try(_ {
    CallPromiseExecutor(executor, resolve, reject, lazy_with_catch_frame_state);
  }).Catch([&](TNode<Object> exception) {
    CallPromiseReject(reject, exception, lazy_with_catch_frame_state);
  });

  return promise;
}

2203 2204
#undef _

2205 2206 2207 2208
bool JSCallReducer::should_disallow_heap_access() const {
  return broker_->is_concurrent_inlining();
}

2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221
Reduction JSCallReducer::ReplaceWithSubgraph(JSCallReducerAssembler* gasm,
                                             Node* subgraph) {
  // TODO(jgruber): Consider a less fiddly way of integrating the new subgraph
  // into the outer graph. For instance, the subgraph could be created in
  // complete isolation, and then plugged into the outer graph in one go.
  // Instead of manually tracking IfException nodes, we could iterate the
  // subgraph.

  // Replace the Call node with the newly-produced subgraph.
  ReplaceWithValue(gasm->node_ptr(), subgraph, gasm->effect(), gasm->control());

  // Wire exception edges contained in the newly-produced subgraph into the
  // outer graph.
2222 2223
  auto catch_scope = gasm->catch_scope();
  DCHECK(catch_scope->is_outermost());
2224

2225 2226 2227 2228 2229 2230 2231 2232 2233 2234
  if (catch_scope->has_handler() &&
      catch_scope->has_exceptional_control_flow()) {
    TNode<Object> handler_exception;
    Effect handler_effect{nullptr};
    Control handler_control{nullptr};
    gasm->catch_scope()->MergeExceptionalPaths(
        &handler_exception, &handler_effect, &handler_control);

    ReplaceWithValue(gasm->outermost_handler(), handler_exception,
                     handler_effect, handler_control);
2235 2236 2237 2238 2239
  }

  return Replace(subgraph);
}

2240
Reduction JSCallReducer::ReduceMathUnary(Node* node, const Operator* op) {
2241 2242
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
2243 2244 2245
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
2246
  if (n.ArgumentCount() < 1) {
2247 2248 2249 2250 2251
    Node* value = jsgraph()->NaNConstant();
    ReplaceWithValue(node, value);
    return Replace(value);
  }

2252
  JSCallReducerAssembler a(this, node);
2253 2254
  Node* subgraph = a.ReduceMathUnary(op);
  return ReplaceWithSubgraph(&a, subgraph);
2255 2256 2257
}

Reduction JSCallReducer::ReduceMathBinary(Node* node, const Operator* op) {
2258 2259
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
2260 2261 2262
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
2263
  if (n.ArgumentCount() < 1) {
2264 2265 2266 2267 2268
    Node* value = jsgraph()->NaNConstant();
    ReplaceWithValue(node, value);
    return Replace(value);
  }

2269
  JSCallReducerAssembler a(this, node);
2270 2271
  Node* subgraph = a.ReduceMathBinary(op);
  return ReplaceWithSubgraph(&a, subgraph);
2272 2273 2274 2275
}

// ES6 section 20.2.2.19 Math.imul ( x, y )
Reduction JSCallReducer::ReduceMathImul(Node* node) {
2276 2277
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
2278 2279 2280
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
2281
  if (n.ArgumentCount() < 1) {
2282 2283 2284 2285
    Node* value = jsgraph()->ZeroConstant();
    ReplaceWithValue(node, value);
    return Replace(value);
  }
2286 2287 2288 2289
  Node* left = n.Argument(0);
  Node* right = n.ArgumentOr(1, jsgraph()->ZeroConstant());
  Effect effect = n.effect();
  Control control = n.control();
2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307

  left = effect =
      graph()->NewNode(simplified()->SpeculativeToNumber(
                           NumberOperationHint::kNumberOrOddball, p.feedback()),
                       left, effect, control);
  right = effect =
      graph()->NewNode(simplified()->SpeculativeToNumber(
                           NumberOperationHint::kNumberOrOddball, p.feedback()),
                       right, effect, control);
  left = graph()->NewNode(simplified()->NumberToUint32(), left);
  right = graph()->NewNode(simplified()->NumberToUint32(), right);
  Node* value = graph()->NewNode(simplified()->NumberImul(), left, right);
  ReplaceWithValue(node, value, effect);
  return Replace(value);
}

// ES6 section 20.2.2.11 Math.clz32 ( x )
Reduction JSCallReducer::ReduceMathClz32(Node* node) {
2308 2309
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
2310 2311 2312
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
2313
  if (n.ArgumentCount() < 1) {
2314
    Node* value = jsgraph()->Constant(32);
2315 2316 2317
    ReplaceWithValue(node, value);
    return Replace(value);
  }
2318 2319 2320
  Node* input = n.Argument(0);
  Effect effect = n.effect();
  Control control = n.control();
2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335

  input = effect =
      graph()->NewNode(simplified()->SpeculativeToNumber(
                           NumberOperationHint::kNumberOrOddball, p.feedback()),
                       input, effect, control);
  input = graph()->NewNode(simplified()->NumberToUint32(), input);
  Node* value = graph()->NewNode(simplified()->NumberClz32(), input);
  ReplaceWithValue(node, value, effect);
  return Replace(value);
}

// ES6 section 20.2.2.24 Math.max ( value1, value2, ...values )
// ES6 section 20.2.2.25 Math.min ( value1, value2, ...values )
Reduction JSCallReducer::ReduceMathMinMax(Node* node, const Operator* op,
                                          Node* empty_value) {
2336 2337
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
2338 2339 2340
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
2341
  if (n.ArgumentCount() < 1) {
2342 2343 2344 2345 2346 2347 2348 2349 2350
    ReplaceWithValue(node, empty_value);
    return Replace(empty_value);
  }
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);

  Node* value = effect =
      graph()->NewNode(simplified()->SpeculativeToNumber(
                           NumberOperationHint::kNumberOrOddball, p.feedback()),
2351 2352
                       n.Argument(0), effect, control);
  for (int i = 1; i < n.ArgumentCount(); i++) {
2353 2354 2355
    Node* input = effect = graph()->NewNode(
        simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
                                          p.feedback()),
2356
        n.Argument(i), effect, control);
2357 2358 2359 2360 2361 2362 2363
    value = graph()->NewNode(op, value, input);
  }

  ReplaceWithValue(node, value, effect);
  return Replace(value);
}

2364
Reduction JSCallReducer::Reduce(Node* node) {
2365
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
2366

2367
  switch (node->opcode()) {
2368 2369
    case IrOpcode::kJSConstruct:
      return ReduceJSConstruct(node);
2370 2371
    case IrOpcode::kJSConstructWithArrayLike:
      return ReduceJSConstructWithArrayLike(node);
2372 2373
    case IrOpcode::kJSConstructWithSpread:
      return ReduceJSConstructWithSpread(node);
2374 2375
    case IrOpcode::kJSCall:
      return ReduceJSCall(node);
2376 2377
    case IrOpcode::kJSCallWithArrayLike:
      return ReduceJSCallWithArrayLike(node);
2378 2379
    case IrOpcode::kJSCallWithSpread:
      return ReduceJSCallWithSpread(node);
2380 2381
    default:
      break;
2382 2383 2384 2385
  }
  return NoChange();
}

2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402
void JSCallReducer::Finalize() {
  // TODO(turbofan): This is not the best solution; ideally we would be able
  // to teach the GraphReducer about arbitrary dependencies between different
  // nodes, even if they don't show up in the use list of the other node.
  std::set<Node*> const waitlist = std::move(waitlist_);
  for (Node* node : waitlist) {
    if (!node->IsDead()) {
      Reduction const reduction = Reduce(node);
      if (reduction.Changed()) {
        Node* replacement = reduction.replacement();
        if (replacement != node) {
          Replace(node, replacement);
        }
      }
    }
  }
}
2403

2404 2405
// ES6 section 22.1.1 The Array Constructor
Reduction JSCallReducer::ReduceArrayConstructor(Node* node) {
2406
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
2407

2408 2409 2410
  JSCallNode n(node);
  Node* target = n.target();
  CallParameters const& p = n.Parameters();
2411 2412

  // Turn the {node} into a {JSCreateArray} call.
2413
  size_t const arity = p.arity_without_implicit_args();
2414
  node->RemoveInput(n.FeedbackVectorIndex());
2415 2416
  NodeProperties::ReplaceValueInput(node, target, 0);
  NodeProperties::ReplaceValueInput(node, target, 1);
2417 2418
  NodeProperties::ChangeOp(
      node, javascript()->CreateArray(arity, MaybeHandle<AllocationSite>()));
2419 2420 2421
  return Changed(node);
}

2422 2423
// ES6 section 19.3.1.1 Boolean ( value )
Reduction JSCallReducer::ReduceBooleanConstructor(Node* node) {
2424
  // Replace the {node} with a proper {ToBoolean} operator.
2425 2426
  JSCallNode n(node);
  Node* value = n.ArgumentOrUndefined(0, jsgraph());
2427
  value = graph()->NewNode(simplified()->ToBoolean(), value);
2428 2429 2430
  ReplaceWithValue(node, value);
  return Replace(value);
}
2431

2432 2433
// ES section #sec-object-constructor
Reduction JSCallReducer::ReduceObjectConstructor(Node* node) {
2434 2435 2436 2437
  JSCallNode n(node);
  if (n.ArgumentCount() < 1) return NoChange();
  Node* value = n.Argument(0);
  Effect effect = n.effect();
2438 2439

  // We can fold away the Object(x) call if |x| is definitely not a primitive.
2440 2441
  if (NodeProperties::CanBePrimitive(broker(), value, effect)) {
    if (!NodeProperties::CanBeNullOrUndefined(broker(), value, effect)) {
2442 2443 2444 2445 2446
      // Turn the {node} into a {JSToObject} call if we know that
      // the {value} cannot be null or undefined.
      NodeProperties::ReplaceValueInputs(node, value);
      NodeProperties::ChangeOp(node, javascript()->ToObject());
      return Changed(node);
2447
    }
2448 2449
  } else {
    ReplaceWithValue(node, value);
2450
    return Replace(value);
2451
  }
2452
  return NoChange();
2453 2454
}

2455 2456
// ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray )
Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
2457
  DisallowHeapAccessIf no_heap_access(should_disallow_heap_access());
2458

2459 2460 2461
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
  int arity = p.arity_without_implicit_args();
2462
  ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny;
2463
  if (arity == 0) {
2464 2465
    // Neither thisArg nor argArray was provided.
    convert_mode = ConvertReceiverMode::kNullOrUndefined;
2466 2467
    node->ReplaceInput(n.TargetIndex(), n.receiver());
    node->ReplaceInput(n.ReceiverIndex(), jsgraph()->UndefinedConstant());
2468
  } else if (arity == 1) {
2469
    // The argArray was not provided, just remove the {target}.
2470
    node->RemoveInput(n.TargetIndex());
2471
    --arity;
2472
  } else {
2473 2474 2475 2476 2477 2478 2479
    Node* target = n.receiver();
    Node* this_argument = n.Argument(0);
    Node* arguments_list = n.Argument(1);
    Node* context = n.context();
    FrameState frame_state = n.frame_state();
    Effect effect = n.effect();
    Control control = n.control();
2480 2481 2482

    // If {arguments_list} cannot be null or undefined, we don't need
    // to expand this {node} to control-flow.
2483
    if (!NodeProperties::CanBeNullOrUndefined(broker(), arguments_list,
2484
                                              effect)) {
2485
      // Massage the value inputs appropriately.
2486 2487 2488 2489
      node->ReplaceInput(n.TargetIndex(), target);
      node->ReplaceInput(n.ReceiverIndex(), this_argument);
      node->ReplaceInput(n.ArgumentIndex(0), arguments_list);
      while (arity-- > 1) node->RemoveInput(n.ArgumentIndex(1));
2490 2491

      // Morph the {node} to a {JSCallWithArrayLike}.
2492 2493 2494 2495
      NodeProperties::ChangeOp(
          node, javascript()->CallWithArrayLike(
                    p.frequency(), p.feedback(), p.speculation_mode(),
                    CallFeedbackRelation::kUnrelated));
2496
      return Changed(node).FollowedBy(ReduceJSCallWithArrayLike(node));
2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520
    } else {
      // Check whether {arguments_list} is null.
      Node* check_null =
          graph()->NewNode(simplified()->ReferenceEqual(), arguments_list,
                           jsgraph()->NullConstant());
      control = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                 check_null, control);
      Node* if_null = graph()->NewNode(common()->IfTrue(), control);
      control = graph()->NewNode(common()->IfFalse(), control);

      // Check whether {arguments_list} is undefined.
      Node* check_undefined =
          graph()->NewNode(simplified()->ReferenceEqual(), arguments_list,
                           jsgraph()->UndefinedConstant());
      control = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                 check_undefined, control);
      Node* if_undefined = graph()->NewNode(common()->IfTrue(), control);
      control = graph()->NewNode(common()->IfFalse(), control);

      // Lower to {JSCallWithArrayLike} if {arguments_list} is neither null
      // nor undefined.
      Node* effect0 = effect;
      Node* control0 = control;
      Node* value0 = effect0 = control0 = graph()->NewNode(
2521 2522 2523
          javascript()->CallWithArrayLike(p.frequency(), p.feedback(),
                                          p.speculation_mode(),
                                          CallFeedbackRelation::kUnrelated),
2524 2525
          target, this_argument, arguments_list, n.feedback_vector(), context,
          frame_state, effect0, control0);
2526 2527 2528 2529 2530

      // Lower to {JSCall} if {arguments_list} is either null or undefined.
      Node* effect1 = effect;
      Node* control1 =
          graph()->NewNode(common()->Merge(2), if_null, if_undefined);
2531 2532 2533 2534
      Node* value1 = effect1 = control1 =
          graph()->NewNode(javascript()->Call(JSCallNode::ArityForArgc(0)),
                           target, this_argument, n.feedback_vector(), context,
                           frame_state, effect1, control1);
2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555

      // Rewire potential exception edges.
      Node* if_exception = nullptr;
      if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
        // Create appropriate {IfException} and {IfSuccess} nodes.
        Node* if_exception0 =
            graph()->NewNode(common()->IfException(), control0, effect0);
        control0 = graph()->NewNode(common()->IfSuccess(), control0);
        Node* if_exception1 =
            graph()->NewNode(common()->IfException(), control1, effect1);
        control1 = graph()->NewNode(common()->IfSuccess(), control1);

        // Join the exception edges.
        Node* merge =
            graph()->NewNode(common()->Merge(2), if_exception0, if_exception1);
        Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception0,
                                      if_exception1, merge);
        Node* phi =
            graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                             if_exception0, if_exception1, merge);
        ReplaceWithValue(if_exception, phi, ephi, merge);
2556
      }
2557 2558 2559 2560 2561 2562 2563 2564 2565 2566

      // Join control paths.
      control = graph()->NewNode(common()->Merge(2), control0, control1);
      effect =
          graph()->NewNode(common()->EffectPhi(2), effect0, effect1, control);
      Node* value =
          graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                           value0, value1, control);
      ReplaceWithValue(node, value, effect, control);
      return Replace(value);
2567 2568
    }
  }
2569
  // Change {node} to the new {JSCall} operator.
2570
  NodeProperties::ChangeOp(
2571
      node, javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(),
2572
                               p.feedback(), convert_mode, p.speculation_mode(),
2573
                               CallFeedbackRelation::kUnrelated));
2574
  // Try to further reduce the JSCall {node}.
2575
  return Changed(node).FollowedBy(ReduceJSCall(node));
2576 2577
}

2578 2579
// ES section #sec-function.prototype.bind
Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
2580
  DisallowHeapAccessIf no_heap_access(should_disallow_heap_access());
2581

2582 2583
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
2584 2585 2586 2587
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

2588 2589 2590 2591 2592
  // Value inputs to the {node} are as follows:
  //
  //  - target, which is Function.prototype.bind JSFunction
  //  - receiver, which is the [[BoundTargetFunction]]
  //  - bound_this (optional), which is the [[BoundThis]]
2593
  //  - and all the remaining value inputs are [[BoundArguments]]
2594 2595 2596 2597
  Node* receiver = n.receiver();
  Node* context = n.context();
  Effect effect = n.effect();
  Control control = n.control();
2598 2599 2600 2601 2602

  // Ensure that the {receiver} is known to be a JSBoundFunction or
  // a JSFunction with the same [[Prototype]], and all maps we've
  // seen for the {receiver} so far indicate that {receiver} is
  // definitely a constructor or not a constructor.
2603
  MapInference inference(broker(), receiver, effect);
2604
  if (!inference.HaveMaps()) return NoChange();
2605 2606
  MapHandles const& receiver_maps = inference.GetMaps();

2607
  MapRef first_receiver_map(broker(), receiver_maps[0]);
2608
  bool const is_constructor = first_receiver_map.is_constructor();
2609

2610 2611
  if (should_disallow_heap_access() &&
      !first_receiver_map.serialized_prototype()) {
2612 2613 2614
    TRACE_BROKER_MISSING(broker(),
                         "serialized prototype on map " << first_receiver_map);
    return inference.NoChange();
2615
  }
2616 2617 2618 2619
  ObjectRef const prototype = first_receiver_map.prototype();
  for (Handle<Map> const map : receiver_maps) {
    MapRef receiver_map(broker(), map);

2620
    if (should_disallow_heap_access() && !receiver_map.serialized_prototype()) {
2621 2622 2623
      TRACE_BROKER_MISSING(broker(),
                           "serialized prototype on map " << receiver_map);
      return inference.NoChange();
2624 2625
    }

2626 2627
    // Check for consistency among the {receiver_maps}.
    STATIC_ASSERT(LAST_TYPE == LAST_FUNCTION_TYPE);
2628 2629 2630
    if (!receiver_map.prototype().equals(prototype) ||
        receiver_map.is_constructor() != is_constructor ||
        receiver_map.instance_type() < FIRST_FUNCTION_TYPE) {
2631
      return inference.NoChange();
2632
    }
2633 2634 2635

    // Disallow binding of slow-mode functions. We need to figure out
    // whether the length and name property are in the original state.
2636
    if (receiver_map.is_dictionary_map()) return inference.NoChange();
2637 2638 2639 2640 2641 2642

    // Check whether the length and name properties are still present
    // as AccessorInfo objects. In that case, their values can be
    // recomputed even if the actual value of the object changes.
    // This mirrors the checks done in builtins-function-gen.cc at
    // runtime otherwise.
2643 2644
    int minimum_nof_descriptors = std::max({JSFunction::kLengthDescriptorIndex,
                                            JSFunction::kNameDescriptorIndex}) +
2645
                                  1;
2646
    if (receiver_map.NumberOfOwnDescriptors() < minimum_nof_descriptors) {
2647
      return inference.NoChange();
2648
    }
2649 2650 2651 2652
    const InternalIndex kLengthIndex(JSFunction::kLengthDescriptorIndex);
    const InternalIndex kNameIndex(JSFunction::kNameDescriptorIndex);
    if (!receiver_map.serialized_own_descriptor(kLengthIndex) ||
        !receiver_map.serialized_own_descriptor(kNameIndex)) {
2653 2654
      TRACE_BROKER_MISSING(broker(),
                           "serialized descriptors on map " << receiver_map);
2655
      return inference.NoChange();
2656
    }
2657 2658 2659 2660
    ReadOnlyRoots roots(isolate());
    StringRef length_string(broker(), roots.length_string_handle());
    StringRef name_string(broker(), roots.name_string_handle());

2661 2662 2663 2664
    base::Optional<ObjectRef> length_value(
        receiver_map.GetStrongValue(kLengthIndex));
    base::Optional<ObjectRef> name_value(
        receiver_map.GetStrongValue(kNameIndex));
2665 2666 2667 2668 2669
    if (!length_value || !name_value) {
      TRACE_BROKER_MISSING(
          broker(), "name or length descriptors on map " << receiver_map);
      return inference.NoChange();
    }
2670
    if (!receiver_map.GetPropertyKey(kLengthIndex).equals(length_string) ||
2671
        !length_value->IsAccessorInfo() ||
2672
        !receiver_map.GetPropertyKey(kNameIndex).equals(name_string) ||
2673
        !name_value->IsAccessorInfo()) {
2674
      return inference.NoChange();
2675 2676 2677
    }
  }

2678 2679
  // Choose the map for the resulting JSBoundFunction (but bail out in case of a
  // custom prototype).
2680 2681 2682
  MapRef map = is_constructor
                   ? native_context().bound_function_with_constructor_map()
                   : native_context().bound_function_without_constructor_map();
2683
  if (!map.prototype().equals(prototype)) return inference.NoChange();
2684

2685 2686
  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
                                      control, p.feedback());
2687 2688

  // Replace the {node} with a JSCreateBoundFunction.
2689 2690 2691 2692 2693 2694
  static constexpr int kBoundThis = 1;
  static constexpr int kReceiverContextEffectAndControl = 4;
  int const arity = n.ArgumentCount();
  int const arity_with_bound_this = std::max(arity, kBoundThis);
  int const input_count =
      arity_with_bound_this + kReceiverContextEffectAndControl;
2695
  Node** inputs = graph()->zone()->NewArray<Node*>(input_count);
2696 2697 2698 2699 2700 2701 2702 2703 2704 2705
  int cursor = 0;
  inputs[cursor++] = receiver;
  inputs[cursor++] = n.ArgumentOrUndefined(0, jsgraph());  // bound_this.
  for (int i = 1; i < arity; ++i) {
    inputs[cursor++] = n.Argument(i);
  }
  inputs[cursor++] = context;
  inputs[cursor++] = effect;
  inputs[cursor++] = control;
  DCHECK_EQ(cursor, input_count);
2706
  Node* value = effect =
2707 2708
      graph()->NewNode(javascript()->CreateBoundFunction(
                           arity_with_bound_this - kBoundThis, map.object()),
2709
                       input_count, inputs);
2710 2711 2712
  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
}
2713 2714 2715

// ES6 section 19.2.3.3 Function.prototype.call (thisArg, ...args)
Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
2716
  DisallowHeapAccessIf no_heap_access(should_disallow_heap_access());
2717

2718 2719 2720 2721 2722
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
  Node* target = n.target();
  Effect effect = n.effect();
  Control control = n.control();
2723

2724 2725
  // Change context of {node} to the Function.prototype.call context,
  // to ensure any exception is thrown in the correct context.
2726 2727
  Node* context;
  HeapObjectMatcher m(target);
2728
  if (m.HasResolvedValue() && m.Ref(broker()).IsJSFunction()) {
2729
    JSFunctionRef function = m.Ref(broker()).AsJSFunction();
2730
    if (should_disallow_heap_access() && !function.serialized()) {
2731 2732 2733
      TRACE_BROKER_MISSING(broker(), "Serialize call on function " << function);
      return NoChange();
    }
2734
    context = jsgraph()->Constant(function.context());
2735 2736 2737 2738 2739 2740 2741 2742
  } else {
    context = effect = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
        effect, control);
  }
  NodeProperties::ReplaceContextInput(node, context);
  NodeProperties::ReplaceEffectInput(node, effect);

2743 2744 2745
  // Remove the target from {node} and use the receiver as target instead, and
  // the thisArg becomes the new target.  If thisArg was not provided, insert
  // undefined instead.
2746
  int arity = p.arity_without_implicit_args();
2747
  ConvertReceiverMode convert_mode;
2748
  if (arity == 0) {
2749 2750
    // The thisArg was not provided, use undefined as receiver.
    convert_mode = ConvertReceiverMode::kNullOrUndefined;
2751 2752
    node->ReplaceInput(n.TargetIndex(), n.receiver());
    node->ReplaceInput(n.ReceiverIndex(), jsgraph()->UndefinedConstant());
2753 2754 2755
  } else {
    // Just remove the target, which is the first value input.
    convert_mode = ConvertReceiverMode::kAny;
2756
    node->RemoveInput(n.TargetIndex());
2757 2758 2759
    --arity;
  }
  NodeProperties::ChangeOp(
2760
      node, javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(),
2761
                               p.feedback(), convert_mode, p.speculation_mode(),
2762
                               CallFeedbackRelation::kUnrelated));
2763
  // Try to further reduce the JSCall {node}.
2764
  return Changed(node).FollowedBy(ReduceJSCall(node));
2765 2766
}

2767 2768
// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] (V)
Reduction JSCallReducer::ReduceFunctionPrototypeHasInstance(Node* node) {
2769 2770 2771 2772 2773 2774 2775
  JSCallNode n(node);
  Node* receiver = n.receiver();
  Node* object = n.ArgumentOrUndefined(0, jsgraph());
  Node* context = n.context();
  FrameState frame_state = n.frame_state();
  Effect effect = n.effect();
  Control control = n.control();
2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793

  // TODO(turbofan): If JSOrdinaryToInstance raises an exception, the
  // stack trace doesn't contain the @@hasInstance call; we have the
  // corresponding bug in the baseline case. Some massaging of the frame
  // state would be necessary here.

  // Morph this {node} into a JSOrdinaryHasInstance node.
  node->ReplaceInput(0, receiver);
  node->ReplaceInput(1, object);
  node->ReplaceInput(2, context);
  node->ReplaceInput(3, frame_state);
  node->ReplaceInput(4, effect);
  node->ReplaceInput(5, control);
  node->TrimInputCount(6);
  NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
  return Changed(node);
}

2794
Reduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) {
2795
  Node* effect = NodeProperties::GetEffectInput(node);
2796

2797
  // Try to determine the {object} map.
2798
  MapInference inference(broker(), object, effect);
2799
  if (!inference.HaveMaps()) return NoChange();
2800 2801 2802
  MapHandles const& object_maps = inference.GetMaps();

  MapRef candidate_map(broker(), object_maps[0]);
2803
  if (should_disallow_heap_access() && !candidate_map.serialized_prototype()) {
2804 2805 2806
    TRACE_BROKER_MISSING(broker(), "prototype for map " << candidate_map);
    return inference.NoChange();
  }
2807 2808 2809 2810 2811
  ObjectRef candidate_prototype = candidate_map.prototype();

  // Check if we can constant-fold the {candidate_prototype}.
  for (size_t i = 0; i < object_maps.size(); ++i) {
    MapRef object_map(broker(), object_maps[i]);
2812
    if (should_disallow_heap_access() && !object_map.serialized_prototype()) {
2813 2814 2815
      TRACE_BROKER_MISSING(broker(), "prototype for map " << object_map);
      return inference.NoChange();
    }
2816 2817 2818 2819 2820 2821
    if (IsSpecialReceiverInstanceType(object_map.instance_type()) ||
        !object_map.prototype().equals(candidate_prototype)) {
      // We exclude special receivers, like JSProxy or API objects that
      // might require access checks here; we also don't want to deal
      // with hidden prototypes at this point.
      return inference.NoChange();
2822
    }
2823 2824 2825
    // The above check also excludes maps for primitive values, which is
    // important because we are not applying [[ToObject]] here as expected.
    DCHECK(!object_map.IsPrimitiveMap() && object_map.IsJSReceiverMap());
2826
  }
2827 2828 2829 2830 2831 2832
  if (!inference.RelyOnMapsViaStability(dependencies())) {
    return inference.NoChange();
  }
  Node* value = jsgraph()->Constant(candidate_prototype);
  ReplaceWithValue(node, value);
  return Replace(value);
2833
}
2834

2835 2836
// ES6 section 19.1.2.11 Object.getPrototypeOf ( O )
Reduction JSCallReducer::ReduceObjectGetPrototypeOf(Node* node) {
2837 2838
  JSCallNode n(node);
  Node* object = n.ArgumentOrUndefined(0, jsgraph());
2839 2840 2841
  return ReduceObjectGetPrototype(node, object);
}

2842 2843
// ES section #sec-object.is
Reduction JSCallReducer::ReduceObjectIs(Node* node) {
2844 2845 2846
  JSCallNode n(node);
  Node* lhs = n.ArgumentOrUndefined(0, jsgraph());
  Node* rhs = n.ArgumentOrUndefined(1, jsgraph());
2847 2848 2849 2850 2851
  Node* value = graph()->NewNode(simplified()->SameValue(), lhs, rhs);
  ReplaceWithValue(node, value);
  return Replace(value);
}

2852 2853
// ES6 section B.2.2.1.1 get Object.prototype.__proto__
Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) {
2854 2855
  JSCallNode n(node);
  return ReduceObjectGetPrototype(node, n.receiver());
2856 2857
}

2858 2859
// ES #sec-object.prototype.hasownproperty
Reduction JSCallReducer::ReduceObjectPrototypeHasOwnProperty(Node* node) {
2860 2861 2862 2863 2864
  JSCallNode n(node);
  Node* receiver = n.receiver();
  Node* name = n.ArgumentOrUndefined(0, jsgraph());
  Effect effect = n.effect();
  Control control = n.control();
2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884

  // We can optimize a call to Object.prototype.hasOwnProperty if it's being
  // used inside a fast-mode for..in, so for code like this:
  //
  //   for (name in receiver) {
  //     if (receiver.hasOwnProperty(name)) {
  //        ...
  //     }
  //   }
  //
  // If the for..in is in fast-mode, we know that the {receiver} has {name}
  // as own property, otherwise the enumeration wouldn't include it. The graph
  // constructed by the BytecodeGraphBuilder in this case looks like this:

  // receiver
  //  ^    ^
  //  |    |
  //  |    +-+
  //  |      |
  //  |   JSToObject
2885 2886 2887 2888 2889 2890
  //  |      ^
  //  |      |
  //  |   JSForInNext
  //  |      ^
  //  +----+ |
  //       | |
2891 2892
  //  JSCall[hasOwnProperty]

2893 2894
  // We can constant-fold the {node} to True in this case, and insert
  // a (potentially redundant) map check to guard the fact that the
2895 2896 2897 2898
  // {receiver} map didn't change since the dominating JSForInNext. This
  // map check is only necessary when TurboFan cannot prove that there
  // is no observable side effect between the {JSForInNext} and the
  // {JSCall} to Object.prototype.hasOwnProperty.
2899 2900 2901 2902
  //
  // Also note that it's safe to look through the {JSToObject}, since the
  // Object.prototype.hasOwnProperty does an implicit ToObject anyway, and
  // these operations are not observable.
2903
  if (name->opcode() == IrOpcode::kJSForInNext) {
2904 2905 2906 2907
    JSForInNextNode n(name);
    if (n.Parameters().mode() != ForInMode::kGeneric) {
      Node* object = n.receiver();
      Node* cache_type = n.cache_type();
2908 2909 2910 2911
      if (object->opcode() == IrOpcode::kJSToObject) {
        object = NodeProperties::GetValueInput(object, 0);
      }
      if (object == receiver) {
2912 2913 2914 2915 2916 2917 2918 2919
        // No need to repeat the map check if we can prove that there's no
        // observable side effect between {effect} and {name].
        if (!NodeProperties::NoObservableSideEffectBetween(effect, name)) {
          Node* receiver_map = effect =
              graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
                               receiver, effect, control);
          Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
                                         receiver_map, cache_type);
2920
          effect = graph()->NewNode(
2921
              simplified()->CheckIf(DeoptimizeReason::kWrongMap), check, effect,
2922
              control);
2923
        }
2924 2925 2926 2927 2928 2929 2930 2931 2932 2933
        Node* value = jsgraph()->TrueConstant();
        ReplaceWithValue(node, value, effect, control);
        return Replace(value);
      }
    }
  }

  return NoChange();
}

2934 2935
// ES #sec-object.prototype.isprototypeof
Reduction JSCallReducer::ReduceObjectPrototypeIsPrototypeOf(Node* node) {
2936
  DisallowHeapAccessIf no_heap_access(should_disallow_heap_access());
2937

2938 2939 2940 2941
  JSCallNode n(node);
  Node* receiver = n.receiver();
  Node* value = n.ArgumentOrUndefined(0, jsgraph());
  Effect effect = n.effect();
2942 2943 2944

  // Ensure that the {receiver} is known to be a JSReceiver (so that
  // the ToObject step of Object.prototype.isPrototypeOf is a no-op).
2945 2946
  MapInference inference(broker(), receiver, effect);
  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAreJSReceiver()) {
2947
    return NoChange();
2948 2949 2950 2951 2952 2953
  }

  // We don't check whether {value} is a proper JSReceiver here explicitly,
  // and don't explicitly rule out Primitive {value}s, since all of them
  // have null as their prototype, so the prototype chain walk inside the
  // JSHasInPrototypeChain operator immediately aborts and yields false.
2954 2955 2956
  NodeProperties::ReplaceValueInput(node, value, n.TargetIndex());
  for (int i = node->op()->ValueInputCount(); i > 2; i--) {
    node->RemoveInput(2);
2957 2958 2959 2960 2961
  }
  NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain());
  return Changed(node);
}

2962 2963
// ES6 section 26.1.1 Reflect.apply ( target, thisArgument, argumentsList )
Reduction JSCallReducer::ReduceReflectApply(Node* node) {
2964 2965
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
2966
  int arity = p.arity_without_implicit_args();
2967
  // Massage value inputs appropriately.
2968 2969 2970
  STATIC_ASSERT(n.ReceiverIndex() > n.TargetIndex());
  node->RemoveInput(n.ReceiverIndex());
  node->RemoveInput(n.TargetIndex());
2971 2972 2973 2974 2975 2976
  while (arity < 3) {
    node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant());
  }
  while (arity-- > 3) {
    node->RemoveInput(arity);
  }
2977 2978 2979 2980
  NodeProperties::ChangeOp(
      node, javascript()->CallWithArrayLike(p.frequency(), p.feedback(),
                                            p.speculation_mode(),
                                            CallFeedbackRelation::kUnrelated));
2981
  return Changed(node).FollowedBy(ReduceJSCallWithArrayLike(node));
2982 2983
}

2984 2985
// ES6 section 26.1.2 Reflect.construct ( target, argumentsList [, newTarget] )
Reduction JSCallReducer::ReduceReflectConstruct(Node* node) {
2986 2987
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
2988
  int arity = p.arity_without_implicit_args();
2989
  // Massage value inputs appropriately.
2990 2991 2992 2993
  Node* arg_target = n.ArgumentOrUndefined(0, jsgraph());
  Node* arg_argument_list = n.ArgumentOrUndefined(1, jsgraph());
  Node* arg_new_target = n.ArgumentOr(2, arg_target);

2994 2995 2996
  STATIC_ASSERT(n.ReceiverIndex() > n.TargetIndex());
  node->RemoveInput(n.ReceiverIndex());
  node->RemoveInput(n.TargetIndex());
2997 2998 2999 3000 3001

  // TODO(jgruber): This pattern essentially ensures that we have the correct
  // number of inputs for a given argument count. Wrap it in a helper function.
  STATIC_ASSERT(JSConstructNode::FirstArgumentIndex() == 2);
  while (arity < 3) {
3002 3003 3004 3005 3006
    node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant());
  }
  while (arity-- > 3) {
    node->RemoveInput(arity);
  }
3007 3008 3009 3010 3011 3012 3013 3014

  STATIC_ASSERT(JSConstructNode::TargetIndex() == 0);
  STATIC_ASSERT(JSConstructNode::NewTargetIndex() == 1);
  STATIC_ASSERT(JSConstructNode::kFeedbackVectorIsLastInput);
  node->ReplaceInput(JSConstructNode::TargetIndex(), arg_target);
  node->ReplaceInput(JSConstructNode::NewTargetIndex(), arg_new_target);
  node->ReplaceInput(JSConstructNode::ArgumentIndex(0), arg_argument_list);

3015 3016
  NodeProperties::ChangeOp(
      node, javascript()->ConstructWithArrayLike(p.frequency(), p.feedback()));
3017
  return Changed(node).FollowedBy(ReduceJSConstructWithArrayLike(node));
3018 3019
}

3020 3021
// ES6 section 26.1.7 Reflect.getPrototypeOf ( target )
Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) {
3022 3023
  JSCallNode n(node);
  Node* target = n.ArgumentOrUndefined(0, jsgraph());
3024 3025 3026
  return ReduceObjectGetPrototype(node, target);
}

3027 3028
// ES6 section #sec-object.create Object.create(proto, properties)
Reduction JSCallReducer::ReduceObjectCreate(Node* node) {
3029 3030
  JSCallNode n(node);
  Node* properties = n.ArgumentOrUndefined(1, jsgraph());
3031 3032
  if (properties != jsgraph()->UndefinedConstant()) return NoChange();

3033 3034 3035 3036 3037
  Node* context = n.context();
  FrameState frame_state = n.frame_state();
  Effect effect = n.effect();
  Control control = n.control();
  Node* prototype = n.ArgumentOrUndefined(0, jsgraph());
3038 3039 3040 3041 3042 3043 3044 3045 3046 3047
  node->ReplaceInput(0, prototype);
  node->ReplaceInput(1, context);
  node->ReplaceInput(2, frame_state);
  node->ReplaceInput(3, effect);
  node->ReplaceInput(4, control);
  node->TrimInputCount(5);
  NodeProperties::ChangeOp(node, javascript()->CreateObject());
  return Changed(node);
}

3048 3049
// ES section #sec-reflect.get
Reduction JSCallReducer::ReduceReflectGet(Node* node) {
3050 3051
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
3052
  int arity = p.arity_without_implicit_args();
3053
  if (arity != 2) return NoChange();
3054 3055 3056 3057 3058 3059
  Node* target = n.Argument(0);
  Node* key = n.Argument(1);
  Node* context = n.context();
  FrameState frame_state = n.frame_state();
  Effect effect = n.effect();
  Control control = n.control();
3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071

  // Check whether {target} is a JSReceiver.
  Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), target);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  // Throw an appropriate TypeError if the {target} is not a JSReceiver.
  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  {
    if_false = efalse = graph()->NewNode(
        javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
3072 3073
        jsgraph()->Constant(
            static_cast<int>(MessageTemplate::kCalledOnNonObject)),
3074 3075
        jsgraph()->HeapConstant(factory()->ReflectGet_string()), context,
        frame_state, efalse, if_false);
3076 3077 3078 3079 3080 3081 3082
  }

  // Otherwise just use the existing GetPropertyStub.
  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue;
  {
3083 3084
    Callable callable =
        Builtins::CallableFor(isolate(), Builtins::kGetProperty);
3085
    auto call_descriptor = Linkage::GetStubCallDescriptor(
3086 3087
        graph()->zone(), callable.descriptor(),
        callable.descriptor().GetStackParameterCount(),
3088
        CallDescriptor::kNeedsFrameState, Operator::kNoProperties);
3089 3090
    Node* stub_code = jsgraph()->HeapConstant(callable.code());
    vtrue = etrue = if_true =
3091 3092
        graph()->NewNode(common()->Call(call_descriptor), stub_code, target,
                         key, context, frame_state, etrue, if_true);
3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122
  }

  // Rewire potential exception edges.
  Node* on_exception = nullptr;
  if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
    // Create appropriate {IfException} and {IfSuccess} nodes.
    Node* extrue = graph()->NewNode(common()->IfException(), etrue, if_true);
    if_true = graph()->NewNode(common()->IfSuccess(), if_true);
    Node* exfalse = graph()->NewNode(common()->IfException(), efalse, if_false);
    if_false = graph()->NewNode(common()->IfSuccess(), if_false);

    // Join the exception edges.
    Node* merge = graph()->NewNode(common()->Merge(2), extrue, exfalse);
    Node* ephi =
        graph()->NewNode(common()->EffectPhi(2), extrue, exfalse, merge);
    Node* phi =
        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                         extrue, exfalse, merge);
    ReplaceWithValue(on_exception, phi, ephi, merge);
  }

  // Connect the throwing path to end.
  if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
  NodeProperties::MergeControlToEnd(graph(), common(), if_false);

  // Continue on the regular path.
  ReplaceWithValue(node, vtrue, etrue, if_true);
  return Changed(vtrue);
}

3123 3124
// ES section #sec-reflect.has
Reduction JSCallReducer::ReduceReflectHas(Node* node) {
3125 3126 3127 3128 3129 3130 3131
  JSCallNode n(node);
  Node* target = n.ArgumentOrUndefined(0, jsgraph());
  Node* key = n.ArgumentOrUndefined(1, jsgraph());
  Node* context = n.context();
  Effect effect = n.effect();
  Control control = n.control();
  FrameState frame_state = n.frame_state();
3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143

  // Check whether {target} is a JSReceiver.
  Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), target);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  // Throw an appropriate TypeError if the {target} is not a JSReceiver.
  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  {
    if_false = efalse = graph()->NewNode(
        javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
3144 3145
        jsgraph()->Constant(
            static_cast<int>(MessageTemplate::kCalledOnNonObject)),
3146 3147
        jsgraph()->HeapConstant(factory()->ReflectHas_string()), context,
        frame_state, efalse, if_false);
3148 3149 3150 3151 3152 3153 3154
  }

  // Otherwise just use the existing {JSHasProperty} logic.
  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue;
  {
3155
    // TODO(magardn): collect feedback so this can be optimized
3156 3157 3158
    vtrue = etrue = if_true = graph()->NewNode(
        javascript()->HasProperty(FeedbackSource()), target, key,
        jsgraph()->UndefinedConstant(), context, frame_state, etrue, if_true);
3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188
  }

  // Rewire potential exception edges.
  Node* on_exception = nullptr;
  if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
    // Create appropriate {IfException} and {IfSuccess} nodes.
    Node* extrue = graph()->NewNode(common()->IfException(), etrue, if_true);
    if_true = graph()->NewNode(common()->IfSuccess(), if_true);
    Node* exfalse = graph()->NewNode(common()->IfException(), efalse, if_false);
    if_false = graph()->NewNode(common()->IfSuccess(), if_false);

    // Join the exception edges.
    Node* merge = graph()->NewNode(common()->Merge(2), extrue, exfalse);
    Node* ephi =
        graph()->NewNode(common()->EffectPhi(2), extrue, exfalse, merge);
    Node* phi =
        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                         extrue, exfalse, merge);
    ReplaceWithValue(on_exception, phi, ephi, merge);
  }

  // Connect the throwing path to end.
  if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
  NodeProperties::MergeControlToEnd(graph(), common(), if_false);

  // Continue on the regular path.
  ReplaceWithValue(node, vtrue, etrue, if_true);
  return Changed(vtrue);
}

3189 3190
namespace {
bool CanInlineArrayIteratingBuiltin(JSHeapBroker* broker,
3191
                                    MapHandles const& receiver_maps,
3192 3193 3194 3195 3196
                                    ElementsKind* kind_return) {
  DCHECK_NE(0, receiver_maps.size());
  *kind_return = MapRef(broker, receiver_maps[0]).elements_kind();
  for (auto receiver_map : receiver_maps) {
    MapRef map(broker, receiver_map);
3197 3198
    if (!map.supports_fast_array_iteration() ||
        !UnionElementsKindUptoSize(kind_return, map.elements_kind())) {
3199 3200 3201 3202 3203
      return false;
    }
  }
  return true;
}
3204

3205 3206 3207 3208
bool CanInlineArrayResizingBuiltin(JSHeapBroker* broker,
                                   MapHandles const& receiver_maps,
                                   std::vector<ElementsKind>* kinds,
                                   bool builtin_is_push = false) {
3209 3210 3211 3212
  DCHECK_NE(0, receiver_maps.size());
  for (auto receiver_map : receiver_maps) {
    MapRef map(broker, receiver_map);
    if (!map.supports_fast_array_resize()) return false;
3213 3214 3215 3216 3217 3218
    // TODO(turbofan): We should also handle fast holey double elements once
    // we got the hole NaN mess sorted out in TurboFan/V8.
    if (map.elements_kind() == HOLEY_DOUBLE_ELEMENTS && !builtin_is_push) {
      return false;
    }
    ElementsKind current_kind = map.elements_kind();
3219
    auto kind_ptr = kinds->data();
3220
    size_t i;
3221
    for (i = 0; i < kinds->size(); i++, kind_ptr++) {
3222 3223
      if (UnionElementsKindUptoPackedness(kind_ptr, current_kind)) {
        break;
3224 3225
      }
    }
3226
    if (i == kinds->size()) kinds->push_back(current_kind);
3227 3228 3229
  }
  return true;
}
3230

3231 3232 3233 3234 3235 3236
// Wraps common setup code for iterating array builtins.
class IteratingArrayBuiltinHelper {
 public:
  IteratingArrayBuiltinHelper(Node* node, JSHeapBroker* broker,
                              JSGraph* jsgraph,
                              CompilationDependencies* dependencies)
3237
      : receiver_(NodeProperties::GetValueInput(node, 1)),
3238 3239 3240 3241 3242 3243 3244 3245 3246 3247
        effect_(NodeProperties::GetEffectInput(node)),
        control_(NodeProperties::GetControlInput(node)),
        inference_(broker, receiver_, effect_) {
    if (!FLAG_turbo_inline_array_builtins) return;

    DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
    const CallParameters& p = CallParametersOf(node->op());
    if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
      return;
    }
3248

3249 3250 3251
    // Try to determine the {receiver} map.
    if (!inference_.HaveMaps()) return;
    MapHandles const& receiver_maps = inference_.GetMaps();
3252

3253 3254 3255 3256
    if (!CanInlineArrayIteratingBuiltin(broker, receiver_maps,
                                        &elements_kind_)) {
      return;
    }
3257

3258
    // TODO(jgruber): May only be needed for holey elements kinds.
3259 3260 3261
    if (!dependencies->DependOnNoElementsProtector()) UNREACHABLE();
    has_stability_dependency_ = inference_.RelyOnMapsPreferStability(
        dependencies, jsgraph, &effect_, control_, p.feedback());
3262

3263
    can_reduce_ = true;
3264
  }
3265

3266 3267
  bool can_reduce() const { return can_reduce_; }
  bool has_stability_dependency() const { return has_stability_dependency_; }
3268 3269
  Effect effect() const { return effect_; }
  Control control() const { return control_; }
3270 3271
  MapInference* inference() { return &inference_; }
  ElementsKind elements_kind() const { return elements_kind_; }
3272

3273 3274 3275 3276
 private:
  bool can_reduce_ = false;
  bool has_stability_dependency_ = false;
  Node* receiver_;
3277 3278
  Effect effect_;
  Control control_;
3279 3280 3281 3282 3283 3284 3285 3286
  MapInference inference_;
  ElementsKind elements_kind_;
};

}  // namespace

Reduction JSCallReducer::ReduceArrayForEach(
    Node* node, const SharedFunctionInfoRef& shared) {
3287
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
3288 3289
  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
  if (!h.can_reduce()) return h.inference()->NoChange();
3290

3291
  IteratingArrayBuiltinReducerAssembler a(this, node);
3292
  a.InitializeEffectControl(h.effect(), h.control());
3293
  TNode<Object> subgraph = a.ReduceArrayPrototypeForEach(
3294
      h.inference(), h.has_stability_dependency(), h.elements_kind(), shared);
3295
  return ReplaceWithSubgraph(&a, subgraph);
3296
}
3297

3298
Reduction JSCallReducer::ReduceArrayReduce(
3299 3300 3301 3302
    Node* node, const SharedFunctionInfoRef& shared) {
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
  if (!h.can_reduce()) return h.inference()->NoChange();
3303

3304
  IteratingArrayBuiltinReducerAssembler a(this, node);
3305 3306 3307 3308 3309 3310
  a.InitializeEffectControl(h.effect(), h.control());
  TNode<Object> subgraph = a.ReduceArrayPrototypeReduce(
      h.inference(), h.has_stability_dependency(), h.elements_kind(),
      ArrayReduceDirection::kLeft, shared);
  return ReplaceWithSubgraph(&a, subgraph);
}
3311

3312 3313 3314 3315 3316
Reduction JSCallReducer::ReduceArrayReduceRight(
    Node* node, const SharedFunctionInfoRef& shared) {
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
  if (!h.can_reduce()) return h.inference()->NoChange();
3317

3318
  IteratingArrayBuiltinReducerAssembler a(this, node);
3319 3320 3321 3322 3323
  a.InitializeEffectControl(h.effect(), h.control());
  TNode<Object> subgraph = a.ReduceArrayPrototypeReduce(
      h.inference(), h.has_stability_dependency(), h.elements_kind(),
      ArrayReduceDirection::kRight, shared);
  return ReplaceWithSubgraph(&a, subgraph);
3324
}
3325

3326
Reduction JSCallReducer::ReduceArrayMap(Node* node,
3327
                                        const SharedFunctionInfoRef& shared) {
3328
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
3329 3330
  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
  if (!h.can_reduce()) return h.inference()->NoChange();
3331

3332
  // Calls CreateArray and thus requires this additional protector dependency.
3333 3334
  if (!dependencies()->DependOnArraySpeciesProtector()) {
    return h.inference()->NoChange();
3335 3336
  }

3337
  IteratingArrayBuiltinReducerAssembler a(this, node);
3338
  a.InitializeEffectControl(h.effect(), h.control());
3339

3340 3341 3342 3343
  TNode<Object> subgraph =
      a.ReduceArrayPrototypeMap(h.inference(), h.has_stability_dependency(),
                                h.elements_kind(), shared, native_context());
  return ReplaceWithSubgraph(&a, subgraph);
3344 3345
}

3346 3347
Reduction JSCallReducer::ReduceArrayFilter(
    Node* node, const SharedFunctionInfoRef& shared) {
3348
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
3349 3350
  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
  if (!h.can_reduce()) return h.inference()->NoChange();
3351

3352 3353 3354
  // Calls CreateArray and thus requires this additional protector dependency.
  if (!dependencies()->DependOnArraySpeciesProtector()) {
    return h.inference()->NoChange();
3355 3356
  }

3357
  IteratingArrayBuiltinReducerAssembler a(this, node);
3358
  a.InitializeEffectControl(h.effect(), h.control());
3359

3360 3361 3362 3363
  TNode<Object> subgraph =
      a.ReduceArrayPrototypeFilter(h.inference(), h.has_stability_dependency(),
                                   h.elements_kind(), shared, native_context());
  return ReplaceWithSubgraph(&a, subgraph);
3364 3365
}

3366
Reduction JSCallReducer::ReduceArrayFind(Node* node,
3367
                                         const SharedFunctionInfoRef& shared) {
3368
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
3369 3370
  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
  if (!h.can_reduce()) return h.inference()->NoChange();
3371

3372
  IteratingArrayBuiltinReducerAssembler a(this, node);
3373
  a.InitializeEffectControl(h.effect(), h.control());
3374

3375 3376 3377 3378 3379
  TNode<Object> subgraph = a.ReduceArrayPrototypeFind(
      h.inference(), h.has_stability_dependency(), h.elements_kind(), shared,
      native_context(), ArrayFindVariant::kFind);
  return ReplaceWithSubgraph(&a, subgraph);
}
3380

3381 3382
Reduction JSCallReducer::ReduceArrayFindIndex(
    Node* node, const SharedFunctionInfoRef& shared) {
3383
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
3384 3385
  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
  if (!h.can_reduce()) return h.inference()->NoChange();
3386

3387
  IteratingArrayBuiltinReducerAssembler a(this, node);
3388
  a.InitializeEffectControl(h.effect(), h.control());
3389

3390 3391 3392 3393
  TNode<Object> subgraph = a.ReduceArrayPrototypeFind(
      h.inference(), h.has_stability_dependency(), h.elements_kind(), shared,
      native_context(), ArrayFindVariant::kFindIndex);
  return ReplaceWithSubgraph(&a, subgraph);
3394 3395
}

3396
Reduction JSCallReducer::ReduceArrayEvery(Node* node,
3397
                                          const SharedFunctionInfoRef& shared) {
3398
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
3399 3400
  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
  if (!h.can_reduce()) return h.inference()->NoChange();
3401

3402
  IteratingArrayBuiltinReducerAssembler a(this, node);
3403
  a.InitializeEffectControl(h.effect(), h.control());
3404

3405 3406 3407 3408
  TNode<Object> subgraph = a.ReduceArrayPrototypeEverySome(
      h.inference(), h.has_stability_dependency(), h.elements_kind(), shared,
      native_context(), ArrayEverySomeVariant::kEvery);
  return ReplaceWithSubgraph(&a, subgraph);
3409 3410
}

3411 3412
// ES7 Array.prototype.inludes(searchElement[, fromIndex])
// #sec-array.prototype.includes
3413
Reduction JSCallReducer::ReduceArrayIncludes(Node* node) {
3414
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
3415 3416
  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
  if (!h.can_reduce()) return h.inference()->NoChange();
3417

3418
  IteratingArrayBuiltinReducerAssembler a(this, node);
3419
  a.InitializeEffectControl(h.effect(), h.control());
3420

3421 3422 3423 3424
  TNode<Object> subgraph = a.ReduceArrayPrototypeIndexOfIncludes(
      h.elements_kind(), ArrayIndexOfIncludesVariant::kIncludes);
  return ReplaceWithSubgraph(&a, subgraph);
}
3425

3426 3427 3428
// ES6 Array.prototype.indexOf(searchElement[, fromIndex])
// #sec-array.prototype.indexof
Reduction JSCallReducer::ReduceArrayIndexOf(Node* node) {
3429
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
3430 3431
  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
  if (!h.can_reduce()) return h.inference()->NoChange();
3432

3433
  IteratingArrayBuiltinReducerAssembler a(this, node);
3434
  a.InitializeEffectControl(h.effect(), h.control());
3435

3436 3437 3438
  TNode<Object> subgraph = a.ReduceArrayPrototypeIndexOfIncludes(
      h.elements_kind(), ArrayIndexOfIncludesVariant::kIndexOf);
  return ReplaceWithSubgraph(&a, subgraph);
3439 3440
}

3441
Reduction JSCallReducer::ReduceArraySome(Node* node,
3442
                                         const SharedFunctionInfoRef& shared) {
3443
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
3444 3445
  IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies());
  if (!h.can_reduce()) return h.inference()->NoChange();
3446

3447
  IteratingArrayBuiltinReducerAssembler a(this, node);
3448
  a.InitializeEffectControl(h.effect(), h.control());
3449

3450 3451 3452 3453
  TNode<Object> subgraph = a.ReduceArrayPrototypeEverySome(
      h.inference(), h.has_stability_dependency(), h.elements_kind(), shared,
      native_context(), ArrayEverySomeVariant::kSome);
  return ReplaceWithSubgraph(&a, subgraph);
3454 3455
}

3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469
#ifndef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
namespace {
bool HasFPParamsInSignature(const CFunctionInfo* c_signature) {
  for (unsigned int i = 0; i < c_signature->ArgumentCount(); ++i) {
    if (c_signature->ArgumentInfo(i).GetType() == CTypeInfo::Type::kFloat32 ||
        c_signature->ArgumentInfo(i).GetType() == CTypeInfo::Type::kFloat64) {
      return true;
    }
  }
  return false;
}
}  // namespace
#endif

3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503
#ifndef V8_TARGET_ARCH_64_BIT
namespace {
bool Has64BitIntegerParamsInSignature(const CFunctionInfo* c_signature) {
  for (unsigned int i = 0; i < c_signature->ArgumentCount(); ++i) {
    if (c_signature->ArgumentInfo(i).GetType() == CTypeInfo::Type::kInt64 ||
        c_signature->ArgumentInfo(i).GetType() == CTypeInfo::Type::kUint64) {
      return true;
    }
  }
  return false;
}
}  // namespace
#endif

bool CanOptimizeFastCall(
    const FunctionTemplateInfoRef& function_template_info) {
  const CFunctionInfo* c_signature = function_template_info.c_signature();

  bool optimize_to_fast_call =
      FLAG_turbo_fast_api_calls &&
      function_template_info.c_function() != kNullAddress;
#ifndef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
  optimize_to_fast_call =
      optimize_to_fast_call && !HasFPParamsInSignature(c_signature);
#else
  USE(c_signature);
#endif
#ifndef V8_TARGET_ARCH_64_BIT
  optimize_to_fast_call =
      optimize_to_fast_call && !Has64BitIntegerParamsInSignature(c_signature);
#endif
  return optimize_to_fast_call;
}

3504
Reduction JSCallReducer::ReduceCallApiFunction(
3505
    Node* node, const SharedFunctionInfoRef& shared) {
3506
  DisallowHeapAccessIf no_heap_access(should_disallow_heap_access());
3507

3508 3509
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
3510
  int const argc = p.arity_without_implicit_args();
3511
  Node* target = n.target();
3512 3513 3514 3515
  Node* global_proxy =
      jsgraph()->Constant(native_context().global_proxy_object());
  Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined)
                       ? global_proxy
3516
                       : n.receiver();
3517
  Node* holder;
3518 3519 3520 3521
  Node* context = n.context();
  Effect effect = n.effect();
  Control control = n.control();
  FrameState frame_state = n.frame_state();
3522

3523 3524 3525 3526 3527
  if (!shared.function_template_info().has_value()) {
    TRACE_BROKER_MISSING(
        broker(), "FunctionTemplateInfo for function with SFI " << shared);
    return NoChange();
  }
3528

3529 3530 3531
  // See if we can optimize this API call to {shared}.
  FunctionTemplateInfoRef function_template_info(
      shared.function_template_info().value());
3532

3533
  if (!function_template_info.has_call_code()) return NoChange();
3534

3535 3536 3537
  if (function_template_info.accept_any_receiver() &&
      function_template_info.is_signature_undefined()) {
    // We might be able to
3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555
    // optimize the API call depending on the {function_template_info}.
    // If the API function accepts any kind of {receiver}, we only need to
    // ensure that the {receiver} is actually a JSReceiver at this point,
    // and also pass that as the {holder}. There are two independent bits
    // here:
    //
    //  a. When the "accept any receiver" bit is set, it means we don't
    //     need to perform access checks, even if the {receiver}'s map
    //     has the "needs access check" bit set.
    //  b. When the {function_template_info} has no signature, we don't
    //     need to do the compatible receiver check, since all receivers
    //     are considered compatible at that point, and the {receiver}
    //     will be pass as the {holder}.
    //
    receiver = holder = effect =
        graph()->NewNode(simplified()->ConvertReceiver(p.convert_mode()),
                         receiver, global_proxy, effect, control);
  } else {
3556 3557 3558 3559 3560 3561 3562 3563
    // Try to infer the {receiver} maps from the graph.
    MapInference inference(broker(), receiver, effect);
    if (inference.HaveMaps()) {
      MapHandles const& receiver_maps = inference.GetMaps();
      MapRef first_receiver_map(broker(), receiver_maps[0]);

      // See if we can constant-fold the compatible receiver checks.
      HolderLookupResult api_holder =
3564
          function_template_info.LookupHolderOfExpectedType(first_receiver_map);
3565
      if (api_holder.lookup == CallOptimization::kHolderNotFound) {
3566
        return inference.NoChange();
3567
      }
3568

3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594
      // Check that all {receiver_maps} are actually JSReceiver maps and
      // that the {function_template_info} accepts them without access
      // checks (even if "access check needed" is set for {receiver}).
      //
      // Note that we don't need to know the concrete {receiver} maps here,
      // meaning it's fine if the {receiver_maps} are unreliable, and we also
      // don't need to install any stability dependencies, since the only
      // relevant information regarding the {receiver} is the Map::constructor
      // field on the root map (which is different from the JavaScript exposed
      // "constructor" property) and that field cannot change.
      //
      // So if we know that {receiver} had a certain constructor at some point
      // in the past (i.e. it had a certain map), then this constructor is going
      // to be the same later, since this information cannot change with map
      // transitions.
      //
      // The same is true for the instance type, e.g. we still know that the
      // instance type is JSObject even if that information is unreliable, and
      // the "access check needed" bit, which also cannot change later.
      CHECK(first_receiver_map.IsJSReceiverMap());
      CHECK(!first_receiver_map.is_access_check_needed() ||
            function_template_info.accept_any_receiver());

      for (size_t i = 1; i < receiver_maps.size(); ++i) {
        MapRef receiver_map(broker(), receiver_maps[i]);
        HolderLookupResult holder_i =
3595
            function_template_info.LookupHolderOfExpectedType(receiver_map);
3596 3597

        if (api_holder.lookup != holder_i.lookup) return inference.NoChange();
3598 3599 3600 3601 3602 3603 3604 3605
        DCHECK(holder_i.lookup == CallOptimization::kHolderFound ||
               holder_i.lookup == CallOptimization::kHolderIsReceiver);
        if (holder_i.lookup == CallOptimization::kHolderFound) {
          DCHECK(api_holder.holder.has_value() && holder_i.holder.has_value());
          if (!api_holder.holder->equals(*holder_i.holder)) {
            return inference.NoChange();
          }
        }
3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653

        CHECK(receiver_map.IsJSReceiverMap());
        CHECK(!receiver_map.is_access_check_needed() ||
              function_template_info.accept_any_receiver());
      }

      if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation &&
          !inference.RelyOnMapsViaStability(dependencies())) {
        // We were not able to make the receiver maps reliable without map
        // checks but doing map checks would lead to deopt loops, so give up.
        return inference.NoChange();
      }

      // TODO(neis): The maps were used in a way that does not actually require
      // map checks or stability dependencies.
      inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
                                          control, p.feedback());

      // Determine the appropriate holder for the {lookup}.
      holder = api_holder.lookup == CallOptimization::kHolderFound
                   ? jsgraph()->Constant(*api_holder.holder)
                   : receiver;
    } else {
      // We don't have enough information to eliminate the access check
      // and/or the compatible receiver check, so use the generic builtin
      // that does those checks dynamically. This is still significantly
      // faster than the generic call sequence.
      Builtins::Name builtin_name;
      if (function_template_info.accept_any_receiver()) {
        builtin_name = Builtins::kCallFunctionTemplate_CheckCompatibleReceiver;
      } else if (function_template_info.is_signature_undefined()) {
        builtin_name = Builtins::kCallFunctionTemplate_CheckAccess;
      } else {
        builtin_name =
            Builtins::kCallFunctionTemplate_CheckAccessAndCompatibleReceiver;
      }

      // The CallFunctionTemplate builtin requires the {receiver} to be
      // an actual JSReceiver, so make sure we do the proper conversion
      // first if necessary.
      receiver = holder = effect =
          graph()->NewNode(simplified()->ConvertReceiver(p.convert_mode()),
                           receiver, global_proxy, effect, control);

      Callable callable = Builtins::CallableFor(isolate(), builtin_name);
      auto call_descriptor = Linkage::GetStubCallDescriptor(
          graph()->zone(), callable.descriptor(),
          argc + 1 /* implicit receiver */, CallDescriptor::kNeedsFrameState);
3654
      node->RemoveInput(n.FeedbackVectorIndex());
3655 3656 3657 3658 3659 3660 3661 3662 3663
      node->InsertInput(graph()->zone(), 0,
                        jsgraph()->HeapConstant(callable.code()));
      node->ReplaceInput(1, jsgraph()->Constant(function_template_info));
      node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(argc));
      node->ReplaceInput(3, receiver);       // Update receiver input.
      node->ReplaceInput(6 + argc, effect);  // Update effect input.
      NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
      return Changed(node);
    }
3664 3665 3666 3667 3668
  }

  // TODO(turbofan): Consider introducing a JSCallApiCallback operator for
  // this and lower it during JSGenericLowering, and unify this with the
  // JSNativeContextSpecialization::InlineApiCall method a bit.
3669 3670 3671 3672 3673
  if (!function_template_info.call_code().has_value()) {
    TRACE_BROKER_MISSING(broker(), "call code for function template info "
                                       << function_template_info);
    return NoChange();
  }
3674

3675 3676 3677
  if (CanOptimizeFastCall(function_template_info)) {
    FastApiCallReducerAssembler a(this, node, function_template_info, receiver,
                                  holder, shared, target, argc, effect);
3678 3679 3680 3681
    Node* fast_call_subgraph = a.ReduceFastApiCall();
    ReplaceWithSubgraph(&a, fast_call_subgraph);

    return Replace(fast_call_subgraph);
3682 3683
  }

3684
  CallHandlerInfoRef call_handler_info = *function_template_info.call_code();
3685
  Callable call_api_callback = CodeFactory::CallApiCallback(isolate());
3686
  CallInterfaceDescriptor cid = call_api_callback.descriptor();
3687 3688 3689
  auto call_descriptor =
      Linkage::GetStubCallDescriptor(graph()->zone(), cid, argc + 1 /*
     implicit receiver */, CallDescriptor::kNeedsFrameState);
3690
  ApiFunction api_function(call_handler_info.callback());
3691 3692
  ExternalReference function_reference = ExternalReference::Create(
      &api_function, ExternalReference::DIRECT_API_CALL);
3693 3694 3695 3696

  Node* continuation_frame_state = CreateGenericLazyDeoptContinuationFrameState(
      jsgraph(), shared, target, context, receiver, frame_state);

3697
  node->RemoveInput(n.FeedbackVectorIndex());
3698
  node->InsertInput(graph()->zone(), 0,
3699
                    jsgraph()->HeapConstant(call_api_callback.code()));
3700 3701
  node->ReplaceInput(1, jsgraph()->ExternalConstant(function_reference));
  node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(argc));
3702 3703
  node->InsertInput(graph()->zone(), 3,
                    jsgraph()->Constant(call_handler_info.data()));
3704
  node->InsertInput(graph()->zone(), 4, holder);
3705 3706 3707 3708
  node->ReplaceInput(5, receiver);  // Update receiver input.
  // 6 + argc is context input.
  node->ReplaceInput(6 + argc + 1, continuation_frame_state);
  node->ReplaceInput(6 + argc + 2, effect);
3709 3710 3711 3712
  NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
  return Changed(node);
}

3713 3714 3715
namespace {

// Check whether elements aren't mutated; we play it extremely safe here by
3716 3717
// explicitly checking that {node} is only used by {LoadField} or
// {LoadElement}.
3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728
bool IsSafeArgumentsElements(Node* node) {
  for (Edge const edge : node->use_edges()) {
    if (!NodeProperties::IsValueEdge(edge)) continue;
    if (edge.from()->opcode() != IrOpcode::kLoadField &&
        edge.from()->opcode() != IrOpcode::kLoadElement) {
      return false;
    }
  }
  return true;
}

3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745
#ifdef DEBUG
bool IsCallOrConstructWithArrayLike(Node* node) {
  return node->opcode() == IrOpcode::kJSCallWithArrayLike ||
         node->opcode() == IrOpcode::kJSConstructWithArrayLike;
}
#endif

bool IsCallOrConstructWithSpread(Node* node) {
  return node->opcode() == IrOpcode::kJSCallWithSpread ||
         node->opcode() == IrOpcode::kJSConstructWithSpread;
}

bool IsCallWithArrayLikeOrSpread(Node* node) {
  return node->opcode() == IrOpcode::kJSCallWithArrayLike ||
         node->opcode() == IrOpcode::kJSCallWithSpread;
}

3746 3747
}  // namespace

3748
Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
3749
    Node* node, int arraylike_or_spread_index, CallFrequency const& frequency,
3750 3751
    FeedbackSource const& feedback, SpeculationMode speculation_mode,
    CallFeedbackRelation feedback_relation) {
3752 3753
  DCHECK(IsCallOrConstructWithArrayLike(node) ||
         IsCallOrConstructWithSpread(node));
3754 3755
  DCHECK_IMPLIES(speculation_mode == SpeculationMode::kAllowSpeculation,
                 feedback.IsValid());
3756

3757 3758
  Node* arguments_list =
      NodeProperties::GetValueInput(node, arraylike_or_spread_index);
3759
  if (arguments_list->opcode() != IrOpcode::kJSCreateArguments) {
3760
    return NoChange();
3761
  }
3762 3763 3764

  // Check if {node} is the only value user of {arguments_list} (except for
  // value uses in frame states). If not, we give up for now.
3765
  for (Edge edge : arguments_list->use_edges()) {
3766
    if (!NodeProperties::IsValueEdge(edge)) continue;
3767
    Node* const user = edge.from();
3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780
    switch (user->opcode()) {
      case IrOpcode::kCheckMaps:
      case IrOpcode::kFrameState:
      case IrOpcode::kStateValues:
      case IrOpcode::kReferenceEqual:
      case IrOpcode::kReturn:
        // Ignore safe uses that definitely don't mess with the arguments.
        continue;
      case IrOpcode::kLoadField: {
        DCHECK_EQ(arguments_list, user->InputAt(0));
        FieldAccess const& access = FieldAccessOf(user->op());
        if (access.offset == JSArray::kLengthOffset) {
          // Ignore uses for arguments#length.
3781 3782
          STATIC_ASSERT(
              static_cast<int>(JSArray::kLengthOffset) ==
3783 3784 3785 3786
              static_cast<int>(JSStrictArgumentsObject::kLengthOffset));
          STATIC_ASSERT(
              static_cast<int>(JSArray::kLengthOffset) ==
              static_cast<int>(JSSloppyArgumentsObject::kLengthOffset));
3787 3788 3789 3790 3791 3792 3793
          continue;
        } else if (access.offset == JSObject::kElementsOffset) {
          // Ignore safe uses for arguments#elements.
          if (IsSafeArgumentsElements(user)) continue;
        }
        break;
      }
3794
      case IrOpcode::kJSCallWithArrayLike: {
3795
        // Ignore uses as argumentsList input to calls with array like.
3796 3797
        JSCallWithArrayLikeNode n(user);
        if (n.Argument(0) == arguments_list) continue;
3798
        break;
3799
      }
3800
      case IrOpcode::kJSConstructWithArrayLike: {
3801
        // Ignore uses as argumentsList input to calls with array like.
3802 3803
        JSConstructWithArrayLikeNode n(user);
        if (n.Argument(0) == arguments_list) continue;
3804
        break;
3805
      }
3806 3807
      case IrOpcode::kJSCallWithSpread: {
        // Ignore uses as spread input to calls with spread.
3808 3809
        JSCallWithSpreadNode n(user);
        if (n.LastArgument() == arguments_list) continue;
3810 3811 3812 3813
        break;
      }
      case IrOpcode::kJSConstructWithSpread: {
        // Ignore uses as spread input to construct with spread.
3814 3815
        JSConstructWithSpreadNode n(user);
        if (n.LastArgument() == arguments_list) continue;
3816 3817 3818 3819
        break;
      }
      default:
        break;
3820
    }
3821 3822 3823 3824
    // We cannot currently reduce the {node} to something better than what
    // it already is, but we might be able to do something about the {node}
    // later, so put it on the waitlist and try again during finalization.
    waitlist_.insert(node);
3825 3826 3827 3828 3829
    return NoChange();
  }

  // Get to the actual frame state from which to extract the arguments;
  // we can only optimize this in case the {node} was already inlined into
3830 3831 3832
  // some other function (and same for the {arguments_list}).
  CreateArgumentsType const type = CreateArgumentsTypeOf(arguments_list->op());
  Node* frame_state = NodeProperties::GetFrameStateInput(arguments_list);
3833
  FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
3834
  int start_index = 0;
3835 3836 3837 3838 3839 3840 3841 3842 3843

  int formal_parameter_count;
  {
    Handle<SharedFunctionInfo> shared;
    if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
    formal_parameter_count = SharedFunctionInfoRef(broker(), shared)
                                 .internal_formal_parameter_count();
  }

3844
  if (type == CreateArgumentsType::kMappedArguments) {
3845 3846 3847 3848 3849
    // Mapped arguments (sloppy mode) that are aliased can only be handled
    // here if there's no side-effect between the {node} and the {arg_array}.
    // TODO(turbofan): Further relax this constraint.
    if (formal_parameter_count != 0) {
      Node* effect = NodeProperties::GetEffectInput(node);
3850 3851 3852
      if (!NodeProperties::NoObservableSideEffectBetween(effect,
                                                         arguments_list)) {
        return NoChange();
3853 3854
      }
    }
3855
  } else if (type == CreateArgumentsType::kRestParameter) {
3856
    start_index = formal_parameter_count;
3857 3858
  }

3859 3860 3861 3862
  // TODO(jgruber,v8:8888): Attempt to remove this restriction. The reason it
  // currently exists is because we cannot create code dependencies in NCI code.
  if (broker()->is_native_context_independent()) return NoChange();

3863
  // For call/construct with spread, we need to also install a code
3864 3865
  // dependency on the array iterator lookup protector cell to ensure
  // that no one messed with the %ArrayIteratorPrototype%.next method.
3866
  if (IsCallOrConstructWithSpread(node)) {
3867
    if (!dependencies()->DependOnArrayIteratorProtector()) return NoChange();
3868
  }
3869 3870

  // Remove the {arguments_list} input from the {node}.
3871
  node->RemoveInput(arraylike_or_spread_index);
3872 3873 3874 3875

  // After removing the arraylike or spread object, the argument count is:
  int argc =
      arraylike_or_spread_index - JSCallOrConstructNode::FirstArgumentIndex();
3876 3877 3878 3879
  // Check if are spreading to inlined arguments or to the arguments of
  // the outermost function.
  Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
  if (outer_state->opcode() != IrOpcode::kFrameState) {
3880 3881
    Operator const* op;
    if (IsCallWithArrayLikeOrSpread(node)) {
3882 3883 3884
      static constexpr int kTargetAndReceiver = 2;
      op = javascript()->CallForwardVarargs(argc + kTargetAndReceiver,
                                            start_index);
3885
    } else {
3886 3887 3888
      static constexpr int kTargetAndNewTarget = 2;
      op = javascript()->ConstructForwardVarargs(argc + kTargetAndNewTarget,
                                                 start_index);
3889
    }
3890
    node->RemoveInput(JSCallOrConstructNode::FeedbackVectorIndexForArgc(argc));
3891 3892 3893 3894 3895 3896
    NodeProperties::ChangeOp(node, op);
    return Changed(node);
  }
  // Get to the actual frame state from which to extract the arguments;
  // we can only optimize this in case the {node} was already inlined into
  // some other function (and same for the {arg_array}).
3897
  FrameStateInfo outer_info = FrameStateInfoOf(outer_state->op());
3898 3899 3900 3901
  if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
    // Need to take the parameters from the arguments adaptor.
    frame_state = outer_state;
  }
3902 3903
  // Add the actual parameters to the {node}, skipping the receiver.
  Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
3904
  for (int i = start_index + 1; i < parameters->InputCount(); ++i) {
3905 3906
    node->InsertInput(graph()->zone(),
                      JSCallOrConstructNode::ArgumentIndex(argc++),
3907 3908 3909
                      parameters->InputAt(i));
  }

3910
  if (IsCallWithArrayLikeOrSpread(node)) {
3911
    NodeProperties::ChangeOp(
3912
        node,
3913 3914 3915
        javascript()->Call(JSCallNode::ArityForArgc(argc), frequency, feedback,
                           ConvertReceiverMode::kAny, speculation_mode,
                           CallFeedbackRelation::kUnrelated));
3916
    return Changed(node).FollowedBy(ReduceJSCall(node));
3917
  } else {
3918
    NodeProperties::ChangeOp(
3919 3920 3921 3922 3923 3924 3925 3926 3927
        node, javascript()->Construct(JSConstructNode::ArityForArgc(argc),
                                      frequency, feedback));

    JSConstructNode n(node);
    Node* new_target = n.new_target();
    FrameState frame_state = n.frame_state();
    Node* context = n.context();
    Effect effect = n.effect();
    Control control = n.control();
3928 3929 3930 3931 3932 3933 3934 3935 3936

    // Check whether the given new target value is a constructor function. The
    // replacement {JSConstruct} operator only checks the passed target value
    // but relies on the new target value to be implicitly valid.
    Node* check =
        graph()->NewNode(simplified()->ObjectIsConstructor(), new_target);
    Node* check_branch =
        graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
    Node* check_fail = graph()->NewNode(common()->IfFalse(), check_branch);
3937 3938 3939 3940
    Node* check_throw = check_fail = graph()->NewNode(
        javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
        jsgraph()->Constant(static_cast<int>(MessageTemplate::kNotConstructor)),
        new_target, context, frame_state, effect, check_fail);
3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965
    control = graph()->NewNode(common()->IfTrue(), check_branch);
    NodeProperties::ReplaceControlInput(node, control);

    // Rewire potential exception edges.
    Node* on_exception = nullptr;
    if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
      // Create appropriate {IfException}  and {IfSuccess} nodes.
      Node* if_exception =
          graph()->NewNode(common()->IfException(), check_throw, check_fail);
      check_fail = graph()->NewNode(common()->IfSuccess(), check_fail);

      // Join the exception edges.
      Node* merge =
          graph()->NewNode(common()->Merge(2), if_exception, on_exception);
      Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception,
                                    on_exception, merge);
      Node* phi =
          graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                           if_exception, on_exception, merge);
      ReplaceWithValue(on_exception, phi, ephi, merge);
      merge->ReplaceInput(1, on_exception);
      ephi->ReplaceInput(1, on_exception);
      phi->ReplaceInput(1, on_exception);
    }

3966 3967 3968
    // The above %ThrowTypeError runtime call is an unconditional throw,
    // making it impossible to return a successful completion in this case. We
    // simply connect the successful completion to the graph end.
3969
    Node* throw_node =
3970
        graph()->NewNode(common()->Throw(), check_throw, check_fail);
3971
    NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
3972

3973
    return Changed(node).FollowedBy(ReduceJSConstruct(node));
3974 3975 3976
  }
}

3977 3978 3979 3980
namespace {

bool ShouldUseCallICFeedback(Node* node) {
  HeapObjectMatcher m(node);
3981
  if (m.HasResolvedValue() || m.IsCheckClosure() || m.IsJSCreateClosure()) {
3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002
    // Don't use CallIC feedback when we know the function
    // being called, i.e. either know the closure itself or
    // at least the SharedFunctionInfo.
    return false;
  } else if (m.IsPhi()) {
    // Protect against endless loops here.
    Node* control = NodeProperties::GetControlInput(node);
    if (control->opcode() == IrOpcode::kLoop) return false;
    // Check if {node} is a Phi of nodes which shouldn't
    // use CallIC feedback (not looking through loops).
    int const value_input_count = m.node()->op()->ValueInputCount();
    for (int n = 0; n < value_input_count; ++n) {
      if (ShouldUseCallICFeedback(node->InputAt(n))) return true;
    }
    return false;
  }
  return true;
}

}  // namespace

4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015
bool JSCallReducer::IsBuiltinOrApiFunction(JSFunctionRef function) const {
  if (should_disallow_heap_access() && !function.serialized()) {
    TRACE_BROKER_MISSING(broker(), "data for function " << function);
    return false;
  }

  // TODO(neis): Add a way to check if function template info isn't serialized
  // and add a warning in such cases. Currently we can't tell if function
  // template info doesn't exist or wasn't serialized.
  return function.shared().HasBuiltinId() ||
         function.shared().function_template_info().has_value();
}

4016
Reduction JSCallReducer::ReduceJSCall(Node* node) {
4017 4018
  if (broker()->StackHasOverflowed()) return NoChange();

4019 4020 4021 4022 4023 4024
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
  Node* target = n.target();
  Effect effect = n.effect();
  Control control = n.control();
  int arity = p.arity_without_implicit_args();
4025

4026
  // Try to specialize JSCall {node}s with constant {target}s.
4027
  HeapObjectMatcher m(target);
4028
  if (m.HasResolvedValue()) {
4029 4030 4031
    ObjectRef target_ref = m.Ref(broker());
    if (target_ref.IsJSFunction()) {
      JSFunctionRef function = target_ref.AsJSFunction();
4032
      if (should_disallow_heap_access() && !function.serialized()) {
4033
        TRACE_BROKER_MISSING(broker(), "data for function " << function);
4034 4035
        return NoChange();
      }
4036

4037
      // Don't inline cross native context.
4038 4039 4040
      if (!function.native_context().equals(native_context())) {
        return NoChange();
      }
4041

4042
      return ReduceJSCall(node, function.shared());
4043 4044
    } else if (target_ref.IsJSBoundFunction()) {
      JSBoundFunctionRef function = target_ref.AsJSBoundFunction();
4045
      if (should_disallow_heap_access() && !function.serialized()) {
4046
        TRACE_BROKER_MISSING(broker(), "data for function " << function);
4047 4048
        return NoChange();
      }
4049 4050

      ObjectRef bound_this = function.bound_this();
4051
      ConvertReceiverMode const convert_mode =
4052
          bound_this.IsNullOrUndefined()
4053 4054
              ? ConvertReceiverMode::kNullOrUndefined
              : ConvertReceiverMode::kNotNullOrUndefined;
4055

4056 4057
      // Patch {node} to use [[BoundTargetFunction]] and [[BoundThis]].
      NodeProperties::ReplaceValueInput(
4058 4059
          node, jsgraph()->Constant(function.bound_target_function()),
          JSCallNode::TargetIndex());
4060
      NodeProperties::ReplaceValueInput(node, jsgraph()->Constant(bound_this),
4061
                                        JSCallNode::ReceiverIndex());
4062

4063
      // Insert the [[BoundArguments]] for {node}.
4064 4065 4066 4067
      FixedArrayRef bound_arguments = function.bound_arguments();
      for (int i = 0; i < bound_arguments.length(); ++i) {
        node->InsertInput(graph()->zone(), i + 2,
                          jsgraph()->Constant(bound_arguments.get(i)));
4068 4069
        arity++;
      }
4070

4071
      NodeProperties::ChangeOp(
4072
          node,
4073
          javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(),
4074 4075
                             p.feedback(), convert_mode, p.speculation_mode(),
                             CallFeedbackRelation::kUnrelated));
4076

4077
      // Try to further reduce the JSCall {node}.
4078
      return Changed(node).FollowedBy(ReduceJSCall(node));
4079
    }
4080

4081
    // Don't mess with other {node}s that have a constant {target}.
4082
    // TODO(bmeurer): Also support proxies here.
4083 4084 4085
    return NoChange();
  }

4086 4087 4088 4089
  // If {target} is the result of a JSCreateClosure operation, we can
  // just immediately try to inline based on the SharedFunctionInfo,
  // since TurboFan generally doesn't inline cross-context, and hence
  // the {target} must have the same native context as the call site.
4090
  // Same if the {target} is the result of a CheckClosure operation.
4091
  if (target->opcode() == IrOpcode::kJSCreateClosure) {
4092
    CreateClosureParameters const& p = JSCreateClosureNode{target}.Parameters();
4093
    return ReduceJSCall(node, SharedFunctionInfoRef(broker(), p.shared_info()));
4094 4095 4096 4097
  } else if (target->opcode() == IrOpcode::kCheckClosure) {
    FeedbackCellRef cell(broker(), FeedbackCellOf(target->op()));
    return ReduceJSCall(node,
                        cell.value().AsFeedbackVector().shared_function_info());
4098 4099
  }

4100 4101 4102 4103 4104 4105 4106 4107 4108 4109
  // If {target} is the result of a JSCreateBoundFunction operation,
  // we can just fold the construction and call the bound target
  // function directly instead.
  if (target->opcode() == IrOpcode::kJSCreateBoundFunction) {
    Node* bound_target_function = NodeProperties::GetValueInput(target, 0);
    Node* bound_this = NodeProperties::GetValueInput(target, 1);
    int const bound_arguments_length =
        static_cast<int>(CreateBoundFunctionParametersOf(target->op()).arity());

    // Patch the {node} to use [[BoundTargetFunction]] and [[BoundThis]].
4110 4111 4112
    NodeProperties::ReplaceValueInput(node, bound_target_function,
                                      n.TargetIndex());
    NodeProperties::ReplaceValueInput(node, bound_this, n.ReceiverIndex());
4113 4114 4115 4116

    // Insert the [[BoundArguments]] for {node}.
    for (int i = 0; i < bound_arguments_length; ++i) {
      Node* value = NodeProperties::GetValueInput(target, 2 + i);
4117
      node->InsertInput(graph()->zone(), n.ArgumentIndex(i), value);
4118 4119 4120 4121 4122
      arity++;
    }

    // Update the JSCall operator on {node}.
    ConvertReceiverMode const convert_mode =
4123
        NodeProperties::CanBeNullOrUndefined(broker(), bound_this, effect)
4124 4125 4126
            ? ConvertReceiverMode::kAny
            : ConvertReceiverMode::kNotNullOrUndefined;
    NodeProperties::ChangeOp(
4127
        node,
4128
        javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(),
4129 4130
                           p.feedback(), convert_mode, p.speculation_mode(),
                           CallFeedbackRelation::kUnrelated));
4131 4132

    // Try to further reduce the JSCall {node}.
4133
    return Changed(node).FollowedBy(ReduceJSCall(node));
4134 4135
  }

4136 4137 4138 4139 4140 4141
  if (!ShouldUseCallICFeedback(target) ||
      p.feedback_relation() != CallFeedbackRelation::kRelated ||
      !p.feedback().IsValid()) {
    return NoChange();
  }

4142
  ProcessedFeedback const& feedback =
4143
      broker()->GetFeedbackForCall(p.feedback());
4144
  if (feedback.IsInsufficient()) {
4145
    return ReduceForInsufficientFeedback(
4146
        node, DeoptimizeReason::kInsufficientTypeFeedbackForCall);
4147
  }
4148

4149
  base::Optional<HeapObjectRef> feedback_target = feedback.AsCall().target();
4150
  if (feedback_target.has_value() && feedback_target->map().is_callable()) {
4151
    Node* target_function = jsgraph()->Constant(*feedback_target);
4152

4153
    if (broker()->is_turboprop()) {
4154 4155 4156 4157 4158 4159
      if (!feedback_target->IsJSFunction()) return NoChange();
      if (!IsBuiltinOrApiFunction(feedback_target->AsJSFunction())) {
        return NoChange();
      }
    }

4160 4161 4162 4163 4164 4165
    // Check that the {target} is still the {target_function}.
    Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
                                   target_function);
    effect = graph()->NewNode(
        simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
        effect, control);
4166

4167
    // Specialize the JSCall node to the {target_function}.
4168
    NodeProperties::ReplaceValueInput(node, target_function, n.TargetIndex());
4169
    NodeProperties::ReplaceEffectInput(node, effect);
4170

4171
    // Try to further reduce the JSCall {node}.
4172
    return Changed(node).FollowedBy(ReduceJSCall(node));
4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185
  } else if (feedback_target.has_value() && feedback_target->IsFeedbackCell()) {
    FeedbackCellRef feedback_cell(
        broker(), feedback_target.value().AsFeedbackCell().object());
    if (feedback_cell.value().IsFeedbackVector()) {
      // Check that {target} is a closure with given {feedback_cell},
      // which uniquely identifies a given function inside a native context.
      FeedbackVectorRef feedback_vector =
          feedback_cell.value().AsFeedbackVector();
      if (!feedback_vector.serialized()) {
        TRACE_BROKER_MISSING(
            broker(), "feedback vector, not serialized: " << feedback_vector);
        return NoChange();
      }
4186

4187
      if (broker()->is_turboprop() &&
4188 4189 4190 4191
          !feedback_vector.shared_function_info().HasBuiltinId()) {
        return NoChange();
      }

4192 4193 4194
      Node* target_closure = effect =
          graph()->NewNode(simplified()->CheckClosure(feedback_cell.object()),
                           target, effect, control);
4195

4196
      // Specialize the JSCall node to the {target_closure}.
4197
      NodeProperties::ReplaceValueInput(node, target_closure, n.TargetIndex());
4198 4199 4200
      NodeProperties::ReplaceEffectInput(node, effect);

      // Try to further reduce the JSCall {node}.
4201
      return Changed(node).FollowedBy(ReduceJSCall(node));
4202 4203
    }
  }
4204
  return NoChange();
4205 4206
}

4207
Reduction JSCallReducer::ReduceJSCall(Node* node,
4208
                                      const SharedFunctionInfoRef& shared) {
4209 4210
  JSCallNode n(node);
  Node* target = n.target();
4211 4212

  // Do not reduce calls to functions with break points.
4213
  if (shared.HasBreakInfo()) return NoChange();
4214 4215

  // Raise a TypeError if the {target} is a "classConstructor".
4216
  if (IsClassConstructor(shared.kind())) {
4217 4218 4219 4220 4221 4222 4223 4224
    NodeProperties::ReplaceValueInputs(node, target);
    NodeProperties::ChangeOp(
        node, javascript()->CallRuntime(
                  Runtime::kThrowConstructorNonCallableError, 1));
    return Changed(node);
  }

  // Check for known builtin functions.
4225 4226

  int builtin_id =
4227
      shared.HasBuiltinId() ? shared.builtin_id() : Builtins::kNoBuiltinId;
4228
  switch (builtin_id) {
4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242
    case Builtins::kArrayConstructor:
      return ReduceArrayConstructor(node);
    case Builtins::kBooleanConstructor:
      return ReduceBooleanConstructor(node);
    case Builtins::kFunctionPrototypeApply:
      return ReduceFunctionPrototypeApply(node);
    case Builtins::kFastFunctionPrototypeBind:
      return ReduceFunctionPrototypeBind(node);
    case Builtins::kFunctionPrototypeCall:
      return ReduceFunctionPrototypeCall(node);
    case Builtins::kFunctionPrototypeHasInstance:
      return ReduceFunctionPrototypeHasInstance(node);
    case Builtins::kObjectConstructor:
      return ReduceObjectConstructor(node);
4243 4244
    case Builtins::kObjectCreate:
      return ReduceObjectCreate(node);
4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271
    case Builtins::kObjectGetPrototypeOf:
      return ReduceObjectGetPrototypeOf(node);
    case Builtins::kObjectIs:
      return ReduceObjectIs(node);
    case Builtins::kObjectPrototypeGetProto:
      return ReduceObjectPrototypeGetProto(node);
    case Builtins::kObjectPrototypeHasOwnProperty:
      return ReduceObjectPrototypeHasOwnProperty(node);
    case Builtins::kObjectPrototypeIsPrototypeOf:
      return ReduceObjectPrototypeIsPrototypeOf(node);
    case Builtins::kReflectApply:
      return ReduceReflectApply(node);
    case Builtins::kReflectConstruct:
      return ReduceReflectConstruct(node);
    case Builtins::kReflectGet:
      return ReduceReflectGet(node);
    case Builtins::kReflectGetPrototypeOf:
      return ReduceReflectGetPrototypeOf(node);
    case Builtins::kReflectHas:
      return ReduceReflectHas(node);
    case Builtins::kArrayForEach:
      return ReduceArrayForEach(node, shared);
    case Builtins::kArrayMap:
      return ReduceArrayMap(node, shared);
    case Builtins::kArrayFilter:
      return ReduceArrayFilter(node, shared);
    case Builtins::kArrayReduce:
4272
      return ReduceArrayReduce(node, shared);
4273
    case Builtins::kArrayReduceRight:
4274
      return ReduceArrayReduceRight(node, shared);
4275
    case Builtins::kArrayPrototypeFind:
4276
      return ReduceArrayFind(node, shared);
4277
    case Builtins::kArrayPrototypeFindIndex:
4278
      return ReduceArrayFindIndex(node, shared);
4279 4280
    case Builtins::kArrayEvery:
      return ReduceArrayEvery(node, shared);
4281
    case Builtins::kArrayIndexOf:
4282
      return ReduceArrayIndexOf(node);
4283
    case Builtins::kArrayIncludes:
4284
      return ReduceArrayIncludes(node);
4285 4286 4287 4288 4289 4290 4291 4292
    case Builtins::kArraySome:
      return ReduceArraySome(node, shared);
    case Builtins::kArrayPrototypePush:
      return ReduceArrayPrototypePush(node);
    case Builtins::kArrayPrototypePop:
      return ReduceArrayPrototypePop(node);
    case Builtins::kArrayPrototypeShift:
      return ReduceArrayPrototypeShift(node);
4293 4294
    case Builtins::kArrayPrototypeSlice:
      return ReduceArrayPrototypeSlice(node);
4295
    case Builtins::kArrayPrototypeEntries:
4296 4297
      return ReduceArrayIterator(node, ArrayIteratorKind::kArrayLike,
                                 IterationKind::kEntries);
4298
    case Builtins::kArrayPrototypeKeys:
4299 4300
      return ReduceArrayIterator(node, ArrayIteratorKind::kArrayLike,
                                 IterationKind::kKeys);
4301
    case Builtins::kArrayPrototypeValues:
4302 4303
      return ReduceArrayIterator(node, ArrayIteratorKind::kArrayLike,
                                 IterationKind::kValues);
4304
    case Builtins::kArrayIteratorPrototypeNext:
4305
      return ReduceArrayIteratorPrototypeNext(node);
4306 4307
    case Builtins::kArrayIsArray:
      return ReduceArrayIsArray(node);
4308 4309 4310 4311 4312 4313 4314 4315 4316 4317
    case Builtins::kArrayBufferIsView:
      return ReduceArrayBufferIsView(node);
    case Builtins::kDataViewPrototypeGetByteLength:
      return ReduceArrayBufferViewAccessor(
          node, JS_DATA_VIEW_TYPE,
          AccessBuilder::ForJSArrayBufferViewByteLength());
    case Builtins::kDataViewPrototypeGetByteOffset:
      return ReduceArrayBufferViewAccessor(
          node, JS_DATA_VIEW_TYPE,
          AccessBuilder::ForJSArrayBufferViewByteOffset());
4318
    case Builtins::kDataViewPrototypeGetUint8:
4319 4320
      return ReduceDataViewAccess(node, DataViewAccess::kGet,
                                  ExternalArrayType::kExternalUint8Array);
4321
    case Builtins::kDataViewPrototypeGetInt8:
4322 4323
      return ReduceDataViewAccess(node, DataViewAccess::kGet,
                                  ExternalArrayType::kExternalInt8Array);
4324
    case Builtins::kDataViewPrototypeGetUint16:
4325 4326
      return ReduceDataViewAccess(node, DataViewAccess::kGet,
                                  ExternalArrayType::kExternalUint16Array);
4327
    case Builtins::kDataViewPrototypeGetInt16:
4328 4329
      return ReduceDataViewAccess(node, DataViewAccess::kGet,
                                  ExternalArrayType::kExternalInt16Array);
4330
    case Builtins::kDataViewPrototypeGetUint32:
4331 4332
      return ReduceDataViewAccess(node, DataViewAccess::kGet,
                                  ExternalArrayType::kExternalUint32Array);
4333
    case Builtins::kDataViewPrototypeGetInt32:
4334 4335
      return ReduceDataViewAccess(node, DataViewAccess::kGet,
                                  ExternalArrayType::kExternalInt32Array);
4336
    case Builtins::kDataViewPrototypeGetFloat32:
4337 4338
      return ReduceDataViewAccess(node, DataViewAccess::kGet,
                                  ExternalArrayType::kExternalFloat32Array);
4339
    case Builtins::kDataViewPrototypeGetFloat64:
4340 4341
      return ReduceDataViewAccess(node, DataViewAccess::kGet,
                                  ExternalArrayType::kExternalFloat64Array);
4342
    case Builtins::kDataViewPrototypeSetUint8:
4343 4344
      return ReduceDataViewAccess(node, DataViewAccess::kSet,
                                  ExternalArrayType::kExternalUint8Array);
4345
    case Builtins::kDataViewPrototypeSetInt8:
4346 4347
      return ReduceDataViewAccess(node, DataViewAccess::kSet,
                                  ExternalArrayType::kExternalInt8Array);
4348
    case Builtins::kDataViewPrototypeSetUint16:
4349 4350
      return ReduceDataViewAccess(node, DataViewAccess::kSet,
                                  ExternalArrayType::kExternalUint16Array);
4351
    case Builtins::kDataViewPrototypeSetInt16:
4352 4353
      return ReduceDataViewAccess(node, DataViewAccess::kSet,
                                  ExternalArrayType::kExternalInt16Array);
4354
    case Builtins::kDataViewPrototypeSetUint32:
4355 4356
      return ReduceDataViewAccess(node, DataViewAccess::kSet,
                                  ExternalArrayType::kExternalUint32Array);
4357
    case Builtins::kDataViewPrototypeSetInt32:
4358 4359
      return ReduceDataViewAccess(node, DataViewAccess::kSet,
                                  ExternalArrayType::kExternalInt32Array);
4360
    case Builtins::kDataViewPrototypeSetFloat32:
4361 4362
      return ReduceDataViewAccess(node, DataViewAccess::kSet,
                                  ExternalArrayType::kExternalFloat32Array);
4363
    case Builtins::kDataViewPrototypeSetFloat64:
4364 4365
      return ReduceDataViewAccess(node, DataViewAccess::kSet,
                                  ExternalArrayType::kExternalFloat64Array);
4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378
    case Builtins::kTypedArrayPrototypeByteLength:
      return ReduceArrayBufferViewAccessor(
          node, JS_TYPED_ARRAY_TYPE,
          AccessBuilder::ForJSArrayBufferViewByteLength());
    case Builtins::kTypedArrayPrototypeByteOffset:
      return ReduceArrayBufferViewAccessor(
          node, JS_TYPED_ARRAY_TYPE,
          AccessBuilder::ForJSArrayBufferViewByteOffset());
    case Builtins::kTypedArrayPrototypeLength:
      return ReduceArrayBufferViewAccessor(
          node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
    case Builtins::kTypedArrayPrototypeToStringTag:
      return ReduceTypedArrayPrototypeToStringTag(node);
4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446
    case Builtins::kMathAbs:
      return ReduceMathUnary(node, simplified()->NumberAbs());
    case Builtins::kMathAcos:
      return ReduceMathUnary(node, simplified()->NumberAcos());
    case Builtins::kMathAcosh:
      return ReduceMathUnary(node, simplified()->NumberAcosh());
    case Builtins::kMathAsin:
      return ReduceMathUnary(node, simplified()->NumberAsin());
    case Builtins::kMathAsinh:
      return ReduceMathUnary(node, simplified()->NumberAsinh());
    case Builtins::kMathAtan:
      return ReduceMathUnary(node, simplified()->NumberAtan());
    case Builtins::kMathAtanh:
      return ReduceMathUnary(node, simplified()->NumberAtanh());
    case Builtins::kMathCbrt:
      return ReduceMathUnary(node, simplified()->NumberCbrt());
    case Builtins::kMathCeil:
      return ReduceMathUnary(node, simplified()->NumberCeil());
    case Builtins::kMathCos:
      return ReduceMathUnary(node, simplified()->NumberCos());
    case Builtins::kMathCosh:
      return ReduceMathUnary(node, simplified()->NumberCosh());
    case Builtins::kMathExp:
      return ReduceMathUnary(node, simplified()->NumberExp());
    case Builtins::kMathExpm1:
      return ReduceMathUnary(node, simplified()->NumberExpm1());
    case Builtins::kMathFloor:
      return ReduceMathUnary(node, simplified()->NumberFloor());
    case Builtins::kMathFround:
      return ReduceMathUnary(node, simplified()->NumberFround());
    case Builtins::kMathLog:
      return ReduceMathUnary(node, simplified()->NumberLog());
    case Builtins::kMathLog1p:
      return ReduceMathUnary(node, simplified()->NumberLog1p());
    case Builtins::kMathLog10:
      return ReduceMathUnary(node, simplified()->NumberLog10());
    case Builtins::kMathLog2:
      return ReduceMathUnary(node, simplified()->NumberLog2());
    case Builtins::kMathRound:
      return ReduceMathUnary(node, simplified()->NumberRound());
    case Builtins::kMathSign:
      return ReduceMathUnary(node, simplified()->NumberSign());
    case Builtins::kMathSin:
      return ReduceMathUnary(node, simplified()->NumberSin());
    case Builtins::kMathSinh:
      return ReduceMathUnary(node, simplified()->NumberSinh());
    case Builtins::kMathSqrt:
      return ReduceMathUnary(node, simplified()->NumberSqrt());
    case Builtins::kMathTan:
      return ReduceMathUnary(node, simplified()->NumberTan());
    case Builtins::kMathTanh:
      return ReduceMathUnary(node, simplified()->NumberTanh());
    case Builtins::kMathTrunc:
      return ReduceMathUnary(node, simplified()->NumberTrunc());
    case Builtins::kMathAtan2:
      return ReduceMathBinary(node, simplified()->NumberAtan2());
    case Builtins::kMathPow:
      return ReduceMathBinary(node, simplified()->NumberPow());
    case Builtins::kMathClz32:
      return ReduceMathClz32(node);
    case Builtins::kMathImul:
      return ReduceMathImul(node);
    case Builtins::kMathMax:
      return ReduceMathMinMax(node, simplified()->NumberMax(),
                              jsgraph()->Constant(-V8_INFINITY));
    case Builtins::kMathMin:
      return ReduceMathMinMax(node, simplified()->NumberMin(),
                              jsgraph()->Constant(V8_INFINITY));
4447 4448
    case Builtins::kNumberIsFinite:
      return ReduceNumberIsFinite(node);
4449 4450
    case Builtins::kNumberIsInteger:
      return ReduceNumberIsInteger(node);
4451 4452
    case Builtins::kNumberIsSafeInteger:
      return ReduceNumberIsSafeInteger(node);
4453 4454
    case Builtins::kNumberIsNaN:
      return ReduceNumberIsNaN(node);
4455 4456
    case Builtins::kNumberParseInt:
      return ReduceNumberParseInt(node);
4457 4458 4459 4460
    case Builtins::kGlobalIsFinite:
      return ReduceGlobalIsFinite(node);
    case Builtins::kGlobalIsNaN:
      return ReduceGlobalIsNaN(node);
4461 4462 4463 4464
    case Builtins::kMapPrototypeGet:
      return ReduceMapPrototypeGet(node);
    case Builtins::kMapPrototypeHas:
      return ReduceMapPrototypeHas(node);
4465 4466
    case Builtins::kRegExpPrototypeTest:
      return ReduceRegExpPrototypeTest(node);
4467 4468 4469 4470 4471
    case Builtins::kReturnReceiver:
      return ReduceReturnReceiver(node);
    case Builtins::kStringPrototypeIndexOf:
      return ReduceStringPrototypeIndexOf(node);
    case Builtins::kStringPrototypeCharAt:
4472
      return ReduceStringPrototypeCharAt(node);
4473 4474 4475 4476
    case Builtins::kStringPrototypeCharCodeAt:
      return ReduceStringPrototypeStringAt(simplified()->StringCharCodeAt(),
                                           node);
    case Builtins::kStringPrototypeCodePointAt:
4477 4478
      return ReduceStringPrototypeStringAt(simplified()->StringCodePointAt(),
                                           node);
4479 4480
    case Builtins::kStringPrototypeSubstring:
      return ReduceStringPrototypeSubstring(node);
4481 4482
    case Builtins::kStringPrototypeSlice:
      return ReduceStringPrototypeSlice(node);
4483 4484
    case Builtins::kStringPrototypeSubstr:
      return ReduceStringPrototypeSubstr(node);
4485 4486
    case Builtins::kStringPrototypeStartsWith:
      return ReduceStringPrototypeStartsWith(node);
4487 4488 4489 4490 4491 4492 4493 4494
#ifdef V8_INTL_SUPPORT
    case Builtins::kStringPrototypeToLowerCaseIntl:
      return ReduceStringPrototypeToLowerCaseIntl(node);
    case Builtins::kStringPrototypeToUpperCaseIntl:
      return ReduceStringPrototypeToUpperCaseIntl(node);
#endif  // V8_INTL_SUPPORT
    case Builtins::kStringFromCharCode:
      return ReduceStringFromCharCode(node);
4495 4496
    case Builtins::kStringFromCodePoint:
      return ReduceStringFromCodePoint(node);
4497 4498 4499 4500
    case Builtins::kStringPrototypeIterator:
      return ReduceStringPrototypeIterator(node);
    case Builtins::kStringIteratorPrototypeNext:
      return ReduceStringIteratorPrototypeNext(node);
4501
    case Builtins::kStringPrototypeConcat:
4502
      return ReduceStringPrototypeConcat(node);
4503
    case Builtins::kTypedArrayPrototypeEntries:
4504 4505
      return ReduceArrayIterator(node, ArrayIteratorKind::kTypedArray,
                                 IterationKind::kEntries);
4506
    case Builtins::kTypedArrayPrototypeKeys:
4507 4508
      return ReduceArrayIterator(node, ArrayIteratorKind::kTypedArray,
                                 IterationKind::kKeys);
4509
    case Builtins::kTypedArrayPrototypeValues:
4510 4511
      return ReduceArrayIterator(node, ArrayIteratorKind::kTypedArray,
                                 IterationKind::kValues);
4512 4513 4514 4515 4516 4517
    case Builtins::kPromisePrototypeCatch:
      return ReducePromisePrototypeCatch(node);
    case Builtins::kPromisePrototypeFinally:
      return ReducePromisePrototypeFinally(node);
    case Builtins::kPromisePrototypeThen:
      return ReducePromisePrototypeThen(node);
4518 4519
    case Builtins::kPromiseResolveTrampoline:
      return ReducePromiseResolveTrampoline(node);
4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533
    case Builtins::kMapPrototypeEntries:
      return ReduceCollectionIteration(node, CollectionKind::kMap,
                                       IterationKind::kEntries);
    case Builtins::kMapPrototypeKeys:
      return ReduceCollectionIteration(node, CollectionKind::kMap,
                                       IterationKind::kKeys);
    case Builtins::kMapPrototypeGetSize:
      return ReduceCollectionPrototypeSize(node, CollectionKind::kMap);
    case Builtins::kMapPrototypeValues:
      return ReduceCollectionIteration(node, CollectionKind::kMap,
                                       IterationKind::kValues);
    case Builtins::kMapIteratorPrototypeNext:
      return ReduceCollectionIteratorPrototypeNext(
          node, OrderedHashMap::kEntrySize, factory()->empty_ordered_hash_map(),
4534
          FIRST_JS_MAP_ITERATOR_TYPE, LAST_JS_MAP_ITERATOR_TYPE);
4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545
    case Builtins::kSetPrototypeEntries:
      return ReduceCollectionIteration(node, CollectionKind::kSet,
                                       IterationKind::kEntries);
    case Builtins::kSetPrototypeGetSize:
      return ReduceCollectionPrototypeSize(node, CollectionKind::kSet);
    case Builtins::kSetPrototypeValues:
      return ReduceCollectionIteration(node, CollectionKind::kSet,
                                       IterationKind::kValues);
    case Builtins::kSetIteratorPrototypeNext:
      return ReduceCollectionIteratorPrototypeNext(
          node, OrderedHashSet::kEntrySize, factory()->empty_ordered_hash_set(),
4546
          FIRST_JS_SET_ITERATOR_TYPE, LAST_JS_SET_ITERATOR_TYPE);
4547 4548 4549 4550
    case Builtins::kDatePrototypeGetTime:
      return ReduceDatePrototypeGetTime(node);
    case Builtins::kDateNow:
      return ReduceDateNow(node);
4551 4552
    case Builtins::kNumberConstructor:
      return ReduceNumberConstructor(node);
4553 4554
    case Builtins::kBigIntAsUintN:
      return ReduceBigIntAsUintN(node);
4555 4556 4557 4558
    default:
      break;
  }

4559
  if (shared.function_template_info().has_value()) {
4560 4561 4562 4563 4564
    return ReduceCallApiFunction(node, shared);
  }
  return NoChange();
}

4565
Reduction JSCallReducer::ReduceJSCallWithArrayLike(Node* node) {
4566 4567 4568
  JSCallWithArrayLikeNode n(node);
  CallParameters const& p = n.Parameters();
  DCHECK_EQ(p.arity_without_implicit_args(), 1);  // The arraylike object.
4569
  return ReduceCallOrConstructWithArrayLikeOrSpread(
4570
      node, n.LastArgumentIndex(), p.frequency(), p.feedback(),
4571
      p.speculation_mode(), p.feedback_relation());
4572 4573
}

4574
Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) {
4575 4576 4577
  JSCallWithSpreadNode n(node);
  CallParameters const& p = n.Parameters();
  DCHECK_GE(p.arity_without_implicit_args(), 1);  // At least the spread.
4578
  return ReduceCallOrConstructWithArrayLikeOrSpread(
4579
      node, n.LastArgumentIndex(), p.frequency(), p.feedback(),
4580
      p.speculation_mode(), p.feedback_relation());
4581 4582
}

4583
Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
4584 4585
  JSConstructNode n(node);
  ConstructParameters const& p = n.Parameters();
4586
  int arity = p.arity_without_implicit_args();
4587 4588 4589 4590
  Node* target = n.target();
  Node* new_target = n.new_target();
  Effect effect = n.effect();
  Control control = n.control();
4591

4592
  if (p.feedback().IsValid()) {
4593
    ProcessedFeedback const& feedback =
4594
        broker()->GetFeedbackForCall(p.feedback());
4595
    if (feedback.IsInsufficient()) {
4596
      return ReduceForInsufficientFeedback(
4597
          node, DeoptimizeReason::kInsufficientTypeFeedbackForConstruct);
4598 4599
    }

4600
    base::Optional<HeapObjectRef> feedback_target = feedback.AsCall().target();
4601
    if (feedback_target.has_value() && feedback_target->IsAllocationSite()) {
4602 4603 4604 4605 4606
      // The feedback is an AllocationSite, which means we have called the
      // Array function and collected transition (and pretenuring) feedback
      // for the resulting arrays.  This has to be kept in sync with the
      // implementation in Ignition.

4607 4608
      Node* array_function =
          jsgraph()->Constant(native_context().array_function());
4609 4610 4611 4612

      // Check that the {target} is still the {array_function}.
      Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
                                     array_function);
4613 4614 4615
      effect = graph()->NewNode(
          simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
          effect, control);
4616 4617 4618

      // Turn the {node} into a {JSCreateArray} call.
      NodeProperties::ReplaceEffectInput(node, effect);
4619 4620 4621
      STATIC_ASSERT(JSConstructNode::NewTargetIndex() == 1);
      node->ReplaceInput(n.NewTargetIndex(), array_function);
      node->RemoveInput(n.FeedbackVectorIndex());
4622 4623
      NodeProperties::ChangeOp(
          node, javascript()->CreateArray(
4624
                    arity, feedback_target->AsAllocationSite().object()));
4625
      return Changed(node);
4626
    } else if (feedback_target.has_value() &&
4627
               !HeapObjectMatcher(new_target).HasResolvedValue() &&
4628 4629
               feedback_target->map().is_constructor()) {
      Node* new_target_feedback = jsgraph()->Constant(*feedback_target);
4630 4631 4632 4633 4634 4635 4636

      // Check that the {new_target} is still the {new_target_feedback}.
      Node* check = graph()->NewNode(simplified()->ReferenceEqual(), new_target,
                                     new_target_feedback);
      effect = graph()->NewNode(
          simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check,
          effect, control);
4637

4638
      // Specialize the JSConstruct node to the {new_target_feedback}.
4639
      node->ReplaceInput(n.NewTargetIndex(), new_target_feedback);
4640 4641
      NodeProperties::ReplaceEffectInput(node, effect);
      if (target == new_target) {
4642
        node->ReplaceInput(n.TargetIndex(), new_target_feedback);
4643
      }
4644 4645

      // Try to further reduce the JSConstruct {node}.
4646
      return Changed(node).FollowedBy(ReduceJSConstruct(node));
4647 4648 4649
    }
  }

4650
  // Try to specialize JSConstruct {node}s with constant {target}s.
4651
  HeapObjectMatcher m(target);
4652
  if (m.HasResolvedValue()) {
4653
    HeapObjectRef target_ref = m.Ref(broker());
4654

4655
    // Raise a TypeError if the {target} is not a constructor.
4656
    if (!target_ref.map().is_constructor()) {
4657 4658 4659 4660 4661 4662 4663
      NodeProperties::ReplaceValueInputs(node, target);
      NodeProperties::ChangeOp(node,
                               javascript()->CallRuntime(
                                   Runtime::kThrowConstructedNonConstructable));
      return Changed(node);
    }

4664 4665
    if (target_ref.IsJSFunction()) {
      JSFunctionRef function = target_ref.AsJSFunction();
4666
      if (should_disallow_heap_access() && !function.serialized()) {
4667 4668 4669 4670
        TRACE_BROKER_MISSING(broker(),
                             "function, not serialized: " << function);
        return NoChange();
      }
4671

4672
      // Do not reduce constructors with break points.
4673
      if (function.shared().HasBreakInfo()) return NoChange();
4674

4675
      // Don't inline cross native context.
4676 4677 4678
      if (!function.native_context().equals(native_context())) {
        return NoChange();
      }
4679

4680
      // Check for known builtin functions.
4681 4682
      int builtin_id = function.shared().HasBuiltinId()
                           ? function.shared().builtin_id()
4683 4684
                           : Builtins::kNoBuiltinId;
      switch (builtin_id) {
4685 4686 4687
        case Builtins::kArrayConstructor: {
          // TODO(bmeurer): Deal with Array subclasses here.
          // Turn the {node} into a {JSCreateArray} call.
4688 4689 4690
          STATIC_ASSERT(JSConstructNode::NewTargetIndex() == 1);
          node->ReplaceInput(n.NewTargetIndex(), new_target);
          node->RemoveInput(n.FeedbackVectorIndex());
4691 4692
          NodeProperties::ChangeOp(
              node, javascript()->CreateArray(arity, Handle<AllocationSite>()));
4693 4694
          return Changed(node);
        }
4695 4696 4697 4698
        case Builtins::kObjectConstructor: {
          // If no value is passed, we can immediately lower to a simple
          // JSCreate and don't need to do any massaging of the {node}.
          if (arity == 0) {
4699
            node->RemoveInput(n.FeedbackVectorIndex());
4700 4701 4702 4703
            NodeProperties::ChangeOp(node, javascript()->Create());
            return Changed(node);
          }

4704 4705 4706
          // If {target} is not the same as {new_target} (i.e. the Object
          // constructor), {value} will be ignored and therefore we can lower
          // to {JSCreate}. See https://tc39.es/ecma262/#sec-object-value.
4707
          HeapObjectMatcher mnew_target(new_target);
4708
          if (mnew_target.HasResolvedValue() &&
4709
              !mnew_target.Ref(broker()).equals(function)) {
4710
            // Drop the value inputs.
4711 4712 4713 4714
            node->RemoveInput(n.FeedbackVectorIndex());
            for (int i = n.ArgumentCount() - 1; i >= 0; i--) {
              node->RemoveInput(n.ArgumentIndex(i));
            }
4715 4716 4717 4718
            NodeProperties::ChangeOp(node, javascript()->Create());
            return Changed(node);
          }
          break;
4719
        }
4720 4721 4722
        case Builtins::kPromiseConstructor:
          return ReducePromiseConstructor(node);
        case Builtins::kTypedArrayConstructor:
4723
          return ReduceTypedArrayConstructor(node, function.shared());
4724 4725
        default:
          break;
4726
      }
4727 4728
    } else if (target_ref.IsJSBoundFunction()) {
      JSBoundFunctionRef function = target_ref.AsJSBoundFunction();
4729
      if (should_disallow_heap_access() && !function.serialized()) {
4730 4731 4732 4733
        TRACE_BROKER_MISSING(broker(),
                             "function, not serialized: " << function);
        return NoChange();
      }
4734 4735 4736

      ObjectRef bound_target_function = function.bound_target_function();
      FixedArrayRef bound_arguments = function.bound_arguments();
4737 4738

      // Patch {node} to use [[BoundTargetFunction]].
4739 4740
      node->ReplaceInput(n.TargetIndex(),
                         jsgraph()->Constant(bound_target_function));
4741 4742 4743

      // Patch {node} to use [[BoundTargetFunction]]
      // as new.target if {new_target} equals {target}.
4744 4745
      node->ReplaceInput(
          n.NewTargetIndex(),
4746 4747 4748 4749
          graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
                           graph()->NewNode(simplified()->ReferenceEqual(),
                                            target, new_target),
                           jsgraph()->Constant(bound_target_function),
4750
                           new_target));
4751 4752

      // Insert the [[BoundArguments]] for {node}.
4753
      for (int i = 0; i < bound_arguments.length(); ++i) {
4754
        node->InsertInput(graph()->zone(), n.ArgumentIndex(i),
4755
                          jsgraph()->Constant(bound_arguments.get(i)));
4756 4757 4758 4759 4760
        arity++;
      }

      // Update the JSConstruct operator on {node}.
      NodeProperties::ChangeOp(
4761
          node, javascript()->Construct(JSConstructNode::ArityForArgc(arity),
4762
                                        p.frequency(), FeedbackSource()));
4763 4764

      // Try to further reduce the JSConstruct {node}.
4765
      return Changed(node).FollowedBy(ReduceJSConstruct(node));
4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779
    }

    // TODO(bmeurer): Also support optimizing proxies here.
  }

  // If {target} is the result of a JSCreateBoundFunction operation,
  // we can just fold the construction and construct the bound target
  // function directly instead.
  if (target->opcode() == IrOpcode::kJSCreateBoundFunction) {
    Node* bound_target_function = NodeProperties::GetValueInput(target, 0);
    int const bound_arguments_length =
        static_cast<int>(CreateBoundFunctionParametersOf(target->op()).arity());

    // Patch the {node} to use [[BoundTargetFunction]].
4780
    node->ReplaceInput(n.TargetIndex(), bound_target_function);
4781 4782 4783

    // Patch {node} to use [[BoundTargetFunction]]
    // as new.target if {new_target} equals {target}.
4784 4785
    node->ReplaceInput(
        n.NewTargetIndex(),
4786 4787 4788
        graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
                         graph()->NewNode(simplified()->ReferenceEqual(),
                                          target, new_target),
4789
                         bound_target_function, new_target));
4790 4791 4792 4793

    // Insert the [[BoundArguments]] for {node}.
    for (int i = 0; i < bound_arguments_length; ++i) {
      Node* value = NodeProperties::GetValueInput(target, 2 + i);
4794
      node->InsertInput(graph()->zone(), n.ArgumentIndex(i), value);
4795
      arity++;
4796 4797
    }

4798 4799
    // Update the JSConstruct operator on {node}.
    NodeProperties::ChangeOp(
4800
        node, javascript()->Construct(JSConstructNode::ArityForArgc(arity),
4801
                                      p.frequency(), FeedbackSource()));
4802 4803

    // Try to further reduce the JSConstruct {node}.
4804
    return Changed(node).FollowedBy(ReduceJSConstruct(node));
4805 4806
  }

4807 4808 4809
  return NoChange();
}

4810
// ES #sec-string.prototype.indexof
4811
Reduction JSCallReducer::ReduceStringPrototypeIndexOf(Node* node) {
4812 4813
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
4814 4815 4816 4817
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

4818 4819 4820 4821
  Effect effect = n.effect();
  Control control = n.control();
  if (n.ArgumentCount() > 0) {
    Node* receiver = n.receiver();
4822 4823 4824
    Node* new_receiver = effect = graph()->NewNode(
        simplified()->CheckString(p.feedback()), receiver, effect, control);

4825
    Node* search_string = n.Argument(0);
4826 4827 4828 4829 4830
    Node* new_search_string = effect =
        graph()->NewNode(simplified()->CheckString(p.feedback()), search_string,
                         effect, control);

    Node* new_position = jsgraph()->ZeroConstant();
4831 4832
    if (n.ArgumentCount() > 1) {
      Node* position = n.Argument(1);
4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848
      new_position = effect = graph()->NewNode(
          simplified()->CheckSmi(p.feedback()), position, effect, control);
    }

    NodeProperties::ReplaceEffectInput(node, effect);
    RelaxEffectsAndControls(node);
    node->ReplaceInput(0, new_receiver);
    node->ReplaceInput(1, new_search_string);
    node->ReplaceInput(2, new_position);
    node->TrimInputCount(3);
    NodeProperties::ChangeOp(node, simplified()->StringIndexOf());
    return Changed(node);
  }
  return NoChange();
}

4849
// ES #sec-string.prototype.substring
4850
Reduction JSCallReducer::ReduceStringPrototypeSubstring(Node* node) {
4851 4852 4853
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
  if (n.ArgumentCount() < 1) return NoChange();
4854 4855 4856 4857
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

4858
  JSCallReducerAssembler a(this, node);
4859 4860
  Node* subgraph = a.ReduceStringPrototypeSubstring();
  return ReplaceWithSubgraph(&a, subgraph);
4861 4862
}

4863 4864
// ES #sec-string.prototype.slice
Reduction JSCallReducer::ReduceStringPrototypeSlice(Node* node) {
4865 4866 4867
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
  if (n.ArgumentCount() < 1) return NoChange();
4868 4869 4870 4871
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

4872
  JSCallReducerAssembler a(this, node);
4873 4874
  Node* subgraph = a.ReduceStringPrototypeSlice();
  return ReplaceWithSubgraph(&a, subgraph);
4875 4876
}

Sigurd Schneider's avatar
Sigurd Schneider committed
4877
// ES #sec-string.prototype.substr
4878
Reduction JSCallReducer::ReduceStringPrototypeSubstr(Node* node) {
4879 4880 4881
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
  if (n.ArgumentCount() < 1) return NoChange();
4882 4883 4884 4885
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

4886 4887 4888 4889 4890
  Effect effect = n.effect();
  Control control = n.control();
  Node* receiver = n.receiver();
  Node* start = n.Argument(0);
  Node* end = n.ArgumentOrUndefined(1, jsgraph());
4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964

  receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
                                       receiver, effect, control);

  start = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()), start,
                                    effect, control);

  Node* length = graph()->NewNode(simplified()->StringLength(), receiver);

  // Replace {end} argument with {length} if it is undefined.
  {
    Node* check = graph()->NewNode(simplified()->ReferenceEqual(), end,
                                   jsgraph()->UndefinedConstant());
    Node* branch =
        graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);

    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    Node* etrue = effect;
    Node* vtrue = length;

    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    Node* efalse = effect;
    Node* vfalse = efalse = graph()->NewNode(
        simplified()->CheckSmi(p.feedback()), end, efalse, if_false);

    control = graph()->NewNode(common()->Merge(2), if_true, if_false);
    effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
    end = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                           vtrue, vfalse, control);
  }

  Node* initStart = graph()->NewNode(
      common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
      graph()->NewNode(simplified()->NumberLessThan(), start,
                       jsgraph()->ZeroConstant()),
      graph()->NewNode(
          simplified()->NumberMax(),
          graph()->NewNode(simplified()->NumberAdd(), length, start),
          jsgraph()->ZeroConstant()),
      start);
  // The select above guarantees that initStart is non-negative, but
  // our typer can't figure that out yet.
  initStart = effect = graph()->NewNode(
      common()->TypeGuard(Type::UnsignedSmall()), initStart, effect, control);

  Node* resultLength = graph()->NewNode(
      simplified()->NumberMin(),
      graph()->NewNode(simplified()->NumberMax(), end,
                       jsgraph()->ZeroConstant()),
      graph()->NewNode(simplified()->NumberSubtract(), length, initStart));

  // The the select below uses {resultLength} only if {resultLength > 0},
  // but our typer can't figure that out yet.
  Node* to = effect = graph()->NewNode(
      common()->TypeGuard(Type::UnsignedSmall()),
      graph()->NewNode(simplified()->NumberAdd(), initStart, resultLength),
      effect, control);

  Node* result_string = nullptr;
  // Return empty string if {from} is smaller than {to}.
  {
    Node* check = graph()->NewNode(simplified()->NumberLessThan(),
                                   jsgraph()->ZeroConstant(), resultLength);

    Node* branch =
        graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    Node* etrue = effect;
    Node* vtrue = etrue =
        graph()->NewNode(simplified()->StringSubstring(), receiver, initStart,
                         to, etrue, if_true);

    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978
    Node* efalse = effect;
    Node* vfalse = jsgraph()->EmptyStringConstant();

    control = graph()->NewNode(common()->Merge(2), if_true, if_false);
    effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
    result_string =
        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                         vtrue, vfalse, control);
  }

  ReplaceWithValue(node, result_string, effect, control);
  return Replace(result_string);
}

4979
Reduction JSCallReducer::ReduceJSConstructWithArrayLike(Node* node) {
4980 4981 4982 4983
  JSConstructWithArrayLikeNode n(node);
  ConstructParameters const& p = n.Parameters();
  const int arraylike_index = n.LastArgumentIndex();
  DCHECK_EQ(n.ArgumentCount(), 1);  // The arraylike object.
4984
  return ReduceCallOrConstructWithArrayLikeOrSpread(
4985
      node, arraylike_index, p.frequency(), p.feedback(),
4986
      SpeculationMode::kDisallowSpeculation, CallFeedbackRelation::kRelated);
4987 4988
}

4989
Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) {
4990 4991 4992 4993
  JSConstructWithSpreadNode n(node);
  ConstructParameters const& p = n.Parameters();
  const int spread_index = n.LastArgumentIndex();
  DCHECK_GE(n.ArgumentCount(), 1);  // At least the spread.
4994
  return ReduceCallOrConstructWithArrayLikeOrSpread(
4995 4996
      node, spread_index, p.frequency(), p.feedback(),
      SpeculationMode::kDisallowSpeculation, CallFeedbackRelation::kRelated);
4997 4998
}

4999
Reduction JSCallReducer::ReduceReturnReceiver(Node* node) {
5000 5001
  JSCallNode n(node);
  Node* receiver = n.receiver();
5002 5003 5004 5005
  ReplaceWithValue(node, receiver);
  return Replace(receiver);
}

5006 5007 5008 5009
Reduction JSCallReducer::ReduceForInsufficientFeedback(
    Node* node, DeoptimizeReason reason) {
  DCHECK(node->opcode() == IrOpcode::kJSCall ||
         node->opcode() == IrOpcode::kJSConstruct);
5010
  if (!(flags() & kBailoutOnUninitialized)) return NoChange();
5011 5012 5013
  // TODO(mythria): May be add additional flags to specify if we need to deopt
  // on calls / construct rather than checking for TurboProp here. We may need
  // it for NativeContextIndependent code too.
5014
  if (broker()->is_turboprop()) return NoChange();
5015 5016 5017 5018 5019 5020

  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);
  Node* frame_state =
      NodeProperties::FindFrameStateBefore(node, jsgraph()->Dead());
  Node* deoptimize = graph()->NewNode(
5021
      common()->Deoptimize(DeoptimizeKind::kSoft, reason, FeedbackSource()),
5022 5023 5024 5025 5026 5027 5028
      frame_state, effect, control);
  // TODO(bmeurer): This should be on the AdvancedReducer somehow.
  NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
  Revisit(graph()->end());
  node->TrimInputCount(0);
  NodeProperties::ChangeOp(node, common()->Dead());
  return Changed(node);
5029 5030
}

5031 5032 5033 5034
Node* JSCallReducer::LoadReceiverElementsKind(Node* receiver, Effect* effect,
                                              Control control) {
  Node* effect_node = *effect;
  Node* receiver_map = effect_node =
5035
      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
5036 5037
                       receiver, effect_node, control);
  Node* receiver_bit_field2 = effect_node = graph()->NewNode(
5038
      simplified()->LoadField(AccessBuilder::ForMapBitField2()), receiver_map,
5039
      effect_node, control);
5040 5041
  Node* receiver_elements_kind = graph()->NewNode(
      simplified()->NumberShiftRightLogical(),
5042 5043 5044 5045
      graph()->NewNode(
          simplified()->NumberBitwiseAnd(), receiver_bit_field2,
          jsgraph()->Constant(Map::Bits2::ElementsKindBits::kMask)),
      jsgraph()->Constant(Map::Bits2::ElementsKindBits::kShift));
5046
  *effect = effect_node;
5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079
  return receiver_elements_kind;
}

void JSCallReducer::CheckIfElementsKind(Node* receiver_elements_kind,
                                        ElementsKind kind, Node* control,
                                        Node** if_true, Node** if_false) {
  Node* is_packed_kind =
      graph()->NewNode(simplified()->NumberEqual(), receiver_elements_kind,
                       jsgraph()->Constant(GetPackedElementsKind(kind)));
  Node* packed_branch =
      graph()->NewNode(common()->Branch(), is_packed_kind, control);
  Node* if_packed = graph()->NewNode(common()->IfTrue(), packed_branch);

  if (IsHoleyElementsKind(kind)) {
    Node* if_not_packed = graph()->NewNode(common()->IfFalse(), packed_branch);
    Node* is_holey_kind =
        graph()->NewNode(simplified()->NumberEqual(), receiver_elements_kind,
                         jsgraph()->Constant(GetHoleyElementsKind(kind)));
    Node* holey_branch =
        graph()->NewNode(common()->Branch(), is_holey_kind, if_not_packed);
    Node* if_holey = graph()->NewNode(common()->IfTrue(), holey_branch);

    Node* if_not_packed_not_holey =
        graph()->NewNode(common()->IfFalse(), holey_branch);

    *if_true = graph()->NewNode(common()->Merge(2), if_packed, if_holey);
    *if_false = if_not_packed_not_holey;
  } else {
    *if_true = if_packed;
    *if_false = graph()->NewNode(common()->IfFalse(), packed_branch);
  }
}

5080 5081
// ES6 section 22.1.3.18 Array.prototype.push ( )
Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
5082
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
5083

5084 5085
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
5086 5087 5088 5089
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

5090 5091 5092 5093
  int const num_values = n.ArgumentCount();
  Node* receiver = n.receiver();
  Effect effect = n.effect();
  Control control = n.control();
5094

5095
  MapInference inference(broker(), receiver, effect);
5096
  if (!inference.HaveMaps()) return NoChange();
5097
  MapHandles const& receiver_maps = inference.GetMaps();
5098

5099
  std::vector<ElementsKind> kinds;
5100
  if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds, true)) {
5101
    return inference.NoChange();
5102
  }
5103
  if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE();
5104 5105
  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
                                      control, p.feedback());
5106

5107 5108 5109 5110 5111 5112
  std::vector<Node*> controls_to_merge;
  std::vector<Node*> effects_to_merge;
  std::vector<Node*> values_to_merge;
  Node* return_value = jsgraph()->UndefinedConstant();

  Node* receiver_elements_kind =
5113
      LoadReceiverElementsKind(receiver, &effect, control);
5114 5115 5116 5117 5118 5119 5120 5121
  Node* next_control = control;
  Node* next_effect = effect;
  for (size_t i = 0; i < kinds.size(); i++) {
    ElementsKind kind = kinds[i];
    control = next_control;
    effect = next_effect;
    // We do not need branch for the last elements kind.
    if (i != kinds.size() - 1) {
5122 5123 5124 5125
      Node* control_node = control;
      CheckIfElementsKind(receiver_elements_kind, kind, control_node,
                          &control_node, &next_control);
      control = control_node;
5126
    }
5127

5128 5129 5130
    // Collect the value inputs to push.
    std::vector<Node*> values(num_values);
    for (int i = 0; i < num_values; ++i) {
5131
      values[i] = n.Argument(i);
5132
    }
5133

5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144
    for (auto& value : values) {
      if (IsSmiElementsKind(kind)) {
        value = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
                                          value, effect, control);
      } else if (IsDoubleElementsKind(kind)) {
        value = effect = graph()->NewNode(
            simplified()->CheckNumber(p.feedback()), value, effect, control);
        // Make sure we do not store signaling NaNs into double arrays.
        value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
      }
    }
5145

5146 5147 5148 5149 5150
    // Load the "length" property of the {receiver}.
    Node* length = effect = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)),
        receiver, effect, control);
    return_value = length;
5151

5152 5153 5154 5155 5156
    // Check if we have any {values} to push.
    if (num_values > 0) {
      // Compute the resulting "length" of the {receiver}.
      Node* new_length = return_value = graph()->NewNode(
          simplified()->NumberAdd(), length, jsgraph()->Constant(num_values));
5157

5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178
      // Load the elements backing store of the {receiver}.
      Node* elements = effect = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
          receiver, effect, control);
      Node* elements_length = effect = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
          elements, effect, control);

      GrowFastElementsMode mode =
          IsDoubleElementsKind(kind)
              ? GrowFastElementsMode::kDoubleElements
              : GrowFastElementsMode::kSmiOrObjectElements;
      elements = effect = graph()->NewNode(
          simplified()->MaybeGrowFastElements(mode, p.feedback()), receiver,
          elements,
          graph()->NewNode(simplified()->NumberAdd(), length,
                           jsgraph()->Constant(num_values - 1)),
          elements_length, effect, control);

      // Update the JSArray::length field. Since this is observable,
      // there must be no other check after this.
5179
      effect = graph()->NewNode(
5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192
          simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
          receiver, new_length, effect, control);

      // Append the {values} to the {elements}.
      for (int i = 0; i < num_values; ++i) {
        Node* value = values[i];
        Node* index = graph()->NewNode(simplified()->NumberAdd(), length,
                                       jsgraph()->Constant(i));
        effect =
            graph()->NewNode(simplified()->StoreElement(
                                 AccessBuilder::ForFixedArrayElement(kind)),
                             elements, index, value, effect, control);
      }
5193
    }
5194 5195 5196 5197

    controls_to_merge.push_back(control);
    effects_to_merge.push_back(effect);
    values_to_merge.push_back(return_value);
5198
  }
5199

5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215
  if (controls_to_merge.size() > 1) {
    int const count = static_cast<int>(controls_to_merge.size());

    control = graph()->NewNode(common()->Merge(count), count,
                               &controls_to_merge.front());
    effects_to_merge.push_back(control);
    effect = graph()->NewNode(common()->EffectPhi(count), count + 1,
                              &effects_to_merge.front());
    values_to_merge.push_back(control);
    return_value =
        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
                         count + 1, &values_to_merge.front());
  }

  ReplaceWithValue(node, return_value, effect, control);
  return Replace(return_value);
5216 5217 5218 5219
}

// ES6 section 22.1.3.17 Array.prototype.pop ( )
Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
5220
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
5221

5222 5223
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
5224 5225 5226 5227
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

5228 5229 5230
  Effect effect = n.effect();
  Control control = n.control();
  Node* receiver = n.receiver();
5231

5232
  MapInference inference(broker(), receiver, effect);
5233
  if (!inference.HaveMaps()) return NoChange();
5234
  MapHandles const& receiver_maps = inference.GetMaps();
5235

5236
  std::vector<ElementsKind> kinds;
5237
  if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds)) {
5238
    return inference.NoChange();
5239
  }
5240
  if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE();
5241 5242
  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
                                      control, p.feedback());
5243

5244 5245 5246 5247 5248 5249
  std::vector<Node*> controls_to_merge;
  std::vector<Node*> effects_to_merge;
  std::vector<Node*> values_to_merge;
  Node* value = jsgraph()->UndefinedConstant();

  Node* receiver_elements_kind =
5250
      LoadReceiverElementsKind(receiver, &effect, control);
5251 5252 5253 5254 5255 5256 5257 5258
  Node* next_control = control;
  Node* next_effect = effect;
  for (size_t i = 0; i < kinds.size(); i++) {
    ElementsKind kind = kinds[i];
    control = next_control;
    effect = next_effect;
    // We do not need branch for the last elements kind.
    if (i != kinds.size() - 1) {
5259 5260 5261 5262
      Node* control_node = control;
      CheckIfElementsKind(receiver_elements_kind, kind, control_node,
                          &control_node, &next_control);
      control = control_node;
5263
    }
5264

5265 5266 5267 5268
    // Load the "length" property of the {receiver}.
    Node* length = effect = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)),
        receiver, effect, control);
5269

5270 5271 5272 5273 5274
    // Check if the {receiver} has any elements.
    Node* check = graph()->NewNode(simplified()->NumberEqual(), length,
                                   jsgraph()->ZeroConstant());
    Node* branch =
        graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
5275

5276 5277 5278
    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
    Node* etrue = effect;
    Node* vtrue = jsgraph()->UndefinedConstant();
5279

5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318
    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
    Node* efalse = effect;
    Node* vfalse;
    {
      // TODO(tebbi): We should trim the backing store if the capacity is too
      // big, as implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.

      // Load the elements backing store from the {receiver}.
      Node* elements = efalse = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
          receiver, efalse, if_false);

      // Ensure that we aren't popping from a copy-on-write backing store.
      if (IsSmiOrObjectElementsKind(kind)) {
        elements = efalse =
            graph()->NewNode(simplified()->EnsureWritableFastElements(),
                             receiver, elements, efalse, if_false);
      }

      // Compute the new {length}.
      length = graph()->NewNode(simplified()->NumberSubtract(), length,
                                jsgraph()->OneConstant());

      // Store the new {length} to the {receiver}.
      efalse = graph()->NewNode(
          simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
          receiver, length, efalse, if_false);

      // Load the last entry from the {elements}.
      vfalse = efalse = graph()->NewNode(
          simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(kind)),
          elements, length, efalse, if_false);

      // Store a hole to the element we just removed from the {receiver}.
      efalse = graph()->NewNode(
          simplified()->StoreElement(
              AccessBuilder::ForFixedArrayElement(GetHoleyElementsKind(kind))),
          elements, length, jsgraph()->TheHoleConstant(), efalse, if_false);
    }
5319

5320 5321 5322 5323
    control = graph()->NewNode(common()->Merge(2), if_true, if_false);
    effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
    value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                             vtrue, vfalse, control);
5324

5325 5326 5327 5328 5329 5330
    // Convert the hole to undefined. Do this last, so that we can optimize
    // conversion operator via some smart strength reduction in many cases.
    if (IsHoleyElementsKind(kind)) {
      value =
          graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
    }
5331

5332 5333 5334
    controls_to_merge.push_back(control);
    effects_to_merge.push_back(effect);
    values_to_merge.push_back(value);
5335
  }
5336

5337 5338
  if (controls_to_merge.size() > 1) {
    int const count = static_cast<int>(controls_to_merge.size());
5339

5340 5341 5342 5343 5344 5345
    control = graph()->NewNode(common()->Merge(count), count,
                               &controls_to_merge.front());
    effects_to_merge.push_back(control);
    effect = graph()->NewNode(common()->EffectPhi(count), count + 1,
                              &effects_to_merge.front());
    values_to_merge.push_back(control);
5346
    value =
5347 5348
        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
                         count + 1, &values_to_merge.front());
5349 5350 5351 5352
  }

  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
5353 5354 5355 5356
}

// ES6 section 22.1.3.22 Array.prototype.shift ( )
Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
5357
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
5358

5359 5360
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
5361 5362 5363 5364
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

5365 5366 5367 5368 5369 5370
  Node* target = n.target();
  Node* receiver = n.receiver();
  Node* context = n.context();
  FrameState frame_state = n.frame_state();
  Effect effect = n.effect();
  Control control = n.control();
5371

5372
  MapInference inference(broker(), receiver, effect);
5373
  if (!inference.HaveMaps()) return NoChange();
5374
  MapHandles const& receiver_maps = inference.GetMaps();
5375

5376
  std::vector<ElementsKind> kinds;
5377
  if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds)) {
5378
    return inference.NoChange();
5379
  }
5380
  if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE();
5381 5382
  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
                                      control, p.feedback());
5383

5384 5385 5386 5387 5388 5389
  std::vector<Node*> controls_to_merge;
  std::vector<Node*> effects_to_merge;
  std::vector<Node*> values_to_merge;
  Node* value = jsgraph()->UndefinedConstant();

  Node* receiver_elements_kind =
5390
      LoadReceiverElementsKind(receiver, &effect, control);
5391 5392 5393 5394 5395 5396 5397 5398
  Node* next_control = control;
  Node* next_effect = effect;
  for (size_t i = 0; i < kinds.size(); i++) {
    ElementsKind kind = kinds[i];
    control = next_control;
    effect = next_effect;
    // We do not need branch for the last elements kind.
    if (i != kinds.size() - 1) {
5399 5400 5401 5402
      Node* control_node = control;
      CheckIfElementsKind(receiver_elements_kind, kind, control_node,
                          &control_node, &next_control);
      control = control_node;
5403
    }
5404

5405 5406 5407 5408
    // Load length of the {receiver}.
    Node* length = effect = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)),
        receiver, effect, control);
5409

5410 5411 5412 5413 5414
    // Return undefined if {receiver} has no elements.
    Node* check0 = graph()->NewNode(simplified()->NumberEqual(), length,
                                    jsgraph()->ZeroConstant());
    Node* branch0 =
        graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
5415

5416 5417 5418
    Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
    Node* etrue0 = effect;
    Node* vtrue0 = jsgraph()->UndefinedConstant();
5419

5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433
    Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
    Node* efalse0 = effect;
    Node* vfalse0;
    {
      // Check if we should take the fast-path.
      Node* check1 =
          graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
                           jsgraph()->Constant(JSArray::kMaxCopyElements));
      Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
                                       check1, if_false0);

      Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
      Node* etrue1 = efalse0;
      Node* vtrue1;
5434
      {
5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450
        Node* elements = etrue1 = graph()->NewNode(
            simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
            receiver, etrue1, if_true1);

        // Load the first element here, which we return below.
        vtrue1 = etrue1 = graph()->NewNode(
            simplified()->LoadElement(
                AccessBuilder::ForFixedArrayElement(kind)),
            elements, jsgraph()->ZeroConstant(), etrue1, if_true1);

        // Ensure that we aren't shifting a copy-on-write backing store.
        if (IsSmiOrObjectElementsKind(kind)) {
          elements = etrue1 =
              graph()->NewNode(simplified()->EnsureWritableFastElements(),
                               receiver, elements, etrue1, if_true1);
        }
5451

5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490
        // Shift the remaining {elements} by one towards the start.
        Node* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1);
        Node* eloop =
            graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop);
        Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
        NodeProperties::MergeControlToEnd(graph(), common(), terminate);
        Node* index = graph()->NewNode(
            common()->Phi(MachineRepresentation::kTagged, 2),
            jsgraph()->OneConstant(),
            jsgraph()->Constant(JSArray::kMaxCopyElements - 1), loop);

        {
          Node* check2 =
              graph()->NewNode(simplified()->NumberLessThan(), index, length);
          Node* branch2 = graph()->NewNode(common()->Branch(), check2, loop);

          if_true1 = graph()->NewNode(common()->IfFalse(), branch2);
          etrue1 = eloop;

          Node* control = graph()->NewNode(common()->IfTrue(), branch2);
          Node* effect = etrue1;

          ElementAccess const access =
              AccessBuilder::ForFixedArrayElement(kind);
          Node* value = effect =
              graph()->NewNode(simplified()->LoadElement(access), elements,
                               index, effect, control);
          effect = graph()->NewNode(
              simplified()->StoreElement(access), elements,
              graph()->NewNode(simplified()->NumberSubtract(), index,
                               jsgraph()->OneConstant()),
              value, effect, control);

          loop->ReplaceInput(1, control);
          eloop->ReplaceInput(1, effect);
          index->ReplaceInput(1,
                              graph()->NewNode(simplified()->NumberAdd(), index,
                                               jsgraph()->OneConstant()));
        }
5491

5492 5493 5494
        // Compute the new {length}.
        length = graph()->NewNode(simplified()->NumberSubtract(), length,
                                  jsgraph()->OneConstant());
5495

5496 5497 5498 5499
        // Store the new {length} to the {receiver}.
        etrue1 = graph()->NewNode(
            simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)),
            receiver, length, etrue1, if_true1);
5500

5501 5502 5503 5504 5505 5506
        // Store a hole to the element we just removed from the {receiver}.
        etrue1 = graph()->NewNode(
            simplified()->StoreElement(AccessBuilder::ForFixedArrayElement(
                GetHoleyElementsKind(kind))),
            elements, length, jsgraph()->TheHoleConstant(), etrue1, if_true1);
      }
5507

5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530
      Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
      Node* efalse1 = efalse0;
      Node* vfalse1;
      {
        // Call the generic C++ implementation.
        const int builtin_index = Builtins::kArrayShift;
        auto call_descriptor = Linkage::GetCEntryStubCallDescriptor(
            graph()->zone(), 1, BuiltinArguments::kNumExtraArgsWithReceiver,
            Builtins::name(builtin_index), node->op()->properties(),
            CallDescriptor::kNeedsFrameState);
        Node* stub_code = jsgraph()->CEntryStubConstant(1, kDontSaveFPRegs,
                                                        kArgvOnStack, true);
        Address builtin_entry = Builtins::CppEntryOf(builtin_index);
        Node* entry = jsgraph()->ExternalConstant(
            ExternalReference::Create(builtin_entry));
        Node* argc =
            jsgraph()->Constant(BuiltinArguments::kNumExtraArgsWithReceiver);
        if_false1 = efalse1 = vfalse1 =
            graph()->NewNode(common()->Call(call_descriptor), stub_code,
                             receiver, jsgraph()->PaddingConstant(), argc,
                             target, jsgraph()->UndefinedConstant(), entry,
                             argc, context, frame_state, efalse1, if_false1);
      }
5531

5532 5533 5534 5535 5536 5537
      if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
      efalse0 =
          graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
      vfalse0 =
          graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                           vtrue1, vfalse1, if_false0);
5538 5539 5540 5541
    }

    control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
    effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
5542 5543
    value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                             vtrue0, vfalse0, control);
5544 5545 5546

    // Convert the hole to undefined. Do this last, so that we can optimize
    // conversion operator via some smart strength reduction in many cases.
5547
    if (IsHoleyElementsKind(kind)) {
5548 5549 5550 5551
      value =
          graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value);
    }

5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572
    controls_to_merge.push_back(control);
    effects_to_merge.push_back(effect);
    values_to_merge.push_back(value);
  }

  if (controls_to_merge.size() > 1) {
    int const count = static_cast<int>(controls_to_merge.size());

    control = graph()->NewNode(common()->Merge(count), count,
                               &controls_to_merge.front());
    effects_to_merge.push_back(control);
    effect = graph()->NewNode(common()->EffectPhi(count), count + 1,
                              &effects_to_merge.front());
    values_to_merge.push_back(control);
    value =
        graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
                         count + 1, &values_to_merge.front());
  }

  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
5573 5574
}

5575 5576
// ES6 section 22.1.3.23 Array.prototype.slice ( )
Reduction JSCallReducer::ReduceArrayPrototypeSlice(Node* node) {
5577
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
5578

5579
  if (!FLAG_turbo_inline_array_builtins) return NoChange();
5580 5581
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
5582 5583 5584 5585
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

5586 5587 5588 5589 5590 5591
  Node* receiver = n.receiver();
  Node* start = n.ArgumentOr(0, jsgraph()->ZeroConstant());
  Node* end = n.ArgumentOrUndefined(1, jsgraph());
  Node* context = n.context();
  Effect effect = n.effect();
  Control control = n.control();
5592

5593 5594 5595 5596 5597 5598 5599 5600
  // Optimize for the case where we simply clone the {receiver},
  // i.e. when the {start} is zero and the {end} is undefined
  // (meaning it will be set to {receiver}s "length" property).
  if (!NumberMatcher(start).Is(0) ||
      !HeapObjectMatcher(end).Is(factory()->undefined_value())) {
    return NoChange();
  }

5601
  MapInference inference(broker(), receiver, effect);
5602
  if (!inference.HaveMaps()) return NoChange();
5603
  MapHandles const& receiver_maps = inference.GetMaps();
5604

5605 5606 5607
  // Check that the maps are of JSArray (and more).
  // TODO(turbofan): Consider adding special case for the common pattern
  // `slice.call(arguments)`, for example jQuery makes heavy use of that.
5608
  bool can_be_holey = false;
5609 5610
  for (Handle<Map> map : receiver_maps) {
    MapRef receiver_map(broker(), map);
5611 5612
    if (!receiver_map.supports_fast_array_iteration())
      return inference.NoChange();
5613 5614 5615
    if (IsHoleyElementsKind(receiver_map.elements_kind())) {
      can_be_holey = true;
    }
5616 5617
  }

5618 5619
  if (!dependencies()->DependOnArraySpeciesProtector())
    return inference.NoChange();
5620
  if (can_be_holey) {
5621
    if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE();
5622
  }
5623 5624
  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
                                      control, p.feedback());
5625

5626 5627 5628 5629 5630 5631
  // TODO(turbofan): We can do even better here, either adding a CloneArray
  // simplified operator, whose output type indicates that it's an Array,
  // saving subsequent checks, or yet better, by introducing new operators
  // CopySmiOrObjectElements / CopyDoubleElements and inlining the JSArray
  // allocation in here. That way we'd even get escape analysis and scalar
  // replacement to help in some cases.
5632 5633 5634
  Callable callable =
      Builtins::CallableFor(isolate(), Builtins::kCloneFastJSArray);
  auto call_descriptor = Linkage::GetStubCallDescriptor(
5635 5636
      graph()->zone(), callable.descriptor(),
      callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags,
5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648
      Operator::kNoThrow | Operator::kNoDeopt);

  // Calls to Builtins::kCloneFastJSArray produce COW arrays
  // if the original array is COW
  Node* clone = effect = graph()->NewNode(
      common()->Call(call_descriptor), jsgraph()->HeapConstant(callable.code()),
      receiver, context, effect, control);

  ReplaceWithValue(node, clone, effect, control);
  return Replace(clone);
}

5649 5650
// ES6 section 22.1.2.2 Array.isArray ( arg )
Reduction JSCallReducer::ReduceArrayIsArray(Node* node) {
5651
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
5652

5653
  // We certainly know that undefined is not an array.
5654 5655
  JSCallNode n(node);
  if (n.ArgumentCount() < 1) {
5656 5657 5658 5659 5660
    Node* value = jsgraph()->FalseConstant();
    ReplaceWithValue(node, value);
    return Replace(value);
  }

5661 5662 5663 5664 5665
  Effect effect = n.effect();
  Control control = n.control();
  Node* context = n.context();
  FrameState frame_state = n.frame_state();
  Node* object = n.Argument(0);
5666 5667 5668 5669 5670 5671 5672 5673 5674 5675
  node->ReplaceInput(0, object);
  node->ReplaceInput(1, context);
  node->ReplaceInput(2, frame_state);
  node->ReplaceInput(3, effect);
  node->ReplaceInput(4, control);
  node->TrimInputCount(5);
  NodeProperties::ChangeOp(node, javascript()->ObjectIsArray());
  return Changed(node);
}

5676 5677 5678
Reduction JSCallReducer::ReduceArrayIterator(Node* node,
                                             ArrayIteratorKind array_kind,
                                             IterationKind iteration_kind) {
5679
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
5680

5681 5682 5683 5684 5685
  JSCallNode n(node);
  Node* receiver = n.receiver();
  Node* context = n.context();
  Effect effect = n.effect();
  Control control = n.control();
5686

5687
  // Check if we know that {receiver} is a valid JSReceiver.
5688 5689
  MapInference inference(broker(), receiver, effect);
  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAreJSReceiver()) {
5690
    return NoChange();
5691 5692
  }

5693 5694 5695 5696 5697 5698 5699
  // TypedArray iteration is stricter: it throws if the receiver is not a typed
  // array. So don't bother optimizing in that case.
  if (array_kind == ArrayIteratorKind::kTypedArray &&
      !inference.AllOfInstanceTypesAre(InstanceType::JS_TYPED_ARRAY_TYPE)) {
    return NoChange();
  }

5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725
  if (array_kind == ArrayIteratorKind::kTypedArray) {
    // Make sure we deopt when the JSArrayBuffer is detached.
    if (!dependencies()->DependOnArrayBufferDetachingProtector()) {
      CallParameters const& p = CallParametersOf(node->op());
      if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
        return NoChange();
      }
      Node* buffer = effect = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
          receiver, effect, control);
      Node* buffer_bit_field = effect = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
          buffer, effect, control);
      Node* check = graph()->NewNode(
          simplified()->NumberEqual(),
          graph()->NewNode(
              simplified()->NumberBitwiseAnd(), buffer_bit_field,
              jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
          jsgraph()->ZeroConstant());
      effect = graph()->NewNode(
          simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached,
                                p.feedback()),
          check, effect, control);
    }
  }

5726 5727 5728 5729 5730 5731 5732
  // Morph the {node} into a JSCreateArrayIterator with the given {kind}.
  RelaxControls(node);
  node->ReplaceInput(0, receiver);
  node->ReplaceInput(1, context);
  node->ReplaceInput(2, effect);
  node->ReplaceInput(3, control);
  node->TrimInputCount(4);
5733 5734
  NodeProperties::ChangeOp(node,
                           javascript()->CreateArrayIterator(iteration_kind));
5735
  return Changed(node);
5736 5737
}

5738 5739
// ES #sec-%arrayiteratorprototype%.next
Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
5740
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
5741

5742 5743 5744 5745 5746 5747
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
  Node* iterator = n.receiver();
  Node* context = n.context();
  Effect effect = n.effect();
  Control control = n.control();
5748

5749 5750
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
5751 5752
  }

5753
  if (iterator->opcode() != IrOpcode::kJSCreateArrayIterator) return NoChange();
5754

5755 5756
  IterationKind const iteration_kind =
      CreateArrayIteratorParametersOf(iterator->op()).kind();
5757 5758
  Node* iterated_object = NodeProperties::GetValueInput(iterator, 0);
  Node* iterator_effect = NodeProperties::GetEffectInput(iterator);
5759

5760
  MapInference inference(broker(), iterated_object, iterator_effect);
5761
  if (!inference.HaveMaps()) return NoChange();
5762
  MapHandles const& iterated_object_maps = inference.GetMaps();
5763

5764
  // Check that various {iterated_object_maps} have compatible elements kinds.
5765 5766
  ElementsKind elements_kind =
      MapRef(broker(), iterated_object_maps[0]).elements_kind();
5767
  if (IsTypedArrayElementsKind(elements_kind)) {
5768 5769 5770
    // TurboFan doesn't support loading from BigInt typed arrays yet.
    if (elements_kind == BIGUINT64_ELEMENTS ||
        elements_kind == BIGINT64_ELEMENTS) {
5771
      return inference.NoChange();
5772
    }
5773 5774 5775
    for (Handle<Map> map : iterated_object_maps) {
      MapRef iterated_object_map(broker(), map);
      if (iterated_object_map.elements_kind() != elements_kind) {
5776
        return inference.NoChange();
5777 5778
      }
    }
5779
  } else {
5780 5781
    if (!CanInlineArrayIteratingBuiltin(broker(), iterated_object_maps,
                                        &elements_kind)) {
5782
      return inference.NoChange();
5783 5784 5785
    }
  }

5786
  if (IsHoleyElementsKind(elements_kind)) {
5787
    if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE();
5788
  }
5789 5790 5791 5792
  // Since the map inference was done relative to {iterator_effect} rather than
  // {effect}, we need to guard the use of the map(s) even when the inference
  // was reliable.
  inference.InsertMapChecks(jsgraph(), &effect, control, p.feedback());
5793

5794
  if (IsTypedArrayElementsKind(elements_kind)) {
5795
    // See if we can skip the detaching check.
5796
    if (!dependencies()->DependOnArrayBufferDetachingProtector()) {
5797
      // Bail out if the {iterated_object}s JSArrayBuffer was detached.
5798 5799 5800
      Node* buffer = effect = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
          iterated_object, effect, control);
5801 5802 5803 5804 5805 5806 5807
      Node* buffer_bit_field = effect = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
          buffer, effect, control);
      Node* check = graph()->NewNode(
          simplified()->NumberEqual(),
          graph()->NewNode(
              simplified()->NumberBitwiseAnd(), buffer_bit_field,
5808
              jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
5809
          jsgraph()->ZeroConstant());
5810
      effect = graph()->NewNode(
5811
          simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached,
5812
                                p.feedback()),
5813
          check, effect, control);
5814
    }
5815
  }
5816

5817 5818 5819 5820 5821
  // Load the [[NextIndex]] from the {iterator} and leverage the fact
  // that we definitely know that it's in Unsigned32 range since the
  // {iterated_object} is either a JSArray or a JSTypedArray. For the
  // latter case we even know that it's a Smi in UnsignedSmall range.
  FieldAccess index_access = AccessBuilder::ForJSArrayIteratorNextIndex();
5822
  if (IsTypedArrayElementsKind(elements_kind)) {
5823
    index_access.type = TypeCache::Get()->kJSTypedArrayLengthType;
5824
  } else {
5825
    index_access.type = TypeCache::Get()->kJSArrayLengthType;
5826 5827 5828 5829
  }
  Node* index = effect = graph()->NewNode(simplified()->LoadField(index_access),
                                          iterator, effect, control);

5830 5831 5832 5833 5834 5835 5836 5837 5838 5839
  // Load the elements of the {iterated_object}. While it feels
  // counter-intuitive to place the elements pointer load before
  // the condition below, as it might not be needed (if the {index}
  // is out of bounds for the {iterated_object}), it's better this
  // way as it allows the LoadElimination to eliminate redundant
  // reloads of the elements pointer.
  Node* elements = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
      iterated_object, effect, control);

5840 5841 5842 5843
  // Load the length of the {iterated_object}. Due to the map checks we
  // already know something about the length here, which we can leverage
  // to generate Word32 operations below without additional checking.
  FieldAccess length_access =
5844
      IsTypedArrayElementsKind(elements_kind)
5845 5846 5847 5848
          ? AccessBuilder::ForJSTypedArrayLength()
          : AccessBuilder::ForJSArrayLength(elements_kind);
  Node* length = effect = graph()->NewNode(
      simplified()->LoadField(length_access), iterated_object, effect, control);
5849

5850 5851 5852
  // Check whether {index} is within the valid range for the {iterated_object}.
  Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, length);
  Node* branch =
5853
      graph()->NewNode(common()->Branch(BranchHint::kNone), check, control);
5854

5855 5856 5857 5858 5859 5860 5861 5862
  Node* done_true;
  Node* value_true;
  Node* etrue = effect;
  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  {
    // We know that the {index} is range of the {length} now.
    index = etrue = graph()->NewNode(
        common()->TypeGuard(
5863
            Type::Range(0.0, length_access.type.Max() - 1.0, graph()->zone())),
5864 5865 5866 5867 5868 5869 5870 5871 5872
        index, etrue, if_true);

    done_true = jsgraph()->FalseConstant();
    if (iteration_kind == IterationKind::kKeys) {
      // Just return the {index}.
      value_true = index;
    } else {
      DCHECK(iteration_kind == IterationKind::kEntries ||
             iteration_kind == IterationKind::kValues);
5873

5874 5875 5876 5877 5878
      if (IsTypedArrayElementsKind(elements_kind)) {
        Node* base_ptr = etrue =
            graph()->NewNode(simplified()->LoadField(
                                 AccessBuilder::ForJSTypedArrayBasePointer()),
                             iterated_object, etrue, if_true);
5879
        Node* external_ptr = etrue = graph()->NewNode(
5880
            simplified()->LoadField(
5881 5882
                AccessBuilder::ForJSTypedArrayExternalPointer()),
            iterated_object, etrue, if_true);
5883 5884 5885

        ExternalArrayType array_type = kExternalInt8Array;
        switch (elements_kind) {
5886 5887 5888
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
  case TYPE##_ELEMENTS:                           \
    array_type = kExternal##Type##Array;          \
5889 5890 5891 5892 5893 5894 5895
    break;
          TYPED_ARRAYS(TYPED_ARRAY_CASE)
          default:
            UNREACHABLE();
#undef TYPED_ARRAY_CASE
        }

5896 5897 5898 5899 5900 5901
        Node* buffer = etrue =
            graph()->NewNode(simplified()->LoadField(
                                 AccessBuilder::ForJSArrayBufferViewBuffer()),
                             iterated_object, etrue, if_true);

        value_true = etrue =
5902
            graph()->NewNode(simplified()->LoadTypedElement(array_type), buffer,
5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918
                             base_ptr, external_ptr, index, etrue, if_true);
      } else {
        value_true = etrue = graph()->NewNode(
            simplified()->LoadElement(
                AccessBuilder::ForFixedArrayElement(elements_kind)),
            elements, index, etrue, if_true);

        // Convert hole to undefined if needed.
        if (elements_kind == HOLEY_ELEMENTS ||
            elements_kind == HOLEY_SMI_ELEMENTS) {
          value_true = graph()->NewNode(
              simplified()->ConvertTaggedHoleToUndefined(), value_true);
        } else if (elements_kind == HOLEY_DOUBLE_ELEMENTS) {
          // TODO(6587): avoid deopt if not all uses of value are truncated.
          CheckFloat64HoleMode mode = CheckFloat64HoleMode::kAllowReturnHole;
          value_true = etrue = graph()->NewNode(
5919 5920
              simplified()->CheckFloat64Hole(mode, p.feedback()), value_true,
              etrue, if_true);
5921 5922 5923
        }
      }

5924 5925 5926 5927 5928 5929 5930 5931
      if (iteration_kind == IterationKind::kEntries) {
        // Allocate elements for key/value pair
        value_true = etrue =
            graph()->NewNode(javascript()->CreateKeyValueArray(), index,
                             value_true, context, etrue);
      } else {
        DCHECK_EQ(IterationKind::kValues, iteration_kind);
      }
5932
    }
5933 5934 5935 5936 5937 5938 5939

    // Increment the [[NextIndex]] field in the {iterator}. The TypeGuards
    // above guarantee that the {next_index} is in the UnsignedSmall range.
    Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
                                        jsgraph()->OneConstant());
    etrue = graph()->NewNode(simplified()->StoreField(index_access), iterator,
                             next_index, etrue, if_true);
5940 5941
  }

5942 5943 5944 5945
  Node* done_false;
  Node* value_false;
  Node* efalse = effect;
  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
5946
  {
5947 5948 5949
    // iterator.[[NextIndex]] >= array.length, stop iterating.
    done_false = jsgraph()->TrueConstant();
    value_false = jsgraph()->UndefinedConstant();
5950

5951
    if (!IsTypedArrayElementsKind(elements_kind)) {
5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965
      // Mark the {iterator} as exhausted by setting the [[NextIndex]] to a
      // value that will never pass the length check again (aka the maximum
      // value possible for the specific iterated object). Note that this is
      // different from what the specification says, which is changing the
      // [[IteratedObject]] field to undefined, but that makes it difficult
      // to eliminate the map checks and "length" accesses in for..of loops.
      //
      // This is not necessary for JSTypedArray's, since the length of those
      // cannot change later and so if we were ever out of bounds for them
      // we will stay out-of-bounds forever.
      Node* end_index = jsgraph()->Constant(index_access.type.Max());
      efalse = graph()->NewNode(simplified()->StoreField(index_access),
                                iterator, end_index, efalse, if_false);
    }
5966 5967
  }

5968 5969
  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
5970 5971
  Node* value =
      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
5972
                       value_true, value_false, control);
5973 5974
  Node* done =
      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
5975
                       done_true, done_false, control);
5976 5977 5978 5979 5980 5981 5982 5983

  // Create IteratorResult object.
  value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
                                    value, done, context, effect);
  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
}

5984 5985 5986
// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
// ES6 section 21.1.3.3 String.prototype.codePointAt ( pos )
Reduction JSCallReducer::ReduceStringPrototypeStringAt(
5987
    const Operator* string_access_operator, Node* node) {
5988
  DCHECK(string_access_operator->opcode() == IrOpcode::kStringCharCodeAt ||
5989
         string_access_operator->opcode() == IrOpcode::kStringCodePointAt);
5990 5991
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
5992 5993 5994 5995
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

5996 5997 5998 5999
  Node* receiver = n.receiver();
  Node* index = n.ArgumentOr(0, jsgraph()->ZeroConstant());
  Effect effect = n.effect();
  Control control = n.control();
6000

6001
  // Ensure that the {receiver} is actually a String.
6002 6003 6004 6005 6006 6007 6008
  receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
                                       receiver, effect, control);

  // Determine the {receiver} length.
  Node* receiver_length =
      graph()->NewNode(simplified()->StringLength(), receiver);

6009 6010 6011
  // Check that the {index} is within range.
  index = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
                                    index, receiver_length, effect, control);
6012

6013
  // Return the character from the {receiver} as single character string.
6014
  Node* masked_index = graph()->NewNode(simplified()->PoisonIndex(), index);
6015 6016
  Node* value = effect = graph()->NewNode(string_access_operator, receiver,
                                          masked_index, effect, control);
6017 6018 6019 6020 6021

  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
}

6022 6023 6024
// ES section 21.1.3.20
// String.prototype.startsWith ( searchString [ , position ] )
Reduction JSCallReducer::ReduceStringPrototypeStartsWith(Node* node) {
6025 6026
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
6027 6028 6029
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
6030

6031 6032 6033
  Node* receiver = n.receiver();
  Effect effect = n.effect();
  Control control = n.control();
6034

6035
  if (n.ArgumentCount() < 1) {
6036 6037 6038
    effect = graph()->NewNode(simplified()->CheckString(p.feedback()), receiver,
                              effect, control);

6039
    Node* value = jsgraph()->FalseConstant();
6040
    ReplaceWithValue(node, value, effect, control);
6041 6042 6043
    return Replace(value);
  }

6044 6045
  Node* search_string = n.Argument(0);
  Node* position = n.ArgumentOr(1, jsgraph()->ZeroConstant());
6046 6047

  HeapObjectMatcher m(search_string);
6048
  if (m.HasResolvedValue()) {
6049 6050 6051 6052
    ObjectRef target_ref = m.Ref(broker());
    if (target_ref.IsString()) {
      StringRef str = target_ref.AsString();
      if (str.length() == 1) {
6053 6054 6055
        receiver = effect = graph()->NewNode(
            simplified()->CheckString(p.feedback()), receiver, effect, control);

6056 6057 6058 6059
        position = effect = graph()->NewNode(
            simplified()->CheckSmi(p.feedback()), position, effect, control);

        Node* string_length =
6060
            graph()->NewNode(simplified()->StringLength(), receiver);
6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079
        Node* unsigned_position = graph()->NewNode(
            simplified()->NumberMax(), position, jsgraph()->ZeroConstant());

        Node* check = graph()->NewNode(simplified()->NumberLessThan(),
                                       unsigned_position, string_length);
        Node* branch = graph()->NewNode(common()->Branch(BranchHint::kNone),
                                        check, control);

        Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
        Node* efalse = effect;
        Node* vfalse = jsgraph()->FalseConstant();

        Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
        Node* etrue = effect;
        Node* vtrue;
        {
          Node* masked_position =
              graph()->NewNode(simplified()->PoisonIndex(), unsigned_position);
          Node* string_first = etrue =
6080
              graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103
                               masked_position, etrue, if_true);

          Node* search_first = jsgraph()->Constant(str.GetFirstChar());
          vtrue = graph()->NewNode(simplified()->NumberEqual(), string_first,
                                   search_first);
        }

        control = graph()->NewNode(common()->Merge(2), if_true, if_false);
        Node* value =
            graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                             vtrue, vfalse, control);
        effect =
            graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);

        ReplaceWithValue(node, value, effect, control);
        return Replace(value);
      }
    }
  }

  return NoChange();
}

6104 6105
// ES section 21.1.3.1 String.prototype.charAt ( pos )
Reduction JSCallReducer::ReduceStringPrototypeCharAt(Node* node) {
6106 6107
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
6108 6109 6110 6111
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

6112 6113 6114 6115
  Node* receiver = n.receiver();
  Node* index = n.ArgumentOr(0, jsgraph()->ZeroConstant());
  Effect effect = n.effect();
  Control control = n.control();
6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129

  // Ensure that the {receiver} is actually a String.
  receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
                                       receiver, effect, control);

  // Determine the {receiver} length.
  Node* receiver_length =
      graph()->NewNode(simplified()->StringLength(), receiver);

  // Check that the {index} is within range.
  index = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
                                    index, receiver_length, effect, control);

  // Return the character from the {receiver} as single character string.
6130
  Node* masked_index = graph()->NewNode(simplified()->PoisonIndex(), index);
6131 6132 6133
  Node* value = effect =
      graph()->NewNode(simplified()->StringCharCodeAt(), receiver, masked_index,
                       effect, control);
6134
  value = graph()->NewNode(simplified()->StringFromSingleCharCode(), value);
6135 6136 6137 6138 6139

  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
}

6140 6141 6142
#ifdef V8_INTL_SUPPORT

Reduction JSCallReducer::ReduceStringPrototypeToLowerCaseIntl(Node* node) {
6143 6144
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
6145 6146 6147
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
6148 6149
  Effect effect = n.effect();
  Control control = n.control();
6150

6151 6152
  Node* receiver = effect = graph()->NewNode(
      simplified()->CheckString(p.feedback()), n.receiver(), effect, control);
6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163

  NodeProperties::ReplaceEffectInput(node, effect);
  RelaxEffectsAndControls(node);
  node->ReplaceInput(0, receiver);
  node->TrimInputCount(1);
  NodeProperties::ChangeOp(node, simplified()->StringToLowerCaseIntl());
  NodeProperties::SetType(node, Type::String());
  return Changed(node);
}

Reduction JSCallReducer::ReduceStringPrototypeToUpperCaseIntl(Node* node) {
6164 6165
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
6166 6167 6168
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
6169 6170
  Effect effect = n.effect();
  Control control = n.control();
6171

6172 6173
  Node* receiver = effect = graph()->NewNode(
      simplified()->CheckString(p.feedback()), n.receiver(), effect, control);
6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185

  NodeProperties::ReplaceEffectInput(node, effect);
  RelaxEffectsAndControls(node);
  node->ReplaceInput(0, receiver);
  node->TrimInputCount(1);
  NodeProperties::ChangeOp(node, simplified()->StringToUpperCaseIntl());
  NodeProperties::SetType(node, Type::String());
  return Changed(node);
}

#endif  // V8_INTL_SUPPORT

6186
// ES #sec-string.fromcharcode
6187
Reduction JSCallReducer::ReduceStringFromCharCode(Node* node) {
6188 6189
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
6190 6191 6192
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
6193 6194 6195 6196
  if (n.ArgumentCount() == 1) {
    Effect effect = n.effect();
    Control control = n.control();
    Node* input = n.Argument(0);
6197 6198 6199 6200 6201 6202

    input = effect = graph()->NewNode(
        simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
                                          p.feedback()),
        input, effect, control);

6203 6204
    Node* value =
        graph()->NewNode(simplified()->StringFromSingleCharCode(), input);
6205 6206 6207 6208 6209 6210
    ReplaceWithValue(node, value, effect);
    return Replace(value);
  }
  return NoChange();
}

6211 6212
// ES #sec-string.fromcodepoint
Reduction JSCallReducer::ReduceStringFromCodePoint(Node* node) {
6213 6214
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
6215 6216 6217
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
6218
  if (n.ArgumentCount() != 1) return NoChange();
6219

6220 6221 6222
  Effect effect = n.effect();
  Control control = n.control();
  Node* input = n.Argument(0);
6223

6224 6225 6226 6227 6228 6229 6230 6231 6232
  input = effect = graph()->NewNode(
      simplified()->CheckBounds(p.feedback(),
                                CheckBoundsFlag::kConvertStringAndMinusZero),
      input, jsgraph()->Constant(0x10FFFF + 1), effect, control);

  Node* value =
      graph()->NewNode(simplified()->StringFromSingleCodePoint(), input);
  ReplaceWithValue(node, value, effect);
  return Replace(value);
6233 6234
}

6235
Reduction JSCallReducer::ReduceStringPrototypeIterator(Node* node) {
6236 6237 6238 6239
  // TODO(jgruber): We could reduce here when generating native context
  // independent code, if LowerJSCreateStringIterator were implemented in
  // generic lowering.
  if (broker()->is_native_context_independent()) return NoChange();
6240 6241
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
6242 6243 6244 6245 6246
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);
6247 6248
  Node* receiver = effect = graph()->NewNode(
      simplified()->CheckString(p.feedback()), n.receiver(), effect, control);
6249 6250 6251 6252 6253 6254 6255 6256
  Node* iterator = effect =
      graph()->NewNode(javascript()->CreateStringIterator(), receiver,
                       jsgraph()->NoContextConstant(), effect);
  ReplaceWithValue(node, iterator, effect, control);
  return Replace(iterator);
}

Reduction JSCallReducer::ReduceStringIteratorPrototypeNext(Node* node) {
6257 6258 6259 6260 6261
  JSCallNode n(node);
  Node* receiver = n.receiver();
  Effect effect = n.effect();
  Control control = n.control();
  Node* context = n.context();
6262

6263 6264 6265
  MapInference inference(broker(), receiver, effect);
  if (!inference.HaveMaps() ||
      !inference.AllOfInstanceTypesAre(JS_STRING_ITERATOR_TYPE)) {
6266
    return NoChange();
6267
  }
6268

6269 6270 6271 6272 6273 6274 6275
  Node* string = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()),
      receiver, effect, control);
  Node* index = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()),
      receiver, effect, control);
  Node* length = graph()->NewNode(simplified()->StringLength(), string);
6276

6277 6278 6279 6280 6281
  // branch0: if (index < length)
  Node* check0 =
      graph()->NewNode(simplified()->NumberLessThan(), index, length);
  Node* branch0 =
      graph()->NewNode(common()->Branch(BranchHint::kNone), check0, control);
6282

6283 6284 6285 6286 6287 6288
  Node* etrue0 = effect;
  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* done_true;
  Node* vtrue0;
  {
    done_true = jsgraph()->FalseConstant();
6289 6290
    vtrue0 = etrue0 = graph()->NewNode(simplified()->StringFromCodePointAt(),
                                       string, index, etrue0, if_true0);
6291 6292 6293 6294 6295 6296 6297

    // Update iterator.[[NextIndex]]
    Node* char_length = graph()->NewNode(simplified()->StringLength(), vtrue0);
    index = graph()->NewNode(simplified()->NumberAdd(), index, char_length);
    etrue0 = graph()->NewNode(
        simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()),
        receiver, index, etrue0, if_true0);
6298
  }
6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* done_false;
  Node* vfalse0;
  {
    vfalse0 = jsgraph()->UndefinedConstant();
    done_false = jsgraph()->TrueConstant();
  }

  control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue0, effect, control);
  Node* value =
      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), vtrue0,
                       vfalse0, control);
  Node* done =
      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                       done_true, done_false, control);

  value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
                                    value, done, context, effect);

  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
6322 6323
}

6324
// ES #sec-string.prototype.concat
6325
Reduction JSCallReducer::ReduceStringPrototypeConcat(Node* node) {
6326 6327 6328 6329
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
  const int parameter_count = n.ArgumentCount();
  if (parameter_count > 1) return NoChange();
6330 6331 6332
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
6333

6334 6335 6336 6337
  Effect effect = n.effect();
  Control control = n.control();
  Node* receiver = effect = graph()->NewNode(
      simplified()->CheckString(p.feedback()), n.receiver(), effect, control);
6338

6339
  if (parameter_count == 0) {
6340 6341 6342
    ReplaceWithValue(node, receiver, effect, control);
    return Replace(receiver);
  }
6343

6344 6345
  Node* argument = effect = graph()->NewNode(
      simplified()->CheckString(p.feedback()), n.Argument(0), effect, control);
6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357
  Node* receiver_length =
      graph()->NewNode(simplified()->StringLength(), receiver);
  Node* argument_length =
      graph()->NewNode(simplified()->StringLength(), argument);
  Node* length = graph()->NewNode(simplified()->NumberAdd(), receiver_length,
                                  argument_length);
  length = effect = graph()->NewNode(
      simplified()->CheckBounds(p.feedback()), length,
      jsgraph()->Constant(String::kMaxLength + 1), effect, control);

  Node* value = graph()->NewNode(simplified()->StringConcat(), length, receiver,
                                 argument);
6358 6359 6360 6361 6362

  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
}

6363
Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
6364 6365 6366 6367 6368
  // TODO(jgruber): We could reduce here when generating native context
  // independent code, if LowerJSCreatePromise were implemented in generic
  // lowering.
  if (broker()->is_native_context_independent()) return NoChange();

6369
  DisallowHeapAccessIf no_heap_access(should_disallow_heap_access());
6370
  PromiseBuiltinReducerAssembler a(this, node, broker());
6371

6372
  // We only inline when we have the executor.
6373
  if (a.ConstructArity() < 1) return NoChange();
6374
  // Only handle builtins Promises, not subclasses.
6375
  if (a.TargetInput() != a.NewTargetInput()) return NoChange();
6376
  if (!dependencies()->DependOnPromiseHookProtector()) return NoChange();
6377

6378 6379
  TNode<Object> subgraph = a.ReducePromiseConstructor(native_context());
  return ReplaceWithSubgraph(&a, subgraph);
6380 6381
}

6382 6383 6384 6385 6386 6387 6388 6389 6390
bool JSCallReducer::DoPromiseChecks(MapInference* inference) {
  if (!inference->HaveMaps()) return false;
  MapHandles const& receiver_maps = inference->GetMaps();

  // Check whether all {receiver_maps} are JSPromise maps and
  // have the initial Promise.prototype as their [[Prototype]].
  for (Handle<Map> map : receiver_maps) {
    MapRef receiver_map(broker(), map);
    if (!receiver_map.IsJSPromiseMap()) return false;
6391
    if (should_disallow_heap_access() && !receiver_map.serialized_prototype()) {
6392
      TRACE_BROKER_MISSING(broker(), "prototype for map " << receiver_map);
6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403
      return false;
    }
    if (!receiver_map.prototype().equals(
            native_context().promise_prototype())) {
      return false;
    }
  }

  return true;
}

6404 6405
// ES section #sec-promise.prototype.catch
Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
6406 6407
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
6408 6409 6410
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
6411
  int arity = p.arity_without_implicit_args();
6412 6413 6414
  Node* receiver = n.receiver();
  Effect effect = n.effect();
  Control control = n.control();
6415

6416
  MapInference inference(broker(), receiver, effect);
6417
  if (!DoPromiseChecks(&inference)) return inference.NoChange();
6418

6419
  if (!dependencies()->DependOnPromiseThenProtector()) {
6420
    return inference.NoChange();
6421
  }
6422 6423
  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
                                      control, p.feedback());
6424 6425 6426 6427

  // Massage the {node} to call "then" instead by first removing all inputs
  // following the onRejected parameter, and then filling up the parameters
  // to two inputs from the left with undefined.
6428
  Node* target = jsgraph()->Constant(native_context().promise_then());
6429 6430 6431 6432 6433 6434 6435
  NodeProperties::ReplaceValueInput(node, target, 0);
  NodeProperties::ReplaceEffectInput(node, effect);
  for (; arity > 1; --arity) node->RemoveInput(3);
  for (; arity < 2; ++arity) {
    node->InsertInput(graph()->zone(), 2, jsgraph()->UndefinedConstant());
  }
  NodeProperties::ChangeOp(
6436
      node, javascript()->Call(
6437
                JSCallNode::ArityForArgc(arity), p.frequency(), p.feedback(),
6438 6439
                ConvertReceiverMode::kNotNullOrUndefined, p.speculation_mode(),
                CallFeedbackRelation::kUnrelated));
6440
  return Changed(node).FollowedBy(ReducePromisePrototypeThen(node));
6441 6442
}

6443 6444 6445
Node* JSCallReducer::CreateClosureFromBuiltinSharedFunctionInfo(
    SharedFunctionInfoRef shared, Node* context, Node* effect, Node* control) {
  DCHECK(shared.HasBuiltinId());
6446 6447
  Handle<FeedbackCell> feedback_cell =
      isolate()->factory()->many_closures_cell();
6448 6449 6450
  Callable const callable = Builtins::CallableFor(
      isolate(), static_cast<Builtins::Name>(shared.builtin_id()));
  return graph()->NewNode(
6451 6452
      javascript()->CreateClosure(shared.object(), callable.code()),
      jsgraph()->HeapConstant(feedback_cell), context, effect, control);
6453 6454
}

6455 6456
// ES section #sec-promise.prototype.finally
Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
6457
  DisallowHeapAccessIf no_heap_access(should_disallow_heap_access());
6458

6459 6460
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
6461
  int arity = p.arity_without_implicit_args();
6462 6463 6464 6465
  Node* receiver = n.receiver();
  Node* on_finally = n.ArgumentOrUndefined(0, jsgraph());
  Effect effect = n.effect();
  Control control = n.control();
6466 6467 6468 6469
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

6470
  MapInference inference(broker(), receiver, effect);
6471
  if (!DoPromiseChecks(&inference)) return inference.NoChange();
6472
  MapHandles const& receiver_maps = inference.GetMaps();
6473

6474
  if (!dependencies()->DependOnPromiseHookProtector()) {
6475
    return inference.NoChange();
6476 6477
  }
  if (!dependencies()->DependOnPromiseThenProtector()) {
6478
    return inference.NoChange();
6479 6480
  }
  if (!dependencies()->DependOnPromiseSpeciesProtector()) {
6481
    return inference.NoChange();
6482
  }
6483 6484
  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
                                      control, p.feedback());
6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496

  // Check if {on_finally} is callable, and if so wrap it into appropriate
  // closures that perform the finalization.
  Node* check = graph()->NewNode(simplified()->ObjectIsCallable(), on_finally);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* catch_true;
  Node* then_true;
  {
6497 6498 6499
    Node* context = jsgraph()->Constant(native_context());
    Node* constructor =
        jsgraph()->Constant(native_context().promise_function());
6500 6501

    // Allocate shared context for the closures below.
6502 6503
    context = etrue =
        graph()->NewNode(javascript()->CreateFunctionContext(
6504
                             native_context().scope_info().object(),
6505 6506 6507 6508
                             PromiseBuiltins::kPromiseFinallyContextLength -
                                 Context::MIN_CONTEXT_SLOTS,
                             FUNCTION_SCOPE),
                         context, etrue, if_true);
6509 6510 6511 6512 6513 6514 6515 6516
    etrue = graph()->NewNode(
        simplified()->StoreField(
            AccessBuilder::ForContextSlot(PromiseBuiltins::kOnFinallySlot)),
        context, on_finally, etrue, if_true);
    etrue = graph()->NewNode(
        simplified()->StoreField(
            AccessBuilder::ForContextSlot(PromiseBuiltins::kConstructorSlot)),
        context, constructor, etrue, if_true);
6517 6518

    // Allocate the closure for the reject case.
6519 6520
    SharedFunctionInfoRef promise_catch_finally(
        broker(), factory()->promise_catch_finally_shared_fun());
6521
    catch_true = etrue = CreateClosureFromBuiltinSharedFunctionInfo(
6522
        promise_catch_finally, context, etrue, if_true);
6523 6524

    // Allocate the closure for the fulfill case.
6525 6526
    SharedFunctionInfoRef promise_then_finally(
        broker(), factory()->promise_then_finally_shared_fun());
6527
    then_true = etrue = CreateClosureFromBuiltinSharedFunctionInfo(
6528
        promise_then_finally, context, etrue, if_true);
6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547
  }

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* catch_false = on_finally;
  Node* then_false = on_finally;

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  Node* catch_finally =
      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                       catch_true, catch_false, control);
  Node* then_finally =
      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                       then_true, then_false, control);

  // At this point we definitely know that {receiver} has one of the
  // {receiver_maps}, so insert a MapGuard as a hint for the lowering
  // of the call to "then" below.
6548 6549 6550 6551 6552 6553
  {
    ZoneHandleSet<Map> maps;
    for (Handle<Map> map : receiver_maps) maps.insert(map, graph()->zone());
    effect = graph()->NewNode(simplified()->MapGuard(maps), receiver, effect,
                              control);
  }
6554 6555 6556 6557

  // Massage the {node} to call "then" instead by first removing all inputs
  // following the onFinally parameter, and then replacing the only parameter
  // input with the {on_finally} value.
6558
  Node* target = jsgraph()->Constant(native_context().promise_then());
6559
  NodeProperties::ReplaceValueInput(node, target, n.TargetIndex());
6560 6561 6562
  NodeProperties::ReplaceEffectInput(node, effect);
  NodeProperties::ReplaceControlInput(node, control);
  for (; arity > 2; --arity) node->RemoveInput(2);
6563
  for (; arity < 2; ++arity) {
6564
    node->InsertInput(graph()->zone(), 2, then_finally);
6565
  }
6566 6567 6568
  node->ReplaceInput(2, then_finally);
  node->ReplaceInput(3, catch_finally);
  NodeProperties::ChangeOp(
6569
      node, javascript()->Call(
6570
                JSCallNode::ArityForArgc(arity), p.frequency(), p.feedback(),
6571 6572
                ConvertReceiverMode::kNotNullOrUndefined, p.speculation_mode(),
                CallFeedbackRelation::kUnrelated));
6573
  return Changed(node).FollowedBy(ReducePromisePrototypeThen(node));
6574 6575 6576
}

Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
6577
  DisallowHeapAccessIf no_heap_access(should_disallow_heap_access());
6578

6579 6580
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
6581 6582 6583 6584
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

6585 6586 6587 6588 6589 6590 6591
  Node* receiver = n.receiver();
  Node* on_fulfilled = n.ArgumentOrUndefined(0, jsgraph());
  Node* on_rejected = n.ArgumentOrUndefined(1, jsgraph());
  Node* context = n.context();
  Effect effect = n.effect();
  Control control = n.control();
  FrameState frame_state = n.frame_state();
6592

6593
  MapInference inference(broker(), receiver, effect);
6594
  if (!DoPromiseChecks(&inference)) return inference.NoChange();
6595

6596
  if (!dependencies()->DependOnPromiseHookProtector()) {
6597
    return inference.NoChange();
6598 6599
  }
  if (!dependencies()->DependOnPromiseSpeciesProtector()) {
6600
    return inference.NoChange();
6601
  }
6602 6603
  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
                                      control, p.feedback());
6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617

  // Check that {on_fulfilled} is callable.
  on_fulfilled = graph()->NewNode(
      common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
      graph()->NewNode(simplified()->ObjectIsCallable(), on_fulfilled),
      on_fulfilled, jsgraph()->UndefinedConstant());

  // Check that {on_rejected} is callable.
  on_rejected = graph()->NewNode(
      common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
      graph()->NewNode(simplified()->ObjectIsCallable(), on_rejected),
      on_rejected, jsgraph()->UndefinedConstant());

  // Create the resulting JSPromise.
6618
  Node* promise = effect =
6619 6620 6621
      graph()->NewNode(javascript()->CreatePromise(), context, effect);

  // Chain {result} onto {receiver}.
6622
  promise = effect = graph()->NewNode(
6623
      javascript()->PerformPromiseThen(), receiver, on_fulfilled, on_rejected,
6624
      promise, context, frame_state, effect, control);
6625

6626
  // At this point we know that {promise} is going to have the
6627
  // initial Promise map, since even if {PerformPromiseThen}
6628
  // above called into the host rejection tracker, the {promise}
6629 6630 6631
  // doesn't escape to user JavaScript. So bake this information
  // into the graph such that subsequent passes can use the
  // information for further optimizations.
6632
  MapRef promise_map = native_context().promise_function().initial_map();
6633
  effect = graph()->NewNode(
6634
      simplified()->MapGuard(ZoneHandleSet<Map>(promise_map.object())), promise,
6635
      effect, control);
6636

6637 6638
  ReplaceWithValue(node, promise, effect, control);
  return Replace(promise);
6639 6640
}

6641 6642
// ES section #sec-promise.resolve
Reduction JSCallReducer::ReducePromiseResolveTrampoline(Node* node) {
6643
  DisallowHeapAccessIf no_heap_access(should_disallow_heap_access());
6644

6645 6646 6647 6648 6649 6650 6651
  JSCallNode n(node);
  Node* receiver = n.receiver();
  Node* value = n.ArgumentOrUndefined(0, jsgraph());
  Node* context = n.context();
  Effect effect = n.effect();
  Control control = n.control();
  FrameState frame_state = n.frame_state();
6652

6653 6654 6655
  // Only reduce when the receiver is guaranteed to be a JSReceiver.
  MapInference inference(broker(), receiver, effect);
  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAreJSReceiver()) {
6656
    return NoChange();
6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670
  }

  // Morph the {node} into a JSPromiseResolve operation.
  node->ReplaceInput(0, receiver);
  node->ReplaceInput(1, value);
  node->ReplaceInput(2, context);
  node->ReplaceInput(3, frame_state);
  node->ReplaceInput(4, effect);
  node->ReplaceInput(5, control);
  node->TrimInputCount(6);
  NodeProperties::ChangeOp(node, javascript()->PromiseResolve());
  return Changed(node);
}

6671 6672
// ES #sec-typedarray-constructors
Reduction JSCallReducer::ReduceTypedArrayConstructor(
6673
    Node* node, const SharedFunctionInfoRef& shared) {
6674 6675
  JSConstructNode n(node);
  ConstructParameters const& p = n.Parameters();
6676
  int arity = p.arity_without_implicit_args();
6677 6678 6679 6680 6681 6682 6683 6684 6685
  Node* target = n.target();
  Node* arg0 = n.ArgumentOrUndefined(0, jsgraph());
  Node* arg1 = n.ArgumentOrUndefined(1, jsgraph());
  Node* arg2 = n.ArgumentOrUndefined(2, jsgraph());
  Node* new_target = n.new_target();
  Node* context = n.context();
  FrameState frame_state = n.frame_state();
  Effect effect = n.effect();
  Control control = n.control();
6686 6687 6688 6689 6690

  // Insert a construct stub frame into the chain of frame states. This will
  // reconstruct the proper frame when deoptimizing within the constructor.
  frame_state = CreateArtificialFrameState(
      node, frame_state, arity, BailoutId::ConstructStubInvoke(),
6691
      FrameStateType::kConstructStub, shared, context, common(), graph());
6692 6693 6694 6695 6696 6697 6698

  // This continuation just returns the newly created JSTypedArray. We
  // pass the_hole as the receiver, just like the builtin construct stub
  // does in this case.
  Node* const parameters[] = {jsgraph()->TheHoleConstant()};
  int const num_parameters = static_cast<int>(arraysize(parameters));
  frame_state = CreateJavaScriptBuiltinContinuationFrameState(
6699 6700
      jsgraph(), shared, Builtins::kGenericLazyDeoptContinuation, target,
      context, parameters, num_parameters, frame_state,
6701 6702 6703 6704
      ContinuationFrameStateMode::LAZY);

  Node* result =
      graph()->NewNode(javascript()->CreateTypedArray(), target, new_target,
6705
                       arg0, arg1, arg2, context, frame_state, effect, control);
6706 6707 6708
  return Replace(result);
}

6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735
// ES #sec-get-%typedarray%.prototype-@@tostringtag
Reduction JSCallReducer::ReduceTypedArrayPrototypeToStringTag(Node* node) {
  Node* receiver = NodeProperties::GetValueInput(node, 1);
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);

  NodeVector values(graph()->zone());
  NodeVector effects(graph()->zone());
  NodeVector controls(graph()->zone());

  Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
  control =
      graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);

  values.push_back(jsgraph()->UndefinedConstant());
  effects.push_back(effect);
  controls.push_back(graph()->NewNode(common()->IfTrue(), control));

  control = graph()->NewNode(common()->IfFalse(), control);
  Node* receiver_map = effect =
      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
                       receiver, effect, control);
  Node* receiver_bit_field2 = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForMapBitField2()), receiver_map,
      effect, control);
  Node* receiver_elements_kind = graph()->NewNode(
      simplified()->NumberShiftRightLogical(),
6736 6737 6738 6739
      graph()->NewNode(
          simplified()->NumberBitwiseAnd(), receiver_bit_field2,
          jsgraph()->Constant(Map::Bits2::ElementsKindBits::kMask)),
      jsgraph()->Constant(Map::Bits2::ElementsKindBits::kShift));
6740 6741 6742 6743 6744 6745 6746 6747

  // Offset the elements kind by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
  // so that the branch cascade below is turned into a simple table
  // switch by the ControlFlowOptimizer later.
  receiver_elements_kind = graph()->NewNode(
      simplified()->NumberSubtract(), receiver_elements_kind,
      jsgraph()->Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));

6748
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)                      \
6749 6750 6751 6752 6753 6754
  do {                                                                 \
    Node* check = graph()->NewNode(                                    \
        simplified()->NumberEqual(), receiver_elements_kind,           \
        jsgraph()->Constant(TYPE##_ELEMENTS -                          \
                            FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));   \
    control = graph()->NewNode(common()->Branch(), check, control);    \
6755 6756
    values.push_back(jsgraph()->Constant(                              \
        broker()->GetTypedArrayStringTag(TYPE##_ELEMENTS)));           \
6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780
    effects.push_back(effect);                                         \
    controls.push_back(graph()->NewNode(common()->IfTrue(), control)); \
    control = graph()->NewNode(common()->IfFalse(), control);          \
  } while (false);
  TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE

  values.push_back(jsgraph()->UndefinedConstant());
  effects.push_back(effect);
  controls.push_back(control);

  int const count = static_cast<int>(controls.size());
  control = graph()->NewNode(common()->Merge(count), count, &controls.front());
  effects.push_back(control);
  effect =
      graph()->NewNode(common()->EffectPhi(count), count + 1, &effects.front());
  values.push_back(control);
  Node* value =
      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count),
                       count + 1, &values.front());
  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
}

6781 6782
// ES #sec-number.isfinite
Reduction JSCallReducer::ReduceNumberIsFinite(Node* node) {
6783 6784
  JSCallNode n(node);
  if (n.ArgumentCount() < 1) {
6785 6786 6787 6788
    Node* value = jsgraph()->FalseConstant();
    ReplaceWithValue(node, value);
    return Replace(value);
  }
6789
  Node* input = n.Argument(0);
6790 6791 6792 6793 6794
  Node* value = graph()->NewNode(simplified()->ObjectIsFiniteNumber(), input);
  ReplaceWithValue(node, value);
  return Replace(value);
}

6795 6796
// ES #sec-number.isfinite
Reduction JSCallReducer::ReduceNumberIsInteger(Node* node) {
6797 6798
  JSCallNode n(node);
  if (n.ArgumentCount() < 1) {
6799 6800 6801 6802
    Node* value = jsgraph()->FalseConstant();
    ReplaceWithValue(node, value);
    return Replace(value);
  }
6803
  Node* input = n.Argument(0);
6804 6805 6806 6807 6808
  Node* value = graph()->NewNode(simplified()->ObjectIsInteger(), input);
  ReplaceWithValue(node, value);
  return Replace(value);
}

6809 6810
// ES #sec-number.issafeinteger
Reduction JSCallReducer::ReduceNumberIsSafeInteger(Node* node) {
6811 6812
  JSCallNode n(node);
  if (n.ArgumentCount() < 1) {
6813 6814 6815 6816
    Node* value = jsgraph()->FalseConstant();
    ReplaceWithValue(node, value);
    return Replace(value);
  }
6817
  Node* input = n.Argument(0);
6818 6819 6820 6821 6822
  Node* value = graph()->NewNode(simplified()->ObjectIsSafeInteger(), input);
  ReplaceWithValue(node, value);
  return Replace(value);
}

6823 6824
// ES #sec-number.isnan
Reduction JSCallReducer::ReduceNumberIsNaN(Node* node) {
6825 6826
  JSCallNode n(node);
  if (n.ArgumentCount() < 1) {
6827 6828 6829 6830
    Node* value = jsgraph()->FalseConstant();
    ReplaceWithValue(node, value);
    return Replace(value);
  }
6831
  Node* input = n.Argument(0);
6832 6833 6834 6835 6836
  Node* value = graph()->NewNode(simplified()->ObjectIsNaN(), input);
  ReplaceWithValue(node, value);
  return Replace(value);
}

6837 6838
Reduction JSCallReducer::ReduceMapPrototypeGet(Node* node) {
  // We only optimize if we have target, receiver and key parameters.
6839 6840
  JSCallNode n(node);
  if (n.ArgumentCount() != 1) return NoChange();
6841 6842 6843 6844 6845
  Node* receiver = NodeProperties::GetValueInput(node, 1);
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);
  Node* key = NodeProperties::GetValueInput(node, 2);

6846 6847
  MapInference inference(broker(), receiver, effect);
  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(JS_MAP_TYPE)) {
6848
    return NoChange();
6849
  }
6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885

  Node* table = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
      effect, control);

  Node* entry = effect = graph()->NewNode(
      simplified()->FindOrderedHashMapEntry(), table, key, effect, control);

  Node* check = graph()->NewNode(simplified()->NumberEqual(), entry,
                                 jsgraph()->MinusOneConstant());

  Node* branch = graph()->NewNode(common()->Branch(), check, control);

  // Key not found.
  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = jsgraph()->UndefinedConstant();

  // Key found.
  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse = efalse = graph()->NewNode(
      simplified()->LoadElement(AccessBuilder::ForOrderedHashMapEntryValue()),
      table, entry, efalse, if_false);

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  Node* value = graph()->NewNode(
      common()->Phi(MachineRepresentation::kTagged, 2), vtrue, vfalse, control);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);

  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
}

Reduction JSCallReducer::ReduceMapPrototypeHas(Node* node) {
  // We only optimize if we have target, receiver and key parameters.
6886 6887
  JSCallNode n(node);
  if (n.ArgumentCount() != 1) return NoChange();
6888 6889 6890 6891 6892
  Node* receiver = NodeProperties::GetValueInput(node, 1);
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);
  Node* key = NodeProperties::GetValueInput(node, 2);

6893 6894
  MapInference inference(broker(), receiver, effect);
  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(JS_MAP_TYPE)) {
6895
    return NoChange();
6896
  }
6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912

  Node* table = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
      effect, control);

  Node* index = effect = graph()->NewNode(
      simplified()->FindOrderedHashMapEntry(), table, key, effect, control);

  Node* value = graph()->NewNode(simplified()->NumberEqual(), index,
                                 jsgraph()->MinusOneConstant());
  value = graph()->NewNode(simplified()->BooleanNot(), value);

  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
}

6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933
namespace {

InstanceType InstanceTypeForCollectionKind(CollectionKind kind) {
  switch (kind) {
    case CollectionKind::kMap:
      return JS_MAP_TYPE;
    case CollectionKind::kSet:
      return JS_SET_TYPE;
  }
  UNREACHABLE();
}

}  // namespace

Reduction JSCallReducer::ReduceCollectionIteration(
    Node* node, CollectionKind collection_kind, IterationKind iteration_kind) {
  DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
  Node* receiver = NodeProperties::GetValueInput(node, 1);
  Node* context = NodeProperties::GetContextInput(node);
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);
6934 6935 6936 6937

  InstanceType type = InstanceTypeForCollectionKind(collection_kind);
  MapInference inference(broker(), receiver, effect);
  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(type)) {
6938
    return NoChange();
6939
  }
6940 6941 6942 6943 6944 6945

  Node* js_create_iterator = effect = graph()->NewNode(
      javascript()->CreateCollectionIterator(collection_kind, iteration_kind),
      receiver, context, effect, control);
  ReplaceWithValue(node, js_create_iterator, effect);
  return Replace(js_create_iterator);
6946 6947 6948 6949 6950 6951 6952 6953
}

Reduction JSCallReducer::ReduceCollectionPrototypeSize(
    Node* node, CollectionKind collection_kind) {
  DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
  Node* receiver = NodeProperties::GetValueInput(node, 1);
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);
6954 6955 6956 6957

  InstanceType type = InstanceTypeForCollectionKind(collection_kind);
  MapInference inference(broker(), receiver, effect);
  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(type)) {
6958
    return NoChange();
6959
  }
6960 6961 6962 6963 6964 6965 6966 6967 6968 6969

  Node* table = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
      effect, control);
  Node* value = effect = graph()->NewNode(
      simplified()->LoadField(
          AccessBuilder::ForOrderedHashMapOrSetNumberOfElements()),
      table, effect, control);
  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
6970 6971 6972 6973 6974 6975
}

Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
    Node* node, int entry_size, Handle<HeapObject> empty_collection,
    InstanceType collection_iterator_instance_type_first,
    InstanceType collection_iterator_instance_type_last) {
6976 6977
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
6978 6979 6980 6981
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

6982 6983 6984 6985
  Node* receiver = n.receiver();
  Node* context = n.context();
  Effect effect = n.effect();
  Control control = n.control();
6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999

  // A word of warning to begin with: This whole method might look a bit
  // strange at times, but that's mostly because it was carefully handcrafted
  // to allow for full escape analysis and scalar replacement of both the
  // collection iterator object and the iterator results, including the
  // key-value arrays in case of Set/Map entry iteration.
  //
  // TODO(turbofan): Currently the escape analysis (and the store-load
  // forwarding) is unable to eliminate the allocations for the key-value
  // arrays in case of Set/Map entry iteration, and we should investigate
  // how to update the escape analysis / arrange the graph in a way that
  // this becomes possible.

  InstanceType receiver_instance_type;
7000 7001
  {
    MapInference inference(broker(), receiver, effect);
7002
    if (!inference.HaveMaps()) return NoChange();
7003
    MapHandles const& receiver_maps = inference.GetMaps();
7004
    receiver_instance_type = MapRef(broker(), receiver_maps[0]).instance_type();
7005
    for (size_t i = 1; i < receiver_maps.size(); ++i) {
7006 7007
      if (MapRef(broker(), receiver_maps[i]).instance_type() !=
          receiver_instance_type) {
7008 7009 7010 7011 7012 7013 7014
        return inference.NoChange();
      }
    }
    if (receiver_instance_type < collection_iterator_instance_type_first ||
        receiver_instance_type > collection_iterator_instance_type_last) {
      return inference.NoChange();
    }
7015 7016
    inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
                                        control, p.feedback());
7017
  }
7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036

  // Transition the JSCollectionIterator {receiver} if necessary
  // (i.e. there were certain mutations while we're iterating).
  {
    Node* done_loop;
    Node* done_eloop;
    Node* loop = control =
        graph()->NewNode(common()->Loop(2), control, control);
    Node* eloop = effect =
        graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
    Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
    NodeProperties::MergeControlToEnd(graph(), common(), terminate);

    // Check if reached the final table of the {receiver}.
    Node* table = effect = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorTable()),
        receiver, effect, control);
    Node* next_table = effect =
        graph()->NewNode(simplified()->LoadField(
7037
                             AccessBuilder::ForOrderedHashMapOrSetNextTable()),
7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056
                         table, effect, control);
    Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), next_table);
    control =
        graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

    // Abort the {loop} when we reach the final table.
    done_loop = graph()->NewNode(common()->IfTrue(), control);
    done_eloop = effect;

    // Migrate to the {next_table} otherwise.
    control = graph()->NewNode(common()->IfFalse(), control);

    // Self-heal the {receiver}s index.
    Node* index = effect = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorIndex()),
        receiver, effect, control);
    Callable const callable =
        Builtins::CallableFor(isolate(), Builtins::kOrderedHashTableHealIndex);
    auto call_descriptor = Linkage::GetStubCallDescriptor(
7057 7058 7059
        graph()->zone(), callable.descriptor(),
        callable.descriptor().GetStackParameterCount(),
        CallDescriptor::kNoFlags, Operator::kEliminatable);
7060 7061 7062 7063 7064 7065
    index = effect =
        graph()->NewNode(common()->Call(call_descriptor),
                         jsgraph()->HeapConstant(callable.code()), table, index,
                         jsgraph()->NoContextConstant(), effect);

    index = effect = graph()->NewNode(
7066
        common()->TypeGuard(TypeCache::Get()->kFixedArrayLengthType), index,
7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105
        effect, control);

    // Update the {index} and {table} on the {receiver}.
    effect = graph()->NewNode(
        simplified()->StoreField(AccessBuilder::ForJSCollectionIteratorIndex()),
        receiver, index, effect, control);
    effect = graph()->NewNode(
        simplified()->StoreField(AccessBuilder::ForJSCollectionIteratorTable()),
        receiver, next_table, effect, control);

    // Tie the knot.
    loop->ReplaceInput(1, control);
    eloop->ReplaceInput(1, effect);

    control = done_loop;
    effect = done_eloop;
  }

  // Get current index and table from the JSCollectionIterator {receiver}.
  Node* index = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorIndex()),
      receiver, effect, control);
  Node* table = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorTable()),
      receiver, effect, control);

  // Create the {JSIteratorResult} first to ensure that we always have
  // a dominating Allocate node for the allocation folding phase.
  Node* iterator_result = effect = graph()->NewNode(
      javascript()->CreateIterResultObject(), jsgraph()->UndefinedConstant(),
      jsgraph()->TrueConstant(), context, effect);

  // Look for the next non-holey key, starting from {index} in the {table}.
  Node* controls[2];
  Node* effects[3];
  {
    // Compute the currently used capacity.
    Node* number_of_buckets = effect = graph()->NewNode(
        simplified()->LoadField(
7106
            AccessBuilder::ForOrderedHashMapOrSetNumberOfBuckets()),
7107 7108 7109
        table, effect, control);
    Node* number_of_elements = effect = graph()->NewNode(
        simplified()->LoadField(
7110
            AccessBuilder::ForOrderedHashMapOrSetNumberOfElements()),
7111 7112 7113
        table, effect, control);
    Node* number_of_deleted_elements = effect = graph()->NewNode(
        simplified()->LoadField(
7114
            AccessBuilder::ForOrderedHashMapOrSetNumberOfDeletedElements()),
7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129
        table, effect, control);
    Node* used_capacity =
        graph()->NewNode(simplified()->NumberAdd(), number_of_elements,
                         number_of_deleted_elements);

    // Skip holes and update the {index}.
    Node* loop = graph()->NewNode(common()->Loop(2), control, control);
    Node* eloop =
        graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
    Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
    NodeProperties::MergeControlToEnd(graph(), common(), terminate);
    Node* iloop = graph()->NewNode(
        common()->Phi(MachineRepresentation::kTagged, 2), index, index, loop);

    Node* index = effect = graph()->NewNode(
7130
        common()->TypeGuard(TypeCache::Get()->kFixedArrayLengthType), iloop,
7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155
        eloop, control);
    {
      Node* check0 = graph()->NewNode(simplified()->NumberLessThan(), index,
                                      used_capacity);
      Node* branch0 =
          graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, loop);

      Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
      Node* efalse0 = effect;
      {
        // Mark the {receiver} as exhausted.
        efalse0 = graph()->NewNode(
            simplified()->StoreField(
                AccessBuilder::ForJSCollectionIteratorTable()),
            receiver, jsgraph()->HeapConstant(empty_collection), efalse0,
            if_false0);

        controls[0] = if_false0;
        effects[0] = efalse0;
      }

      Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
      Node* etrue0 = effect;
      {
        // Load the key of the entry.
7156 7157
        STATIC_ASSERT(OrderedHashMap::HashTableStartIndex() ==
                      OrderedHashSet::HashTableStartIndex());
7158 7159 7160 7161 7162 7163 7164
        Node* entry_start_position = graph()->NewNode(
            simplified()->NumberAdd(),
            graph()->NewNode(
                simplified()->NumberAdd(),
                graph()->NewNode(simplified()->NumberMultiply(), index,
                                 jsgraph()->Constant(entry_size)),
                number_of_buckets),
7165
            jsgraph()->Constant(OrderedHashMap::HashTableStartIndex()));
7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266
        Node* entry_key = etrue0 = graph()->NewNode(
            simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
            table, entry_start_position, etrue0, if_true0);

        // Advance the index.
        index = graph()->NewNode(simplified()->NumberAdd(), index,
                                 jsgraph()->OneConstant());

        Node* check1 =
            graph()->NewNode(simplified()->ReferenceEqual(), entry_key,
                             jsgraph()->TheHoleConstant());
        Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                         check1, if_true0);

        {
          // Abort loop with resulting value.
          Node* control = graph()->NewNode(common()->IfFalse(), branch1);
          Node* effect = etrue0;
          Node* value = effect =
              graph()->NewNode(common()->TypeGuard(Type::NonInternal()),
                               entry_key, effect, control);
          Node* done = jsgraph()->FalseConstant();

          // Advance the index on the {receiver}.
          effect = graph()->NewNode(
              simplified()->StoreField(
                  AccessBuilder::ForJSCollectionIteratorIndex()),
              receiver, index, effect, control);

          // The actual {value} depends on the {receiver} iteration type.
          switch (receiver_instance_type) {
            case JS_MAP_KEY_ITERATOR_TYPE:
            case JS_SET_VALUE_ITERATOR_TYPE:
              break;

            case JS_SET_KEY_VALUE_ITERATOR_TYPE:
              value = effect =
                  graph()->NewNode(javascript()->CreateKeyValueArray(), value,
                                   value, context, effect);
              break;

            case JS_MAP_VALUE_ITERATOR_TYPE:
              value = effect = graph()->NewNode(
                  simplified()->LoadElement(
                      AccessBuilder::ForFixedArrayElement()),
                  table,
                  graph()->NewNode(
                      simplified()->NumberAdd(), entry_start_position,
                      jsgraph()->Constant(OrderedHashMap::kValueOffset)),
                  effect, control);
              break;

            case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
              value = effect = graph()->NewNode(
                  simplified()->LoadElement(
                      AccessBuilder::ForFixedArrayElement()),
                  table,
                  graph()->NewNode(
                      simplified()->NumberAdd(), entry_start_position,
                      jsgraph()->Constant(OrderedHashMap::kValueOffset)),
                  effect, control);
              value = effect =
                  graph()->NewNode(javascript()->CreateKeyValueArray(),
                                   entry_key, value, context, effect);
              break;

            default:
              UNREACHABLE();
              break;
          }

          // Store final {value} and {done} into the {iterator_result}.
          effect =
              graph()->NewNode(simplified()->StoreField(
                                   AccessBuilder::ForJSIteratorResultValue()),
                               iterator_result, value, effect, control);
          effect =
              graph()->NewNode(simplified()->StoreField(
                                   AccessBuilder::ForJSIteratorResultDone()),
                               iterator_result, done, effect, control);

          controls[1] = control;
          effects[1] = effect;
        }

        // Continue with next loop index.
        loop->ReplaceInput(1, graph()->NewNode(common()->IfTrue(), branch1));
        eloop->ReplaceInput(1, etrue0);
        iloop->ReplaceInput(1, index);
      }
    }

    control = effects[2] = graph()->NewNode(common()->Merge(2), 2, controls);
    effect = graph()->NewNode(common()->EffectPhi(2), 3, effects);
  }

  // Yield the final {iterator_result}.
  ReplaceWithValue(node, iterator_result, effect, control);
  return Replace(iterator_result);
}

7267
Reduction JSCallReducer::ReduceArrayBufferIsView(Node* node) {
7268
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
7269

7270 7271
  JSCallNode n(node);
  Node* value = n.ArgumentOrUndefined(0, jsgraph());
7272 7273 7274 7275 7276 7277 7278 7279 7280
  RelaxEffectsAndControls(node);
  node->ReplaceInput(0, value);
  node->TrimInputCount(1);
  NodeProperties::ChangeOp(node, simplified()->ObjectIsArrayBufferView());
  return Changed(node);
}

Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
    Node* node, InstanceType instance_type, FieldAccess const& access) {
7281
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
7282

7283 7284 7285
  Node* receiver = NodeProperties::GetValueInput(node, 1);
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);
7286

7287 7288 7289
  MapInference inference(broker(), receiver, effect);
  if (!inference.HaveMaps() ||
      !inference.AllOfInstanceTypesAre(instance_type)) {
7290
    return NoChange();
7291
  }
7292

7293 7294 7295
  // Load the {receiver}s field.
  Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
                                          receiver, effect, control);
7296

7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311
  // See if we can skip the detaching check.
  if (!dependencies()->DependOnArrayBufferDetachingProtector()) {
    // Check whether {receiver}s JSArrayBuffer was detached.
    Node* buffer = effect = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
        receiver, effect, control);
    Node* buffer_bit_field = effect = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
        buffer, effect, control);
    Node* check = graph()->NewNode(
        simplified()->NumberEqual(),
        graph()->NewNode(
            simplified()->NumberBitwiseAnd(), buffer_bit_field,
            jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
        jsgraph()->ZeroConstant());
7312

7313 7314 7315 7316 7317 7318 7319 7320
    // TODO(turbofan): Ideally we would bail out here if the {receiver}s
    // JSArrayBuffer was detached, but there's no way to guard against
    // deoptimization loops right now, since the JSCall {node} is usually
    // created from a LOAD_IC inlining, and so there's no CALL_IC slot
    // from which we could use the speculation bit.
    value = graph()->NewNode(
        common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
        check, value, jsgraph()->ZeroConstant());
7321
  }
7322 7323 7324

  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
7325 7326
}

7327
namespace {
7328
uint32_t ExternalArrayElementSize(const ExternalArrayType element_type) {
7329
  switch (element_type) {
7330 7331 7332 7333
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
  case kExternal##Type##Array:                    \
    DCHECK_LE(sizeof(ctype), 8);                  \
    return sizeof(ctype);
7334 7335 7336 7337 7338 7339 7340 7341
    TYPED_ARRAYS(TYPED_ARRAY_CASE)
    default:
      UNREACHABLE();
#undef TYPED_ARRAY_CASE
  }
}
}  // namespace

7342 7343
Reduction JSCallReducer::ReduceDataViewAccess(Node* node, DataViewAccess access,
                                              ExternalArrayType element_type) {
7344 7345
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
7346
  size_t const element_size = ExternalArrayElementSize(element_type);
7347 7348 7349 7350
  Effect effect = n.effect();
  Control control = n.control();
  Node* receiver = n.receiver();
  Node* offset = n.ArgumentOr(0, jsgraph()->ZeroConstant());
7351 7352
  Node* value = nullptr;
  if (access == DataViewAccess::kSet) {
7353
    value = n.ArgumentOrUndefined(1, jsgraph());
7354
  }
7355
  const int endian_index = (access == DataViewAccess::kGet ? 1 : 2);
7356
  Node* is_little_endian =
7357
      n.ArgumentOr(endian_index, jsgraph()->FalseConstant());
7358

7359 7360 7361 7362
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

7363
  // Only do stuff if the {receiver} is really a DataView.
7364 7365 7366
  MapInference inference(broker(), receiver, effect);
  if (!inference.HaveMaps() ||
      !inference.AllOfInstanceTypesAre(JS_DATA_VIEW_TYPE)) {
7367
    return NoChange();
7368
  }
7369

7370 7371
  // Check that the {offset} is within range for the {receiver}.
  HeapObjectMatcher m(receiver);
7372
  if (m.HasResolvedValue() && m.Ref(broker()).IsJSDataView()) {
7373 7374 7375
    // We only deal with DataViews here whose [[ByteLength]] is at least
    // {element_size}, as for all other DataViews it'll be out-of-bounds.
    JSDataViewRef dataview = m.Ref(broker()).AsJSDataView();
7376 7377
    size_t length = dataview.byte_length();
    if (length < element_size) return NoChange();
7378

7379 7380
    // Check that the {offset} is within range of the {length}.
    Node* byte_length = jsgraph()->Constant(length - (element_size - 1));
7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400
    offset = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
                                       offset, byte_length, effect, control);
  } else {
    // We only deal with DataViews here that have Smi [[ByteLength]]s.
    Node* byte_length = effect =
        graph()->NewNode(simplified()->LoadField(
                             AccessBuilder::ForJSArrayBufferViewByteLength()),
                         receiver, effect, control);

    if (element_size > 1) {
      // For non-byte accesses we also need to check that the {offset}
      // plus the {element_size}-1 fits within the given {byte_length}.
      // So to keep this as a single check on the {offset}, we subtract
      // the {element_size}-1 from the {byte_length} here (clamped to
      // positive safe integer range), and perform a check against that
      // with the {offset} below.
      byte_length = graph()->NewNode(
          simplified()->NumberMax(), jsgraph()->ZeroConstant(),
          graph()->NewNode(simplified()->NumberSubtract(), byte_length,
                           jsgraph()->Constant(element_size - 1)));
7401
    }
7402

7403 7404 7405 7406
    // Check that the {offset} is within range of the {byte_length}.
    offset = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
                                       offset, byte_length, effect, control);
  }
7407

7408 7409 7410
  // Coerce {is_little_endian} to boolean.
  is_little_endian =
      graph()->NewNode(simplified()->ToBoolean(), is_little_endian);
7411

7412 7413 7414 7415 7416 7417 7418
  // Coerce {value} to Number.
  if (access == DataViewAccess::kSet) {
    value = effect = graph()->NewNode(
        simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
                                          p.feedback()),
        value, effect, control);
  }
7419

7420 7421 7422 7423 7424
  // We need to retain either the {receiver} itself or it's backing
  // JSArrayBuffer to make sure that the GC doesn't collect the raw
  // memory. We default to {receiver} here, and only use the buffer
  // if we anyways have to load it (to reduce register pressure).
  Node* buffer_or_receiver = receiver;
7425

7426
  if (!dependencies()->DependOnArrayBufferDetachingProtector()) {
7427 7428 7429 7430 7431
    // Get the underlying buffer and check that it has not been detached.
    Node* buffer = effect = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
        receiver, effect, control);

7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445
    // Bail out if the {buffer} was detached.
    Node* buffer_bit_field = effect = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
        buffer, effect, control);
    Node* check = graph()->NewNode(
        simplified()->NumberEqual(),
        graph()->NewNode(
            simplified()->NumberBitwiseAnd(), buffer_bit_field,
            jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
        jsgraph()->ZeroConstant());
    effect = graph()->NewNode(
        simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached,
                              p.feedback()),
        check, effect, control);
7446 7447 7448 7449

    // We can reduce register pressure by holding on to the {buffer}
    // now to retain the backing store memory.
    buffer_or_receiver = buffer;
7450 7451
  }

7452 7453 7454 7455
  // Load the {receiver}s data pointer.
  Node* data_pointer = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSDataViewDataPointer()),
      receiver, effect, control);
7456 7457 7458 7459

  switch (access) {
    case DataViewAccess::kGet:
      // Perform the load.
7460 7461 7462
      value = effect = graph()->NewNode(
          simplified()->LoadDataViewElement(element_type), buffer_or_receiver,
          data_pointer, offset, is_little_endian, effect, control);
7463 7464 7465
      break;
    case DataViewAccess::kSet:
      // Perform the store.
7466 7467 7468
      effect = graph()->NewNode(
          simplified()->StoreDataViewElement(element_type), buffer_or_receiver,
          data_pointer, offset, value, is_little_endian, effect, control);
7469 7470
      value = jsgraph()->UndefinedConstant();
      break;
7471 7472
  }

7473 7474
  ReplaceWithValue(node, value, effect, control);
  return Changed(value);
7475 7476
}

7477 7478
// ES6 section 18.2.2 isFinite ( number )
Reduction JSCallReducer::ReduceGlobalIsFinite(Node* node) {
7479 7480
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
7481 7482 7483
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
7484
  if (n.ArgumentCount() < 1) {
7485 7486 7487 7488 7489
    Node* value = jsgraph()->FalseConstant();
    ReplaceWithValue(node, value);
    return Replace(value);
  }

7490 7491 7492
  Effect effect = n.effect();
  Control control = n.control();
  Node* input = n.Argument(0);
7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504

  input = effect =
      graph()->NewNode(simplified()->SpeculativeToNumber(
                           NumberOperationHint::kNumberOrOddball, p.feedback()),
                       input, effect, control);
  Node* value = graph()->NewNode(simplified()->NumberIsFinite(), input);
  ReplaceWithValue(node, value, effect);
  return Replace(value);
}

// ES6 section 18.2.3 isNaN ( number )
Reduction JSCallReducer::ReduceGlobalIsNaN(Node* node) {
7505 7506
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
7507 7508 7509
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
7510
  if (n.ArgumentCount() < 1) {
7511 7512 7513 7514 7515
    Node* value = jsgraph()->TrueConstant();
    ReplaceWithValue(node, value);
    return Replace(value);
  }

7516 7517 7518
  Effect effect = n.effect();
  Control control = n.control();
  Node* input = n.Argument(0);
7519 7520 7521 7522 7523 7524 7525 7526 7527 7528

  input = effect =
      graph()->NewNode(simplified()->SpeculativeToNumber(
                           NumberOperationHint::kNumberOrOddball, p.feedback()),
                       input, effect, control);
  Node* value = graph()->NewNode(simplified()->NumberIsNaN(), input);
  ReplaceWithValue(node, value, effect);
  return Replace(value);
}

7529 7530 7531 7532 7533
// ES6 section 20.3.4.10 Date.prototype.getTime ( )
Reduction JSCallReducer::ReduceDatePrototypeGetTime(Node* node) {
  Node* receiver = NodeProperties::GetValueInput(node, 1);
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);
7534 7535 7536

  MapInference inference(broker(), receiver, effect);
  if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(JS_DATE_TYPE)) {
7537
    return NoChange();
7538
  }
7539 7540 7541 7542 7543 7544

  Node* value = effect =
      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForJSDateValue()),
                       receiver, effect, control);
  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556
}

// ES6 section 20.3.3.1 Date.now ( )
Reduction JSCallReducer::ReduceDateNow(Node* node) {
  Node* effect = NodeProperties::GetEffectInput(node);
  Node* control = NodeProperties::GetControlInput(node);
  Node* value = effect =
      graph()->NewNode(simplified()->DateNow(), effect, control);
  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
}

7557 7558
// ES6 section 20.1.2.13 Number.parseInt ( string, radix )
Reduction JSCallReducer::ReduceNumberParseInt(Node* node) {
7559 7560
  JSCallNode n(node);
  if (n.ArgumentCount() < 1) {
7561 7562 7563 7564 7565
    Node* value = jsgraph()->NaNConstant();
    ReplaceWithValue(node, value);
    return Replace(value);
  }

7566 7567 7568 7569 7570 7571
  Effect effect = n.effect();
  Control control = n.control();
  Node* context = n.context();
  FrameState frame_state = n.frame_state();
  Node* object = n.Argument(0);
  Node* radix = n.ArgumentOrUndefined(1, jsgraph());
7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582
  node->ReplaceInput(0, object);
  node->ReplaceInput(1, radix);
  node->ReplaceInput(2, context);
  node->ReplaceInput(3, frame_state);
  node->ReplaceInput(4, effect);
  node->ReplaceInput(5, control);
  node->TrimInputCount(6);
  NodeProperties::ChangeOp(node, javascript()->ParseInt());
  return Changed(node);
}

7583
Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
7584
  DisallowHeapAccessIf disallow_heap_access(should_disallow_heap_access());
7585

7586 7587
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
7588
  if (FLAG_force_slow_path) return NoChange();
7589
  if (n.ArgumentCount() < 1) return NoChange();
7590

7591 7592 7593 7594
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }

7595 7596 7597
  Effect effect = n.effect();
  Control control = n.control();
  Node* regexp = n.receiver();
7598

7599 7600 7601 7602 7603 7604
  // Only the initial JSRegExp map is valid here, since the following lastIndex
  // check as well as the lowered builtin call rely on a known location of the
  // lastIndex field.
  Handle<Map> regexp_initial_map =
      native_context().regexp_function().initial_map().object();

7605
  MapInference inference(broker(), regexp, effect);
7606
  if (!inference.Is(regexp_initial_map)) return inference.NoChange();
7607
  MapHandles const& regexp_maps = inference.GetMaps();
7608

7609 7610 7611
  ZoneVector<PropertyAccessInfo> access_infos(graph()->zone());
  AccessInfoFactory access_info_factory(broker(), dependencies(),
                                        graph()->zone());
7612
  if (should_disallow_heap_access()) {
7613 7614 7615
    // Obtain precomputed access infos from the broker.
    for (auto map : regexp_maps) {
      MapRef map_ref(broker(), map);
7616 7617 7618
      PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo(
          map_ref, NameRef(broker(), isolate()->factory()->exec_string()),
          AccessMode::kLoad);
7619 7620
      access_infos.push_back(access_info);
    }
7621 7622 7623 7624 7625
  } else {
    // Compute property access info for "exec" on {resolution}.
    access_info_factory.ComputePropertyAccessInfos(
        MapHandles(regexp_maps.begin(), regexp_maps.end()),
        factory()->exec_string(), AccessMode::kLoad, &access_infos);
7626 7627
  }

7628 7629 7630
  PropertyAccessInfo ai_exec =
      access_info_factory.FinalizePropertyAccessInfosAsOne(access_infos,
                                                           AccessMode::kLoad);
7631
  if (ai_exec.IsInvalid()) return inference.NoChange();
7632

7633
  // If "exec" has been modified on {regexp}, we can't do anything.
7634 7635 7636
  if (ai_exec.IsDataConstant()) {
    Handle<JSObject> holder;
    // Do not reduce if the exec method is not on the prototype chain.
7637
    if (!ai_exec.holder().ToHandle(&holder)) return inference.NoChange();
7638

7639 7640
    JSObjectRef holder_ref(broker(), holder);

7641
    // Bail out if the exec method is not the original one.
7642
    base::Optional<ObjectRef> constant = holder_ref.GetOwnDataProperty(
7643 7644 7645
        ai_exec.field_representation(), ai_exec.field_index());
    if (!constant.has_value() ||
        !constant->equals(native_context().regexp_exec_function())) {
7646
      return inference.NoChange();
7647 7648
    }

7649
    // Add proper dependencies on the {regexp}s [[Prototype]]s.
7650
    dependencies()->DependOnStablePrototypeChains(
7651
        ai_exec.lookup_start_object_maps(), kStartAtPrototype,
7652
        JSObjectRef(broker(), holder));
7653 7654
  } else {
    return inference.NoChange();
7655
  }
7656

7657 7658
  inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect,
                                      control, p.feedback());
7659

7660 7661 7662
  Node* context = n.context();
  FrameState frame_state = n.frame_state();
  Node* search = n.Argument(0);
7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690
  Node* search_string = effect = graph()->NewNode(
      simplified()->CheckString(p.feedback()), search, effect, control);

  Node* lastIndex = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSRegExpLastIndex()), regexp,
      effect, control);

  Node* lastIndexSmi = effect = graph()->NewNode(
      simplified()->CheckSmi(p.feedback()), lastIndex, effect, control);

  Node* is_positive = graph()->NewNode(simplified()->NumberLessThanOrEqual(),
                                       jsgraph()->ZeroConstant(), lastIndexSmi);

  effect = graph()->NewNode(
      simplified()->CheckIf(DeoptimizeReason::kNotASmi, p.feedback()),
      is_positive, effect, control);

  node->ReplaceInput(0, regexp);
  node->ReplaceInput(1, search_string);
  node->ReplaceInput(2, context);
  node->ReplaceInput(3, frame_state);
  node->ReplaceInput(4, effect);
  node->ReplaceInput(5, control);
  node->TrimInputCount(6);
  NodeProperties::ChangeOp(node, javascript()->RegExpTest());
  return Changed(node);
}

7691 7692
// ES section #sec-number-constructor
Reduction JSCallReducer::ReduceNumberConstructor(Node* node) {
7693 7694 7695 7696 7697 7698
  JSCallNode n(node);
  Node* target = n.target();
  Node* receiver = n.receiver();
  Node* value = n.ArgumentOr(0, jsgraph()->ZeroConstant());
  Node* context = n.context();
  FrameState frame_state = n.frame_state();
7699

7700
  // Create the artificial frame state in the middle of the Number constructor.
7701 7702
  SharedFunctionInfoRef shared_info =
      native_context().number_function().shared();
7703 7704 7705 7706
  Node* stack_parameters[] = {receiver};
  int stack_parameter_count = arraysize(stack_parameters);
  Node* continuation_frame_state =
      CreateJavaScriptBuiltinContinuationFrameState(
7707 7708
          jsgraph(), shared_info, Builtins::kGenericLazyDeoptContinuation,
          target, context, stack_parameters, stack_parameter_count, frame_state,
7709 7710 7711 7712 7713 7714 7715
          ContinuationFrameStateMode::LAZY);

  // Convert the {value} to a Number.
  NodeProperties::ReplaceValueInputs(node, value);
  NodeProperties::ChangeOp(node, javascript()->ToNumberConvertBigInt());
  NodeProperties::ReplaceFrameStateInput(node, continuation_frame_state);
  return Changed(node);
7716 7717
}

7718
Reduction JSCallReducer::ReduceBigIntAsUintN(Node* node) {
7719
  if (!jsgraph()->machine()->Is64()) return NoChange();
7720

7721 7722
  JSCallNode n(node);
  CallParameters const& p = n.Parameters();
7723 7724 7725
  if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
    return NoChange();
  }
7726
  if (n.ArgumentCount() < 2) {
7727 7728 7729
    return NoChange();
  }

7730 7731 7732 7733
  Effect effect = n.effect();
  Control control = n.control();
  Node* bits = n.Argument(0);
  Node* value = n.Argument(1);
7734 7735 7736

  NumberMatcher matcher(bits);
  if (matcher.IsInteger() && matcher.IsInRange(0, 64)) {
7737
    const int bits_value = static_cast<int>(matcher.ResolvedValue());
7738 7739 7740 7741 7742 7743 7744 7745 7746 7747
    value = effect = graph()->NewNode(simplified()->CheckBigInt(p.feedback()),
                                      value, effect, control);
    value = graph()->NewNode(simplified()->BigIntAsUintN(bits_value), value);
    ReplaceWithValue(node, value, effect);
    return Replace(value);
  }

  return NoChange();
}

7748 7749 7750 7751
Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }

Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }

7752 7753
Factory* JSCallReducer::factory() const { return isolate()->factory(); }

7754
NativeContextRef JSCallReducer::native_context() const {
7755
  return broker()->target_native_context();
7756 7757
}

7758 7759 7760 7761
CommonOperatorBuilder* JSCallReducer::common() const {
  return jsgraph()->common();
}

7762 7763 7764 7765
JSOperatorBuilder* JSCallReducer::javascript() const {
  return jsgraph()->javascript();
}

7766 7767 7768 7769
SimplifiedOperatorBuilder* JSCallReducer::simplified() const {
  return jsgraph()->simplified();
}

7770 7771 7772
}  // namespace compiler
}  // namespace internal
}  // namespace v8