// Copyright 2014 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.

#ifndef V8_CODEGEN_INTERFACE_DESCRIPTORS_H_
#define V8_CODEGEN_INTERFACE_DESCRIPTORS_H_

#include <memory>

#include "src/codegen/machine-type.h"
#include "src/codegen/register-arch.h"
#include "src/codegen/tnode.h"
#include "src/common/globals.h"
#include "src/execution/isolate.h"

namespace v8 {
namespace internal {

#define TORQUE_BUILTIN_LIST_TFC(V)                                            \
  BUILTIN_LIST_FROM_TORQUE(IGNORE_BUILTIN, IGNORE_BUILTIN, V, IGNORE_BUILTIN, \
                           IGNORE_BUILTIN, IGNORE_BUILTIN)

#define INTERFACE_DESCRIPTOR_LIST(V)     \
  V(Abort)                               \
  V(Allocate)                            \
  V(ApiCallback)                         \
  V(ApiGetter)                           \
  V(ArgumentsAdaptor)                    \
  V(ArrayConstructor)                    \
  V(ArrayNArgumentsConstructor)          \
  V(ArrayNoArgumentConstructor)          \
  V(ArraySingleArgumentConstructor)      \
  V(AsyncFunctionStackParameter)         \
  V(BigIntToI32Pair)                     \
  V(BigIntToI64)                         \
  V(BinaryOp)                            \
  V(BinaryOp_WithFeedback)               \
  V(CallForwardVarargs)                  \
  V(CallFunctionTemplate)                \
  V(CallTrampoline)                      \
  V(CallTrampoline_WithFeedback)         \
  V(CallVarargs)                         \
  V(CallWithArrayLike)                   \
  V(CallWithArrayLike_WithFeedback)      \
  V(CallWithSpread)                      \
  V(CallWithSpread_WithFeedback)         \
  V(CEntry1ArgvOnStack)                  \
  V(CloneObjectWithVector)               \
  V(Compare)                             \
  V(Compare_WithFeedback)                \
  V(ConstructForwardVarargs)             \
  V(ConstructStub)                       \
  V(ConstructVarargs)                    \
  V(ConstructWithArrayLike)              \
  V(ConstructWithArrayLike_WithFeedback) \
  V(Construct_WithFeedback)              \
  V(ConstructWithSpread)                 \
  V(ConstructWithSpread_WithFeedback)    \
  V(ContextOnly)                         \
  V(CppBuiltinAdaptor)                   \
  V(EphemeronKeyBarrier)                 \
  V(FastNewObject)                       \
  V(FrameDropperTrampoline)              \
  V(GetIteratorStackParameter)           \
  V(GetProperty)                         \
  V(GrowArrayElements)                   \
  V(I32PairToBigInt)                     \
  V(I64ToBigInt)                         \
  V(InterpreterCEntry1)                  \
  V(InterpreterCEntry2)                  \
  V(InterpreterDispatch)                 \
  V(InterpreterPushArgsThenCall)         \
  V(InterpreterPushArgsThenConstruct)    \
  V(JSTrampoline)                        \
  V(Load)                                \
  V(LoadGlobal)                          \
  V(LoadGlobalNoFeedback)                \
  V(LoadGlobalWithVector)                \
  V(LoadNoFeedback)                      \
  V(LoadWithVector)                      \
  V(NoContext)                           \
  V(RecordWrite)                         \
  V(ResumeGenerator)                     \
  V(RunMicrotasks)                       \
  V(RunMicrotasksEntry)                  \
  V(Store)                               \
  V(StoreGlobal)                         \
  V(StoreGlobalWithVector)               \
  V(StoreTransition)                     \
  V(StoreWithVector)                     \
  V(StringAt)                            \
  V(StringAtAsString)                    \
  V(StringSubstring)                     \
  V(TypeConversion)                      \
  V(TypeConversionStackParameter)        \
  V(Typeof)                              \
  V(UnaryOp_WithFeedback)                \
  V(Void)                                \
  V(WasmFloat32ToNumber)                 \
  V(WasmFloat64ToNumber)                 \
  V(WasmI32AtomicWait32)                 \
  V(WasmI64AtomicWait32)                 \
  BUILTIN_LIST_TFS(V)                    \
  TORQUE_BUILTIN_LIST_TFC(V)

enum class StackArgumentOrder {
  kDefault,  // Arguments in the stack are pushed in the default/stub order (the
             // first argument is pushed first).
  kJS,  // Arguments in the stack are pushed in the same order as the one used
        // by JS-to-JS function calls. This should be used if calling a
        // JSFunction or if the builtin is expected to be called directly from a
        // JSFunction. When V8_REVERSE_JSARGS is set, this order is reversed
        // compared to kDefault.
};

class V8_EXPORT_PRIVATE CallInterfaceDescriptorData {
 public:
  enum Flag {
    kNoFlags = 0u,
    kNoContext = 1u << 0,
    // This indicates that the code uses a special frame that does not scan the
    // stack arguments, e.g. EntryFrame. And this allows the code to use
    // untagged stack arguments.
    kNoStackScan = 1u << 1,
    // In addition to the specified parameters, additional arguments can be
    // passed on the stack.
    // This does not indicate if arguments adaption is used or not.
    kAllowVarArgs = 1u << 2,
  };
  using Flags = base::Flags<Flag>;

  CallInterfaceDescriptorData() = default;

  // A copy of the passed in registers and param_representations is made
  // and owned by the CallInterfaceDescriptorData.

  void InitializePlatformSpecific(int register_parameter_count,
                                  const Register* registers);

  // if machine_types is null, then an array of size
  // (return_count + parameter_count) will be created with
  // MachineType::AnyTagged() for each member.
  //
  // if machine_types is not null, then it should be of the size
  // (return_count + parameter_count). Those members of the parameter array will
  // be initialized from {machine_types}, and the rest initialized to
  // MachineType::AnyTagged().
  void InitializePlatformIndependent(Flags flags, int return_count,
                                     int parameter_count,
                                     const MachineType* machine_types,
                                     int machine_types_length,
                                     StackArgumentOrder stack_order);

  void Reset();

  bool IsInitialized() const {
    return IsInitializedPlatformSpecific() &&
           IsInitializedPlatformIndependent();
  }

  Flags flags() const { return flags_; }
  int return_count() const { return return_count_; }
  int param_count() const { return param_count_; }
  int register_param_count() const { return register_param_count_; }
  Register register_param(int index) const { return register_params_[index]; }
  Register* register_params() const { return register_params_; }
  MachineType return_type(int index) const {
    DCHECK_LT(index, return_count_);
    return machine_types_[index];
  }
  MachineType param_type(int index) const {
    DCHECK_LT(index, param_count_);
    return machine_types_[return_count_ + index];
  }
  StackArgumentOrder stack_order() const { return stack_order_; }

  void RestrictAllocatableRegisters(const Register* registers, int num) {
    DCHECK_EQ(allocatable_registers_, 0);
    for (int i = 0; i < num; ++i) {
      allocatable_registers_ |= registers[i].bit();
    }
    DCHECK_GT(NumRegs(allocatable_registers_), 0);
  }

  RegList allocatable_registers() const { return allocatable_registers_; }

 private:
  bool IsInitializedPlatformSpecific() const {
    const bool initialized =
        (register_param_count_ == 0 && register_params_ == nullptr) ||
        (register_param_count_ > 0 && register_params_ != nullptr);
    // Platform-specific initialization happens before platform-independent.
    return initialized;
  }
  bool IsInitializedPlatformIndependent() const {
    const bool initialized =
        return_count_ >= 0 && param_count_ >= 0 && machine_types_ != nullptr;
    // Platform-specific initialization happens before platform-independent.
    return initialized;
  }

#ifdef DEBUG
  bool AllStackParametersAreTagged() const;
#endif  // DEBUG

