common-operator.h 28.2 KB
Newer Older
1
// Copyright 2014 the V8 project authors. All rights reserved.
2 3 4 5 6 7
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_COMPILER_COMMON_OPERATOR_H_
#define V8_COMPILER_COMMON_OPERATOR_H_

8
#include "src/base/compiler-specific.h"
9 10 11
#include "src/codegen/machine-type.h"
#include "src/codegen/reloc-info.h"
#include "src/codegen/string-constants.h"
12
#include "src/common/globals.h"
13
#include "src/compiler/feedback-source.h"
14
#include "src/compiler/frame-states.h"
15 16
#include "src/compiler/linkage.h"
#include "src/compiler/node-properties.h"
17
#include "src/deoptimizer/deoptimize-reason.h"
18
#include "src/zone/zone-containers.h"
19
#include "src/zone/zone-handle-set.h"
20 21 22

namespace v8 {
namespace internal {
23 24 25

class StringConstantBase;

26 27
namespace compiler {

28 29
// Forward declarations.
class CallDescriptor;
30
struct CommonOperatorGlobalCache;
31
class Operator;
32
class Type;
33
class Node;
34

35 36 37
// Prediction hint for branches.
enum class BranchHint : uint8_t { kNone, kTrue, kFalse };

38 39 40 41 42 43 44 45 46 47 48 49
inline BranchHint NegateBranchHint(BranchHint hint) {
  switch (hint) {
    case BranchHint::kNone:
      return hint;
    case BranchHint::kTrue:
      return BranchHint::kFalse;
    case BranchHint::kFalse:
      return BranchHint::kTrue;
  }
  UNREACHABLE();
}

50 51
inline size_t hash_value(BranchHint hint) { return static_cast<size_t>(hint); }

52
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, BranchHint);
53

54 55 56 57 58 59 60 61 62 63 64 65 66
enum class TrapId : uint32_t {
#define DEF_ENUM(Name, ...) k##Name,
  FOREACH_WASM_TRAPREASON(DEF_ENUM)
#undef DEF_ENUM
      kInvalid
};

inline size_t hash_value(TrapId id) { return static_cast<uint32_t>(id); }

std::ostream& operator<<(std::ostream&, TrapId trap_id);

TrapId TrapIdOf(const Operator* const op);

67
V8_EXPORT_PRIVATE BranchHint BranchHintOf(const Operator* const)
68
    V8_WARN_UNUSED_RESULT;
69

70 71 72
// Helper function for return nodes, because returns have a hidden value input.
int ValueInputCountOfReturn(Operator const* const op);

73 74 75
// Parameters for the {Deoptimize} operator.
class DeoptimizeParameters final {
 public:
76
  DeoptimizeParameters(DeoptimizeKind kind, DeoptimizeReason reason,
77 78
                       FeedbackSource const& feedback)
      : kind_(kind), reason_(reason), feedback_(feedback) {}
79 80 81

  DeoptimizeKind kind() const { return kind_; }
  DeoptimizeReason reason() const { return reason_; }
82
  const FeedbackSource& feedback() const { return feedback_; }
83 84 85 86

 private:
  DeoptimizeKind const kind_;
  DeoptimizeReason const reason_;
87
  FeedbackSource const feedback_;
88 89 90 91 92 93 94 95
};

bool operator==(DeoptimizeParameters, DeoptimizeParameters);
bool operator!=(DeoptimizeParameters, DeoptimizeParameters);

size_t hast_value(DeoptimizeParameters p);

std::ostream& operator<<(std::ostream&, DeoptimizeParameters p);
96

97
DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const)
98
    V8_WARN_UNUSED_RESULT;
99

100
class SelectParameters final {
101
 public:
102
  explicit SelectParameters(MachineRepresentation representation,
103
                            BranchHint hint = BranchHint::kNone)
104
      : representation_(representation), hint_(hint) {}
105

106
  MachineRepresentation representation() const { return representation_; }
107 108 109
  BranchHint hint() const { return hint_; }

