current commit
261015.17 · deps: update V8 to 15.6.75.13
// Copyright 2016 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.

// Note 1: Any file that includes this one should include object-macros-undef.h
// at the bottom.

// Note 2: This file is deliberately missing the include guards (the undeffing
// approach wouldn't work otherwise).
//
// PRESUBMIT_INTENTIONALLY_MISSING_INCLUDE_GUARD

// The accessors with RELAXED_, ACQUIRE_, and RELEASE_ prefixes should be used
// for fields that can be written to and read from multiple threads at the same
// time. See comments in src/base/atomicops.h for the memory ordering sematics.

// First, ensure that we do not include object-macros.h twice without including
// object-macros-undef.h in between.
#ifdef V8_OBJECT_MACROS_DEFINED
#error Include object-macros-undef.h before including object-macros.h again
#endif
#define V8_OBJECT_MACROS_DEFINED

#include "src/base/memory.h"

// V8 objects are defined as:
//
//     V8_OBJECT class Foo : public Base {
//       ...
//     } V8_OBJECT_END;
//
//     V8_ABSTRACT_OBJECT class AbstractFoo : public Base {
//       ...
//       // unused padding used in subclasses.
//     } V8_OBJECT_END;
//
// These macros are to enable packing down to 4-byte alignment (i.e. int32
// alignment, since we have int32 fields), and to add warnings which ensure that
// there is no unwanted within-object padding. When defining an abstract class,
// it might be useful to enable packing down to 1-byte alignment to let the
// subclasses utilize the unused padding in the base class appropriately, use
// V8_ABSTRACT_OBJECT instead of V8_OBJECT in that case.
#if V8_CC_GNU
#define V8_OBJECT_PUSH                                                    \
  _Pragma("pack(push)") _Pragma("pack(4)") _Pragma("GCC diagnostic push") \
      _Pragma("GCC diagnostic error \"-Wpadded\"")
#define V8_ABSTRACT_OBJECT_PUSH                                           \
  _Pragma("pack(push)") _Pragma("pack(1)") _Pragma("GCC diagnostic push") \
      _Pragma("GCC diagnostic error \"-Wpadded\"")
#define V8_OBJECT_POP _Pragma("pack(pop)") _Pragma("GCC diagnostic pop")
#elif V8_CC_MSVC
#define V8_OBJECT_PUSH                                           \
  __pragma(pack(push)) __pragma(pack(4)) __pragma(warning(push)) \
      __pragma(warning(default : 4820))
#define V8_ABSTRACT_OBJECT_PUSH                                  \
  __pragma(pack(push)) __pragma(pack(1)) __pragma(warning(push)) \
      __pragma(warning(default : 4820))
#define V8_OBJECT_POP __pragma(pack(pop)) __pragma(warning(pop))
#else
#error Unsupported compiler
#endif

#define V8_OBJECT V8_OBJECT_PUSH
#define V8_ABSTRACT_OBJECT V8_ABSTRACT_OBJECT_PUSH
// Compilers wants the pragmas to be a new statement, but we prefer to have
// V8_OBJECT_END look like part of the definition. Insert a semicolon before the
// pragma to make the compilers happy, and use static_assert(true) to swallow
// the next semicolon.
#define V8_OBJECT_END \
  ;                   \
  V8_OBJECT_POP static_assert(true)

#define V8_OBJECT_INNER_CLASS V8_OBJECT_POP
#define V8_OBJECT_INNER_CLASS_END \
  ;                               \
  V8_OBJECT_PUSH static_assert(true)

// Instance-type markers for V8_OBJECT classes. They exist solely for the
// libclang-driven instance-type generator, which harvests them to drive
// `instance-type.h` emission, and they reach no other build: outside the
// harvest's parse they expand to a static_assert. Mirror the meanings of
// the Torque annotations they replace (see `src/torque/...` and the IT
// solver).
//
// Usage -- one per line in the class body, in any order:
//
//   V8_OBJECT class JSReceiver : public HeapObject {
//    public:
//     V8_IT_ABSTRACT;
//     ...
//   } V8_OBJECT_END;
//
// Only the harvest's parse declares anything here, and it has to: an
// attribute must appertain to a declaration, and a bare `[[...]];` in a
// class body declares nothing, so the attribute rides an alias -- the
// carrier that adds no value, enumerator or function to the class.
// Everywhere else the marker's own `;` terminates a static_assert and
// the class is left untouched.
#ifdef V8_METAGEN_GENERATION_PASS
#define V8_IT_MARK(NAME, PAYLOAD) \
  using V8IT_##NAME [[clang::annotate(PAYLOAD)]] = void
#else
#define V8_IT_MARK(NAME, PAYLOAD) static_assert(true)
#endif
#define V8_IT_ABSTRACT V8_IT_MARK(Abstract, "V8_IT_ABSTRACT")
#define V8_IT_REUSE_PARENT V8_IT_MARK(ReuseParent, "V8_IT_REUSE_PARENT")
#define V8_IT_FIXED_VALUE(N) V8_IT_MARK(FixedValue, "V8_IT_FIXED_VALUE(" #N ")")
#define V8_IT_FLAG_BITS(N) V8_IT_MARK(FlagBits, "V8_IT_FLAG_BITS(" #N ")")
#define V8_IT_ORDER(POS) V8_IT_MARK(Order, "V8_IT_ORDER(" #POS ")")
// Explicit participation marker for concrete classes that also have
// concrete subclasses among the IT participants (concrete
// non-leaves). The default discovery rule -- "leaf in the candidate
// set OR carries any V8_IT_* annotation" -- treats unannotated
// intermediates as inheritance bookkeeping, not IT participants. A
// concrete intermediate that wants its own _TYPE value emitted has
// to opt in via this annotation.
//
// Examples: Map (has Map sub-types as children), JSArray (parent of
// TemplateLiteralObject), FixedArray (parent of FixedArrayExact),
// HashTable (parent of EphemeronHashTable / NameToIndexHashTable /
// RegisteredSymbolTable), etc.
//
// Pure-leaf classes don't need this -- they auto-participate.
// Abstract non-leaves use V8_IT_ABSTRACT (no own value, range
// markers only). V8_IT_REUSE_PARENT classes share the parent's IT.
#define V8_IT_OWN_TYPE V8_IT_MARK(OwnType, "V8_IT_OWN_TYPE")
// Excludes the class from metagen's generated checker bucket lists. By
// default it also excludes the class from the instance-type harvest entirely,
// so it gets no instance-type value of its own. Combine it with
// V8_IT_OWN_TYPE to retain the class and its own instance-type value while
// suppressing only its generated checker entries.
//
// Used for classes with a hand-written `IsX(...)` predicate (in
// instance-type-checker.h's INSTANCE_TYPE_CHECKERS_CUSTOM list, in the
// SINGLE/RANGE manual extras, or via DEF_HEAP_OBJECT_PREDICATE across src/)
// whose auto-emitted definition would collide with it.
#define V8_IT_NO_AUTO_CHECKER V8_IT_MARK(NoAutoChecker, "V8_IT_NO_AUTO_CHECKER")
// Excludes the class from the generated
// HEAP_OBJECT_DIAGNOSTIC_DISPATCH_LIST even though it declares both
// Name##Print and Name##Verify. Carriers are dispatched by hand-written
// cases in HeapObject::HeapObjectPrint (objects-printer.cc) and
// HeapObject::HeapObjectVerify (objects-debug.cc); without this marker
// the generated entry would produce a duplicate case label there
// (which is also the loud failure mode if the marker is forgotten).
#define V8_IT_NO_AUTO_DISPATCH \
  V8_IT_MARK(NoAutoDispatch, "V8_IT_NO_AUTO_DISPATCH")

