cppgc: Force inline Member

With pointer compression enabled the compiler may not inline some Member
functions on some platforms, because Member stores and loads become
slightly more expensive. Inlining is however important with pointer
compression - it allows to further optimize the code by eliminating
the global load.

Bug: chromium:1325007
Change-Id: Ia37d223e78853a8218e0b2732a3f08aa58929000
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3756141
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Anton Bikineev <bikineev@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81648}
This commit is contained in:
Anton Bikineev 2022-07-11 19:43:39 +02:00 committed by V8 LUCI CQ
parent 126d477925
commit 4b25eaef5f
2 changed files with 89 additions and 73 deletions

View File

@ -27,11 +27,11 @@ class WeakMemberTag;
class UntracedMemberTag;
struct DijkstraWriteBarrierPolicy {
static void InitializingBarrier(const void*, const void*) {
V8_INLINE static void InitializingBarrier(const void*, const void*) {
// Since in initializing writes the source object is always white, having no
// barrier doesn't break the tri-color invariant.
}
static void AssigningBarrier(const void* slot, const void* value) {
V8_INLINE static void AssigningBarrier(const void* slot, const void* value) {
WriteBarrier::Params params;
switch (WriteBarrier::GetWriteBarrierType(slot, value, params)) {
case WriteBarrier::Type::kGenerational:
@ -48,8 +48,8 @@ struct DijkstraWriteBarrierPolicy {
};
struct NoWriteBarrierPolicy {
static void InitializingBarrier(const void*, const void*) {}
static void AssigningBarrier(const void*, const void*) {}
V8_INLINE static void InitializingBarrier(const void*, const void*) {}
V8_INLINE static void AssigningBarrier(const void*, const void*) {}
};
class V8_EXPORT SameThreadEnabledCheckingPolicyBase {
@ -90,7 +90,7 @@ class V8_EXPORT SameThreadEnabledCheckingPolicy
class DisabledCheckingPolicy {
protected:
void CheckPointer(const void*) {}
V8_INLINE void CheckPointer(const void*) {}
};
#ifdef DEBUG

View File

@ -143,8 +143,8 @@ class RawPointer final {
public:
using Storage = uintptr_t;
RawPointer() : ptr_(nullptr) {}
explicit RawPointer(const void* ptr) : ptr_(ptr) {}
V8_INLINE RawPointer() : ptr_(nullptr) {}
V8_INLINE explicit RawPointer(const void* ptr) : ptr_(ptr) {}
V8_INLINE const void* Load() const { return ptr_; }
V8_INLINE const void* LoadAtomic() const {
@ -184,32 +184,34 @@ class MemberBase {
struct AtomicInitializerTag {};
MemberBase() = default;
explicit MemberBase(const void* value) : raw_(value) {}
MemberBase(const void* value, AtomicInitializerTag) { SetRawAtomic(value); }
V8_INLINE MemberBase() = default;
V8_INLINE explicit MemberBase(const void* value) : raw_(value) {}
V8_INLINE MemberBase(const void* value, AtomicInitializerTag) {
SetRawAtomic(value);
}
explicit MemberBase(RawStorage raw) : raw_(raw) {}
explicit MemberBase(std::nullptr_t) : raw_(nullptr) {}
explicit MemberBase(SentinelPointer s) : raw_(s) {}
V8_INLINE explicit MemberBase(RawStorage raw) : raw_(raw) {}
V8_INLINE explicit MemberBase(std::nullptr_t) : raw_(nullptr) {}
V8_INLINE explicit MemberBase(SentinelPointer s) : raw_(s) {}
const void** GetRawSlot() const {
V8_INLINE const void** GetRawSlot() const {
return reinterpret_cast<const void**>(const_cast<MemberBase*>(this));
}
const void* GetRaw() const { return raw_.Load(); }
void SetRaw(void* value) { raw_.Store(value); }
V8_INLINE const void* GetRaw() const { return raw_.Load(); }
V8_INLINE void SetRaw(void* value) { raw_.Store(value); }
const void* GetRawAtomic() const { return raw_.LoadAtomic(); }
void SetRawAtomic(const void* value) { raw_.StoreAtomic(value); }
V8_INLINE const void* GetRawAtomic() const { return raw_.LoadAtomic(); }
V8_INLINE void SetRawAtomic(const void* value) { raw_.StoreAtomic(value); }
RawStorage GetRawStorage() const { return raw_; }
void SetRawStorageAtomic(RawStorage other) {
V8_INLINE RawStorage GetRawStorage() const { return raw_; }
V8_INLINE void SetRawStorageAtomic(RawStorage other) {
reinterpret_cast<std::atomic<RawStorage>&>(raw_).store(
other, std::memory_order_relaxed);
}
bool IsCleared() const { return raw_.IsCleared(); }
V8_INLINE bool IsCleared() const { return raw_.IsCleared(); }
void ClearFromGC() const { raw_.Clear(); }
V8_INLINE void ClearFromGC() const { raw_.Clear(); }
private:
mutable RawStorage raw_;
@ -222,40 +224,46 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
public:
using PointeeType = T;
constexpr BasicMember() = default;
constexpr BasicMember(std::nullptr_t) {} // NOLINT
BasicMember(SentinelPointer s) : MemberBase(s) {} // NOLINT
BasicMember(T* raw) : MemberBase(raw) { // NOLINT
V8_INLINE constexpr BasicMember() = default;
V8_INLINE constexpr BasicMember(std::nullptr_t) {} // NOLINT
V8_INLINE BasicMember(SentinelPointer s) : MemberBase(s) {} // NOLINT
V8_INLINE BasicMember(T* raw) : MemberBase(raw) { // NOLINT
InitializingWriteBarrier();
this->CheckPointer(Get());
}
BasicMember(T& raw) : BasicMember(&raw) {} // NOLINT
V8_INLINE BasicMember(T& raw) // NOLINT
: BasicMember(&raw) {}
// Atomic ctor. Using the AtomicInitializerTag forces BasicMember to
// initialize using atomic assignments. This is required for preventing
// data races with concurrent marking.
using AtomicInitializerTag = MemberBase::AtomicInitializerTag;
BasicMember(std::nullptr_t, AtomicInitializerTag atomic)
V8_INLINE BasicMember(std::nullptr_t, AtomicInitializerTag atomic)
: MemberBase(nullptr, atomic) {}
BasicMember(SentinelPointer s, AtomicInitializerTag atomic)
V8_INLINE BasicMember(SentinelPointer s, AtomicInitializerTag atomic)
: MemberBase(s, atomic) {}
BasicMember(T* raw, AtomicInitializerTag atomic) : MemberBase(raw, atomic) {
V8_INLINE BasicMember(T* raw, AtomicInitializerTag atomic)
: MemberBase(raw, atomic) {
InitializingWriteBarrier();
this->CheckPointer(Get());
}
BasicMember(T& raw, AtomicInitializerTag atomic)
V8_INLINE BasicMember(T& raw, AtomicInitializerTag atomic)
: BasicMember(&raw, atomic) {}
// Copy ctor.
BasicMember(const BasicMember& other) : BasicMember(other.GetRawStorage()) {}
V8_INLINE BasicMember(const BasicMember& other)
: BasicMember(other.GetRawStorage()) {}
// Allow heterogeneous construction.
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember( // NOLINT
V8_INLINE BasicMember( // NOLINT
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>& other)
: BasicMember(other.GetRawStorage()) {}
// Move ctor.
BasicMember(BasicMember&& other) noexcept
V8_INLINE BasicMember(BasicMember&& other) noexcept
: BasicMember(other.GetRawStorage()) {
other.Clear();
}
@ -263,36 +271,38 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember(BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>&& other) noexcept
V8_INLINE BasicMember(BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>&& other) noexcept
: BasicMember(other.GetRawStorage()) {
other.Clear();
}
// Construction from Persistent.
template <typename U, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy,
typename PersistentCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember(const BasicPersistent<U, PersistentWeaknessPolicy,
PersistentLocationPolicy,
PersistentCheckingPolicy>& p)
V8_INLINE BasicMember(const BasicPersistent<U, PersistentWeaknessPolicy,
PersistentLocationPolicy,
PersistentCheckingPolicy>& p)
: BasicMember(p.Get()) {}
// Copy assignment.
BasicMember& operator=(const BasicMember& other) {
V8_INLINE BasicMember& operator=(const BasicMember& other) {
return operator=(other.GetRawStorage());
}
// Allow heterogeneous copy assignment.
template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember& operator=(
V8_INLINE BasicMember& operator=(
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>& other) {
return operator=(other.GetRawStorage());
}
// Move assignment.
BasicMember& operator=(BasicMember&& other) noexcept {
V8_INLINE BasicMember& operator=(BasicMember&& other) noexcept {
operator=(other.GetRawStorage());
other.Clear();
return *this;
@ -301,56 +311,60 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
typename OtherCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember& operator=(BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>&& other) noexcept {
V8_INLINE BasicMember& operator=(
BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>&& other) noexcept {
operator=(other.GetRawStorage());
other.Clear();
return *this;
}
// Assignment from Persistent.
template <typename U, typename PersistentWeaknessPolicy,
typename PersistentLocationPolicy,
typename PersistentCheckingPolicy,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember& operator=(
V8_INLINE BasicMember& operator=(
const BasicPersistent<U, PersistentWeaknessPolicy,
PersistentLocationPolicy, PersistentCheckingPolicy>&
other) {
return operator=(other.Get());
}
BasicMember& operator=(T* other) {
V8_INLINE BasicMember& operator=(T* other) {
SetRawAtomic(other);
AssigningWriteBarrier();
this->CheckPointer(Get());
return *this;
}
BasicMember& operator=(std::nullptr_t) {
V8_INLINE BasicMember& operator=(std::nullptr_t) {
Clear();
return *this;
}
BasicMember& operator=(SentinelPointer s) {
V8_INLINE BasicMember& operator=(SentinelPointer s) {
SetRawAtomic(s);
return *this;
}
template <typename OtherWeaknessTag, typename OtherBarrierPolicy,
typename OtherCheckingPolicy>
void Swap(BasicMember<T, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>& other) {
V8_INLINE void Swap(BasicMember<T, OtherWeaknessTag, OtherBarrierPolicy,
OtherCheckingPolicy>& other) {
auto tmp = GetRawStorage();
*this = other;
other = tmp;
}
explicit operator bool() const { return !IsCleared(); }
operator T*() const { return Get(); }
T* operator->() const { return Get(); }
T& operator*() const { return *Get(); }
V8_INLINE explicit operator bool() const { return !IsCleared(); }
V8_INLINE operator T*() const { return Get(); }
V8_INLINE T* operator->() const { return Get(); }
V8_INLINE T& operator*() const { return *Get(); }
// CFI cast exemption to allow passing SentinelPointer through T* and support
// heterogeneous assignments between different Member and Persistent handles
// based on their actual types.
V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
V8_INLINE V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
// Executed by the mutator, hence non atomic load.
//
// The const_cast below removes the constness from MemberBase storage. The
@ -359,45 +373,45 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
return static_cast<T*>(const_cast<void*>(MemberBase::GetRaw()));
}
void Clear() { SetRawStorageAtomic(RawStorage{}); }
V8_INLINE void Clear() { SetRawStorageAtomic(RawStorage{}); }
T* Release() {
V8_INLINE T* Release() {
T* result = Get();
Clear();
return result;
}
const T** GetSlotForTesting() const {
V8_INLINE const T** GetSlotForTesting() const {
return reinterpret_cast<const T**>(GetRawSlot());
}
private:
explicit BasicMember(RawStorage raw) : MemberBase(raw) {
V8_INLINE explicit BasicMember(RawStorage raw) : MemberBase(raw) {
InitializingWriteBarrier();
this->CheckPointer(Get());
}
BasicMember& operator=(RawStorage other) {
V8_INLINE BasicMember& operator=(RawStorage other) {
SetRawStorageAtomic(other);
AssigningWriteBarrier();
this->CheckPointer(Get());
return *this;
}
const T* GetRawAtomic() const {
V8_INLINE const T* GetRawAtomic() const {
return static_cast<const T*>(MemberBase::GetRawAtomic());
}
void InitializingWriteBarrier() const {
V8_INLINE void InitializingWriteBarrier() const {
WriteBarrierPolicy::InitializingBarrier(GetRawSlot(), GetRaw());
}
void AssigningWriteBarrier() const {
V8_INLINE void AssigningWriteBarrier() const {
WriteBarrierPolicy::AssigningBarrier(GetRawSlot(), GetRaw());
}
void ClearFromGC() const { MemberBase::ClearFromGC(); }
V8_INLINE void ClearFromGC() const { MemberBase::ClearFromGC(); }
T* GetFromGC() const { return Get(); }
V8_INLINE T* GetFromGC() const { return Get(); }
friend class cppgc::Visitor;
template <typename U>
@ -418,20 +432,22 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
typename WriteBarrierPolicy2, typename CheckingPolicy2>
bool operator==(const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1,
CheckingPolicy1>& member1,
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2,
CheckingPolicy2>& member2) {
V8_INLINE bool operator==(
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1>&
member1,
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2>&
member2) {
return member1.GetRawStorage() == member2.GetRawStorage();
}
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
typename WriteBarrierPolicy2, typename CheckingPolicy2>
bool operator!=(const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1,
CheckingPolicy1>& member1,
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2,
CheckingPolicy2>& member2) {
V8_INLINE bool operator!=(
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1>&
member1,
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2>&
member2) {
return !(member1 == member2);
}