 private:
110
  const MachineRepresentation representation_;
111 112 113 114 115 116 117 118 119 120
  const BranchHint hint_;
};

bool operator==(SelectParameters const&, SelectParameters const&);
bool operator!=(SelectParameters const&, SelectParameters const&);

size_t hash_value(SelectParameters const& p);

std::ostream& operator<<(std::ostream&, SelectParameters const& p);

121
V8_EXPORT_PRIVATE SelectParameters const& SelectParametersOf(
122
    const Operator* const) V8_WARN_UNUSED_RESULT;
123

124
V8_EXPORT_PRIVATE CallDescriptor const* CallDescriptorOf(const Operator* const)
125
    V8_WARN_UNUSED_RESULT;
126

127
V8_EXPORT_PRIVATE size_t ProjectionIndexOf(const Operator* const)
128
    V8_WARN_UNUSED_RESULT;
129

130 131 132
V8_EXPORT_PRIVATE MachineRepresentation
LoopExitValueRepresentationOf(const Operator* const) V8_WARN_UNUSED_RESULT;

133
V8_EXPORT_PRIVATE MachineRepresentation
134
PhiRepresentationOf(const Operator* const) V8_WARN_UNUSED_RESULT;
135

136 137 138 139
// The {IrOpcode::kParameter} opcode represents an incoming parameter to the
// function. This class bundles the index and a debug name for such operators.
class ParameterInfo final {
 public:
140 141
  static constexpr int kMinIndex = Linkage::kJSCallClosureParamIndex;

142
  ParameterInfo(int index, const char* debug_name)
143 144 145
      : index_(index), debug_name_(debug_name) {
    DCHECK_LE(kMinIndex, index);
  }
146 147 148 149 150 151 152 153 154 155 156

  int index() const { return index_; }
  const char* debug_name() const { return debug_name_; }

 private:
  int index_;
  const char* debug_name_;
};

std::ostream& operator<<(std::ostream&, ParameterInfo const&);

157
V8_EXPORT_PRIVATE int ParameterIndexOf(const Operator* const)
158 159 160
    V8_WARN_UNUSED_RESULT;
const ParameterInfo& ParameterInfoOf(const Operator* const)
    V8_WARN_UNUSED_RESULT;
161

162
struct ObjectStateInfo final : std::pair<uint32_t, int> {
163 164
  ObjectStateInfo(uint32_t object_id, int size)
      : std::pair<uint32_t, int>(object_id, size) {}
165 166 167 168 169 170 171 172
  uint32_t object_id() const { return first; }
  int size() const { return second; }
};
std::ostream& operator<<(std::ostream&, ObjectStateInfo const&);
size_t hash_value(ObjectStateInfo const& p);

struct TypedObjectStateInfo final
    : std::pair<uint32_t, const ZoneVector<MachineType>*> {
173 174 175 176
  TypedObjectStateInfo(uint32_t object_id,
                       const ZoneVector<MachineType>* machine_types)
      : std::pair<uint32_t, const ZoneVector<MachineType>*>(object_id,
                                                            machine_types) {}
177 178 179 180 181 182
  uint32_t object_id() const { return first; }
  const ZoneVector<MachineType>* machine_types() const { return second; }
};
std::ostream& operator<<(std::ostream&, TypedObjectStateInfo const&);
size_t hash_value(TypedObjectStateInfo const& p);

183 184
class RelocatablePtrConstantInfo final {
 public:
185 186 187 188 189 190
  enum Type { kInt32, kInt64 };

  RelocatablePtrConstantInfo(int32_t value, RelocInfo::Mode rmode)
      : value_(value), rmode_(rmode), type_(kInt32) {}
  RelocatablePtrConstantInfo(int64_t value, RelocInfo::Mode rmode)
      : value_(value), rmode_(rmode), type_(kInt64) {}
191 192 193

  intptr_t value() const { return value_; }
  RelocInfo::Mode rmode() const { return rmode_; }
194
  Type type() const { return type_; }
195 196 197 198