#define DECL_PRIMITIVE_GETTER(name, type) inline type name() const;

#define DECL_PRIMITIVE_SETTER(name, type) inline void set_##name(type value);

#define DECL_PRIMITIVE_ACCESSORS(name, type) \
  DECL_PRIMITIVE_GETTER(name, type)          \
  DECL_PRIMITIVE_SETTER(name, type)

#define DECL_BOOLEAN_ACCESSORS(name) DECL_PRIMITIVE_ACCESSORS(name, bool)

#define DECL_INT_ACCESSORS(name) DECL_PRIMITIVE_ACCESSORS(name, int)

#define DECL_INT32_ACCESSORS(name) DECL_PRIMITIVE_ACCESSORS(name, int32_t)

#define DECL_SANDBOXED_POINTER_ACCESSORS(name, type) \
  DECL_PRIMITIVE_GETTER(name, type)                  \
  DECL_PRIMITIVE_SETTER(name, type)

#define DECL_UINT16_ACCESSORS(name) DECL_PRIMITIVE_ACCESSORS(name, uint16_t)

#define DECL_INT16_ACCESSORS(name) DECL_PRIMITIVE_ACCESSORS(name, int16_t)

#define DECL_UINT8_ACCESSORS(name) DECL_PRIMITIVE_ACCESSORS(name, uint8_t)

#define DECL_RELAXED_PRIMITIVE_ACCESSORS(name, type) \
  inline type name(RelaxedLoadTag) const;            \
  inline void set_##name(type value, RelaxedStoreTag);

#define DECL_RELAXED_INT32_ACCESSORS(name) \
  DECL_RELAXED_PRIMITIVE_ACCESSORS(name, int32_t)

#define DECL_RELAXED_UINT32_ACCESSORS(name) \
  DECL_RELAXED_PRIMITIVE_ACCESSORS(name, uint32_t)

#define DECL_RELAXED_UINT16_ACCESSORS(name) \
  DECL_RELAXED_PRIMITIVE_ACCESSORS(name, uint16_t)

#define DECL_RELAXED_UINT8_ACCESSORS(name) \
  DECL_RELAXED_PRIMITIVE_ACCESSORS(name, uint8_t)

#define DECL_GETTER(name, ...) inline __VA_ARGS__ name() const;

#define DEF_GETTER(holder, name, ...) __VA_ARGS__ holder::name() const

#define DEF_RELAXED_GETTER(holder, name, ...) \
  __VA_ARGS__ holder::name(RelaxedLoadTag tag) const

#define DEF_ACQUIRE_GETTER(holder, name, ...) \
  __VA_ARGS__ holder::name(AcquireLoadTag tag) const

#define DEF_HEAP_OBJECT_PREDICATE(name)               \
  bool name(Tagged<Object> obj) {                     \
    Tagged<HeapObject> ho;                            \
    return TryCast<HeapObject>(obj, &ho) && name(ho); \
  }                                                   \
  bool name(Tagged<HeapObject> obj)

#define DEF_CAST_TRAITS(Type, ...)                           \
  template <>                                                \
  struct CastTraits<Type> {                                  \
    static inline bool AllowFrom(Tagged<Object> value) {     \
      return Is##Type(value);                                \
    }                                                        \
    static inline bool AllowFrom(Tagged<HeapObject> value) { \
      return Is##Type(value);                                \
    }                                                        \
  };

#define TQ_FIELD_TYPE(name, tq_type) \
  static constexpr const char* k##name##TqFieldType = tq_type;

#define DECL_FIELD_OFFSET_TQ(name, value, tq_type) \
  static const int k##name##Offset = value;        \
  TQ_FIELD_TYPE(name, tq_type)

#define DECL_SETTER(name, ...)              \
  inline void set_##name(__VA_ARGS__ value, \
                         WriteBarrierMode mode = UPDATE_WRITE_BARRIER);

#define DECL_ACCESSORS(name, ...) \
  DECL_GETTER(name, __VA_ARGS__)  \
  DECL_SETTER(name, __VA_ARGS__)

#define DECL_ACCESSORS_LOAD_TAG(name, type, tag_type) \
  inline UNPAREN(type) name(tag_type tag) const;

#define DECL_ACCESSORS_STORE_TAG(name, type, tag_type)  \
  inline void set_##name(UNPAREN(type) value, tag_type, \
                         WriteBarrierMode mode = UPDATE_WRITE_BARRIER);

#define DECL_RELAXED_GETTER(name, ...) \
  DECL_ACCESSORS_LOAD_TAG(name, (__VA_ARGS__), RelaxedLoadTag)

#define DECL_RELAXED_SETTER(name, ...) \
  DECL_ACCESSORS_STORE_TAG(name, (__VA_ARGS__), RelaxedStoreTag)

#define DECL_RELAXED_ACCESSORS(name, ...) \
  DECL_RELAXED_GETTER(name, __VA_ARGS__)  \
  DECL_RELAXED_SETTER(name, __VA_ARGS__)

#define DECL_ACQUIRE_GETTER(name, ...) \
  DECL_ACCESSORS_LOAD_TAG(name, (__VA_ARGS__), AcquireLoadTag)

#define DECL_RELEASE_SETTER(name, ...) \
  DECL_ACCESSORS_STORE_TAG(name, (__VA_ARGS__), ReleaseStoreTag)

#define DECL_RELEASE_ACQUIRE_ACCESSORS(name, ...) \
  DECL_ACQUIRE_GETTER(name, __VA_ARGS__)          \
  DECL_RELEASE_SETTER(name, __VA_ARGS__)

#define DEF_PRIMITIVE_ACCESSORS(holder, name, offset, type)     \
  type holder::name() const { return ReadField<type>(offset); } \
  void holder::set_##name(type value) { WriteField<type>(offset, value); }

#define INT_ACCESSORS(holder, name, offset) \
  DEF_PRIMITIVE_ACCESSORS(holder, name, offset, int)

#define INT32_ACCESSORS(holder, name, offset) \
  DEF_PRIMITIVE_ACCESSORS(holder, name, offset, int32_t)

#define UINT16_ACCESSORS(holder, name, offset) \
  DEF_PRIMITIVE_ACCESSORS(holder, name, offset, uint16_t)

#define UINT8_ACCESSORS(holder, name, offset) \
  DEF_PRIMITIVE_ACCESSORS(holder, name, offset, uint8_t)

#define RELAXED_INT32_ACCESSORS(holder, name, offset)       \
  int32_t holder::name(RelaxedLoadTag) const {              \
    return RELAXED_READ_INT32_FIELD(this, offset);          \
  }                                                         \
  void holder::set_##name(int32_t value, RelaxedStoreTag) { \
    RELAXED_WRITE_INT32_FIELD(this, offset, value);         \
  }

#define RELAXED_UINT32_ACCESSORS(holder, name, offset)       \
  uint32_t holder::name(RelaxedLoadTag) const {              \
    return RELAXED_READ_UINT32_FIELD(this, offset);          \
  }                                                          \
  void holder::set_##name(uint32_t value, RelaxedStoreTag) { \
    RELAXED_WRITE_UINT32_FIELD(this, offset, value);         \
  }

#define RELAXED_UINT16_ACCESSORS(holder, name, offset)       \
  uint16_t holder::name(RelaxedLoadTag) const {              \
    return RELAXED_READ_UINT16_FIELD(this, offset);          \
  }                                                          \
  void holder::set_##name(uint16_t value, RelaxedStoreTag) { \
    RELAXED_WRITE_UINT16_FIELD(this, offset, value);         \
  }

