// Copyright 2020 the V8 project 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 V8_HEAP_CPPGC_GC_INFO_TABLE_H_ #define V8_HEAP_CPPGC_GC_INFO_TABLE_H_ #include #include "include/cppgc/internal/gc-info.h" #include "include/cppgc/platform.h" #include "include/v8config.h" #include "src/base/logging.h" #include "src/base/macros.h" #include "src/base/platform/mutex.h" #include "src/base/platform/platform.h" namespace cppgc { namespace internal { // GCInfo contains metadata for objects that are instantiated from classes that // inherit from GarbageCollected. struct GCInfo final { FinalizationCallback finalize; TraceCallback trace; NameCallback name; bool has_v_table; }; class V8_EXPORT GCInfoTable final { public: // At maximum |kMaxIndex - 1| indices are supported. // // We assume that 14 bits are enough to represent all possible types. // // For Blink 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. Different contexts may require adjusting this limit. static constexpr GCInfoIndex kMaxIndex = 1 << 14; // Minimum index returned. Values smaller |kMinIndex| may be used as // sentinels. static constexpr GCInfoIndex kMinIndex = 1; // (Light) experimentation suggests that Blink doesn't need more than this // while handling content on popular web properties. static constexpr GCInfoIndex kInitialWantedLimit = 512; // Refer through GlobalGCInfoTable for retrieving the global table outside // of testing code. explicit GCInfoTable(PageAllocator* page_allocator); ~GCInfoTable(); GCInfoIndex RegisterNewGCInfo(const GCInfo& info); const GCInfo& GCInfoFromIndex(GCInfoIndex index) const { DCHECK_GE(index, kMinIndex); DCHECK_LT(index, kMaxIndex); DCHECK(table_); return table_[index]; } GCInfoIndex NumberOfGCInfosForTesting() const { return current_index_; } GCInfoIndex LimitForTesting() const { return limit_; } GCInfo& TableSlotForTesting(GCInfoIndex index) { return table_[index]; } private: void Resize(); GCInfoIndex InitialTableLimit() const; size_t MaxTableSize() const; void CheckMemoryIsZeroed(uintptr_t* base, size_t len); PageAllocator* page_allocator_; // Holds the per-class GCInfo descriptors; each HeapObjectHeader keeps an // index into this table. GCInfo* table_; uint8_t* read_only_table_end_; // Current index used when requiring a new GCInfo object. GCInfoIndex current_index_ = kMinIndex; // The limit (exclusive) of the currently allocated table. GCInfoIndex limit_ = 0; v8::base::Mutex table_mutex_; DISALLOW_COPY_AND_ASSIGN(GCInfoTable); }; class V8_EXPORT GlobalGCInfoTable final { public: // Sets up a singleton table that can be acquired using Get(). static void Create(PageAllocator* page_allocator); // Accessors for the singleton table. static GCInfoTable& GetMutable() { return *global_table_; } static const GCInfoTable& Get() { return *global_table_; } static const GCInfo& GCInfoFromIndex(GCInfoIndex index) { return Get().GCInfoFromIndex(index); } private: // Singleton for each process. Retrieved through Get(). static GCInfoTable* global_table_; DISALLOW_NEW_AND_DELETE() DISALLOW_COPY_AND_ASSIGN(GlobalGCInfoTable); }; } // namespace internal } // namespace cppgc #endif // V8_HEAP_CPPGC_GC_INFO_TABLE_H_