  int register_param_count_ = -1;
  int return_count_ = -1;
  int param_count_ = -1;
  Flags flags_ = kNoFlags;
  StackArgumentOrder stack_order_ = StackArgumentOrder::kDefault;

  // Specifying the set of registers that could be used by the register
  // allocator. Currently, it's only used by RecordWrite code stub.
  RegList allocatable_registers_ = 0;

  // |registers_params_| defines registers that are used for parameter passing.
  // |machine_types_| defines machine types for resulting values and incomping
  // parameters.
  // Both arrays are allocated dynamically by the InterfaceDescriptor and
  // freed on destruction. This is because static arrays cause creation of
  // runtime static initializers which we don't want.
  Register* register_params_ = nullptr;
  MachineType* machine_types_ = nullptr;

  DISALLOW_COPY_AND_ASSIGN(CallInterfaceDescriptorData);
};

class V8_EXPORT_PRIVATE CallDescriptors : public AllStatic {
 public:
  enum Key {
#define DEF_ENUM(name, ...) name,
    INTERFACE_DESCRIPTOR_LIST(DEF_ENUM)
#undef DEF_ENUM
        NUMBER_OF_DESCRIPTORS
  };

  static void InitializeOncePerProcess();
  static void TearDown();

  static CallInterfaceDescriptorData* call_descriptor_data(
      CallDescriptors::Key key) {
    return &call_descriptor_data_[key];
  }

  static Key GetKey(const CallInterfaceDescriptorData* data) {
    ptrdiff_t index = data - call_descriptor_data_;
    DCHECK_LE(0, index);
    DCHECK_LT(index, CallDescriptors::NUMBER_OF_DESCRIPTORS);
    return static_cast<CallDescriptors::Key>(index);
  }

 private:
  static CallInterfaceDescriptorData
      call_descriptor_data_[NUMBER_OF_DESCRIPTORS];
};

class V8_EXPORT_PRIVATE CallInterfaceDescriptor {
 public:
  using Flags = CallInterfaceDescriptorData::Flags;

  CallInterfaceDescriptor() : data_(nullptr) {}
  virtual ~CallInterfaceDescriptor() = default;

  explicit CallInterfaceDescriptor(CallDescriptors::Key key)
      : data_(CallDescriptors::call_descriptor_data(key)) {}

  Flags flags() const { return data()->flags(); }

  bool HasContextParameter() const {
    return (flags() & CallInterfaceDescriptorData::kNoContext) == 0;
  }

  bool AllowVarArgs() const {
    return flags() & CallInterfaceDescriptorData::kAllowVarArgs;
  }

  int GetReturnCount() const { return data()->return_count(); }

  MachineType GetReturnType(int index) const {
    DCHECK_LT(index, data()->return_count());
    return data()->return_type(index);
  }

  int GetParameterCount() const { return data()->param_count(); }

  int GetRegisterParameterCount() const {
    return data()->register_param_count();
  }

  int GetStackParameterCount() const {
    return data()->param_count() - data()->register_param_count();
  }

  Register GetRegisterParameter(int index) const {
    return data()->register_param(index);
  }

  MachineType GetParameterType(int index) const {
    DCHECK_LT(index, data()->param_count());
    return data()->param_type(index);
  }

  RegList allocatable_registers() const {
    return data()->allocatable_registers();
  }

  StackArgumentOrder GetStackArgumentOrder() const {
    return data()->stack_order();
  }

  static const Register ContextRegister();

  const char* DebugName() const;

  bool operator==(const CallInterfaceDescriptor& other) const {
    return data() == other.data();
  }

 protected:
  const CallInterfaceDescriptorData* data() const { return data_; }

  virtual void InitializePlatformSpecific(CallInterfaceDescriptorData* data) {
    UNREACHABLE();
  }

  virtual void InitializePlatformIndependent(
      CallInterfaceDescriptorData* data) {
    // Default descriptor configuration: one result, all parameters are passed
    // in registers and all parameters have MachineType::AnyTagged() type.
    data->InitializePlatformIndependent(
        CallInterfaceDescriptorData::kNoFlags, 1, data->register_param_count(),
        nullptr, 0, StackArgumentOrder::kDefault);
  }

  // Initializes |data| using the platform dependent default set of registers.
  // It is intended to be used for TurboFan stubs when particular set of
  // registers does not matter.
  static void DefaultInitializePlatformSpecific(
      CallInterfaceDescriptorData* data, int register_parameter_count);

  // Initializes |data| using the platform dependent default set of registers
  // for JavaScript-compatible calling convention.
  // It is intended to be used for TurboFan stubs being called with JavaScript
  // linkage + additional parameters on registers and stack.
  static void JSDefaultInitializePlatformSpecific(
      CallInterfaceDescriptorData* data, int non_js_register_parameter_count);

  // Checks if float parameters are not assigned invalid registers.
  bool CheckFloatingPointParameters(CallInterfaceDescriptorData* data) {
    for (int i = 0; i < data->register_param_count(); i++) {
      if (IsFloatingPoint(data->param_type(i).representation())) {
        if (!IsValidFloatParameterRegister(data->register_param(i))) {
          return false;
        }
      }
    }
    return true;
  }

  bool IsValidFloatParameterRegister(Register reg);

 private:
  // {CallDescriptors} is allowed to call the private {Initialize} method.
  friend class CallDescriptors;

  const CallInterfaceDescriptorData* data_;

  void Initialize(CallInterfaceDescriptorData* data) {
    // The passed pointer should be a modifiable pointer to our own data.
    DCHECK_EQ(data, data_);
    DCHECK(!data->IsInitialized());
    InitializePlatformSpecific(data);
    InitializePlatformIndependent(data);
    DCHECK(data->IsInitialized());
    DCHECK(CheckFloatingPointParameters(data));
  }
};

#define DECLARE_DESCRIPTOR_WITH_BASE(name, base) \
 public:                                         \
  explicit name() : base(key()) {}               \
  static inline CallDescriptors::Key key();

#if defined(V8_TARGET_ARCH_IA32)
// To support all possible cases, we must limit the number of register args for
// TFS builtins on ia32 to 3. Out of the 6 allocatable registers, esi is taken
// as the context register and ebx is the root register. One register must
// remain available to store the jump/call target. Thus 3 registers remain for
// arguments. The reason this applies to TFS builtins specifically is because
// this becomes relevant for builtins used as targets of Torque function
// pointers (which must have a register available to store the target).
// TODO(jgruber): Ideally we should just decrement kMaxBuiltinRegisterParams but
// that comes with its own set of complications. It's possible, but requires
// refactoring the calling convention of other existing stubs.
constexpr int kMaxBuiltinRegisterParams = 4;
constexpr int kMaxTFSBuiltinRegisterParams = 3;
#else
constexpr int kMaxBuiltinRegisterParams = 5;
constexpr int kMaxTFSBuiltinRegisterParams = kMaxBuiltinRegisterParams;
#endif
STATIC_ASSERT(kMaxTFSBuiltinRegisterParams <= kMaxBuiltinRegisterParams);

#define DECLARE_DEFAULT_DESCRIPTOR(name, base)                                 \
  DECLARE_DESCRIPTOR_WITH_BASE(name, base)                                     \
 protected:                                                                    \
  static const int kRegisterParams =                                           \
      kParameterCount > kMaxTFSBuiltinRegisterParams                           \
          ? kMaxTFSBuiltinRegisterParams                                       \
          : kParameterCount;                                                   \
  static const int kStackParams = kParameterCount - kRegisterParams;           \
  void InitializePlatformSpecific(CallInterfaceDescriptorData* data)           \
      override {                                                               \
    DefaultInitializePlatformSpecific(data, kRegisterParams);                  \
  }                                                                            \
  void InitializePlatformIndependent(CallInterfaceDescriptorData* data)        \
      override {                                                               \
    data->InitializePlatformIndependent(Flags(kDescriptorFlags), kReturnCount, \
                                        kParameterCount, nullptr, 0,           \
                                        kStackArgumentOrder);                  \
  }                                                                            \
  name(CallDescriptors::Key key) : base(key) {}                                \
                                                                               \
 public:

#define DECLARE_JS_COMPATIBLE_DESCRIPTOR(name, base,                        \
                                         non_js_reg_parameters_count)       \
  DECLARE_DESCRIPTOR_WITH_BASE(name, base)                                  \
 protected:                                                                 \
  void InitializePlatformSpecific(CallInterfaceDescriptorData* data)        \
      override {                                                            \
    JSDefaultInitializePlatformSpecific(data, non_js_reg_parameters_count); \
  }                                                                         \
  name(CallDescriptors::Key key) : base(key) {}                             \
                                                                            \
 public:

#define DEFINE_FLAGS_AND_RESULT_AND_PARAMETERS(flags, stack_order,       \
                                               return_count, ...)        \
  static constexpr int kDescriptorFlags = flags;                         \
  static constexpr int kReturnCount = return_count;                      \
  static constexpr StackArgumentOrder kStackArgumentOrder = stack_order; \
  enum ParameterIndices {                                                \
    __dummy = -1, /* to be able to pass zero arguments */                \
    ##__VA_ARGS__,                                                       \
                                                                         \
    kParameterCount,                                                     \
    kContext = kParameterCount /* implicit parameter */                  \
  };