#define RELAXED_UINT8_ACCESSORS(holder, name, offset)       \
  uint8_t holder::name(RelaxedLoadTag) const {              \
    return RELAXED_READ_UINT8_FIELD(this, offset);          \
  }                                                         \
  void holder::set_##name(uint8_t value, RelaxedStoreTag) { \
    RELAXED_WRITE_UINT8_FIELD(this, offset, value);         \
  }

#define ACCESSORS_CHECKED2(holder, name, type, offset, get_condition,   \
                           set_condition)                               \
  DEF_GETTER(holder, name, UNPAREN(type)) {                             \
    UNPAREN(type)                                                       \
    value = TaggedField<UNPAREN(type), offset>::load(this);             \
    DCHECK(get_condition);                                              \
    return value;                                                       \
  }                                                                     \
  void holder::set_##name(UNPAREN(type) value, WriteBarrierMode mode) { \
    DCHECK(set_condition);                                              \
    TaggedField<UNPAREN(type), offset>::store(this, value);             \
    CONDITIONAL_WRITE_BARRIER(this, offset, value, mode);               \
  }

#define ACCESSORS_CHECKED(holder, name, type, offset, condition) \
  ACCESSORS_CHECKED2(holder, name, type, offset, condition, condition)

#define ACCESSORS(holder, name, type, offset) \
  ACCESSORS_CHECKED(holder, name, type, offset, true)

#define RENAME_TORQUE_ACCESSORS(holder, name, torque_name, ...)              \
  inline __VA_ARGS__ holder::name() const {                                  \
    return TorqueGeneratedClass::torque_name();                              \
  }                                                                          \
  inline void holder::set_##name(__VA_ARGS__ value, WriteBarrierMode mode) { \
    TorqueGeneratedClass::set_##torque_name(value, mode);                    \
  }

#define RENAME_PRIMITIVE_TORQUE_ACCESSORS(holder, name, torque_name, type)  \
  type holder::name() const { return TorqueGeneratedClass::torque_name(); } \
  void holder::set_##name(type value) {                                     \
    TorqueGeneratedClass::set_##torque_name(value);                         \
  }

#define ACCESSORS_RELAXED_CHECKED2(holder, name, type, offset, get_condition, \
                                   set_condition)                             \
  type holder::name() const {                                                 \
    type value = TaggedField<type, offset>::Relaxed_Load(this);               \
    DCHECK(get_condition);                                                    \
    return value;                                                             \
  }                                                                           \
  void holder::set_##name(type value, WriteBarrierMode mode) {                \
    DCHECK(set_condition);                                                    \
    TaggedField<type, offset>::Relaxed_Store(this, value);                    \
    CONDITIONAL_WRITE_BARRIER(this, offset, value, mode);                     \
  }

#define ACCESSORS_RELAXED_CHECKED(holder, name, type, offset, condition) \
  ACCESSORS_RELAXED_CHECKED2(holder, name, type, offset, condition, condition)

#define ACCESSORS_RELAXED(holder, name, type, offset) \
  ACCESSORS_RELAXED_CHECKED(holder, name, type, offset, true)

// Similar to ACCESSORS_RELAXED above but with respective relaxed tags.
#define RELAXED_ACCESSORS_CHECKED2(holder, name, type, offset, get_condition, \
                                   set_condition)                             \
  DEF_RELAXED_GETTER(holder, name, UNPAREN(type)) {                           \
    UNPAREN(type)                                                             \
    value = TaggedField<UNPAREN(type), offset>::Relaxed_Load(this);           \
    DCHECK(get_condition);                                                    \
    return value;                                                             \
  }                                                                           \
  void holder::set_##name(UNPAREN(type) value, RelaxedStoreTag,               \
                          WriteBarrierMode mode) {                            \
    DCHECK(set_condition);                                                    \
    TaggedField<UNPAREN(type), offset>::Relaxed_Store(this, value);           \
    CONDITIONAL_WRITE_BARRIER(this, offset, value, mode);                     \
  }

#define RELAXED_ACCESSORS_CHECKED(holder, name, type, offset, condition) \
  RELAXED_ACCESSORS_CHECKED2(holder, name, type, offset, condition, condition)

#define RELAXED_ACCESSORS(holder, name, type, offset) \
  RELAXED_ACCESSORS_CHECKED(holder, name, type, offset, true)

#define RELEASE_ACQUIRE_GETTER_CHECKED(holder, name, type, offset,  \
                                       get_condition)               \
  DEF_ACQUIRE_GETTER(holder, name, UNPAREN(type)) {                 \
    UNPAREN(type)                                                   \
    value = TaggedField<UNPAREN(type), offset>::Acquire_Load(this); \
    DCHECK(get_condition);                                          \
    return value;                                                   \
  }

#define RELEASE_ACQUIRE_SETTER_CHECKED(holder, name, type, offset,  \
                                       set_condition)               \
  void holder::set_##name(UNPAREN(type) value, ReleaseStoreTag,     \
                          WriteBarrierMode mode) {                  \
    DCHECK(set_condition);                                          \
    TaggedField<UNPAREN(type), offset>::Release_Store(this, value); \
    CONDITIONAL_WRITE_BARRIER(this, offset, value, mode);           \
  }

#define RELEASE_ACQUIRE_ACCESSORS_CHECKED2(holder, name, type, offset,      \
                                           get_condition, set_condition)    \
  RELEASE_ACQUIRE_GETTER_CHECKED(holder, name, type, offset, get_condition) \
  RELEASE_ACQUIRE_SETTER_CHECKED(holder, name, type, offset, set_condition)

#define RELEASE_ACQUIRE_ACCESSORS_CHECKED(holder, name, type, offset,       \
                                          condition)                        \
  RELEASE_ACQUIRE_ACCESSORS_CHECKED2(holder, name, type, offset, condition, \
                                     condition)

#define RELEASE_ACQUIRE_ACCESSORS(holder, name, type, offset) \
  RELEASE_ACQUIRE_ACCESSORS_CHECKED(holder, name, type, offset, true)

// Getter that returns a Smi as an int and writes an int as a Smi.
#define SMI_ACCESSORS_CHECKED(holder, name, offset, condition)  \
  int holder::name() const {                                    \
    DCHECK(condition);                                          \
    Tagged<Smi> value = TaggedField<Smi, offset>::load(this);   \
    return value.value();                                       \
  }                                                             \
  void holder::set_##name(int value) {                          \
    DCHECK(condition);                                          \
    TaggedField<Smi, offset>::store(this, Smi::FromInt(value)); \
  }

#define SMI_ACCESSORS(holder, name, offset) \
  SMI_ACCESSORS_CHECKED(holder, name, offset, true)

#define DECL_RELEASE_ACQUIRE_INT_ACCESSORS(name) \
  inline int name(AcquireLoadTag) const;         \
  inline void set_##name(int value, ReleaseStoreTag);

#define RELEASE_ACQUIRE_SMI_ACCESSORS(holder, name, offset)             \
  int holder::name(AcquireLoadTag) const {                              \
    Tagged<Smi> value = TaggedField<Smi, offset>::Acquire_Load(this);   \
    return value.value();                                               \
  }                                                                     \
  void holder::set_##name(int value, ReleaseStoreTag) {                 \
    TaggedField<Smi, offset>::Release_Store(this, Smi::FromInt(value)); \
  }

