v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
gc-info-table.cc
Go to the documentation of this file.
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
6
7#include <algorithm>
8#include <limits>
9#include <memory>
10
13#include "src/base/bits.h"
17
18namespace cppgc {
19namespace internal {
20
21namespace {
22
23// GCInfoTable::table_, the table which holds GCInfos, is maintained as a
24// contiguous array reserved upfront. Subparts of the array are (re-)committed
25// as read/write or read-only in OS pages, whose size is a power of 2. To avoid
26// having GCInfos that cross the boundaries between these subparts we force the
27// size of GCInfo to be a power of 2 as well.
28constexpr size_t kEntrySize = sizeof(GCInfo);
29static_assert(v8::base::bits::IsPowerOfTwo(kEntrySize),
30 "GCInfoTable entries size must be power of "
31 "two");
32
33} // namespace
34
35GCInfoTable* GlobalGCInfoTable::global_table_ = nullptr;
36
40
41// static
43 static v8::base::LeakyObject<GCInfoTable> table(page_allocator,
45 if (!global_table_) {
46 global_table_ = table.get();
47 } else {
48 CHECK_EQ(&page_allocator, &global_table_->allocator());
49 }
50}
51
53 FatalOutOfMemoryHandler& oom_handler)
54 : page_allocator_(page_allocator),
55 oom_handler_(oom_handler),
56 table_(static_cast<decltype(table_)>(page_allocator_.AllocatePages(
57 nullptr, MaxTableSize(), page_allocator_.AllocatePageSize(),
58 PageAllocator::kNoAccess))),
59 read_only_table_end_(reinterpret_cast<uint8_t*>(table_)) {
60 if (!table_) {
61 oom_handler_("Oilpan: GCInfoTable initial reservation.");
62 }
63 Resize();
64}
65
69
74
76 // Different OSes have different page sizes, so we have to choose the minimum
77 // of memory wanted and OS page size.
78 constexpr size_t memory_wanted = kInitialWantedLimit * kEntrySize;
79 const size_t initial_limit =
80 RoundUp(memory_wanted, page_allocator_.AllocatePageSize()) / kEntrySize;
81 CHECK_GT(std::numeric_limits<GCInfoIndex>::max(), initial_limit);
82 return static_cast<GCInfoIndex>(
83 std::min(static_cast<size_t>(kMaxIndex), initial_limit));
84}
85
87 const GCInfoIndex new_limit = (limit_) ? 2 * limit_ : InitialTableLimit();
88 CHECK_GT(new_limit, limit_);
89 const size_t old_committed_size = limit_ * kEntrySize;
90 const size_t new_committed_size = new_limit * kEntrySize;
92 CHECK_EQ(0u, new_committed_size % page_allocator_.AllocatePageSize());
93 CHECK_GE(MaxTableSize(), new_committed_size);
94 // Recommit new area as read/write.
95 uint8_t* current_table_end =
96 reinterpret_cast<uint8_t*>(table_) + old_committed_size;
97 const size_t table_size_delta = new_committed_size - old_committed_size;
98 if (!page_allocator_.SetPermissions(current_table_end, table_size_delta,
100 oom_handler_("Oilpan: GCInfoTable resize.");
101 }
102
103 // Recommit old area as read-only.
104 if (read_only_table_end_ != current_table_end) {
105 DCHECK_GT(current_table_end, read_only_table_end_);
106 const size_t read_only_delta = current_table_end - read_only_table_end_;
109 read_only_table_end_ += read_only_delta;
110 }
111
112 // Check that newly-committed memory is zero-initialized.
113 CheckMemoryIsZeroed(reinterpret_cast<uintptr_t*>(current_table_end),
114 table_size_delta / sizeof(uintptr_t));
115
116 limit_ = new_limit;
117}
118
119void GCInfoTable::CheckMemoryIsZeroed(uintptr_t* base, size_t len) {
120#if DEBUG
121 for (size_t i = 0; i < len; ++i) {
122 DCHECK(!base[i]);
123 }
124#endif // DEBUG
125}
126
128 std::atomic<GCInfoIndex>& registered_index, const GCInfo& info) {
129 // Ensuring a new index involves current index adjustment as well as
130 // potentially resizing the table. For simplicity we use a lock.
132
133 // Check the registered index again after taking the lock as some other
134 // thread may have registered the info at the same time.
135 const GCInfoIndex index = registered_index.load(std::memory_order_relaxed);
136 if (index) {
137 return index;
138 }
139
140 if (current_index_ == limit_) {
141 Resize();
142 }
143
144 const GCInfoIndex new_index = current_index_++;
146 table_[new_index] = info;
147 registered_index.store(new_index, std::memory_order_release);
148 return new_index;
149}
150
151} // namespace internal
152} // namespace cppgc
FatalOutOfMemoryHandler & oom_handler_
static constexpr GCInfoIndex kInitialWantedLimit
GCInfoIndex InitialTableLimit() const
GCInfoIndex RegisterNewGCInfo(std::atomic< uint16_t > &, const GCInfo &info)
PageAllocator & allocator() const
static constexpr GCInfoIndex kMinIndex
GCInfoTable(PageAllocator &page_allocator, FatalOutOfMemoryHandler &oom_handler)
PageAllocator & page_allocator_
static constexpr GCInfoIndex kMaxIndex
void CheckMemoryIsZeroed(uintptr_t *base, size_t len)
static void Initialize(PageAllocator &page_allocator)
virtual bool ReleasePages(void *address, size_t length, size_t new_length)=0
virtual size_t AllocatePageSize()=0
virtual bool SetPermissions(void *address, size_t length, Permission permissions)=0
cppgc::PageAllocator * page_allocator_
Definition cpp-heap.cc:194
Handle< SharedFunctionInfo > info
OptionalOpIndex index
uint16_t GCInfoIndex
Definition gc-info.h:21
FatalOutOfMemoryHandler & GetGlobalOOMHandler()
Definition platform.cc:73
constexpr bool IsPowerOfTwo(T value)
Definition bits.h:187
SourcePositionTable *const table_
Definition pipeline.cc:227
#define CHECK_GE(lhs, rhs)
#define CHECK(condition)
Definition logging.h:124
#define CHECK_GT(lhs, rhs)
#define CHECK_LT(lhs, rhs)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_GT(v1, v2)
Definition logging.h:487
constexpr T RoundUp(T x, intptr_t m)
Definition macros.h:387