#define DEFINE_RESULT_AND_PARAMETERS(return_count, ...)                    \
  DEFINE_FLAGS_AND_RESULT_AND_PARAMETERS(                                  \
      CallInterfaceDescriptorData::kNoFlags, StackArgumentOrder::kDefault, \
      return_count, ##__VA_ARGS__)

// This is valid only for builtins that use EntryFrame, which does not scan
// stack arguments on GC.
#define DEFINE_PARAMETERS_ENTRY(...)                        \
  static constexpr int kDescriptorFlags =                   \
      CallInterfaceDescriptorData::kNoContext |             \
      CallInterfaceDescriptorData::kNoStackScan;            \
  static constexpr StackArgumentOrder kStackArgumentOrder = \
      StackArgumentOrder::kDefault;                         \
  static constexpr int kReturnCount = 1;                    \
  enum ParameterIndices {                                   \
    __dummy = -1, /* to be able to pass zero arguments */   \
    ##__VA_ARGS__,                                          \
                                                            \
    kParameterCount                                         \
  };

#define DEFINE_PARAMETERS(...)                                                \
  DEFINE_FLAGS_AND_RESULT_AND_PARAMETERS(                                     \
      CallInterfaceDescriptorData::kNoFlags, StackArgumentOrder::kDefault, 1, \
      ##__VA_ARGS__)

#define DEFINE_PARAMETERS_NO_CONTEXT(...)                                    \
  DEFINE_FLAGS_AND_RESULT_AND_PARAMETERS(                                    \
      CallInterfaceDescriptorData::kNoContext, StackArgumentOrder::kDefault, \
      1, ##__VA_ARGS__)

#define DEFINE_PARAMETERS_VARARGS(...)                                        \
  DEFINE_FLAGS_AND_RESULT_AND_PARAMETERS(                                     \
      CallInterfaceDescriptorData::kAllowVarArgs, StackArgumentOrder::kJS, 1, \
      ##__VA_ARGS__)

#define DEFINE_RESULT_AND_PARAMETER_TYPES_WITH_FLAG(flag, ...)                \
  void InitializePlatformIndependent(CallInterfaceDescriptorData* data)       \
      override {                                                              \
    MachineType machine_types[] = {__VA_ARGS__};                              \
    static_assert(                                                            \
        kReturnCount + kParameterCount == arraysize(machine_types),           \
        "Parameter names definition is not consistent with parameter types"); \
    data->InitializePlatformIndependent(                                      \
        Flags(flag | kDescriptorFlags), kReturnCount, kParameterCount,        \
        machine_types, arraysize(machine_types), kStackArgumentOrder);        \
  }

#define DEFINE_RESULT_AND_PARAMETER_TYPES(...) \
  DEFINE_RESULT_AND_PARAMETER_TYPES_WITH_FLAG( \
      CallInterfaceDescriptorData::kNoFlags, __VA_ARGS__)

#define DEFINE_PARAMETER_TYPES(...)                                        \
  DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged() /* result */, \
                                    ##__VA_ARGS__)

#define DEFINE_JS_PARAMETERS(...)                           \
  static constexpr int kDescriptorFlags =                   \
      CallInterfaceDescriptorData::kAllowVarArgs;           \
  static constexpr int kReturnCount = 1;                    \
  static constexpr StackArgumentOrder kStackArgumentOrder = \
      StackArgumentOrder::kJS;                              \
  enum ParameterIndices {                                   \
    kTarget,                                                \
    kNewTarget,                                             \
    kActualArgumentsCount,                                  \
    ##__VA_ARGS__,                                          \
                                                            \
    kParameterCount,                                        \
    kContext = kParameterCount /* implicit parameter */     \
  };

#define DEFINE_JS_PARAMETER_TYPES(...)                                         \
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), /* kTarget */               \
                         MachineType::AnyTagged(), /* kNewTarget */            \
                         MachineType::Int32(),     /* kActualArgumentsCount */ \
                         ##__VA_ARGS__)

#define DECLARE_DESCRIPTOR(name, base)                                         \
  DECLARE_DESCRIPTOR_WITH_BASE(name, base)                                     \
 protected:                                                                    \
  void InitializePlatformSpecific(CallInterfaceDescriptorData* data) override; \
  name(CallDescriptors::Key key) : base(key) {}                                \
                                                                               \
 public:

class V8_EXPORT_PRIVATE VoidDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS()
  DEFINE_PARAMETER_TYPES()
  DECLARE_DESCRIPTOR(VoidDescriptor, CallInterfaceDescriptor)
};

// This class is subclassed by Torque-generated call interface descriptors.
template <int parameter_count, bool has_context_parameter>
class TorqueInterfaceDescriptor : public CallInterfaceDescriptor {
 public:
  static constexpr int kDescriptorFlags =
      has_context_parameter ? CallInterfaceDescriptorData::kNoFlags
                            : CallInterfaceDescriptorData::kNoContext;
  static constexpr int kParameterCount = parameter_count;
  enum ParameterIndices { kContext = kParameterCount };
  template <int i>
  static ParameterIndices ParameterIndex() {
    STATIC_ASSERT(0 <= i && i < kParameterCount);
    return static_cast<ParameterIndices>(i);
  }
  static constexpr int kReturnCount = 1;

  using CallInterfaceDescriptor::CallInterfaceDescriptor;

 protected:
  static const int kRegisterParams =
      kParameterCount > kMaxTFSBuiltinRegisterParams
          ? kMaxTFSBuiltinRegisterParams
          : kParameterCount;
  static const int kStackParams = kParameterCount - kRegisterParams;
  virtual MachineType ReturnType() = 0;
  virtual std::array<MachineType, kParameterCount> ParameterTypes() = 0;
  void InitializePlatformSpecific(CallInterfaceDescriptorData* data) override {
    DefaultInitializePlatformSpecific(data, kRegisterParams);
  }
  void InitializePlatformIndependent(
      CallInterfaceDescriptorData* data) override {
    std::vector<MachineType> machine_types = {ReturnType()};
    auto parameter_types = ParameterTypes();
    machine_types.insert(machine_types.end(), parameter_types.begin(),
                         parameter_types.end());
    DCHECK_EQ(kReturnCount + kParameterCount, machine_types.size());
    data->InitializePlatformIndependent(Flags(kDescriptorFlags), kReturnCount,
                                        kParameterCount, machine_types.data(),
                                        static_cast<int>(machine_types.size()),
                                        StackArgumentOrder::kDefault);
  }
};

// Dummy descriptor used to mark builtins that don't yet have their proper
// descriptor associated.
using DummyDescriptor = VoidDescriptor;

// Dummy descriptor that marks builtins with C calling convention.
using CCallDescriptor = VoidDescriptor;

class AllocateDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_NO_CONTEXT(kRequestedSize)
  DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(),  // result 1
                                    MachineType::IntPtr())  // kRequestedSize
  DECLARE_DESCRIPTOR(AllocateDescriptor, CallInterfaceDescriptor)
};