#define DECL_RELAXED_INT_ACCESSORS(name) \
  inline int name(RelaxedLoadTag) const; \
  inline void set_##name(int value, RelaxedStoreTag);

#define RELAXED_SMI_ACCESSORS(holder, name, offset)                     \
  int holder::name(RelaxedLoadTag) const {                              \
    Tagged<Smi> value = TaggedField<Smi, offset>::Relaxed_Load(this);   \
    return value.value();                                               \
  }                                                                     \
  void holder::set_##name(int value, RelaxedStoreTag) {                 \
    TaggedField<Smi, offset>::Relaxed_Store(this, Smi::FromInt(value)); \
  }

#define BOOL_GETTER(holder, field, name, offset) \
  bool holder::name() const { return BooleanBit::get(field(), offset); }

#define BOOL_ACCESSORS(holder, field, name, offset)                      \
  bool holder::name() const { return BooleanBit::get(field(), offset); } \
  void holder::set_##name(bool value) {                                  \
    set_##field(BooleanBit::set(field(), offset, value));                \
  }

#define DECL_RELAXED_BOOL_ACCESSORS(name) \
  inline bool name(RelaxedLoadTag) const; \
  inline void set_##name(bool value, RelaxedStoreTag);

#define RELAXED_BOOL_ACCESSORS(holder, field, name, offset)          \
  bool holder::name(RelaxedLoadTag) const {                          \
    return BooleanBit::get(field(kRelaxedLoad), offset);             \
  }                                                                  \
  void holder::set_##name(bool value, RelaxedStoreTag) {             \
    set_##field(BooleanBit::set(field(kRelaxedLoad), offset, value), \
                kRelaxedStore);                                      \
  }

// Host objects in ReadOnlySpace can't define the isolate-less accessor.
#define DECL_LAZY_EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST(name, type) \
  inline void init_##name();                                                  \
  inline bool has_##name() const;                                             \
  inline type name(i::IsolateForSandbox isolate) const;                       \
  inline void set_##name(i::IsolateForSandbox isolate, const type value);

// Host objects in ReadOnlySpace can't define the isolate-less accessor.
#define LAZY_EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST_CHECKED2(       \
    holder, name, type, offset, tag, get_condition, set_condition)           \
  void holder::init_##name() {                                               \
    this->SetupLazilyInitializedExternalPointerField(offset);                \
  }                                                                          \
  bool holder::has_##name() const {                                          \
    return this->IsLazilyInitializedExternalPointerFieldInitialized(offset); \
  }                                                                          \
  type holder::name(i::IsolateForSandbox isolate) const {                    \
    DCHECK(get_condition);                                                   \
    /* This is a workaround for MSVC error C2440 not allowing  */            \
    /* reinterpret casts to the same type. */                                \
    struct C2440 {};                                                         \
    Address result =                                                         \
        this->template ReadExternalPointerField<tag>(offset, isolate);       \
    return reinterpret_cast<type>(reinterpret_cast<C2440*>(result));         \
  }                                                                          \
  void holder::set_##name(i::IsolateForSandbox isolate, const type value) {  \
    DCHECK(set_condition);                                                   \
    /* This is a workaround for MSVC error C2440 not allowing  */            \
    /* reinterpret casts to the same type. */                                \
    struct C2440 {};                                                         \
    Address the_value =                                                      \
        reinterpret_cast<Address>(reinterpret_cast<const C2440*>(value));    \
    this->template WriteLazilyInitializedExternalPointerField<tag>(          \
        offset, isolate, the_value);                                         \
  }

#define LAZY_EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST_CHECKED( \
    holder, name, type, offset, tag, condition)                       \
  LAZY_EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST_CHECKED2(      \
      holder, name, type, offset, tag, condition, condition)

#define LAZY_EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST(    \
    holder, name, type, offset, tag)                             \
  LAZY_EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST_CHECKED2( \
      holder, name, type, offset, tag, true, true)

// Declares all required accessors for a lazily initialized C function pointer
// that can be called from native code.
// In case the host and target architectures are different (i.e. simulator
// is enabled), we can't just call the C function from native code because
// of architecture difference and we need to "ask" the simulator to call
// the C function on behalf of the native code. This is a so-called
// "redirection". The pointer stored in the object is redirected while C++
// accessors operate on an original C function pointer (wrapping/unwrapping
// is done the under the hood).
// Host objects in ReadOnlySpace can't define the isolate-less accessor.
#define DECL_LAZY_REDIRECTED_CALLBACK_ACCESSORS_MAYBE_READ_ONLY_HOST(name,    \
                                                                     type)    \
 private:                                                                     \
  /* Returns a potentially redirected callback pointer as it's stored */      \
  /* in the object. This getter is used for printing of redirected value. */  \
  inline Address name##_raw(i::IsolateForSandbox isolate) const;              \
  /* Adds/removes redirection for a callback pointer stored in the object. */ \
  inline void init_##name##_redirection(i::IsolateForSandbox isolate);        \
  inline void remove_##name##_redirection(i::IsolateForSandbox isolate);      \
                                                                              \
 public:                                                                      \
  DECL_LAZY_EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST(name, type)

// Defines all required accessors for a lazily initialized C function pointer
// that can be called from native code.
// See DECL_LAZY_REDIRECTED_CALLBACK_ACCESSORS_MAYBE_READ_ONLY_HOST for details.
// Host objects in ReadOnlySpace can't define the isolate-less accessor.
#define LAZY_REDIRECTED_CALLBACK_ACCESSORS_MAYBE_READ_ONLY_HOST_CHECKED2(    \
    holder, name, type, offset, tag, ext_ref_type, get_condition,            \
    set_condition)                                                           \
                                                                             \
  /* Accessors for un-redirected callback pointer that can be used */        \
  /* in C++ code and an accessor to the raw value for printing. */           \
  void holder::init_##name() {                                               \
    this->SetupLazilyInitializedExternalPointerField(offset);                \
  }                                                                          \
  bool holder::has_##name() const {                                          \
    return this->IsLazilyInitializedExternalPointerFieldInitialized(offset); \
  }                                                                          \
  Address holder::name##_raw(i::IsolateForSandbox isolate) const {           \
    return this->template ReadExternalPointerField<tag>(offset, isolate);    \
  }                                                                          \
  type holder::name(i::IsolateForSandbox isolate) const {                    \
    Address result = name##_raw(isolate);                                    \
    if (!USE_SIMULATOR_BOOL) return result;                                  \
    if (result == kNullAddress) return kNullAddress;                         \
    return ExternalReference::UnwrapRedirection(result);                     \
  }                                                                          \
  void holder::set_##name(i::IsolateForSandbox isolate, Address value) {     \
    this->template WriteLazilyInitializedExternalPointerField<tag>(          \
        offset, isolate, value);                                             \
    if (USE_SIMULATOR_BOOL) {                                                \
      init_##name##_redirection(isolate);                                    \
    }                                                                        \
  }                                                                          \
                                                                             \
  /* Implementation of init/remove callback redirection methods. */          \
  void holder::init_##name##_redirection(i::IsolateForSandbox isolate) {     \
    CHECK(USE_SIMULATOR_BOOL);                                               \
    Address value = name##_raw(isolate);                                     \
    if (value == kNullAddress) return;                                       \
    value = ExternalReference::Redirect(value, ext_ref_type);                \
    this->template WriteLazilyInitializedExternalPointerField<tag>(          \
        offset, isolate, value);                                             \
  }                                                                          \
  void holder::remove_##name##_redirection(i::IsolateForSandbox isolate) {   \
    CHECK(USE_SIMULATOR_BOOL);                                               \
    Address value = name##_raw(isolate);                                     \
    if (value == kNullAddress) return;                                       \
    value = ExternalReference::UnwrapRedirection(value);                     \
    this->template WriteLazilyInitializedExternalPointerField<tag>(          \
        offset, isolate, value);                                             \
  }

