| // 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>; |