// This descriptor defines the JavaScript calling convention that can be used
// by stubs: target, new.target, argc (not including the receiver) and context
// are passed in registers while receiver and the rest of the JS arguments are
// passed on the stack.
class JSTrampolineDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_JS_PARAMETERS()
  DEFINE_JS_PARAMETER_TYPES()

  DECLARE_JS_COMPATIBLE_DESCRIPTOR(JSTrampolineDescriptor,
                                   CallInterfaceDescriptor, 0)
};

class ContextOnlyDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS()
  DEFINE_PARAMETER_TYPES()
  DECLARE_DESCRIPTOR(ContextOnlyDescriptor, CallInterfaceDescriptor)
};

class NoContextDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_NO_CONTEXT()
  DEFINE_PARAMETER_TYPES()
  DECLARE_DESCRIPTOR(NoContextDescriptor, CallInterfaceDescriptor)
};

// LoadDescriptor is used by all stubs that implement Load/KeyedLoad ICs.
class LoadDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kReceiver, kName, kSlot)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),     // kReceiver
                         MachineType::AnyTagged(),     // kName
                         MachineType::TaggedSigned())  // kSlot
  DECLARE_DESCRIPTOR(LoadDescriptor, CallInterfaceDescriptor)

  static const Register ReceiverRegister();
  static const Register NameRegister();
  static const Register SlotRegister();
};

class LoadGlobalNoFeedbackDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kName, kICKind)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),     // kName
                         MachineType::TaggedSigned())  // kICKind
  DECLARE_DESCRIPTOR(LoadGlobalNoFeedbackDescriptor, CallInterfaceDescriptor)

  static const Register NameRegister() {
    return LoadDescriptor::NameRegister();
  }

  static const Register ICKindRegister() {
    return LoadDescriptor::SlotRegister();
  }
};

class LoadNoFeedbackDescriptor : public LoadGlobalNoFeedbackDescriptor {
 public:
  DEFINE_PARAMETERS(kReceiver, kName, kICKind)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),     // kReceiver
                         MachineType::AnyTagged(),     // kName
                         MachineType::TaggedSigned())  // kICKind
  DECLARE_DESCRIPTOR(LoadNoFeedbackDescriptor, LoadGlobalNoFeedbackDescriptor)

  static const Register ReceiverRegister() {
    return LoadDescriptor::ReceiverRegister();
  }

  static const Register NameRegister() {
    return LoadGlobalNoFeedbackDescriptor::NameRegister();
  }

  static const Register ICKindRegister() {
    return LoadGlobalNoFeedbackDescriptor::ICKindRegister();
  }
};

class LoadGlobalDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kName, kSlot)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),     // kName
                         MachineType::TaggedSigned())  // kSlot
  DECLARE_DESCRIPTOR(LoadGlobalDescriptor, CallInterfaceDescriptor)

  static const Register NameRegister() {
    return LoadDescriptor::NameRegister();
  }

  static const Register SlotRegister() {
    return LoadDescriptor::SlotRegister();
  }
};

class StoreDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kReceiver, kName, kValue, kSlot)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),     // kReceiver
                         MachineType::AnyTagged(),     // kName
                         MachineType::AnyTagged(),     // kValue
                         MachineType::TaggedSigned())  // kSlot
  DECLARE_DESCRIPTOR(StoreDescriptor, CallInterfaceDescriptor)

  static const Register ReceiverRegister();
  static const Register NameRegister();
  static const Register ValueRegister();
  static const Register SlotRegister();

#if V8_TARGET_ARCH_IA32
  static const bool kPassLastArgsOnStack = true;
#else
  static const bool kPassLastArgsOnStack = false;
#endif

  // Pass value and slot through the stack.
  static const int kStackArgumentsCount = kPassLastArgsOnStack ? 2 : 0;
};

class StoreTransitionDescriptor : public StoreDescriptor {
 public:
  DEFINE_PARAMETERS(kReceiver, kName, kMap, kValue, kSlot, kVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),     // kReceiver
                         MachineType::AnyTagged(),     // kName
                         MachineType::AnyTagged(),     // kMap
                         MachineType::AnyTagged(),     // kValue
                         MachineType::TaggedSigned(),  // kSlot
                         MachineType::AnyTagged())     // kVector
  DECLARE_DESCRIPTOR(StoreTransitionDescriptor, StoreDescriptor)

  static const Register MapRegister();
  static const Register SlotRegister();
  static const Register VectorRegister();

  // Pass value, slot and vector through the stack.
  static const int kStackArgumentsCount = kPassLastArgsOnStack ? 3 : 0;
};

class StoreWithVectorDescriptor : public StoreDescriptor {
 public:
  DEFINE_PARAMETERS(kReceiver, kName, kValue, kSlot, kVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),     // kReceiver
                         MachineType::AnyTagged(),     // kName
                         MachineType::AnyTagged(),     // kValue
                         MachineType::TaggedSigned(),  // kSlot
                         MachineType::AnyTagged())     // kVector
  DECLARE_DESCRIPTOR(StoreWithVectorDescriptor, StoreDescriptor)

  static const Register VectorRegister();

  // Pass value, slot and vector through the stack.
  static const int kStackArgumentsCount = kPassLastArgsOnStack ? 3 : 0;
};

class StoreGlobalDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kName, kValue, kSlot)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),     // kName
                         MachineType::AnyTagged(),     // kValue
                         MachineType::TaggedSigned())  // kSlot
  DECLARE_DESCRIPTOR(StoreGlobalDescriptor, CallInterfaceDescriptor)

  static const bool kPassLastArgsOnStack =
      StoreDescriptor::kPassLastArgsOnStack;
  // Pass value and slot through the stack.
  static const int kStackArgumentsCount = kPassLastArgsOnStack ? 2 : 0;

  static const Register NameRegister() {
    return StoreDescriptor::NameRegister();
  }

  static const Register ValueRegister() {
    return StoreDescriptor::ValueRegister();
  }

  static const Register SlotRegister() {
    return StoreDescriptor::SlotRegister();
  }
};

class StoreGlobalWithVectorDescriptor : public StoreGlobalDescriptor {
 public:
  DEFINE_PARAMETERS(kName, kValue, kSlot, kVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),     // kName
                         MachineType::AnyTagged(),     // kValue
                         MachineType::TaggedSigned(),  // kSlot
                         MachineType::AnyTagged())     // kVector
  DECLARE_DESCRIPTOR(StoreGlobalWithVectorDescriptor, StoreGlobalDescriptor)

  static const Register VectorRegister() {
    return StoreWithVectorDescriptor::VectorRegister();
  }

  // Pass value, slot and vector through the stack.
  static const int kStackArgumentsCount = kPassLastArgsOnStack ? 3 : 0;
};

class LoadWithVectorDescriptor : public LoadDescriptor {
 public:
  // TODO(v8:9497): Revert the Machine type for kSlot to the
  // TaggedSigned once Torque can emit better call descriptors
  DEFINE_PARAMETERS(kReceiver, kName, kSlot, kVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kReceiver
                         MachineType::AnyTagged(),  // kName
                         MachineType::AnyTagged(),  // kSlot
                         MachineType::AnyTagged())  // kVector
  DECLARE_DESCRIPTOR(LoadWithVectorDescriptor, LoadDescriptor)

