blob: bec05ee6c1b376622a99804fd27f4c4fec1d1913 [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_IMPL_GC_INFO_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_INFO_H_
#include <atomic>
#include "base/gtest_prod_util.h"
#include "third_party/blink/renderer/platform/heap/blink_gc.h"
#include "third_party/blink/renderer/platform/heap/impl/finalizer_traits.h"
#include "third_party/blink/renderer/platform/heap/impl/name_traits.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
namespace blink {
template <typename T>
struct TraceTrait;
using GCInfoIndex = uint32_t;
// GCInfo contains metadata for objects that are instantiated from classes that
// inherit from GarbageCollected.
struct PLATFORM_EXPORT GCInfo final {
static inline const GCInfo& From(GCInfoIndex);
const TraceCallback trace;
const internal::FinalizationCallback finalize;
const NameCallback name;
const bool has_v_table;
};
class PLATFORM_EXPORT GCInfoTable final {
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 GCInfoIndex kMaxIndex = 1 << 14;
// Minimum index returned. Values smaller |kMinIndex| may be used as
// sentinels.
static constexpr GCInfoIndex kMinIndex = 1;
// Sets up a singleton table that can be acquired using Get().
static void CreateGlobalTable();
static GCInfoTable* GetMutable() { return global_table_; }
static const GCInfoTable& Get() { return *global_table_; }
const GCInfo& GCInfoFromIndex(GCInfoIndex index) const {
DCHECK_GE(index, kMinIndex);
DCHECK_LT(index, kMaxIndex);
DCHECK(table_);
const GCInfo* info = table_[index];
DCHECK(info);
return *info;
}
GCInfoIndex EnsureGCInfoIndex(const GCInfo*, std::atomic<GCInfoIndex>*);
// Returns the number of recorded GCInfo objects, including |kMinIndex|.
GCInfoIndex NumberOfGCInfos() const { return current_index_; }
private:
FRIEND_TEST_ALL_PREFIXES(GCInfoTest, InitialEmpty);
FRIEND_TEST_ALL_PREFIXES(GCInfoTest, ResizeToMaxIndex);
FRIEND_TEST_ALL_PREFIXES(GCInfoDeathTest, MoreThanMaxIndexInfos);
// Singleton for each process. Retrieved through Get().
static GCInfoTable* global_table_;
// 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;
// Current index used when requiring a new GCInfo object.
GCInfoIndex current_index_ = kMinIndex;
// The limit (exclusive) of the currently allocated table.
GCInfoIndex limit_ = 0;
Mutex table_mutex_;
};
// static
const GCInfo& GCInfo::From(GCInfoIndex index) {
return GCInfoTable::Get().GCInfoFromIndex(index);
}
template <typename T>
struct GCInfoTrait {
STATIC_ONLY(GCInfoTrait);
static GCInfoIndex Index() {
static_assert(sizeof(T), "T must be fully defined");
static const GCInfo kGcInfo = {
TraceTrait<T>::Trace, internal::FinalizerTrait<T>::kCallback,
NameTrait<T>::GetName, std::is_polymorphic<T>::value};
// This is more complicated than using threadsafe initialization, but this
// is instantiated many times (once for every GC type).
static std::atomic<GCInfoIndex> gc_info_index{0};
GCInfoIndex index = gc_info_index.load(std::memory_order_acquire);
if (!index) {
index = GCInfoTable::GetMutable()->EnsureGCInfoIndex(&kGcInfo,
&gc_info_index);
}
DCHECK_GE(index, GCInfoTable::kMinIndex);
DCHECK_LT(index, GCInfoTable::kMaxIndex);
return index;
}
};
template <typename U>
class GCInfoTrait<const U> : public GCInfoTrait<U> {};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_INFO_H_