 private:
  intptr_t value_;
  RelocInfo::Mode rmode_;
199
  Type type_;
200 201 202 203 204 205
};

bool operator==(RelocatablePtrConstantInfo const& lhs,
                RelocatablePtrConstantInfo const& rhs);
bool operator!=(RelocatablePtrConstantInfo const& lhs,
                RelocatablePtrConstantInfo const& rhs);
206

207
std::ostream& operator<<(std::ostream&, RelocatablePtrConstantInfo const&);
208

209
size_t hash_value(RelocatablePtrConstantInfo const& p);
210

211 212 213 214 215
// Used to define a sparse set of inputs. This can be used to efficiently encode
// nodes that can have a lot of inputs, but where many inputs can have the same
// value.
class SparseInputMask final {
 public:
216
  using BitMaskType = uint32_t;
217 218 219 220 221 222 223 224 225 226 227 228

  // The mask representing a dense input set.
  static const BitMaskType kDenseBitMask = 0x0;
  // The bits representing the end of a sparse input set.
  static const BitMaskType kEndMarker = 0x1;
  // The mask for accessing a sparse input entry in the bitmask.
  static const BitMaskType kEntryMask = 0x1;

  // The number of bits in the mask, minus one for the end marker.
  static const int kMaxSparseInputs = (sizeof(BitMaskType) * kBitsPerByte - 1);

  // An iterator over a node's sparse inputs.
229
  class InputIterator final {
230
   public:
231
    InputIterator() = default;
232 233 234 235 236 237 238 239 240 241 242 243 244
    InputIterator(BitMaskType bit_mask, Node* parent);

    Node* parent() const { return parent_; }
    int real_index() const { return real_index_; }

    // Advance the iterator to the next sparse input. Only valid if the iterator
    // has not reached the end.
    void Advance();

    // Get the current sparse input's real node value. Only valid if the
    // current sparse input is real.
    Node* GetReal() const;

245 246 247 248 249
    // Advance to the next real value or the end. Only valid if the iterator is
    // not dense. Returns the number of empty values that were skipped. This can
    // return 0 and in that case, it does not advance.
    size_t AdvanceToNextRealOrEnd();

250 251 252 253 254 255 256 257
    // Get the current sparse input, returning either a real input node if
    // the current sparse input is real, or the given {empty_value} if the
    // current sparse input is empty.
    Node* Get(Node* empty_value) const {
      return IsReal() ? GetReal() : empty_value;
    }

    // True if the current sparse input is a real input node.
258
    bool IsReal() const;
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285

    // True if the current sparse input is an empty value.
    bool IsEmpty() const { return !IsReal(); }

    // True if the iterator has reached the end of the sparse inputs.
    bool IsEnd() const;

   private:
    BitMaskType bit_mask_;
    Node* parent_;
    int real_index_;
  };

  explicit SparseInputMask(BitMaskType bit_mask) : bit_mask_(bit_mask) {}

  // Provides a SparseInputMask representing a dense input set.
  static SparseInputMask Dense() { return SparseInputMask(kDenseBitMask); }

  BitMaskType mask() const { return bit_mask_; }

  bool IsDense() const { return bit_mask_ == SparseInputMask::kDenseBitMask; }

  // Counts how many real values are in the sparse array. Only valid for
  // non-dense masks.
  int CountReal() const;

  // Returns an iterator over the sparse inputs of {node}.
286
  InputIterator IterateOverInputs(Node* node);
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332

 private:
  //
  // The sparse input mask has a bitmask specifying if the node's inputs are
  // represented sparsely. If the bitmask value is 0, then the inputs are dense;
  // otherwise, they should be interpreted as follows:
  //
  //   * The bitmask represents which values are real, with 1 for real values
  //     and 0 for empty values.
  //   * The inputs to the node are the real values, in the order of the 1s from
  //     least- to most-significant.
  //   * The top bit of the bitmask is a guard indicating the end of the values,
  //     whether real or empty (and is not representative of a real input
  //     itself). This is used so that we don't have to additionally store a
  //     value count.
  //
  // So, for N 1s in the bitmask, there are N - 1 inputs into the node.
  BitMaskType bit_mask_;
};

bool operator==(SparseInputMask const& lhs, SparseInputMask const& rhs);
bool operator!=(SparseInputMask const& lhs, SparseInputMask const& rhs);

class TypedStateValueInfo final {
 public:
  TypedStateValueInfo(ZoneVector<MachineType> const* machine_types,
                      SparseInputMask sparse_input_mask)
      : machine_types_(machine_types), sparse_input_mask_(sparse_input_mask) {}