  static const Register VectorRegister();

#if V8_TARGET_ARCH_IA32
  static const bool kPassLastArgsOnStack = true;
#else
  static const bool kPassLastArgsOnStack = false;
#endif

  // Pass vector through the stack.
  static const int kStackArgumentsCount = kPassLastArgsOnStack ? 1 : 0;
};

class LoadGlobalWithVectorDescriptor : public LoadGlobalDescriptor {
 public:
  DEFINE_PARAMETERS(kName, kSlot, kVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),     // kName
                         MachineType::TaggedSigned(),  // kSlot
                         MachineType::AnyTagged())     // kVector
  DECLARE_DESCRIPTOR(LoadGlobalWithVectorDescriptor, LoadGlobalDescriptor)

#if V8_TARGET_ARCH_IA32
  // On ia32, LoadWithVectorDescriptor passes vector on the stack and thus we
  // need to choose a new register here.
  static const Register VectorRegister() { return edx; }
#else
  static const Register VectorRegister() {
    return LoadWithVectorDescriptor::VectorRegister();
  }
#endif
};

class FastNewObjectDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kTarget, kNewTarget)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kTarget
                         MachineType::AnyTagged())  // kNewTarget
  DECLARE_DESCRIPTOR(FastNewObjectDescriptor, CallInterfaceDescriptor)
  static const Register TargetRegister();
  static const Register NewTargetRegister();
};

class RecordWriteDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_NO_CONTEXT(kObject, kSlot, kRememberedSet, kFPMode)
  DEFINE_PARAMETER_TYPES(MachineType::TaggedPointer(),  // kObject
                         MachineType::Pointer(),        // kSlot
                         MachineType::TaggedSigned(),   // kRememberedSet
                         MachineType::TaggedSigned())   // kFPMode

  DECLARE_DESCRIPTOR(RecordWriteDescriptor, CallInterfaceDescriptor)
};

class EphemeronKeyBarrierDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_NO_CONTEXT(kObject, kSlotAddress, kFPMode)
  DEFINE_PARAMETER_TYPES(MachineType::TaggedPointer(),  // kObject
                         MachineType::Pointer(),        // kSlotAddress
                         MachineType::TaggedSigned())   // kFPMode

  DECLARE_DESCRIPTOR(EphemeronKeyBarrierDescriptor, CallInterfaceDescriptor)
};

class TypeConversionDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kArgument)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged())
  DECLARE_DESCRIPTOR(TypeConversionDescriptor, CallInterfaceDescriptor)

  static const Register ArgumentRegister();
};

class TypeConversionStackParameterDescriptor final
    : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kArgument)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged())
  DECLARE_DESCRIPTOR(TypeConversionStackParameterDescriptor,
                     CallInterfaceDescriptor)
};

class AsyncFunctionStackParameterDescriptor final
    : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kPromise, kResult)
  DEFINE_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged())
  DECLARE_DESCRIPTOR(AsyncFunctionStackParameterDescriptor,
                     CallInterfaceDescriptor)
};

class GetIteratorStackParameterDescriptor final
    : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kReceiver, kCallSlot, kFeedback, kResult)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(),
                         MachineType::AnyTagged(), MachineType::AnyTagged())
  DECLARE_DESCRIPTOR(GetIteratorStackParameterDescriptor,
                     CallInterfaceDescriptor)
};

class GetPropertyDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kObject, kKey)
  DECLARE_DEFAULT_DESCRIPTOR(GetPropertyDescriptor, CallInterfaceDescriptor)
};

class TypeofDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kObject)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged())
  DECLARE_DESCRIPTOR(TypeofDescriptor, CallInterfaceDescriptor)
};

class CallTrampolineDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_VARARGS(kFunction, kActualArgumentsCount)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kFunction
                         MachineType::Int32())      // kActualArgumentsCount
  DECLARE_DESCRIPTOR(CallTrampolineDescriptor, CallInterfaceDescriptor)
};

class CallVarargsDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kTarget, kActualArgumentsCount, kArgumentsLength,
                    kArgumentsList)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kTarget
                         MachineType::Int32(),      // kActualArgumentsCount
                         MachineType::Int32(),      // kArgumentsLength
                         MachineType::AnyTagged())  // kArgumentsList
  DECLARE_DESCRIPTOR(CallVarargsDescriptor, CallInterfaceDescriptor)
};

class CallForwardVarargsDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kTarget, kActualArgumentsCount, kStartIndex)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kTarget
                         MachineType::Int32(),      // kActualArgumentsCount
                         MachineType::Int32())      // kStartIndex
  DECLARE_DESCRIPTOR(CallForwardVarargsDescriptor, CallInterfaceDescriptor)
};

class CallFunctionTemplateDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_VARARGS(kFunctionTemplateInfo, kArgumentsCount)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kFunctionTemplateInfo
                         MachineType::IntPtr())     // kArgumentsCount
  DECLARE_DESCRIPTOR(CallFunctionTemplateDescriptor, CallInterfaceDescriptor)
};

class CallWithSpreadDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_VARARGS(kTarget, kArgumentsCount, kSpread)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kTarget
                         MachineType::Int32(),      // kArgumentsCount
                         MachineType::AnyTagged())  // kSpread
  DECLARE_DESCRIPTOR(CallWithSpreadDescriptor, CallInterfaceDescriptor)
};

// TODO(jgruber): Pass the slot as UintPtr.
class CallWithSpread_WithFeedbackDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_VARARGS(kTarget, kArgumentsCount, kSpread, kSlot,
                            kMaybeFeedbackVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kTarget
                         MachineType::Int32(),      // kArgumentsCount
                         MachineType::AnyTagged(),  // kSpread
                         MachineType::Int32(),      // kSlot
                         MachineType::AnyTagged())  // kMaybeFeedbackVector
  DECLARE_DESCRIPTOR(CallWithSpread_WithFeedbackDescriptor,
                     CallInterfaceDescriptor)
};

class CallWithArrayLikeDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kTarget, kArgumentsList)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kTarget
                         MachineType::AnyTagged())  // kArgumentsList
  DECLARE_DESCRIPTOR(CallWithArrayLikeDescriptor, CallInterfaceDescriptor)
};

// TODO(jgruber): Pass the slot as UintPtr.
class CallWithArrayLike_WithFeedbackDescriptor
    : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kTarget, kArgumentsList, kSlot, kMaybeFeedbackVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kTarget
                         MachineType::AnyTagged(),  // kArgumentsList
                         MachineType::Int32(),      // kSlot
                         MachineType::AnyTagged())  // kMaybeFeedbackVector
  DECLARE_DESCRIPTOR(CallWithArrayLike_WithFeedbackDescriptor,
                     CallInterfaceDescriptor)
};

class ConstructVarargsDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_JS_PARAMETERS(kArgumentsLength, kArgumentsList)
  DEFINE_JS_PARAMETER_TYPES(MachineType::Int32(),      // kArgumentsLength
                            MachineType::AnyTagged())  // kArgumentsList

  DECLARE_DESCRIPTOR(ConstructVarargsDescriptor, CallInterfaceDescriptor)
};

class ConstructForwardVarargsDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_JS_PARAMETERS(kStartIndex)
  DEFINE_JS_PARAMETER_TYPES(MachineType::Int32())
  DECLARE_DESCRIPTOR(ConstructForwardVarargsDescriptor, CallInterfaceDescriptor)
};

class ConstructWithSpreadDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_JS_PARAMETERS(kSpread)
  DEFINE_JS_PARAMETER_TYPES(MachineType::AnyTagged())
  DECLARE_DESCRIPTOR(ConstructWithSpreadDescriptor, CallInterfaceDescriptor)
};

