1// Copyright 2020 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_HEAP_CPPGC_GC_INFO_TABLE_H_
6#define V8_HEAP_CPPGC_GC_INFO_TABLE_H_
7
8#include <stdint.h>
9
10#include "include/cppgc/internal/gc-info.h"
11#include "include/cppgc/platform.h"
12#include "include/v8config.h"
13#include "src/base/logging.h"
14#include "src/base/macros.h"
15#include "src/base/platform/mutex.h"
16#include "src/base/platform/platform.h"
17
18namespace cppgc {
19namespace internal {
20
21// GCInfo contains metadata for objects that are instantiated from classes that
22// inherit from GarbageCollected.
23struct GCInfo final {
24  FinalizationCallback finalize;
25  TraceCallback trace;
26  NameCallback name;
27  bool has_v_table;
28};
29
30class V8_EXPORT GCInfoTable final {
31 public:
32  // At maximum |kMaxIndex - 1| indices are supported.
33  //
34  // We assume that 14 bits are enough to represent all possible types.
35  //
36  // For Blink during telemetry runs, we see about 1,000 different types;
37  // looking at the output of the Oilpan GC clang plugin, there appear to be at
38  // most about 6,000 types. Thus 14 bits should be more than twice as many bits
39  // as we will ever need. Different contexts may require adjusting this limit.
40  static constexpr GCInfoIndex kMaxIndex = 1 << 14;
41
42  // Minimum index returned. Values smaller |kMinIndex| may be used as
43  // sentinels.
44  static constexpr GCInfoIndex kMinIndex = 1;
45
46  // (Light) experimentation suggests that Blink doesn't need more than this
47  // while handling content on popular web properties.
48  static constexpr GCInfoIndex kInitialWantedLimit = 512;
49
50  // Refer through GlobalGCInfoTable for retrieving the global table outside
51  // of testing code.
52  explicit GCInfoTable(PageAllocator* page_allocator);
53  ~GCInfoTable();
54  GCInfoTable(const GCInfoTable&) = delete;
55  GCInfoTable& operator=(const GCInfoTable&) = delete;
56
57  GCInfoIndex RegisterNewGCInfo(std::atomic<uint16_t>&, const GCInfo& info);
58
59  const GCInfo& GCInfoFromIndex(GCInfoIndex index) const {
60    DCHECK_GE(index, kMinIndex);
61    DCHECK_LT(index, kMaxIndex);
62    DCHECK(table_);
63    return table_[index];
64  }
65
66  GCInfoIndex NumberOfGCInfos() const { return current_index_; }
67
68  GCInfoIndex LimitForTesting() const { return limit_; }
69  GCInfo& TableSlotForTesting(GCInfoIndex index) { return table_[index]; }
70
71  PageAllocator* allocator() const { return page_allocator_; }
72
73 private:
74  void Resize();
75
76  GCInfoIndex InitialTableLimit() const;
77  size_t MaxTableSize() const;
78
79  void CheckMemoryIsZeroed(uintptr_t* base, size_t len);
80
81  PageAllocator* page_allocator_;
82  // Holds the per-class GCInfo descriptors; each HeapObjectHeader keeps an
83  // index into this table.
84  GCInfo* table_;
85  uint8_t* read_only_table_end_;
86  // Current index used when requiring a new GCInfo object.
87  GCInfoIndex current_index_ = kMinIndex;
88  // The limit (exclusive) of the currently allocated table.
89  GCInfoIndex limit_ = 0;
90
91  v8::base::Mutex table_mutex_;
92};
93
94class V8_EXPORT GlobalGCInfoTable final {
95 public:
96  GlobalGCInfoTable(const GlobalGCInfoTable&) = delete;
97  GlobalGCInfoTable& operator=(const GlobalGCInfoTable&) = delete;
98
99  // Sets up the table with the provided `page_allocator`. Will use an internal
100  // allocator in case no PageAllocator is provided. May be called multiple
101  // times with the same `page_allocator` argument.
102  static void Initialize(PageAllocator* page_allocator);
103
104  // Accessors for the singleton table.
105  static GCInfoTable& GetMutable() { return *global_table_; }
106  static const GCInfoTable& Get() { return *global_table_; }
107
108  static const GCInfo& GCInfoFromIndex(GCInfoIndex index) {
109    return Get().GCInfoFromIndex(index);
110  }
111
112 private:
113  // Singleton for each process. Retrieved through Get().
114  static GCInfoTable* global_table_;
115
116  DISALLOW_NEW_AND_DELETE()
117};
118
119}  // namespace internal
120}  // namespace cppgc
121
122#endif  // V8_HEAP_CPPGC_GC_INFO_TABLE_H_
123