  ZoneVector<MachineType> const* machine_types() const {
    return machine_types_;
  }
  SparseInputMask sparse_input_mask() const { return sparse_input_mask_; }

 private:
  ZoneVector<MachineType> const* machine_types_;
  SparseInputMask sparse_input_mask_;
};

bool operator==(TypedStateValueInfo const& lhs, TypedStateValueInfo const& rhs);
bool operator!=(TypedStateValueInfo const& lhs, TypedStateValueInfo const& rhs);

std::ostream& operator<<(std::ostream&, TypedStateValueInfo const&);

size_t hash_value(TypedStateValueInfo const& p);

333 334 335 336 337 338 339 340 341
// Used to mark a region (as identified by BeginRegion/FinishRegion) as either
// JavaScript-observable or not (i.e. allocations are not JavaScript observable
// themselves, but transitioning stores are).
enum class RegionObservability : uint8_t { kObservable, kNotObservable };

size_t hash_value(RegionObservability);

std::ostream& operator<<(std::ostream&, RegionObservability);

342 343
RegionObservability RegionObservabilityOf(Operator const*)
    V8_WARN_UNUSED_RESULT;
344

345 346
std::ostream& operator<<(std::ostream& os,
                         const ZoneVector<MachineType>* types);
347

348
Type TypeGuardTypeOf(Operator const*) V8_WARN_UNUSED_RESULT;
349

350
int OsrValueIndexOf(Operator const*) V8_WARN_UNUSED_RESULT;
351

352
SparseInputMask SparseInputMaskOf(Operator const*) V8_WARN_UNUSED_RESULT;
353

354
ZoneVector<MachineType> const* MachineTypesOf(Operator const*)
355
    V8_WARN_UNUSED_RESULT;
356

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
// The ArgumentsElementsState and ArgumentsLengthState can describe the layout
// for backing stores of arguments objects of various types:
//
//                        +------------------------------------+
//  - kUnmappedArguments: | arg0, ... argK-1, argK, ... argN-1 |  {length:N}
//                        +------------------------------------+
//                        +------------------------------------+
//  - kMappedArguments:   | hole, ...   hole, argK, ... argN-1 |  {length:N}
//                        +------------------------------------+
//                                          +------------------+
//  - kRestParameter:                       | argK, ... argN-1 |  {length:N-K}
//                                          +------------------+
//
// Here {K} represents the number for formal parameters of the active function,
// whereas {N} represents the actual number of arguments passed at runtime.
// Note that {N < K} can happen and causes {K} to be capped accordingly.
//
// Also note that it is possible for an arguments object of {kMappedArguments}
// type to carry a backing store of {kUnappedArguments} type when {K == 0}.
376
using ArgumentsStateType = CreateArgumentsType;
377

378
ArgumentsStateType ArgumentsStateTypeOf(Operator const*) V8_WARN_UNUSED_RESULT;
379

380 381
uint32_t ObjectIdOf(Operator const*);

382
MachineRepresentation DeadValueRepresentationOf(Operator const*)
383
    V8_WARN_UNUSED_RESULT;
384

385 386
class IfValueParameters final {
 public:
387 388 389
  IfValueParameters(int32_t value, int32_t comparison_order,
                    BranchHint hint = BranchHint::kNone)
      : value_(value), comparison_order_(comparison_order), hint_(hint) {}
390 391 392

  int32_t value() const { return value_; }
  int32_t comparison_order() const { return comparison_order_; }
393
  BranchHint hint() const { return hint_; }
394 395 396 397

 private:
  int32_t value_;
  int32_t comparison_order_;
398
  BranchHint hint_;
399 400 401 402 403 404 405 406 407 408 409
};

V8_EXPORT_PRIVATE bool operator==(IfValueParameters const&,
                                  IfValueParameters const&);

size_t hash_value(IfValueParameters const&);

V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&,
                                           IfValueParameters const&);

V8_EXPORT_PRIVATE IfValueParameters const& IfValueParametersOf(
410
    const Operator* op) V8_WARN_UNUSED_RESULT;
