blob: e39f2e1978ad949b6517a37c1219b4a74120dd6c [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap/thread_state_storage.h"
#include "third_party/blink/renderer/platform/heap/write_barrier.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/construct_traits.h"
#include "third_party/blink/renderer/platform/wtf/hash_functions.h"
#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
#include "third_party/blink/renderer/platform/wtf/type_traits.h"
#include "v8/include/cppgc/member.h" // IWYU pragma: export
#include "v8/include/cppgc/tagged-member.h"
namespace blink {
template <typename T>
using Member = cppgc::Member<T>;
template <typename T>
using WeakMember = cppgc::WeakMember<T>;
template <typename T>
using UntracedMember = cppgc::UntracedMember<T>;
namespace subtle {
template <typename T>
using UncompressedMember = cppgc::subtle::UncompressedMember<T>;
template <typename T, typename Tag1, typename Tag2>
using TaggedUncompressedMember =
cppgc::subtle::TaggedUncompressedMember<T, Tag1, Tag2>;
}
template <typename T>
inline bool IsHashTableDeletedValue(const Member<T>& m) {
return m == cppgc::kSentinelPointer;
}
constexpr auto kMemberDeletedValue = cppgc::kSentinelPointer;
template <typename T>
struct ThreadingTrait<blink::Member<T>> {
STATIC_ONLY(ThreadingTrait);
static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
};
template <typename T>
struct ThreadingTrait<blink::WeakMember<T>> {
STATIC_ONLY(ThreadingTrait);
static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
};
template <typename T>
struct ThreadingTrait<blink::UntracedMember<T>> {
STATIC_ONLY(ThreadingTrait);
static constexpr ThreadAffinity kAffinity = ThreadingTrait<T>::kAffinity;
};
template <typename T>
inline void swap(Member<T>& a, Member<T>& b) {
a.Swap(b);
}
static constexpr bool kBlinkMemberGCHasDebugChecks =
!std::is_same<cppgc::internal::DefaultMemberCheckingPolicy,
cppgc::internal::DisabledCheckingPolicy>::value;
// We should never bloat the Member<> wrapper.
// NOTE: The Member<void*> works as we never use this Member in a trace method.
static_assert(kBlinkMemberGCHasDebugChecks ||
sizeof(Member<void*>) <= sizeof(void*),
"Member<> should stay small!");
template <typename T>
struct IsTraceable<Member<T>> {
STATIC_ONLY(IsTraceable);
static const bool value = true;
};
template <typename T>
struct IsWeak<WeakMember<T>> : std::true_type {};
template <typename T>
struct IsTraceable<WeakMember<T>> {
STATIC_ONLY(IsTraceable);
static const bool value = true;
};
// Peeker type that allows for using all kinds of Member, Persistent, and T*
// interchangeably. This is necessary for collection methods that are called
// directly with any of those types.
template <typename T>
class ValuePeeker final {
STACK_ALLOCATED();
public:
// NOLINTNEXTLINE
ALWAYS_INLINE ValuePeeker(T* ptr) : ptr_(ptr) {}
template <typename U>
// NOLINTNEXTLINE
ALWAYS_INLINE ValuePeeker(const Member<U>& m) : ptr_(m.Get()) {}
template <typename U>
// NOLINTNEXTLINE
ALWAYS_INLINE ValuePeeker(const WeakMember<U>& m) : ptr_(m.Get()) {}
template <typename U>
// NOLINTNEXTLINE
ALWAYS_INLINE ValuePeeker(const UntracedMember<U>& m) : ptr_(m.Get()) {}
template <typename U>
// NOLINTNEXTLINE
ALWAYS_INLINE ValuePeeker(const Persistent<U>& p) : ptr_(p.Get()) {}
template <typename U>
// NOLINTNEXTLINE
ALWAYS_INLINE ValuePeeker(const WeakPersistent<U>& p) : ptr_(p.Get()) {}
// NOLINTNEXTLINE
ALWAYS_INLINE operator T*() const { return ptr_; }
// NOLINTNEXTLINE
ALWAYS_INLINE operator Member<T>() const { return ptr_; }
// NOLINTNEXTLINE
ALWAYS_INLINE operator WeakMember<T>() const { return ptr_; }
// NOLINTNEXTLINE
ALWAYS_INLINE operator UntracedMember<T>() const { return ptr_; }
private:
T* ptr_;
};
// Default hash for hash tables with Member<>-derived elements.
template <typename T, typename MemberType>
struct BaseMemberHashTraits : SimpleClassHashTraits<MemberType> {
STATIC_ONLY(BaseMemberHashTraits);
// Heap hash containers allow to operate with raw pointers, e.g.
// HeapHashSet<Member<GCed>> set;
// set.find(raw_ptr);
// Therefore, provide two hashing functions, one for raw pointers, another for
// Member. Prefer compressing raw pointers instead of decompressing Members,
// assuming the former is cheaper.
static unsigned GetHash(const T* key) {
#if defined(CPPGC_POINTER_COMPRESSION)
cppgc::internal::CompressedPointer st(key);
#else
cppgc::internal::RawPointer st(key);
#endif
return blink::GetHash(st.GetAsInteger());
}
template <typename Member>
requires(IsAnyMemberType<Member>::value)
static unsigned GetHash(const Member& m) {
return blink::GetHash(m.GetRawStorage().GetAsInteger());
}
static constexpr bool kEmptyValueIsZero = true;
using PeekInType = ValuePeeker<T>;
using PeekOutType = T*;
using IteratorGetType = MemberType*;
using IteratorConstGetType = const MemberType*;
using IteratorReferenceType = MemberType&;
using IteratorConstReferenceType = const MemberType&;
static PeekOutType Peek(const MemberType& value) { return value.Get(); }
static void ConstructDeletedValue(MemberType& slot) {
slot = cppgc::kSentinelPointer;
}
static bool IsDeletedValue(const MemberType& value) {
return value == cppgc::kSentinelPointer;
}
};
// Custom HashTraits<Member<Type>> can inherit this type.
template <typename T>
struct MemberHashTraits : BaseMemberHashTraits<T, blink::Member<T>> {
static constexpr bool kCanTraceConcurrently = true;
static constexpr bool kSupportsCompaction = true;
};
template <typename T>
struct HashTraits<blink::Member<T>> : MemberHashTraits<T> {};
// Custom HashTraits<WeakMember<Type>> can inherit this type.
template <typename T>
struct WeakMemberHashTraits : BaseMemberHashTraits<T, blink::WeakMember<T>> {
static constexpr bool kCanTraceConcurrently = true;
static constexpr bool kSupportsCompaction = true;
};
template <typename T>
struct HashTraits<blink::WeakMember<T>> : WeakMemberHashTraits<T> {};
// Custom HashTraits<UntracedMember<Type>> can inherit this type.
template <typename T>
struct UntracedMemberHashTraits
: BaseMemberHashTraits<T, blink::UntracedMember<T>> {};
template <typename T>
struct HashTraits<blink::UntracedMember<T>> : UntracedMemberHashTraits<T> {};
template <typename T>
class MemberConstructTraits {
STATIC_ONLY(MemberConstructTraits);
public:
template <typename... Args>
static T* Construct(void* location, Args&&... args) {
// `Construct()` creates a new Member which must not be visible to the
// concurrent marker yet, similar to regular ctors in Member.
return new (base::NotNullTag::kNotNull, location)
T(std::forward<Args>(args)...);
}
template <typename... Args>
static T* ConstructAndNotifyElement(void* location, Args&&... args) {
// `ConstructAndNotifyElement()` updates an existing Member which might
// also be concurrently traced while we update it. The regular ctors
// for Member don't use an atomic write which can lead to data races.
T* object = new (base::NotNullTag::kNotNull, location)
T(std::forward<Args>(args)..., typename T::AtomicInitializerTag());
NotifyNewElement(object);
return object;
}
static void NotifyNewElement(T* element) {
WriteBarrier::DispatchForObject(element);
}
static void NotifyNewElements(base::span<T> members) {
// Checking the first element is sufficient for determining whether a
// marking or generational barrier is required.
if (members.empty() ||
!WriteBarrier::IsWriteBarrierNeeded(&members.front())) [[likely]] {
return;
}
for (auto& member : members) {
WriteBarrier::DispatchForObject(&member);
}
}
};
template <typename T, typename Traits, typename Allocator>
class ConstructTraits<Member<T>, Traits, Allocator> final
: public MemberConstructTraits<Member<T>> {};
template <typename T, typename Traits, typename Allocator>
class ConstructTraits<WeakMember<T>, Traits, Allocator> final
: public MemberConstructTraits<WeakMember<T>> {};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_