blob: 1f7f9588f401cbfaa718a9f01f71ec2b3bd27583 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// 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_GC_INFO_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_INFO_H_
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/atomics.h"
#include "third_party/blink/renderer/platform/wtf/deque.h"
#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/hash_table.h"
#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
#include "third_party/blink/renderer/platform/wtf/list_hash_set.h"
#include "third_party/blink/renderer/platform/wtf/type_traits.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
// The FinalizerTraitImpl specifies how to finalize objects. Objects that
// inherit from GarbageCollectedFinalized are finalized by calling their
// |Finalize| method which by default will call the destructor on the object.
template <typename T, bool isGarbageCollectedFinalized>
struct FinalizerTraitImpl;
template <typename T>
struct FinalizerTraitImpl<T, true> {
STATIC_ONLY(FinalizerTraitImpl);
static void Finalize(void* obj) {
static_assert(sizeof(T), "T must be fully defined");
static_cast<T*>(obj)->FinalizeGarbageCollectedObject();
};
};
template <typename T>
struct FinalizerTraitImpl<T, false> {
STATIC_ONLY(FinalizerTraitImpl);
static void Finalize(void* obj) {
static_assert(sizeof(T), "T must be fully defined");
};
};
// The FinalizerTrait is used to determine if a type requires finalization and
// what finalization means.
//
// By default classes that inherit from GarbageCollectedFinalized need
// finalization and finalization means calling the |Finalize| method of the
// object. The FinalizerTrait can be specialized if the default behavior is not
// desired.
template <typename T>
struct FinalizerTrait {
STATIC_ONLY(FinalizerTrait);
static const bool kNonTrivialFinalizer =
WTF::IsSubclassOfTemplate<typename std::remove_const<T>::type,
GarbageCollectedFinalized>::value;
static void Finalize(void* obj) {
FinalizerTraitImpl<T, kNonTrivialFinalizer>::Finalize(obj);
}
};
class HeapAllocator;
template <typename ValueArg, size_t inlineCapacity>
class HeapListHashSetAllocator;
template <typename T, typename Traits>
class HeapVectorBacking;
template <typename Table>
class HeapHashTableBacking;
template <typename T, typename U, typename V>
struct FinalizerTrait<LinkedHashSet<T, U, V, HeapAllocator>> {
STATIC_ONLY(FinalizerTrait);
static const bool kNonTrivialFinalizer = true;
static void Finalize(void* obj) {
FinalizerTraitImpl<LinkedHashSet<T, U, V, HeapAllocator>,
kNonTrivialFinalizer>::Finalize(obj);
}
};
template <typename T, typename Allocator>
struct FinalizerTrait<WTF::ListHashSetNode<T, Allocator>> {
STATIC_ONLY(FinalizerTrait);
static const bool kNonTrivialFinalizer =
!WTF::IsTriviallyDestructible<T>::value;
static void Finalize(void* obj) {
FinalizerTraitImpl<WTF::ListHashSetNode<T, Allocator>,
kNonTrivialFinalizer>::Finalize(obj);
}
};
template <typename T, size_t inlineCapacity>
struct FinalizerTrait<Vector<T, inlineCapacity, HeapAllocator>> {
STATIC_ONLY(FinalizerTrait);
static const bool kNonTrivialFinalizer =
inlineCapacity && VectorTraits<T>::kNeedsDestruction;
static void Finalize(void* obj) {
FinalizerTraitImpl<Vector<T, inlineCapacity, HeapAllocator>,
kNonTrivialFinalizer>::Finalize(obj);
}
};
template <typename T, size_t inlineCapacity>
struct FinalizerTrait<Deque<T, inlineCapacity, HeapAllocator>> {
STATIC_ONLY(FinalizerTrait);
static const bool kNonTrivialFinalizer =
inlineCapacity && VectorTraits<T>::kNeedsDestruction;
static void Finalize(void* obj) {
FinalizerTraitImpl<Deque<T, inlineCapacity, HeapAllocator>,
kNonTrivialFinalizer>::Finalize(obj);
}
};
template <typename Table>
struct FinalizerTrait<HeapHashTableBacking<Table>> {
STATIC_ONLY(FinalizerTrait);
static const bool kNonTrivialFinalizer =
!WTF::IsTriviallyDestructible<typename Table::ValueType>::value;
static void Finalize(void* obj) {
FinalizerTraitImpl<HeapHashTableBacking<Table>,
kNonTrivialFinalizer>::Finalize(obj);
}
};
template <typename T, typename Traits>
struct FinalizerTrait<HeapVectorBacking<T, Traits>> {
STATIC_ONLY(FinalizerTrait);
static const bool kNonTrivialFinalizer = Traits::kNeedsDestruction;
static void Finalize(void* obj) {
FinalizerTraitImpl<HeapVectorBacking<T, Traits>,
kNonTrivialFinalizer>::Finalize(obj);
}
};
// GCInfo contains meta-data associated with object classes allocated in the
// Blink heap. This meta-data consists of a function pointer used to trace the
// pointers in the class instance during garbage collection, an indication of
// whether or not the instance needs a finalization callback, and a function
// pointer used to finalize the instance when the garbage collector determines
// that the instance is no longer reachable. There is a GCInfo struct for each
// class that directly inherits from GarbageCollected or
// GarbageCollectedFinalized.
struct GCInfo {
bool HasFinalizer() const { return non_trivial_finalizer_; }
bool HasVTable() const { return has_v_table_; }
TraceCallback trace_;
FinalizationCallback finalize_;
bool non_trivial_finalizer_;
bool has_v_table_;
};
#if DCHECK_IS_ON()
PLATFORM_EXPORT void AssertObjectHasGCInfo(const void*, size_t gc_info_index);
#endif
class PLATFORM_EXPORT GCInfoTable {
public:
// At maximum |kMaxIndex - 1| indices are supported.
//
// We assume that 14 bits is enough to represent all possible types: during
// telemetry runs, we see about 1,000 different types; looking at the output
// of the Oilpan GC Clang plugin, there appear to be at most about 6,000
// types. Thus 14 bits should be more than twice as many bits as we will ever
// need.
static constexpr size_t kMaxIndex = 1 << 14;
static GCInfoTable& Get() {
DEFINE_THREAD_SAFE_STATIC_LOCAL(GCInfoTable, table, ());
return table;
}
inline const GCInfo* GCInfoFromIndex(size_t index) {
DCHECK_GE(index, 1u);
DCHECK(index < kMaxIndex);
DCHECK(table_);
const GCInfo* info = table_[index];
DCHECK(info);
return info;
}
void EnsureGCInfoIndex(const GCInfo*, size_t*);
size_t GcInfoIndex() { return current_index_; }
private:
FRIEND_TEST_ALL_PREFIXES(GCInfoTest, InitialEmpty);
FRIEND_TEST_ALL_PREFIXES(GCInfoTest, ResizeToMaxIndex);
// Use GCInfoTable::Get() for retrieving the global table outside of testing
// code.
GCInfoTable();
void Resize();
// Holds the per-class GCInfo descriptors; each HeapObjectHeader keeps an
// index into this table.
const GCInfo** table_ = nullptr;
// GCInfo indices start from 1 for heap objects, with 0 being treated
// specially as the index for freelist entries and large heap objects.
size_t current_index_ = 0;
// The limit (exclusive) of the currently allocated table.
size_t limit_ = 0;
Mutex table_mutex_;
};
// GCInfoAtBaseType should be used when returning a unique 14 bit integer
// for a given gcInfo.
template <typename T>
struct GCInfoAtBaseType {
STATIC_ONLY(GCInfoAtBaseType);
static size_t Index() {
static_assert(sizeof(T), "T must be fully defined");
static const GCInfo kGcInfo = {
TraceTrait<T>::Trace, FinalizerTrait<T>::Finalize,
FinalizerTrait<T>::kNonTrivialFinalizer, std::is_polymorphic<T>::value,
};
static size_t gc_info_index = 0;
if (!AcquireLoad(&gc_info_index))
GCInfoTable::Get().EnsureGCInfoIndex(&kGcInfo, &gc_info_index);
DCHECK_GE(gc_info_index, 1u);
DCHECK(gc_info_index < GCInfoTable::kMaxIndex);
return gc_info_index;
}
};
template <typename T,
bool = WTF::IsSubclassOfTemplate<typename std::remove_const<T>::type,
GarbageCollected>::value>
struct GetGarbageCollectedType;
template <typename T>
struct GetGarbageCollectedType<T, true> {
STATIC_ONLY(GetGarbageCollectedType);
using type = typename T::GarbageCollectedType;
};
template <typename T>
struct GetGarbageCollectedType<T, false> {
STATIC_ONLY(GetGarbageCollectedType);
using type = T;
};
template <typename T>
struct GCInfoTrait {
STATIC_ONLY(GCInfoTrait);
static size_t Index() {
return GCInfoAtBaseType<typename GetGarbageCollectedType<T>::type>::Index();
}
};
template <typename U>
class GCInfoTrait<const U> : public GCInfoTrait<U> {};
template <typename T, typename U, typename V, typename W, typename X>
class HeapHashMap;
template <typename T, typename U, typename V>
class HeapHashSet;
template <typename T, typename U, typename V>
class HeapLinkedHashSet;
template <typename T, size_t inlineCapacity, typename U>
class HeapListHashSet;
template <typename T, size_t inlineCapacity>
class HeapVector;
template <typename T, size_t inlineCapacity>
class HeapDeque;
template <typename T, typename U, typename V>
class HeapHashCountedSet;
template <typename T, typename U, typename V, typename W, typename X>
struct GCInfoTrait<HeapHashMap<T, U, V, W, X>>
: public GCInfoTrait<HashMap<T, U, V, W, X, HeapAllocator>> {};
template <typename T, typename U, typename V>
struct GCInfoTrait<HeapHashSet<T, U, V>>
: public GCInfoTrait<HashSet<T, U, V, HeapAllocator>> {};
template <typename T, typename U, typename V>
struct GCInfoTrait<HeapLinkedHashSet<T, U, V>>
: public GCInfoTrait<LinkedHashSet<T, U, V, HeapAllocator>> {};
template <typename T, size_t inlineCapacity, typename U>
struct GCInfoTrait<HeapListHashSet<T, inlineCapacity, U>>
: public GCInfoTrait<
ListHashSet<T,
inlineCapacity,
U,
HeapListHashSetAllocator<T, inlineCapacity>>> {};
template <typename T, size_t inlineCapacity>
struct GCInfoTrait<HeapVector<T, inlineCapacity>>
: public GCInfoTrait<Vector<T, inlineCapacity, HeapAllocator>> {};
template <typename T, size_t inlineCapacity>
struct GCInfoTrait<HeapDeque<T, inlineCapacity>>
: public GCInfoTrait<Deque<T, inlineCapacity, HeapAllocator>> {};
template <typename T, typename U, typename V>
struct GCInfoTrait<HeapHashCountedSet<T, U, V>>
: public GCInfoTrait<HashCountedSet<T, U, V, HeapAllocator>> {};
} // namespace blink
#endif