#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_
#include <tuple>
#include "base/notreached.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/hash_table.h"
#include "third_party/blink/renderer/platform/wtf/key_value_pair.h"
#include "third_party/blink/renderer/platform/wtf/type_traits.h"
#include "v8/include/cppgc/trace-trait.h"
namespace blink {
template <typename T>
struct TraceIfNeeded {
STATIC_ONLY(TraceIfNeeded);
static void Trace(Visitor* visitor, const T& t) {
if constexpr (IsTraceableV<T>) {
visitor->Trace(t);
}
}
};
template <WeakHandlingFlag weakness,
typename T,
typename Traits,
bool = IsTraceableV<typename Traits::TraitType> &&
!IsWeakV<typename Traits::TraitType>,
WeakHandlingFlag = kWeakHandlingTrait<T>>
struct TraceCollectionIfEnabled;
template <WeakHandlingFlag weakness, typename T, typename Traits>
struct TraceCollectionIfEnabled<weakness, T, Traits, false, kNoWeakHandling> {
STATIC_ONLY(TraceCollectionIfEnabled);
static bool IsAlive(const blink::LivenessBroker& info, const T&) {
return true;
}
static void Trace(Visitor*, const void*) {
static_assert(!IsTraceableV<typename Traits::TraitType> ||
IsWeakV<typename Traits::TraitType>,
"T should not be traced");
}
};
template <typename T, typename Traits>
struct TraceCollectionIfEnabled<kNoWeakHandling,
T,
Traits,
false,
kWeakHandling> {
STATIC_ONLY(TraceCollectionIfEnabled);
static void Trace(Visitor* visitor, const void* t) {
TraceInCollectionTrait<kNoWeakHandling, T, Traits>::Trace(
visitor, *reinterpret_cast<const T*>(t));
}
};
template <WeakHandlingFlag weakness,
typename T,
typename Traits,
bool,
WeakHandlingFlag>
struct TraceCollectionIfEnabled {
STATIC_ONLY(TraceCollectionIfEnabled);
static bool IsAlive(const blink::LivenessBroker& info, const T& traceable) {
return TraceInCollectionTrait<weakness, T, Traits>::IsAlive(info,
traceable);
}
static void Trace(Visitor* visitor, const void* t) {
static_assert((IsTraceableV<typename Traits::TraitType> &&
!IsWeakV<typename Traits::TraitType>) ||
weakness == kWeakHandling,
"Traits should be traced");
TraceInCollectionTrait<weakness, T, Traits>::Trace(
visitor, *reinterpret_cast<const T*>(t));
}
};
namespace internal {
template <typename _KeyType,
typename _ValueType,
typename _KeyTraits,
typename _ValueTraits,
bool = IsWeakV<_ValueType>>
struct EphemeronKeyValuePair {
STACK_ALLOCATED();
public:
using KeyType = _KeyType;
using ValueType = _ValueType;
using KeyTraits = _KeyTraits;
using ValueTraits = _ValueTraits;
static constexpr bool kNeedsEphemeronSemantics =
IsWeakV<KeyType> != IsWeakV<ValueType> && IsTraceableV<ValueType>;
static_assert(!IsWeakV<KeyType> || IsWeakMemberType<KeyType>::value,
"Weakness must be encoded using WeakMember.");
static_assert(!IsWeakV<ValueType> || IsWeakMemberType<ValueType>::value,
"Weakness must be encoded using WeakMember.");
EphemeronKeyValuePair(const KeyType& k, const ValueType& v)
: key(k), value(v) {}
const KeyType& key;
const ValueType& value;
};
template <typename _KeyType,
typename _ValueType,
typename _KeyTraits,
typename _ValueTraits>
struct EphemeronKeyValuePair<_KeyType,
_ValueType,
_KeyTraits,
_ValueTraits,
true> : EphemeronKeyValuePair<_ValueType,
_KeyType,
_ValueTraits,
_KeyTraits,
false> {
EphemeronKeyValuePair(const _KeyType& k, const _ValueType& v)
: EphemeronKeyValuePair<_ValueType,
_KeyType,
_ValueTraits,
_KeyTraits,
false>(v, k) {}
};
template <WeakHandlingFlag WeakHandling,
typename Key,
typename Value,
typename Traits>
struct KeyValuePairInCollectionTrait {
static bool IsAlive(const blink::LivenessBroker& info,
const blink::KeyValuePair<Key, Value>& kvp) {
return blink::TraceCollectionIfEnabled<
kWeakHandlingTrait<Key>, Key,
typename Traits::KeyTraits>::IsAlive(info, kvp.key) &&
blink::TraceCollectionIfEnabled<
kWeakHandlingTrait<Value>, Value,
typename Traits::ValueTraits>::IsAlive(info, kvp.value);
}
static void Trace(blink::Visitor* visitor,
const Key* key,
const Value* value) {
TraceImpl::Trace(visitor, key, value);
}
static void Trace(blink::Visitor* visitor,
const blink::KeyValuePair<Key, Value>& kvp) {
TraceImpl::Trace(visitor, &kvp.key, &kvp.value);
}
private:
using EphemeronHelper = EphemeronKeyValuePair<Key,
Value,
typename Traits::KeyTraits,
typename Traits::ValueTraits>;
struct WeakTrait {
static void Trace(blink::Visitor* visitor,
const Key* key,
const Value* value) {
EphemeronHelper helper(*key, *value);
if (WeakHandling == kNoWeakHandling) {
blink::TraceCollectionIfEnabled<
kNoWeakHandling, typename EphemeronHelper::KeyType,
typename EphemeronHelper::KeyTraits>::Trace(visitor, &helper.key);
}
visitor->TraceEphemeron(helper.key, &helper.value);
}
};
struct StrongTrait {
static void Trace(blink::Visitor* visitor,
const Key* key,
const Value* value) {
blink::TraceCollectionIfEnabled<
kNoWeakHandling, Key, typename Traits::KeyTraits>::Trace(visitor,
key);
blink::TraceCollectionIfEnabled<
kNoWeakHandling, Value, typename Traits::ValueTraits>::Trace(visitor,
value);
}
};
using TraceImpl =
typename std::conditional<EphemeronHelper::kNeedsEphemeronSemantics,
WeakTrait,
StrongTrait>::type;
};
}
template <typename Key, typename Value, typename Traits>
struct TraceInCollectionTrait<kNoWeakHandling, KeyValuePair<Key, Value>, Traits>
: public internal::
KeyValuePairInCollectionTrait<kNoWeakHandling, Key, Value, Traits> {};
template <typename Key, typename Value, typename Traits>
struct TraceInCollectionTrait<kWeakHandling, KeyValuePair<Key, Value>, Traits>
: public internal::
KeyValuePairInCollectionTrait<kWeakHandling, Key, Value, Traits> {};
template <typename T, typename Traits>
struct TraceInCollectionTrait<kNoWeakHandling, T, Traits> {
static bool IsAlive(const LivenessBroker& info, const T& t) { return true; }
static void Trace(blink::Visitor* visitor, const T& t) {
static_assert(IsTraceableV<typename Traits::TraitType> &&
!IsWeakV<typename Traits::TraitType>,
"T should be traceable");
visitor->Trace(t);
}
};
template <typename T, typename Traits>
struct TraceInCollectionTrait<kNoWeakHandling, WeakMember<T>, Traits> {
static void Trace(Visitor* visitor, const WeakMember<T>& t) {
visitor->TraceStrongly(t);
}
};
template <typename T, typename Traits>
struct TraceInCollectionTrait<kWeakHandling, T, Traits> {};
template <typename T, typename Traits>
struct TraceInCollectionTrait<kWeakHandling, WeakMember<T>, Traits> {
static bool IsAlive(const LivenessBroker& info, const WeakMember<T>& value) {
return info.IsHeapObjectAlive(value);
}
};
}
namespace cppgc {
template <typename T, typename U>
struct TraceTrait<std::pair<T, U>> {
STATIC_ONLY(TraceTrait);
public:
static TraceDescriptor GetTraceDescriptor(const void* self) {
NOTREACHED();
}
static void Trace(Visitor* visitor, const std::pair<T, U>* pair) {
blink::TraceIfNeeded<U>::Trace(visitor, pair->second);
blink::TraceIfNeeded<T>::Trace(visitor, pair->first);
}
};
}
#endif