411

412 413
const FrameStateInfo& FrameStateInfoOf(const Operator* op)
    V8_WARN_UNUSED_RESULT;
414

415 416
V8_EXPORT_PRIVATE Handle<HeapObject> HeapConstantOf(const Operator* op)
    V8_WARN_UNUSED_RESULT;
417

418 419 420
const StringConstantBase* StringConstantBaseOf(const Operator* op)
    V8_WARN_UNUSED_RESULT;

421 422
const char* StaticAssertSourceOf(const Operator* op);

423 424
// Interface for building common operators that can be used at any level of IR,
// including JavaScript, mid-level, and low-level.
425 426
class V8_EXPORT_PRIVATE CommonOperatorBuilder final
    : public NON_EXPORTED_BASE(ZoneObject) {
427
 public:
428
  explicit CommonOperatorBuilder(Zone* zone);
429 430
  CommonOperatorBuilder(const CommonOperatorBuilder&) = delete;
  CommonOperatorBuilder& operator=(const CommonOperatorBuilder&) = delete;
431

432 433 434 435 436
  // A dummy value node temporarily used as input when the actual value doesn't
  // matter. This operator is inserted only in SimplifiedLowering and is
  // expected to not survive dead code elimination.
  const Operator* Plug();

437
  const Operator* Dead();
438
  const Operator* DeadValue(MachineRepresentation rep);
439
  const Operator* Unreachable();
440
  const Operator* StaticAssert(const char* source);
441
  const Operator* End(size_t control_input_count);
442
  const Operator* Branch(BranchHint = BranchHint::kNone);
443 444
  const Operator* IfTrue();
  const Operator* IfFalse();
445
  const Operator* IfSuccess();
446
  const Operator* IfException();
447
  const Operator* Switch(size_t control_output_count);
448 449 450
  const Operator* IfValue(int32_t value, int32_t order = 0,
                          BranchHint hint = BranchHint::kNone);
  const Operator* IfDefault(BranchHint hint = BranchHint::kNone);
451
  const Operator* Throw();
452
  const Operator* Deoptimize(DeoptimizeKind kind, DeoptimizeReason reason,
453
                             FeedbackSource const& feedback);
454 455 456 457
  const Operator* DeoptimizeIf(DeoptimizeKind kind, DeoptimizeReason reason,
                               FeedbackSource const& feedback);
  const Operator* DeoptimizeUnless(DeoptimizeKind kind, DeoptimizeReason reason,
                                   FeedbackSource const& feedback);
458 459 460
  // DynamicCheckMapsWithDeoptUnless will call the dynamic map check builtin if
  // the condition is false, which may then either deoptimize or resume
  // execution.
461
  const Operator* DynamicCheckMapsWithDeoptUnless(bool is_inlined_frame_state);
462 463
  const Operator* TrapIf(TrapId trap_id);
  const Operator* TrapUnless(TrapId trap_id);
464
  const Operator* Return(int value_input_count = 1);
465
  const Operator* Terminate();
466

467
  const Operator* Start(int value_output_count);
468 469
  const Operator* Loop(int control_input_count);
  const Operator* Merge(int control_input_count);
470
  const Operator* Parameter(int index, const char* debug_name = nullptr);
471

472 473
  const Operator* OsrValue(int index);

474 475
  const Operator* Int32Constant(int32_t);
  const Operator* Int64Constant(int64_t);
476
  const Operator* TaggedIndexConstant(int32_t value);
477
  const Operator* Float32Constant(volatile float);
478 479 480
  const Operator* Float64Constant(volatile double);
  const Operator* ExternalConstant(const ExternalReference&);
  const Operator* NumberConstant(volatile double);
481
  const Operator* PointerConstant(intptr_t);
482
  const Operator* HeapConstant(const Handle<HeapObject>&);
483
  const Operator* CompressedHeapConstant(const Handle<HeapObject>&);
484
  const Operator* ObjectId(uint32_t);
485

486 487 488 489 490
  const Operator* RelocatableInt32Constant(int32_t value,
                                           RelocInfo::Mode rmode);
  const Operator* RelocatableInt64Constant(int64_t value,
                                           RelocInfo::Mode rmode);

491 492 493
  const Operator* Select(MachineRepresentation, BranchHint = BranchHint::kNone);
  const Operator* Phi(MachineRepresentation representation,
                      int value_input_count);
494
  const Operator* EffectPhi(int effect_input_count);
495
  const Operator* InductionVariablePhi(int value_input_count);
496
  const Operator* LoopExit();
497
  const Operator* LoopExitValue(MachineRepresentation rep);
498
  const Operator* LoopExitEffect();
499
  const Operator* Checkpoint();
500
  const Operator* BeginRegion(RegionObservability);
501
  const Operator* FinishRegion();
502 503 504
  const Operator* StateValues(int arguments, SparseInputMask bitmask);
  const Operator* TypedStateValues(const ZoneVector<MachineType>* types,
                                   SparseInputMask bitmask);
505
  const Operator* ArgumentsElementsState(ArgumentsStateType type);
506
  const Operator* ArgumentsLengthState();
507 508
  const Operator* ObjectState(uint32_t object_id, int pointer_slots);
  const Operator* TypedObjectState(uint32_t object_id,
509
                                   const ZoneVector<MachineType>* types);
510
  const Operator* FrameState(BytecodeOffset bailout_id,
511
                             OutputFrameStateCombine state_combine,
512
                             const FrameStateFunctionInfo* function_info);
513 514
  const Operator* Call(const CallDescriptor* call_descriptor);
  const Operator* TailCall(const CallDescriptor* call_descriptor);
515
  const Operator* Projection(size_t index);
516
  const Operator* Retain();
517
  const Operator* TypeGuard(Type type);
518
  const Operator* FoldConstant();
519

520 521 522 523
  // Constructs a new merge or phi operator with the same opcode as {op}, but
  // with {size} inputs.
  const Operator* ResizeMergeOrPhi(const Operator* op, int size);

524 525 526
  // Constructs function info for frame state construction.
  const FrameStateFunctionInfo* CreateFrameStateFunctionInfo(
      FrameStateType type, int parameter_count, int local_count,
527
      Handle<SharedFunctionInfo> shared_info);
528
#if V8_ENABLE_WEBASSEMBLY
529 530 531 532
  const FrameStateFunctionInfo* CreateJSToWasmFrameStateFunctionInfo(
      FrameStateType type, int parameter_count, int local_count,
      Handle<SharedFunctionInfo> shared_info,
      const wasm::FunctionSig* signature);
533
#endif  // V8_ENABLE_WEBASSEMBLY
534

535 536
  const Operator* DelayedStringConstant(const StringConstantBase* str);

537
 private:
538 539
  Zone* zone() const { return zone_; }

540
  const CommonOperatorGlobalCache& cache_;
541
  Zone* const zone_;
542 543
};