// TODO(jgruber): Pass the slot as UintPtr.
class ConstructWithSpread_WithFeedbackDescriptor
    : public CallInterfaceDescriptor {
 public:
  // Note: kSlot comes before kSpread since as an untagged value it must be
  // passed in a register.
  DEFINE_JS_PARAMETERS(kSlot, kSpread, kMaybeFeedbackVector)
  DEFINE_JS_PARAMETER_TYPES(MachineType::Int32(),      // kSlot
                            MachineType::AnyTagged(),  // kSpread
                            MachineType::AnyTagged())  // kMaybeFeedbackVector
  DECLARE_DESCRIPTOR(ConstructWithSpread_WithFeedbackDescriptor,
                     CallInterfaceDescriptor)
};

class ConstructWithArrayLikeDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kTarget, kNewTarget, kArgumentsList)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kTarget
                         MachineType::AnyTagged(),  // kNewTarget
                         MachineType::AnyTagged())  // kArgumentsList
  DECLARE_DESCRIPTOR(ConstructWithArrayLikeDescriptor, CallInterfaceDescriptor)
};

// TODO(jgruber): Pass the slot as UintPtr.
class ConstructWithArrayLike_WithFeedbackDescriptor
    : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kTarget, kNewTarget, kArgumentsList, kSlot,
                    kMaybeFeedbackVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kTarget
                         MachineType::AnyTagged(),  // kNewTarget
                         MachineType::AnyTagged(),  // kArgumentsList
                         MachineType::Int32(),      // kSlot
                         MachineType::AnyTagged())  // kMaybeFeedbackVector
  DECLARE_DESCRIPTOR(ConstructWithArrayLike_WithFeedbackDescriptor,
                     CallInterfaceDescriptor)
};

// TODO(ishell): consider merging this with ArrayConstructorDescriptor
class ConstructStubDescriptor : public CallInterfaceDescriptor {
 public:
  // TODO(jgruber): Remove the unused allocation site parameter.
  DEFINE_JS_PARAMETERS(kAllocationSite)
  DEFINE_JS_PARAMETER_TYPES(MachineType::AnyTagged())

  // TODO(ishell): Use DECLARE_JS_COMPATIBLE_DESCRIPTOR if registers match
  DECLARE_DESCRIPTOR(ConstructStubDescriptor, CallInterfaceDescriptor)
};

class AbortDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_NO_CONTEXT(kMessageOrMessageId)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged())
  DECLARE_DESCRIPTOR(AbortDescriptor, CallInterfaceDescriptor)
};

class ArrayConstructorDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_JS_PARAMETERS(kAllocationSite)
  DEFINE_JS_PARAMETER_TYPES(MachineType::AnyTagged())

  DECLARE_JS_COMPATIBLE_DESCRIPTOR(ArrayConstructorDescriptor,
                                   CallInterfaceDescriptor, 1)
};

class ArrayNArgumentsConstructorDescriptor : public CallInterfaceDescriptor {
 public:
  // This descriptor declares only register arguments while respective number
  // of JS arguments stay on the expression stack.
  // The ArrayNArgumentsConstructor builtin does not access stack arguments
  // directly it just forwards them to the runtime function.
  DEFINE_PARAMETERS(kFunction, kAllocationSite, kActualArgumentsCount)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kFunction,
                         MachineType::AnyTagged(),  // kAllocationSite
                         MachineType::Int32())      // kActualArgumentsCount
  DECLARE_DESCRIPTOR(ArrayNArgumentsConstructorDescriptor,
                     CallInterfaceDescriptor)
};

class ArrayNoArgumentConstructorDescriptor
    : public ArrayNArgumentsConstructorDescriptor {
 public:
  // This descriptor declares same register arguments as the parent
  // ArrayNArgumentsConstructorDescriptor and it declares indices for
  // JS arguments passed on the expression stack.
  DEFINE_PARAMETERS(kFunction, kAllocationSite, kActualArgumentsCount,
                    kFunctionParameter)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kFunction
                         MachineType::AnyTagged(),  // kAllocationSite
                         MachineType::Int32(),      // kActualArgumentsCount
                         MachineType::AnyTagged())  // kFunctionParameter
  DECLARE_DESCRIPTOR(ArrayNoArgumentConstructorDescriptor,
                     ArrayNArgumentsConstructorDescriptor)
};

#ifdef V8_REVERSE_JSARGS
class ArraySingleArgumentConstructorDescriptor
    : public ArrayNArgumentsConstructorDescriptor {
 public:
  // This descriptor declares same register arguments as the parent
  // ArrayNArgumentsConstructorDescriptor and it declares indices for
  // JS arguments passed on the expression stack.
  DEFINE_PARAMETERS(kFunction, kAllocationSite, kActualArgumentsCount,
                    kArraySizeSmiParameter, kReceiverParameter)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kFunction
                         MachineType::AnyTagged(),  // kAllocationSite
                         MachineType::Int32(),      // kActualArgumentsCount
                         // JS arguments on the stack
                         MachineType::AnyTagged(),  // kArraySizeSmiParameter
                         MachineType::AnyTagged())  // kReceiverParameter
  DECLARE_DESCRIPTOR(ArraySingleArgumentConstructorDescriptor,
                     ArrayNArgumentsConstructorDescriptor)
};
#else
class ArraySingleArgumentConstructorDescriptor
    : public ArrayNArgumentsConstructorDescriptor {
 public:
  // This descriptor declares same register arguments as the parent
  // ArrayNArgumentsConstructorDescriptor and it declares indices for
  // JS arguments passed on the expression stack.
  DEFINE_PARAMETERS(kFunction, kAllocationSite, kActualArgumentsCount,
                    kReceiverParameter, kArraySizeSmiParameter)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kFunction
                         MachineType::AnyTagged(),  // kAllocationSite
                         MachineType::Int32(),      // kActualArgumentsCount
                         // JS arguments on the stack
                         MachineType::AnyTagged(),  // kReceiverParameter
                         MachineType::AnyTagged())  // kArraySizeSmiParameter
  DECLARE_DESCRIPTOR(ArraySingleArgumentConstructorDescriptor,
                     ArrayNArgumentsConstructorDescriptor)
};
#endif

class CompareDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kLeft, kRight)
  DECLARE_DESCRIPTOR(CompareDescriptor, CallInterfaceDescriptor)
};

class BinaryOpDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kLeft, kRight)
  DECLARE_DESCRIPTOR(BinaryOpDescriptor, CallInterfaceDescriptor)
};

// This desciptor is shared among String.p.charAt/charCodeAt/codePointAt
// as they all have the same interface.
class StringAtDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kReceiver, kPosition)
  // TODO(turbofan): Return untagged value here.
  DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(),  // result 1
                                    MachineType::AnyTagged(),     // kReceiver
                                    MachineType::IntPtr())        // kPosition
  DECLARE_DESCRIPTOR(StringAtDescriptor, CallInterfaceDescriptor)
};

class StringAtAsStringDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kReceiver, kPosition)
  // TODO(turbofan): Return untagged value here.
  DEFINE_RESULT_AND_PARAMETER_TYPES(
      MachineType::TaggedPointer(),  // result string
      MachineType::AnyTagged(),      // kReceiver
      MachineType::IntPtr())         // kPosition
  DECLARE_DESCRIPTOR(StringAtAsStringDescriptor, CallInterfaceDescriptor)
};

class StringSubstringDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kString, kFrom, kTo)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kString
                         MachineType::IntPtr(),     // kFrom
                         MachineType::IntPtr())     // kTo

  // TODO(turbofan): Allow builtins to return untagged values.
  DECLARE_DESCRIPTOR(StringSubstringDescriptor, CallInterfaceDescriptor)
};

class ArgumentsAdaptorDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_JS_PARAMETERS(kExpectedArgumentsCount)
  DEFINE_JS_PARAMETER_TYPES(MachineType::Int32())
  DECLARE_DESCRIPTOR(ArgumentsAdaptorDescriptor, CallInterfaceDescriptor)
};

class CppBuiltinAdaptorDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_JS_PARAMETERS(kCFunction)
  DEFINE_JS_PARAMETER_TYPES(MachineType::Pointer())
  DECLARE_JS_COMPATIBLE_DESCRIPTOR(CppBuiltinAdaptorDescriptor,
                                   CallInterfaceDescriptor, 1)
};

class CEntry1ArgvOnStackDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kArity,          // register argument
                    kCFunction,      // register argument
                    kPadding,        // stack argument 1 (just padding)
                    kArgcSmi,        // stack argument 2
                    kTargetCopy,     // stack argument 3
                    kNewTargetCopy)  // stack argument 4
  DEFINE_PARAMETER_TYPES(MachineType::Int32(),      // kArity
                         MachineType::Pointer(),    // kCFunction
                         MachineType::AnyTagged(),  // kPadding
                         MachineType::AnyTagged(),  // kArgcSmi
                         MachineType::AnyTagged(),  // kTargetCopy
                         MachineType::AnyTagged())  // kNewTargetCopy
  DECLARE_DESCRIPTOR(CEntry1ArgvOnStackDescriptor, CallInterfaceDescriptor)
};

class ApiCallbackDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_VARARGS(kApiFunctionAddress, kActualArgumentsCount,
                            kCallData, kHolder)
  //                           receiver is implicit stack argument 1
  //                           argv are implicit stack arguments [2, 2 + kArgc[
  DEFINE_PARAMETER_TYPES(MachineType::Pointer(),    // kApiFunctionAddress
                         MachineType::IntPtr(),     // kActualArgumentsCount
                         MachineType::AnyTagged(),  // kCallData
                         MachineType::AnyTagged())  // kHolder
  DECLARE_DESCRIPTOR(ApiCallbackDescriptor, CallInterfaceDescriptor)
};

class ApiGetterDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kReceiver, kHolder, kCallback)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kReceiver
                         MachineType::AnyTagged(),  // kHolder
                         MachineType::AnyTagged())  // kCallback
  DECLARE_DESCRIPTOR(ApiGetterDescriptor, CallInterfaceDescriptor)

  static const Register ReceiverRegister();
  static const Register HolderRegister();
  static const Register CallbackRegister();
};

// TODO(turbofan): We should probably rename this to GrowFastElementsDescriptor.
class GrowArrayElementsDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kObject, kKey)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kObject
                         MachineType::AnyTagged())  // kKey
  DECLARE_DESCRIPTOR(GrowArrayElementsDescriptor, CallInterfaceDescriptor)

  static const Register ObjectRegister();
  static const Register KeyRegister();
};

class V8_EXPORT_PRIVATE InterpreterDispatchDescriptor
    : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kAccumulator, kBytecodeOffset, kBytecodeArray,
                    kDispatchTable)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kAccumulator
                         MachineType::IntPtr(),     // kBytecodeOffset
                         MachineType::AnyTagged(),  // kBytecodeArray
                         MachineType::IntPtr())     // kDispatchTable
  DECLARE_DESCRIPTOR(InterpreterDispatchDescriptor, CallInterfaceDescriptor)
};

class InterpreterPushArgsThenCallDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kNumberOfArguments, kFirstArgument, kFunction)
  DEFINE_PARAMETER_TYPES(MachineType::Int32(),      // kNumberOfArguments
                         MachineType::Pointer(),    // kFirstArgument
                         MachineType::AnyTagged())  // kFunction
  DECLARE_DESCRIPTOR(InterpreterPushArgsThenCallDescriptor,
                     CallInterfaceDescriptor)
};

class InterpreterPushArgsThenConstructDescriptor
    : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kNumberOfArguments, kFirstArgument, kConstructor,
                    kNewTarget, kFeedbackElement)
  DEFINE_PARAMETER_TYPES(MachineType::Int32(),      // kNumberOfArguments
                         MachineType::Pointer(),    // kFirstArgument
                         MachineType::AnyTagged(),  // kConstructor
                         MachineType::AnyTagged(),  // kNewTarget
                         MachineType::AnyTagged())  // kFeedbackElement
  DECLARE_DESCRIPTOR(InterpreterPushArgsThenConstructDescriptor,
                     CallInterfaceDescriptor)

#if V8_TARGET_ARCH_IA32
  static const bool kPassLastArgsOnStack = true;
#else
  static const bool kPassLastArgsOnStack = false;
#endif

  // Pass constructor, new target and feedback element through the stack.
  static const int kStackArgumentsCount = kPassLastArgsOnStack ? 3 : 0;
};

class InterpreterCEntry1Descriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_RESULT_AND_PARAMETERS(1, kNumberOfArguments, kFirstArgument,
                               kFunctionEntry)
  DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(),  // result 1
                                    MachineType::Int32(),  // kNumberOfArguments
                                    MachineType::Pointer(),  // kFirstArgument
                                    MachineType::Pointer())  // kFunctionEntry
  DECLARE_DESCRIPTOR(InterpreterCEntry1Descriptor, CallInterfaceDescriptor)
};

class InterpreterCEntry2Descriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_RESULT_AND_PARAMETERS(2, kNumberOfArguments, kFirstArgument,
                               kFunctionEntry)
  DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(),  // result 1
                                    MachineType::AnyTagged(),  // result 2
                                    MachineType::Int32(),  // kNumberOfArguments
                                    MachineType::Pointer(),  // kFirstArgument
                                    MachineType::Pointer())  // kFunctionEntry
  DECLARE_DESCRIPTOR(InterpreterCEntry2Descriptor, CallInterfaceDescriptor)
};

class ResumeGeneratorDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kValue, kGenerator)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kValue
                         MachineType::AnyTagged())  // kGenerator
  DECLARE_DESCRIPTOR(ResumeGeneratorDescriptor, CallInterfaceDescriptor)
};

class FrameDropperTrampolineDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kRestartFp)
  DEFINE_PARAMETER_TYPES(MachineType::Pointer())
  DECLARE_DESCRIPTOR(FrameDropperTrampolineDescriptor, CallInterfaceDescriptor)
};

class RunMicrotasksEntryDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_ENTRY(kRootRegisterValue, kMicrotaskQueue)
  DEFINE_PARAMETER_TYPES(MachineType::Pointer(),  // kRootRegisterValue
                         MachineType::Pointer())  // kMicrotaskQueue
  DECLARE_DESCRIPTOR(RunMicrotasksEntryDescriptor, CallInterfaceDescriptor)
};

class RunMicrotasksDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kMicrotaskQueue)
  DEFINE_PARAMETER_TYPES(MachineType::Pointer())
  DECLARE_DESCRIPTOR(RunMicrotasksDescriptor, CallInterfaceDescriptor)

  static Register MicrotaskQueueRegister();
};

class WasmFloat32ToNumberDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_NO_CONTEXT(kValue)
  DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(),  // result
                                    MachineType::Float32())    // value
  DECLARE_DESCRIPTOR(WasmFloat32ToNumberDescriptor, CallInterfaceDescriptor)
};

class WasmFloat64ToNumberDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_NO_CONTEXT(kValue)
  DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(),  // result
                                    MachineType::Float64())    // value
  DECLARE_DESCRIPTOR(WasmFloat64ToNumberDescriptor, CallInterfaceDescriptor)
};

class V8_EXPORT_PRIVATE I64ToBigIntDescriptor final
    : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_NO_CONTEXT(kArgument)
  DEFINE_PARAMETER_TYPES(MachineType::Int64())  // kArgument
  DECLARE_DESCRIPTOR(I64ToBigIntDescriptor, CallInterfaceDescriptor)
};