// Host objects in ReadOnlySpace can't define the isolate-less accessor.
#define DECL_EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST(name, type) \
  inline type name(i::IsolateForSandbox isolate) const;                  \
  inline void init_##name(i::IsolateForSandbox isolate,                  \
                          const type initial_value);                     \
  inline void set_##name(i::IsolateForSandbox isolate, const type value);

// Host objects in ReadOnlySpace can't define the isolate-less accessor.
#define EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST(holder, name, type,    \
                                                        offset, tag)           \
  type holder::name(i::IsolateForSandbox isolate) const {                      \
    /* This is a workaround for MSVC error C2440 not allowing  */              \
    /* reinterpret casts to the same type. */                                  \
    struct C2440 {};                                                           \
    Address result =                                                           \
        this->template ReadExternalPointerField<tag>(offset, isolate);         \
    return reinterpret_cast<type>(reinterpret_cast<C2440*>(result));           \
  }                                                                            \
  void holder::init_##name(i::IsolateForSandbox isolate,                       \
                           const type initial_value) {                         \
    /* This is a workaround for MSVC error C2440 not allowing  */              \
    /* reinterpret casts to the same type. */                                  \
    struct C2440 {};                                                           \
    Address the_value = reinterpret_cast<Address>(                             \
        reinterpret_cast<const C2440*>(initial_value));                        \
    this->template InitExternalPointerField<tag>(offset, isolate, the_value);  \
  }                                                                            \
  void holder::set_##name(i::IsolateForSandbox isolate, const type value) {    \
    /* This is a workaround for MSVC error C2440 not allowing  */              \
    /* reinterpret casts to the same type. */                                  \
    struct C2440 {};                                                           \
    Address the_value =                                                        \
        reinterpret_cast<Address>(reinterpret_cast<const C2440*>(value));      \
    this->template WriteExternalPointerField<tag>(offset, isolate, the_value); \
  }

// Declares all required accessors for C function pointer that can be called
// from native code.
// In case the host and target architectures are different (i.e. simulator
// is enabled), we can't just call the C function from native code because
// of architecture difference and we need to "ask" the simulator to call
// the C function on behalf of the native code. This is a so-called
// "redirection". The pointer stored in the object is redirected while C++
// accessors operate on an original C function pointer (wrapping/unwrapping
// is done the under the hood).
// Host objects in ReadOnlySpace can't define the isolate-less accessor.
#define DECL_REDIRECTED_CALLBACK_ACCESSORS_MAYBE_READ_ONLY_HOST(name, type)   \
 private:                                                                     \
  /* Returns a potentially redirected callback pointer as it's stored */      \
  /* in the object. This getter is used for printing of redirected value. */  \
  inline Address name##_raw(i::IsolateForSandbox isolate) const;              \
  /* Adds/removes redirection for a callback pointer stored in the object. */ \
  inline void init_##name##_redirection(i::IsolateForSandbox isolate);        \
  inline void remove_##name##_redirection(i::IsolateForSandbox isolate);      \
                                                                              \
 public:                                                                      \
  /* Declare accessors as for a regular external pointer. */                  \
  DECL_EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST(name, type)

// Defines all required accessors for C function pointer that can be called
// from native code.
// See DECL_REDIRECTED_CALLBACK_ACCESSORS_MAYBE_READ_ONLY_HOST for details.
// Host objects in ReadOnlySpace can't define the isolate-less accessor.
#define REDIRECTED_CALLBACK_ACCESSORS_MAYBE_READ_ONLY_HOST(                \
    holder, name, type, offset, tag, ext_ref_type)                         \
                                                                           \
  Address holder::name##_raw(i::IsolateForSandbox isolate) const {         \
    return this->template ReadExternalPointerField<tag>(offset, isolate);  \
  }                                                                        \
                                                                           \
  /* Accessors for un-redirected callback pointer that can be used */      \
  /* in C++ code. */                                                       \
  type holder::name(i::IsolateForSandbox isolate) const {                  \
    Address value = name##_raw(isolate);                                   \
    if (!USE_SIMULATOR_BOOL) return value;                                 \
    if (value == kNullAddress) return kNullAddress;                        \
    return ExternalReference::UnwrapRedirection(value);                    \
  }                                                                        \
  void holder::init_##name(i::IsolateForSandbox isolate,                   \
                           Address initial_value) {                        \
    this->template InitExternalPointerField<tag>(offset, isolate,          \
                                                 initial_value);           \
    if (USE_SIMULATOR_BOOL) {                                              \
      init_##name##_redirection(isolate);                                  \
    }                                                                      \
  }                                                                        \
  void holder::set_##name(i::IsolateForSandbox isolate, Address value) {   \
    this->template WriteExternalPointerField<tag>(offset, isolate, value); \
    if (USE_SIMULATOR_BOOL) {                                              \
      init_##name##_redirection(isolate);                                  \
    }                                                                      \
  }                                                                        \
                                                                           \
  /* Implementation of init/remove callback redirection methods. */        \
  void holder::init_##name##_redirection(i::IsolateForSandbox isolate) {   \
    CHECK(USE_SIMULATOR_BOOL);                                             \
    Address value = name##_raw(isolate);                                   \
    if (value == kNullAddress) return;                                     \
    value = ExternalReference::Redirect(value, ext_ref_type);              \
    this->template WriteExternalPointerField<tag>(offset, isolate, value); \
  }                                                                        \
  void holder::remove_##name##_redirection(i::IsolateForSandbox isolate) { \
    CHECK(USE_SIMULATOR_BOOL);                                             \
    Address value = name##_raw(isolate);                                   \
    if (value == kNullAddress) return;                                     \
    value = ExternalReference::UnwrapRedirection(value);                   \
    this->template WriteExternalPointerField<tag>(offset, isolate, value); \
  }

#define DECL_EXTERNAL_POINTER_ACCESSORS(name, type) \
  inline type name() const;                         \
  DECL_EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST(name, type)

#define EXTERNAL_POINTER_ACCESSORS(holder, name, type, offset, tag)           \
  type holder::name() const {                                                 \
    i::IsolateForSandbox isolate = GetCurrentIsolateForSandbox();             \
    return holder::name(isolate);                                             \
  }                                                                           \
  EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST(holder, name, type, offset, \
                                                  tag)

// Host objects in ReadOnlySpace can't define the isolate-less accessor.
#define DECL_CPP_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST(name, type) \
  inline type name(i::IsolateForPointerCompression isolate) const;  \
  inline void init_##name(i::IsolateForPointerCompression isolate,  \
                          type initial_value);                      \
  inline void set_##name(i::IsolateForPointerCompression isolate, type value);

#define DECL_CPP_POINTER_ACCESSORS(name, type) \
  inline type name() const;                    \
  DECL_CPP_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST(name, type)

#define DECL_TRUSTED_POINTER_GETTERS(name, type)                             \
  /* Trusted pointers currently always have release-acquire semantics. */    \
  /* However, we still expose explicit release-acquire accessors so it */    \
  /* can be made clear when they are required. */                            \
  /* If desired, we could create separate {Read|Write}TrustedPointer */      \
  /* routines for relaxed- and release-acquire semantics in the future. */   \
  inline Tagged<type> name(IsolateForSandbox isolate) const;                 \
  inline Tagged<type> name(IsolateForSandbox isolate, AcquireLoadTag) const; \
  inline bool has_##name() const;                                            \
  /* Checks if the field in question is populated but unpublished. Most */   \
  /* code shouldn't need to care (i.e. may assume regularly published */     \
  /* fields), but some code needs to be robust to both situations. */        \
  inline bool has_##name##_unpublished(IsolateForSandbox isolate) const;