544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
// Node wrappers.

class CommonNodeWrapperBase : public NodeWrapper {
 public:
  explicit constexpr CommonNodeWrapperBase(Node* node) : NodeWrapper(node) {}

  // Valid iff this node has exactly one effect input.
  Effect effect() const {
    DCHECK_EQ(node()->op()->EffectInputCount(), 1);
    return Effect{NodeProperties::GetEffectInput(node())};
  }

  // Valid iff this node has exactly one control input.
  Control control() const {
    DCHECK_EQ(node()->op()->ControlInputCount(), 1);
    return Control{NodeProperties::GetControlInput(node())};
  }
};

#define DEFINE_INPUT_ACCESSORS(Name, name, TheIndex, Type) \
  static constexpr int Name##Index() { return TheIndex; }  \
  TNode<Type> name() const {                               \
    return TNode<Type>::UncheckedCast(                     \
        NodeProperties::GetValueInput(node(), TheIndex));  \
  }

570 571 572 573 574 575 576
// TODO(jgruber): This class doesn't match the usual OpcodeNode naming
// convention for historical reasons (it was originally a very basic typed node
// wrapper similar to Effect and Control). Consider updating the name, with low
// priority.
class FrameState : public CommonNodeWrapperBase {
 public:
  explicit constexpr FrameState(Node* node) : CommonNodeWrapperBase(node) {
577
    DCHECK_EQ(node->opcode(), IrOpcode::kFrameState);
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
  }