// 32 bits version of the I64ToBigIntDescriptor call interface descriptor
class V8_EXPORT_PRIVATE I32PairToBigIntDescriptor final
    : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_NO_CONTEXT(kLow, kHigh)
  DEFINE_PARAMETER_TYPES(MachineType::Uint32(),  // kLow
                         MachineType::Uint32())  // kHigh
  DECLARE_DESCRIPTOR(I32PairToBigIntDescriptor, CallInterfaceDescriptor)
};

class V8_EXPORT_PRIVATE BigIntToI64Descriptor final
    : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kArgument)
  DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::Int64(),      // result 1
                                    MachineType::AnyTagged())  // kArgument
  DECLARE_DESCRIPTOR(BigIntToI64Descriptor, CallInterfaceDescriptor)
};

class V8_EXPORT_PRIVATE BigIntToI32PairDescriptor final
    : public CallInterfaceDescriptor {
 public:
  DEFINE_RESULT_AND_PARAMETERS(2, kArgument)
  DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::Uint32(),     // result 1
                                    MachineType::Uint32(),     // result 2
                                    MachineType::AnyTagged())  // kArgument
  DECLARE_DESCRIPTOR(BigIntToI32PairDescriptor, CallInterfaceDescriptor)
};

class WasmI32AtomicWait32Descriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_NO_CONTEXT(kAddress, kExpectedValue, kTimeoutLow,
                               kTimeoutHigh)
  DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::Uint32(),  // result 1
                                    MachineType::Uint32(),  // kAddress
                                    MachineType::Int32(),   // kExpectedValue
                                    MachineType::Uint32(),  // kTimeoutLow
                                    MachineType::Uint32())  // kTimeoutHigh
  DECLARE_DESCRIPTOR(WasmI32AtomicWait32Descriptor, CallInterfaceDescriptor)
};

class WasmI64AtomicWait32Descriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_NO_CONTEXT(kAddress, kExpectedValueLow, kExpectedValueHigh,
                               kTimeoutLow, kTimeoutHigh)

  DEFINE_RESULT_AND_PARAMETER_TYPES_WITH_FLAG(
      CallInterfaceDescriptorData::kNoStackScan,  // allow untagged stack params
      MachineType::Uint32(),                      // result 1
      MachineType::Uint32(),                      // kAddress
      MachineType::Uint32(),                      // kExpectedValueLow
      MachineType::Uint32(),                      // kExpectedValueHigh
      MachineType::Uint32(),                      // kTimeoutLow
      MachineType::Uint32())                      // kTimeoutHigh

#if V8_TARGET_ARCH_IA32
  static constexpr bool kPassLastArgOnStack = true;
#else
  static constexpr bool kPassLastArgOnStack = false;
#endif

  // Pass the last parameter through the stack.
  static constexpr int kStackArgumentsCount = kPassLastArgOnStack ? 1 : 0;

  DECLARE_DESCRIPTOR(WasmI64AtomicWait32Descriptor, CallInterfaceDescriptor)
};

class CloneObjectWithVectorDescriptor final : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kSource, kFlags, kSlot, kVector)
  DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(),  // result 1
                                    MachineType::AnyTagged(),      // kSource
                                    MachineType::TaggedSigned(),   // kFlags
                                    MachineType::TaggedSigned(),   // kSlot
                                    MachineType::AnyTagged())      // kVector
  DECLARE_DESCRIPTOR(CloneObjectWithVectorDescriptor, CallInterfaceDescriptor)
};

class BinaryOp_WithFeedbackDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kLeft, kRight, kSlot, kMaybeFeedbackVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kLeft
                         MachineType::AnyTagged(),  // kRight
                         MachineType::UintPtr(),    // kSlot
                         MachineType::AnyTagged())  // kMaybeFeedbackVector
  DECLARE_DESCRIPTOR(BinaryOp_WithFeedbackDescriptor, CallInterfaceDescriptor)
};

// TODO(jgruber): Pass the slot as UintPtr.
class CallTrampoline_WithFeedbackDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS_VARARGS(kFunction, kActualArgumentsCount, kSlot,
                            kMaybeFeedbackVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kFunction
                         MachineType::Int32(),      // kActualArgumentsCount
                         MachineType::Int32(),      // kSlot
                         MachineType::AnyTagged())  // kMaybeFeedbackVector
  DECLARE_DESCRIPTOR(CallTrampoline_WithFeedbackDescriptor,
                     CallInterfaceDescriptor)
};

class Compare_WithFeedbackDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kLeft, kRight, kSlot, kMaybeFeedbackVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kLeft
                         MachineType::AnyTagged(),  // kRight
                         MachineType::UintPtr(),    // kSlot
                         MachineType::AnyTagged())  // kMaybeFeedbackVector
  DECLARE_DESCRIPTOR(Compare_WithFeedbackDescriptor, CallInterfaceDescriptor)
};

// TODO(jgruber): Pass the slot as UintPtr.
class Construct_WithFeedbackDescriptor : public CallInterfaceDescriptor {
 public:
  // kSlot is passed in a register, kMaybeFeedbackVector on the stack.
  DEFINE_JS_PARAMETERS(kSlot, kMaybeFeedbackVector)
  DEFINE_JS_PARAMETER_TYPES(MachineType::Int32(),      // kSlot
                            MachineType::AnyTagged())  // kMaybeFeedbackVector
  DECLARE_JS_COMPATIBLE_DESCRIPTOR(Construct_WithFeedbackDescriptor,
                                   CallInterfaceDescriptor, 1)
};

class UnaryOp_WithFeedbackDescriptor : public CallInterfaceDescriptor {
 public:
  DEFINE_PARAMETERS(kValue, kSlot, kMaybeFeedbackVector)
  DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(),  // kValue
                         MachineType::UintPtr(),    // kSlot
                         MachineType::AnyTagged())  // kMaybeFeedbackVector
  DECLARE_DESCRIPTOR(UnaryOp_WithFeedbackDescriptor, CallInterfaceDescriptor)
};

#define DEFINE_TFS_BUILTIN_DESCRIPTOR(Name, ...)                          \
  class Name##Descriptor : public CallInterfaceDescriptor {               \
   public:                                                                \
    DEFINE_PARAMETERS(__VA_ARGS__)                                        \
    DECLARE_DEFAULT_DESCRIPTOR(Name##Descriptor, CallInterfaceDescriptor) \
  };
BUILTIN_LIST_TFS(DEFINE_TFS_BUILTIN_DESCRIPTOR)
#undef DEFINE_TFS_BUILTIN_DESCRIPTOR

// This file contains interface descriptor class definitions for builtins
// defined in Torque. It is included here because the class definitions need to
// precede the definition of name##Descriptor::key() below.
#include "torque-generated/interface-descriptors-tq.inc"

#undef DECLARE_DEFAULT_DESCRIPTOR
#undef DECLARE_DESCRIPTOR_WITH_BASE
#undef DECLARE_DESCRIPTOR
#undef DECLARE_JS_COMPATIBLE_DESCRIPTOR
#undef DEFINE_FLAGS_AND_RESULT_AND_PARAMETERS
#undef DEFINE_RESULT_AND_PARAMETERS
#undef DEFINE_PARAMETERS
#undef DEFINE_PARAMETERS_VARARGS
#undef DEFINE_PARAMETERS_NO_CONTEXT
#undef DEFINE_RESULT_AND_PARAMETER_TYPES
#undef DEFINE_PARAMETER_TYPES
#undef DEFINE_JS_PARAMETERS
#undef DEFINE_JS_PARAMETER_TYPES

// We define the association between CallDescriptors::Key and the specialized
// descriptor here to reduce boilerplate and mistakes.
#define DEF_KEY(name, ...) \
  CallDescriptors::Key name##Descriptor::key() { return CallDescriptors::name; }
INTERFACE_DESCRIPTOR_LIST(DEF_KEY)
#undef DEF_KEY
}  // namespace internal
}  // namespace v8

#endif  // V8_CODEGEN_INTERFACE_DESCRIPTORS_H_