#define DECL_TRUSTED_POINTER_SETTERS(name, type)                           \
  /* Trusted pointers currently always have release-acquire semantics. */  \
  /* However, we still expose explicit release-acquire accessors so it */  \
  /* can be made clear when they are required. */                          \
  /* If desired, we could create separate {Read|Write}TrustedPointer */    \
  /* routines for relaxed- and release-acquire semantics in the future. */ \
  inline void set_##name(Tagged<type> value,                               \
                         WriteBarrierMode mode = UPDATE_WRITE_BARRIER);    \
  inline void set_##name(Tagged<type> value, ReleaseStoreTag,              \
                         WriteBarrierMode mode = UPDATE_WRITE_BARRIER);    \
  inline void clear_##name();

#define DECL_TRUSTED_POINTER_ACCESSORS(name, type) \
  DECL_TRUSTED_POINTER_GETTERS(name, type)         \
  DECL_TRUSTED_POINTER_SETTERS(name, type)

#define TRUSTED_POINTER_ACCESSORS(holder, name, type, offset, tag)             \
  Tagged<type> holder::name(IsolateForSandbox isolate) const {                 \
    return name(isolate, kAcquireLoad);                                        \
  }                                                                            \
  Tagged<type> holder::name(IsolateForSandbox isolate, AcquireLoadTag) const { \
    DCHECK(has_##name());                                                      \
    return i::TrustedPointerField::ReadTrustedPointerField<tag>(this, offset,  \
                                                                isolate);      \
  }                                                                            \
  void holder::set_##name(Tagged<type> value, WriteBarrierMode mode) {         \
    set_##name(value, kReleaseStore, mode);                                    \
  }                                                                            \
  void holder::set_##name(Tagged<type> value, ReleaseStoreTag,                 \
                          WriteBarrierMode mode) {                             \
    i::TrustedPointerField::WriteTrustedPointerField<tag>(this, offset,        \
                                                          value);              \
    CONDITIONAL_TRUSTED_POINTER_WRITE_BARRIER(this, offset, tag, value, mode); \
  }                                                                            \
  bool holder::has_##name() const {                                            \
    return !i::TrustedPointerField::IsTrustedPointerFieldEmpty(this, offset);  \
  }                                                                            \
  bool holder::has_##name##_unpublished(IsolateForSandbox isolate) const {     \
    return i::TrustedPointerField::IsTrustedPointerFieldUnpublished(           \
        this, offset, tag, isolate);                                           \
  }                                                                            \
  void holder::clear_##name() {                                                \
    i::TrustedPointerField::ClearTrustedPointerField(this, offset);            \
  }

#define DECL_CODE_POINTER_ACCESSORS(name) \
  DECL_TRUSTED_POINTER_ACCESSORS(name, Code)
#define CODE_POINTER_ACCESSORS(holder, name, offset) \
  TRUSTED_POINTER_ACCESSORS(holder, name, Code, offset, kCodeIndirectPointerTag)

// Accessors for "protected" pointers, i.e. references from one trusted object
// to another trusted object. For these pointers it can be assumed that neither
// the pointer nor the pointed-to object can be manipulated by an attacker.
#define DECL_PROTECTED_POINTER_ACCESSORS(name, type)                    \
  inline Tagged<type> name() const;                                     \
  inline void set_##name(Tagged<type> value,                            \
                         WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
  inline bool has_##name() const;                                       \
  inline void clear_##name();

#define PROTECTED_POINTER_ACCESSORS(holder, name, type, offset)             \
  static_assert(std::is_base_of_v<TrustedObject, holder>);                  \
  Tagged<type> holder::name() const {                                       \
    DCHECK(has_##name());                                                   \
    return ReadProtectedPointerField<type>(offset);                         \
  }                                                                         \
  void holder::set_##name(Tagged<type> value, WriteBarrierMode mode) {      \
    WriteProtectedPointerField(offset, value);                              \
    CONDITIONAL_PROTECTED_POINTER_WRITE_BARRIER(this, offset, value, mode); \
  }                                                                         \
  bool holder::has_##name() const {                                         \
    return !IsProtectedPointerFieldEmpty(offset);                           \
  }                                                                         \
  void holder::clear_##name() { return ClearProtectedPointerField(offset); }

#define DECL_RELEASE_ACQUIRE_PROTECTED_POINTER_ACCESSORS(name, type)    \
  inline Tagged<type> name(AcquireLoadTag) const;                       \
  inline void set_##name(Tagged<type> value, ReleaseStoreTag,           \
                         WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
  inline bool has_##name(AcquireLoadTag) const;                         \
  inline void clear_##name(ReleaseStoreTag);

#define RELEASE_ACQUIRE_PROTECTED_POINTER_ACCESSORS(holder, name, type,     \
                                                    offset)                 \
  static_assert(std::is_base_of_v<TrustedObject, holder>);                  \
  Tagged<type> holder::name(AcquireLoadTag tag) const {                     \
    DCHECK(has_##name(tag));                                                \
    return ReadProtectedPointerField<type>(offset, tag);                    \
  }                                                                         \
  void holder::set_##name(Tagged<type> value, ReleaseStoreTag tag,          \
                          WriteBarrierMode mode) {                          \
    WriteProtectedPointerField(offset, value, tag);                         \
    CONDITIONAL_PROTECTED_POINTER_WRITE_BARRIER(this, offset, value, mode); \
  }                                                                         \
  bool holder::has_##name(AcquireLoadTag tag) const {                       \
    return !IsProtectedPointerFieldEmpty(offset, tag);                      \
  }                                                                         \
  void holder::clear_##name(ReleaseStoreTag tag) {                          \
    return ClearProtectedPointerField(offset, tag);                         \
  }

#define BIT_FIELD_ACCESSORS2(holder, get_field, set_field, name, BitField) \
  typename BitField::FieldType holder::name() const {                      \
    return BitField::decode(get_field());                                  \
  }                                                                        \
  void holder::set_##name(typename BitField::FieldType value) {            \
    set_##set_field(BitField::update(set_field(), value));                 \
  }

#define BIT_FIELD_ACCESSORS(holder, field, name, BitField) \
  BIT_FIELD_ACCESSORS2(holder, field, field, name, BitField)

#define RELAXED_INT16_ACCESSORS(holder, name, offset) \
  int16_t holder::name() const {                      \
    return RELAXED_READ_INT16_FIELD(this, offset);    \
  }                                                   \
  void holder::set_##name(int16_t value) {            \
    RELAXED_WRITE_INT16_FIELD(this, offset, value);   \
  }

#define FIELD_ADDR(p, offset) ((p)->ptr() + offset - kHeapObjectTag)

#define SEQ_CST_READ_FIELD(p, offset) \
  TaggedField<Object>::SeqCst_Load(p, offset)

#define ACQUIRE_READ_FIELD(p, offset) \
  TaggedField<Object>::Acquire_Load(p, offset)

#define RELAXED_READ_FIELD(p, offset) \
  TaggedField<Object>::Relaxed_Load(p, offset)

#define RELAXED_READ_WEAK_FIELD(p, offset) \
  TaggedField<MaybeObject>::Relaxed_Load(p, offset)

