cppgc: Avoid compression/decompression in Member operators/ctors
1) In copy/move ctors and operator=() we can just copy raw compressed value; 2) For null check we don't need to decompress the value; 3) Same for operator==(). 4) Hashing can also be optimized in a followup. Bug: chromium:1325007 Change-Id: Ic1bf2c5049802c078b3e0121dcbe62d9ecea83b3 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3647359 Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Commit-Queue: Anton Bikineev <bikineev@chromium.org> Cr-Commit-Position: refs/heads/main@{#80571}
This commit is contained in:
parent
93446e3c12
commit
5c416ad2c3
@ -62,6 +62,9 @@ class CompressedPointer final {
|
||||
V8_INLINE CompressedPointer() : value_(0u) {}
|
||||
V8_INLINE explicit CompressedPointer(const void* ptr)
|
||||
: value_(Compress(ptr)) {}
|
||||
V8_INLINE explicit CompressedPointer(std::nullptr_t) : value_(0u) {}
|
||||
V8_INLINE explicit CompressedPointer(SentinelPointer)
|
||||
: value_(kCompressedSentinel) {}
|
||||
|
||||
V8_INLINE const void* Load() const { return Decompress(value_); }
|
||||
V8_INLINE const void* LoadAtomic() const {
|
||||
@ -69,14 +72,19 @@ class CompressedPointer final {
|
||||
reinterpret_cast<const std::atomic<Storage>&>(value_).load(
|
||||
std::memory_order_relaxed));
|
||||
}
|
||||
V8_INLINE Storage LoadRaw() const { return value_; }
|
||||
|
||||
V8_INLINE void Store(const void* ptr) { value_ = Compress(ptr); }
|
||||
V8_INLINE void StoreAtomic(const void* value) {
|
||||
reinterpret_cast<std::atomic<Storage>&>(value_).store(
|
||||
Compress(value), std::memory_order_relaxed);
|
||||
}
|
||||
V8_INLINE void StoreRaw(Storage value) { value_ = value; }
|
||||
|
||||
V8_INLINE void Clear() { value_ = 0u; }
|
||||
V8_INLINE bool IsCleared() const { return !value_; }
|
||||
|
||||
V8_INLINE friend bool operator==(CompressedPointer a, CompressedPointer b) {
|
||||
return a.value_ == b.value_;
|
||||
}
|
||||
|
||||
static V8_INLINE Storage Compress(const void* ptr) {
|
||||
static_assert(
|
||||
@ -112,6 +120,8 @@ class CompressedPointer final {
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr Storage kCompressedSentinel =
|
||||
SentinelPointer::kSentinelValue >> 1;
|
||||
// All constructors initialize `value_`. Do not add a default value here as it
|
||||
// results in a non-atomic write on some builds, even when the atomic version
|
||||
// of the constructor is used.
|
||||
@ -124,45 +134,55 @@ class RawPointer final {
|
||||
public:
|
||||
using Storage = uintptr_t;
|
||||
|
||||
RawPointer() : value_(0u) {}
|
||||
explicit RawPointer(const void* ptr)
|
||||
: value_(reinterpret_cast<uintptr_t>(ptr)) {}
|
||||
RawPointer() : ptr_(nullptr) {}
|
||||
explicit RawPointer(const void* ptr) : ptr_(ptr) {}
|
||||
|
||||
V8_INLINE const void* Load() const {
|
||||
return reinterpret_cast<const void*>(value_);
|
||||
}
|
||||
V8_INLINE const void* Load() const { return ptr_; }
|
||||
V8_INLINE const void* LoadAtomic() const {
|
||||
return reinterpret_cast<const std::atomic<const void*>&>(value_).load(
|
||||
return reinterpret_cast<const std::atomic<const void*>&>(ptr_).load(
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
V8_INLINE Storage LoadRaw() const { return value_; }
|
||||
|
||||
V8_INLINE void Store(const void* ptr) {
|
||||
value_ = reinterpret_cast<uintptr_t>(ptr);
|
||||
}
|
||||
V8_INLINE void Store(const void* ptr) { ptr_ = ptr; }
|
||||
V8_INLINE void StoreAtomic(const void* ptr) {
|
||||
reinterpret_cast<std::atomic<uintptr_t>&>(value_).store(
|
||||
reinterpret_cast<uintptr_t>(ptr), std::memory_order_relaxed);
|
||||
reinterpret_cast<std::atomic<const void*>&>(ptr_).store(
|
||||
ptr, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
V8_INLINE void Clear() { ptr_ = nullptr; }
|
||||
V8_INLINE bool IsCleared() const { return !ptr_; }
|
||||
|
||||
V8_INLINE friend bool operator==(RawPointer a, RawPointer b) {
|
||||
return a.ptr_ == b.ptr_;
|
||||
}
|
||||
V8_INLINE void StoreRaw(Storage value) { value_ = value; }
|
||||
|
||||
private:
|
||||
// All constructors initialize `ptr_`. Do not add a default value here as it
|
||||
// results in a non-atomic write on some builds, even when the atomic version
|
||||
// of the constructor is used.
|
||||
uintptr_t value_;
|
||||
const void* ptr_;
|
||||
};
|
||||
|
||||
// MemberBase always refers to the object as const object and defers to
|
||||
// BasicMember on casting to the right type as needed.
|
||||
class MemberBase {
|
||||
protected:
|
||||
#if defined(CPPGC_POINTER_COMPRESSION)
|
||||
using RawStorage = CompressedPointer;
|
||||
#else // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
using RawStorage = RawPointer;
|
||||
#endif // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
|
||||
struct AtomicInitializerTag {};
|
||||
|
||||
MemberBase() = default;
|
||||
explicit MemberBase(const void* value) : raw_(value) {}
|
||||
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) {}
|
||||
|
||||
const void** GetRawSlot() const {
|
||||
return reinterpret_cast<const void**>(const_cast<MemberBase*>(this));
|
||||
}
|
||||
@ -172,16 +192,18 @@ class MemberBase {
|
||||
const void* GetRawAtomic() const { return raw_.LoadAtomic(); }
|
||||
void SetRawAtomic(const void* value) { raw_.StoreAtomic(value); }
|
||||
|
||||
void ClearFromGC() const { raw_.StoreRaw(0u); }
|
||||
RawStorage GetRawStorage() const { return raw_; }
|
||||
void SetRawStorageAtomic(RawStorage other) {
|
||||
reinterpret_cast<std::atomic<RawStorage>&>(raw_).store(
|
||||
other, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool IsCleared() const { return raw_.IsCleared(); }
|
||||
|
||||
void ClearFromGC() const { raw_.Clear(); }
|
||||
|
||||
private:
|
||||
#if defined(CPPGC_POINTER_COMPRESSION)
|
||||
using Storage = CompressedPointer;
|
||||
#else // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
using Storage = RawPointer;
|
||||
#endif // !defined(CPPGC_POINTER_COMPRESSION)
|
||||
|
||||
mutable Storage raw_;
|
||||
mutable RawStorage raw_;
|
||||
};
|
||||
|
||||
// The basic class from which all Member classes are 'generated'.
|
||||
@ -214,7 +236,7 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
|
||||
BasicMember(T& raw, AtomicInitializerTag atomic)
|
||||
: BasicMember(&raw, atomic) {}
|
||||
// Copy ctor.
|
||||
BasicMember(const BasicMember& other) : BasicMember(other.Get()) {}
|
||||
BasicMember(const BasicMember& other) : BasicMember(other.GetRawStorage()) {}
|
||||
// Allow heterogeneous construction.
|
||||
template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
|
||||
typename OtherCheckingPolicy,
|
||||
@ -222,9 +244,10 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
|
||||
BasicMember( // NOLINT
|
||||
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy>& other)
|
||||
: BasicMember(other.Get()) {}
|
||||
: BasicMember(other.GetRawStorage()) {}
|
||||
// Move ctor.
|
||||
BasicMember(BasicMember&& other) noexcept : BasicMember(other.Get()) {
|
||||
BasicMember(BasicMember&& other) noexcept
|
||||
: BasicMember(other.GetRawStorage()) {
|
||||
other.Clear();
|
||||
}
|
||||
// Allow heterogeneous move construction.
|
||||
@ -233,7 +256,7 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicMember(BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy>&& other) noexcept
|
||||
: BasicMember(other.Get()) {
|
||||
: BasicMember(other.GetRawStorage()) {
|
||||
other.Clear();
|
||||
}
|
||||
// Construction from Persistent.
|
||||
@ -248,7 +271,7 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
|
||||
|
||||
// Copy assignment.
|
||||
BasicMember& operator=(const BasicMember& other) {
|
||||
return operator=(other.Get());
|
||||
return operator=(other.GetRawStorage());
|
||||
}
|
||||
// Allow heterogeneous copy assignment.
|
||||
template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
|
||||
@ -257,11 +280,11 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
|
||||
BasicMember& operator=(
|
||||
const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy>& other) {
|
||||
return operator=(other.Get());
|
||||
return operator=(other.GetRawStorage());
|
||||
}
|
||||
// Move assignment.
|
||||
BasicMember& operator=(BasicMember&& other) noexcept {
|
||||
operator=(other.Get());
|
||||
operator=(other.GetRawStorage());
|
||||
other.Clear();
|
||||
return *this;
|
||||
}
|
||||
@ -271,7 +294,7 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
|
||||
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
BasicMember& operator=(BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy>&& other) noexcept {
|
||||
operator=(other.Get());
|
||||
operator=(other.GetRawStorage());
|
||||
other.Clear();
|
||||
return *this;
|
||||
}
|
||||
@ -305,12 +328,12 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
|
||||
typename OtherCheckingPolicy>
|
||||
void Swap(BasicMember<T, OtherWeaknessTag, OtherBarrierPolicy,
|
||||
OtherCheckingPolicy>& other) {
|
||||
T* tmp = Get();
|
||||
auto tmp = GetRawStorage();
|
||||
*this = other;
|
||||
other = tmp;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return Get(); }
|
||||
explicit operator bool() const { return !IsCleared(); }
|
||||
operator T*() const { return Get(); }
|
||||
T* operator->() const { return Get(); }
|
||||
T& operator*() const { return *Get(); }
|
||||
@ -327,7 +350,7 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
|
||||
return static_cast<T*>(const_cast<void*>(MemberBase::GetRaw()));
|
||||
}
|
||||
|
||||
void Clear() { SetRawAtomic(nullptr); }
|
||||
void Clear() { SetRawStorageAtomic(RawStorage{}); }
|
||||
|
||||
T* Release() {
|
||||
T* result = Get();
|
||||
@ -340,6 +363,18 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
|
||||
}
|
||||
|
||||
private:
|
||||
explicit BasicMember(RawStorage raw) : MemberBase(raw) {
|
||||
InitializingWriteBarrier();
|
||||
this->CheckPointer(Get());
|
||||
}
|
||||
|
||||
BasicMember& operator=(RawStorage other) {
|
||||
SetRawStorageAtomic(other);
|
||||
AssigningWriteBarrier();
|
||||
this->CheckPointer(Get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T* GetRawAtomic() const {
|
||||
return static_cast<const T*>(MemberBase::GetRawAtomic());
|
||||
}
|
||||
@ -358,6 +393,17 @@ class BasicMember final : private MemberBase, private CheckingPolicy {
|
||||
friend class cppgc::Visitor;
|
||||
template <typename U>
|
||||
friend struct cppgc::TraceTrait;
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
typename CheckingPolicy1>
|
||||
friend class BasicMember;
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
typename CheckingPolicy1, typename T2, typename WeaknessTag2,
|
||||
typename WriteBarrierPolicy2, typename CheckingPolicy2>
|
||||
friend bool operator==(
|
||||
const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1>&
|
||||
member1,
|
||||
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2>&
|
||||
member2);
|
||||
};
|
||||
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
@ -367,7 +413,7 @@ bool operator==(const BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1,
|
||||
CheckingPolicy1>& member1,
|
||||
const BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2,
|
||||
CheckingPolicy2>& member2) {
|
||||
return member1.Get() == member2.Get();
|
||||
return member1.GetRawStorage() == member2.GetRawStorage();
|
||||
}
|
||||
|
||||
template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
|
||||
|
Loading…
Reference in New Issue
Block a user