  FrameStateInfo frame_state_info() const {
    return FrameStateInfoOf(node()->op());
  }

  static constexpr int kFrameStateParametersInput = 0;
  static constexpr int kFrameStateLocalsInput = 1;
  static constexpr int kFrameStateStackInput = 2;
  static constexpr int kFrameStateContextInput = 3;
  static constexpr int kFrameStateFunctionInput = 4;
  static constexpr int kFrameStateOuterStateInput = 5;
  static constexpr int kFrameStateInputCount = 6;

  // Note: The parameters should be accessed through StateValuesAccess.
  Node* parameters() const {
    Node* n = node()->InputAt(kFrameStateParametersInput);
    DCHECK(n->opcode() == IrOpcode::kStateValues ||
           n->opcode() == IrOpcode::kTypedStateValues);
    return n;
  }
  Node* locals() const {
    Node* n = node()->InputAt(kFrameStateLocalsInput);
    DCHECK(n->opcode() == IrOpcode::kStateValues ||
           n->opcode() == IrOpcode::kTypedStateValues);
    return n;
  }
  // TODO(jgruber): Consider renaming this to the more meaningful
  // 'accumulator'.
  Node* stack() const { return node()->InputAt(kFrameStateStackInput); }
  Node* context() const { return node()->InputAt(kFrameStateContextInput); }
  Node* function() const { return node()->InputAt(kFrameStateFunctionInput); }

  // An outer frame state exists for inlined functions; otherwise it points at
612 613 614 615 616 617 618
  // the start node. Could also be dead.
  Node* outer_frame_state() const {
    Node* result = node()->InputAt(kFrameStateOuterStateInput);
    DCHECK(result->opcode() == IrOpcode::kFrameState ||
           result->opcode() == IrOpcode::kStart ||
           result->opcode() == IrOpcode::kDeadValue);
    return result;
619 620 621
  }
};

622 623 624
class StartNode final : public CommonNodeWrapperBase {
 public:
  explicit constexpr StartNode(Node* node) : CommonNodeWrapperBase(node) {
625
    DCHECK_EQ(IrOpcode::kStart, node->opcode());
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
  }

  // The receiver is counted as part of formal parameters.
  static constexpr int kReceiverOutputCount = 1;
  // These outputs are in addition to formal parameters.
  static constexpr int kExtraOutputCount = 4;

  // Takes the formal parameter count of the current function (including
  // receiver) and returns the number of value outputs of the start node.
  static constexpr int OutputArityForFormalParameterCount(int argc) {
    constexpr int kClosure = 1;
    constexpr int kNewTarget = 1;
    constexpr int kArgCount = 1;
    constexpr int kContext = 1;
    STATIC_ASSERT(kClosure + kNewTarget + kArgCount + kContext ==
                  kExtraOutputCount);
    // Checking related linkage methods here since they rely on Start node
    // layout.
644 645 646 647
    DCHECK_EQ(-1, Linkage::kJSCallClosureParamIndex);
    DCHECK_EQ(argc + 0, Linkage::GetJSCallNewTargetParamIndex(argc));
    DCHECK_EQ(argc + 1, Linkage::GetJSCallArgCountParamIndex(argc));
    DCHECK_EQ(argc + 2, Linkage::GetJSCallContextParamIndex(argc));
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
    return argc + kClosure + kNewTarget + kArgCount + kContext;
  }

  int FormalParameterCount() const {
    DCHECK_GE(node()->op()->ValueOutputCount(),
              kExtraOutputCount + kReceiverOutputCount);
    return node()->op()->ValueOutputCount() - kExtraOutputCount;
  }

  int FormalParameterCountWithoutReceiver() const {
    DCHECK_GE(node()->op()->ValueOutputCount(),
              kExtraOutputCount + kReceiverOutputCount);
    return node()->op()->ValueOutputCount() - kExtraOutputCount -
           kReceiverOutputCount;
  }
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723