#define WRITE_FIELD(p, offset, value) \
  TaggedField<Object>::store(p, offset, value)

#define SEQ_CST_WRITE_FIELD(p, offset, value) \
  TaggedField<Object>::SeqCst_Store(p, offset, value)

#define RELEASE_WRITE_FIELD(p, offset, value) \
  TaggedField<Object>::Release_Store(p, offset, value)

#define RELAXED_WRITE_FIELD(p, offset, value) \
  TaggedField<Object>::Relaxed_Store(p, offset, value)

#define RELAXED_WRITE_WEAK_FIELD(p, offset, value) \
  TaggedField<MaybeObject>::Relaxed_Store(p, offset, value)

#define SEQ_CST_SWAP_FIELD(p, offset, value) \
  TaggedField<Object>::SeqCst_Swap(p, offset, value)

#define SEQ_CST_COMPARE_AND_SWAP_FIELD(p, offset, expected, value) \
  TaggedField<Object>::SeqCst_CompareAndSwap(p, offset, expected, value)

#ifdef V8_DISABLE_WRITE_BARRIERS
#define WRITE_BARRIER(object, offset, value)
#else
#define WRITE_BARRIER(object, offset, value)                                   \
  do {                                                                         \
    DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object));                       \
    static_assert(kTaggedCanConvertToRawObjects);                              \
    /* For write barriers, it doesn't matter if the slot is strong or weak, */ \
    /* so use the most generic slot (a maybe weak one). */                     \
    WriteBarrier::ForValue(object, Tagged(object)->RawMaybeWeakField(offset),  \
                           value, UPDATE_WRITE_BARRIER);                       \
  } while (false)
#endif

#ifdef V8_DISABLE_WRITE_BARRIERS
#define EXTERNAL_POINTER_WRITE_BARRIER(object, offset, tag, handle)
#else
#define EXTERNAL_POINTER_WRITE_BARRIER(object, offset, tag, handle)           \
  do {                                                                        \
    DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object));                      \
    WriteBarrier::ForExternalPointer(                                         \
        object, Tagged(object)->RawExternalPointerField(offset, tag), handle, \
        UPDATE_WRITE_BARRIER);                                                \
  } while (false)
#endif

#ifdef V8_DISABLE_WRITE_BARRIERS
#define INDIRECT_POINTER_WRITE_BARRIER(object, offset, tag, value)
#else
#define INDIRECT_POINTER_WRITE_BARRIER(object, offset, tag, value)           \
  do {                                                                       \
    DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object));                     \
    WriteBarrier::ForIndirectPointer(                                        \
        object, Tagged(object)->RawIndirectPointerField(offset, tag), value, \
        UPDATE_WRITE_BARRIER);                                               \
  } while (false)
#endif

#ifdef V8_DISABLE_WRITE_BARRIERS
#define JS_DISPATCH_HANDLE_WRITE_BARRIER(object, handle)
#else
#define JS_DISPATCH_HANDLE_WRITE_BARRIER(object, handle)                     \
  do {                                                                       \
    DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object));                     \
    WriteBarrier::ForJSDispatchHandle(object, handle, UPDATE_WRITE_BARRIER); \
  } while (false)
#endif

#ifdef V8_DISABLE_WRITE_BARRIERS
#define CONDITIONAL_WRITE_BARRIER(object, offset, value, mode)
#elif V8_ENABLE_UNCONDITIONAL_WRITE_BARRIERS
#define CONDITIONAL_WRITE_BARRIER(object, offset, value, mode) \
  WRITE_BARRIER(object, offset, value)
#else
#define CONDITIONAL_WRITE_BARRIER(object, offset, value, mode)                 \
  do {                                                                         \
    DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object));                       \
    /* For write barriers, it doesn't matter if the slot is strong or weak, */ \
    /* so use the most generic slot (a maybe weak one). */                     \
    WriteBarrier::ForValue(object, (object)->RawMaybeWeakField(offset), value, \
                           mode);                                              \
  } while (false)
#endif

#ifdef V8_DISABLE_WRITE_BARRIERS
#define CONDITIONAL_EXTERNAL_POINTER_WRITE_BARRIER(object, offset, tag, \
                                                   handle, mode)
#else
#define CONDITIONAL_EXTERNAL_POINTER_WRITE_BARRIER(object, offset, tag,       \
                                                   handle, mode)              \
  do {                                                                        \
    DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object));                      \
    WriteBarrier::ForExternalPointer(                                         \
        object, Tagged(object)->RawExternalPointerField(offset, tag), handle, \
        mode);                                                                \
  } while (false)
#endif
#ifdef V8_DISABLE_WRITE_BARRIERS
#define CONDITIONAL_INDIRECT_POINTER_WRITE_BARRIER(object, offset, tag, value, \
                                                   mode)
#else
#define CONDITIONAL_INDIRECT_POINTER_WRITE_BARRIER(object, offset, tag, value, \
                                                   mode)                       \
  do {                                                                         \
    DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object));                       \
    WriteBarrier::ForIndirectPointer(                                          \
        object, Tagged(object)->RawIndirectPointerField(offset, tag), value,   \
        mode);                                                                 \
  } while (false)
#endif

#ifdef V8_ENABLE_SANDBOX
#define CONDITIONAL_TRUSTED_POINTER_WRITE_BARRIER(object, offset, tag, value, \
                                                  mode)                       \
  CONDITIONAL_INDIRECT_POINTER_WRITE_BARRIER(object, offset, tag, value, mode)
#else
#define CONDITIONAL_TRUSTED_POINTER_WRITE_BARRIER(object, offset, tag, value, \
                                                  mode)                       \
  CONDITIONAL_WRITE_BARRIER(this, offset, value, mode);
#endif  // V8_ENABLE_SANDBOX
#define CONDITIONAL_CODE_POINTER_WRITE_BARRIER(object, offset, value, mode) \
  CONDITIONAL_TRUSTED_POINTER_WRITE_BARRIER(                                \
      object, offset, kCodeIndirectPointerTag, value, mode)

#define CONDITIONAL_PROTECTED_POINTER_WRITE_BARRIER(object, offset, value, \
                                                    mode)                  \
  do {                                                                     \
    DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object));                   \
    WriteBarrier::ForProtectedPointer(                                     \
        object, (object)->RawProtectedPointerField(offset), value, mode);  \
  } while (false)

#ifdef V8_DISABLE_WRITE_BARRIERS
#define CONDITIONAL_JS_DISPATCH_HANDLE_WRITE_BARRIER(object, handle, mode)
#else
#define CONDITIONAL_JS_DISPATCH_HANDLE_WRITE_BARRIER(object, handle, mode) \
  do {                                                                     \
    DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object));                   \
    WriteBarrier::ForJSDispatchHandle(object, handle, mode);               \
  } while (false)
#endif

#define ACQUIRE_READ_INT8_FIELD(p, offset) \
  static_cast<int8_t>(base::Acquire_Load(  \
      reinterpret_cast<const base::Atomic8*>(FIELD_ADDR(p, offset))))

#define ACQUIRE_READ_INT32_FIELD(p, offset) \
  static_cast<int32_t>(base::Acquire_Load(  \
      reinterpret_cast<const base::Atomic32*>(FIELD_ADDR(p, offset))))

#define RELAXED_WRITE_INT8_FIELD(p, offset, value)                             \
  base::Relaxed_Store(reinterpret_cast<base::Atomic8*>(FIELD_ADDR(p, offset)), \
                      static_cast<base::Atomic8>(value));
#define RELAXED_READ_INT8_FIELD(p, offset) \
  static_cast<int8_t>(base::Relaxed_Load(  \
      reinterpret_cast<const base::Atomic8*>(FIELD_ADDR(p, offset))))

#define RELAXED_WRITE_UINT8_FIELD(p, offset, value)                            \
  base::Relaxed_Store(reinterpret_cast<base::Atomic8*>(FIELD_ADDR(p, offset)), \
                      static_cast<base::Atomic8>(value));
#define RELAXED_READ_UINT8_FIELD(p, offset) \
  static_cast<uint8_t>(base::Relaxed_Load(  \
      reinterpret_cast<const base::Atomic8*>(FIELD_ADDR(p, offset))))

#define RELAXED_READ_UINT16_FIELD(p, offset) \
  static_cast<uint16_t>(base::Relaxed_Load(  \
      reinterpret_cast<const base::Atomic16*>(FIELD_ADDR(p, offset))))

#define RELAXED_WRITE_UINT16_FIELD(p, offset, value)            \
  base::Relaxed_Store(                                          \
      reinterpret_cast<base::Atomic16*>(FIELD_ADDR(p, offset)), \
      static_cast<base::Atomic16>(value));

#define RELAXED_READ_INT16_FIELD(p, offset) \
  static_cast<int16_t>(base::Relaxed_Load(  \
      reinterpret_cast<const base::Atomic16*>(FIELD_ADDR(p, offset))))

#define RELAXED_WRITE_INT16_FIELD(p, offset, value)             \
  base::Relaxed_Store(                                          \
      reinterpret_cast<base::Atomic16*>(FIELD_ADDR(p, offset)), \
      static_cast<base::Atomic16>(value));

#define RELAXED_READ_UINT32_FIELD(p, offset) \
  static_cast<uint32_t>(base::Relaxed_Load(  \
      reinterpret_cast<const base::Atomic32*>(FIELD_ADDR(p, offset))))

#define ACQUIRE_READ_UINT32_FIELD(p, offset) \
  static_cast<uint32_t>(base::Acquire_Load(  \
      reinterpret_cast<const base::Atomic32*>(FIELD_ADDR(p, offset))))

#define RELAXED_WRITE_UINT32_FIELD(p, offset, value)            \
  base::Relaxed_Store(                                          \
      reinterpret_cast<base::Atomic32*>(FIELD_ADDR(p, offset)), \
      static_cast<base::Atomic32>(value));

#define RELEASE_WRITE_INT8_FIELD(p, offset, value)                             \
  base::Release_Store(reinterpret_cast<base::Atomic8*>(FIELD_ADDR(p, offset)), \
                      static_cast<base::Atomic8>(value));

#define RELEASE_WRITE_UINT32_FIELD(p, offset, value)            \
  base::Release_Store(                                          \
      reinterpret_cast<base::Atomic32*>(FIELD_ADDR(p, offset)), \
      static_cast<base::Atomic32>(value));

#define RELAXED_READ_INT32_FIELD(p, offset) \
  static_cast<int32_t>(base::Relaxed_Load(  \
      reinterpret_cast<const base::Atomic32*>(FIELD_ADDR(p, offset))))

#if defined(V8_HOST_ARCH_64_BIT)
#define RELAXED_READ_INT64_FIELD(p, offset) \
  static_cast<int64_t>(base::Relaxed_Load(  \
      reinterpret_cast<const base::Atomic64*>(FIELD_ADDR(p, offset))))
#endif

#define RELEASE_WRITE_INT32_FIELD(p, offset, value)             \
  base::Release_Store(                                          \
      reinterpret_cast<base::Atomic32*>(FIELD_ADDR(p, offset)), \
      static_cast<base::Atomic32>(value))

#define RELAXED_WRITE_INT32_FIELD(p, offset, value)             \
  base::Relaxed_Store(                                          \
      reinterpret_cast<base::Atomic32*>(FIELD_ADDR(p, offset)), \
      static_cast<base::Atomic32>(value))

static_assert(sizeof(int) == sizeof(int32_t),
              "sizeof int must match sizeof int32_t");

#define RELAXED_READ_INT_FIELD(p, offset) RELAXED_READ_INT32_FIELD(p, offset)

#define RELAXED_WRITE_INT_FIELD(p, offset, value) \
  RELAXED_WRITE_INT32_FIELD(p, offset, value)

static_assert(sizeof(unsigned) == sizeof(uint32_t),
              "sizeof unsigned must match sizeof uint32_t");

#define RELAXED_READ_UINT_FIELD(p, offset) RELAXED_READ_UINT32_FIELD(p, offset)

#define RELAXED_WRITE_UINT_FIELD(p, offset, value) \
  RELAXED_WRITE_UINT32_FIELD(p, offset, value)

#define RELAXED_READ_BYTE_FIELD(p, offset) \
  static_cast<uint8_t>(base::Relaxed_Load( \
      reinterpret_cast<const base::Atomic8*>(FIELD_ADDR(p, offset))))

#define ACQUIRE_READ_BYTE_FIELD(p, offset) \
  static_cast<uint8_t>(base::Acquire_Load( \
      reinterpret_cast<const base::Atomic8*>(FIELD_ADDR(p, offset))))

#define RELAXED_WRITE_BYTE_FIELD(p, offset, value)                             \
  base::Relaxed_Store(reinterpret_cast<base::Atomic8*>(FIELD_ADDR(p, offset)), \
                      static_cast<base::Atomic8>(value));

#define RELEASE_WRITE_BYTE_FIELD(p, offset, value)                             \
  base::Release_Store(reinterpret_cast<base::Atomic8*>(FIELD_ADDR(p, offset)), \
                      static_cast<base::Atomic8>(value));

#ifdef OBJECT_PRINT
#define DECL_PRINTER(Name) void Name##Print(std::ostream& os);
#else
#define DECL_PRINTER(Name)
#endif

#ifdef VERIFY_HEAP
#define DECL_VERIFIER(Name) void Name##Verify(Isolate* isolate);
#define EXPORT_DECL_VERIFIER(Name) \
  V8_EXPORT_PRIVATE void Name##Verify(Isolate* isolate);
#define DECL_STATIC_VERIFIER(Name) \
  static void Name##Verify(Tagged<Name> obj, Isolate* isolate);
#define EXPORT_DECL_STATIC_VERIFIER(Name)                      \
  V8_EXPORT_PRIVATE static void Name##Verify(Tagged<Name> obj, \
                                             Isolate* isolate);
#else
#define DECL_VERIFIER(Name)
#define EXPORT_DECL_VERIFIER(Name)
#define DECL_STATIC_VERIFIER(Name)
#define EXPORT_DECL_STATIC_VERIFIER(Name)
#endif

#define DEFINE_DEOPT_ELEMENT_ACCESSORS(name, type)         \
  auto DeoptimizationData::name() const -> Tagged<type> {  \
    return TrustedCast<type>(get(k##name##Index));         \
  }                                                        \
  void DeoptimizationData::Set##name(Tagged<type> value) { \
    set(k##name##Index, value);                            \
  }

#define DEFINE_DEOPT_ENTRY_ACCESSORS(name, type)                  \
  Tagged<type> DeoptimizationData::name(int i) const {            \
    return Cast<type>(get(IndexForEntry(i) + k##name##Offset));   \
  }                                                               \
  void DeoptimizationData::Set##name(int i, Tagged<type> value) { \
    set(IndexForEntry(i) + k##name##Offset, value);               \
  }

#define TQ_CPP_OBJECT_DEFINITION_ASSERTS(_class, parent) \
  template class TorqueGenerated##_class##Asserts<_class, parent>;