  // Note these functions don't return the index of the Start output; instead
  // they return the index assigned to the Parameter node.
  // TODO(jgruber): Consider unifying the two.
  int NewTargetParameterIndex() const {
    return Linkage::GetJSCallNewTargetParamIndex(FormalParameterCount());
  }
  int ArgCountParameterIndex() const {
    return Linkage::GetJSCallArgCountParamIndex(FormalParameterCount());
  }
  int ContextParameterIndex() const {
    return Linkage::GetJSCallContextParamIndex(FormalParameterCount());
  }

  // TODO(jgruber): Remove this function and use
  // Linkage::GetJSCallContextParamIndex instead. This currently doesn't work
  // because tests don't create valid Start nodes - for example, they may add
  // only two context outputs (and not the closure, new target, argc). Once
  // tests are fixed, remove this function.
  int ContextParameterIndex_MaybeNonStandardLayout() const {
    // The context is always the last parameter to a JavaScript function, and
    // {Parameter} indices start at -1, so value outputs of {Start} look like
    // this: closure, receiver, param0, ..., paramN, context.
    //
    // TODO(jgruber): This function is called from spots that operate on
    // CSA/Torque graphs; Start node layout appears to be different there.
    // These should be unified to avoid confusion. Once done, enable this
    // DCHECK: DCHECK_EQ(LastOutputIndex(), ContextOutputIndex());
    return node()->op()->ValueOutputCount() - 2;
  }
  int LastParameterIndex_MaybeNonStandardLayout() const {
    return ContextParameterIndex_MaybeNonStandardLayout();
  }

  // Unlike ContextParameterIndex_MaybeNonStandardLayout above, these return
  // output indices (and not the index assigned to a Parameter).
  int NewTargetOutputIndex() const {
    // Indices assigned to parameters are off-by-one (Parameters indices start
    // at -1).
    // TODO(jgruber): Consider starting at 0.
    DCHECK_EQ(Linkage::GetJSCallNewTargetParamIndex(FormalParameterCount()) + 1,
              node()->op()->ValueOutputCount() - 3);
    return node()->op()->ValueOutputCount() - 3;
  }
  int ArgCountOutputIndex() const {
    // Indices assigned to parameters are off-by-one (Parameters indices start
    // at -1).
    // TODO(jgruber): Consider starting at 0.
    DCHECK_EQ(Linkage::GetJSCallArgCountParamIndex(FormalParameterCount()) + 1,
              node()->op()->ValueOutputCount() - 2);
    return node()->op()->ValueOutputCount() - 2;
  }
  int ContextOutputIndex() const {
    // Indices assigned to parameters are off-by-one (Parameters indices start
    // at -1).
    // TODO(jgruber): Consider starting at 0.
    DCHECK_EQ(Linkage::GetJSCallContextParamIndex(FormalParameterCount()) + 1,
              node()->op()->ValueOutputCount() - 1);
    return node()->op()->ValueOutputCount() - 1;
  }
  int LastOutputIndex() const { return ContextOutputIndex(); }
724 725
};

726
class DynamicCheckMapsWithDeoptUnlessNode final : public CommonNodeWrapperBase {
727
 public:
728
  explicit constexpr DynamicCheckMapsWithDeoptUnlessNode(Node* node)
729
      : CommonNodeWrapperBase(node) {
730
    DCHECK_EQ(IrOpcode::kDynamicCheckMapsWithDeoptUnless, node->opcode());
731 732 733 734 735 736
  }

#define INPUTS(V)                   \
  V(Condition, condition, 0, BoolT) \
  V(Slot, slot, 1, IntPtrT)         \
  V(Map, map, 2, Map)               \
737 738
  V(Handler, handler, 3, Object)    \
  V(FeedbackVector, feedback_vector, 4, FeedbackVector)
739 740 741 742
  INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS

  FrameState frame_state() {
743
    return FrameState{NodeProperties::GetValueInput(node(), 5)};
744 745 746
  }
};

747 748
#undef DEFINE_INPUT_ACCESSORS

749 750 751
}  // namespace compiler
}  // namespace internal
}  // namespace v8
752 753

#endif  // V8_COMPILER_COMMON_OPERATOR_H_