v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
page-pool.cc
Go to the documentation of this file.
1// Copyright 2025 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
11
12namespace v8 {
13namespace internal {
14
16 DCHECK(shared_pool_.empty());
17 DCHECK(local_pools.empty());
18}
19
21 public:
22 ReleasePooledChunksTask(Isolate* isolate, PagePool* pool, size_t id)
23 : CancelableTask(isolate), isolate_(isolate), pool_(pool), id_(id) {}
24
25 ~ReleasePooledChunksTask() override = default;
28
29 private:
30 void RunInternal() override {
31 size_t count = pool_->ReleaseUpTo(id_);
32 if (v8_flags.trace_gc_nvp) {
33 isolate_->PrintWithTimestamp("Removed %zu pages from the shared pool.\n",
34 count);
35 }
36 }
37
40 const size_t id_;
41};
42
45 auto it = local_pools.find(isolate);
46
47 size_t id = next_id_++;
48
49 if (it != local_pools.end()) {
50 DCHECK(!it->second.empty());
51 shared_pool_.push_back(std::make_pair(std::move(it->second), id));
52 local_pools.erase(it);
53 }
54
55 // Always post task when there are pages in the shared pool.
56 if (!shared_pool_.empty()) {
57 auto schedule_task = [this, isolate, id](Isolate* target_isolate) {
58 DCHECK_NE(isolate, target_isolate);
59 USE(isolate);
60 static constexpr base::TimeDelta kReleaseTaskDelayInSeconds =
62 target_isolate->task_runner()->PostDelayedTask(
63 std::make_unique<ReleasePooledChunksTask>(target_isolate, this, id),
64 kReleaseTaskDelayInSeconds.InSecondsF());
65 };
66
67 if (!isolate->isolate_group()->FindAnotherIsolateLocked(isolate,
68 schedule_task)) {
69 // No other isolate could be found. Release pooled pages right away.
70 for (const auto& entry : shared_pool_) {
71 for (auto* page : entry.first) {
73 }
74 }
75 shared_pool_.clear();
76 }
77 }
78}
79
81 std::vector<MutablePageMetadata*> pages_to_free;
82
83 {
85 auto it = local_pools.find(isolate);
86
87 if (it != local_pools.end()) {
88 DCHECK(!it->second.empty());
89 pages_to_free = std::move(it->second);
90 local_pools.erase(it);
91 }
92 }
93
94 for (MutablePageMetadata* page : pages_to_free) {
96 }
97}
98
100 DCHECK(local_pools.empty());
101
102 for (const auto& entry : shared_pool_) {
103 for (auto* page : entry.first) {
105 }
106 }
107 shared_pool_.clear();
108}
109
110size_t PagePool::ReleaseUpTo(size_t id) {
111 std::vector<std::vector<MutablePageMetadata*>> groups_to_free;
112
113 {
114 base::MutexGuard guard(&mutex_);
115 std::erase_if(shared_pool_, [&groups_to_free, id](auto entry) {
116 if (entry.second <= id) {
117 groups_to_free.push_back(std::move(entry.first));
118 return true;
119 }
120
121 return false;
122 });
123 }
124
125 size_t freed = 0;
126
127 for (const auto& group : groups_to_free) {
128 for (auto* page : group) {
130 ++freed;
131 }
132 }
133
134 return freed;
135}
136
137size_t PagePool::GetCount(Isolate* isolate) const {
138 base::MutexGuard guard(&mutex_);
139 auto it = local_pools.find(isolate);
140 if (it != local_pools.end()) {
141 return it->second.size();
142 }
143
144 return 0;
145}
146
148 base::MutexGuard guard(&mutex_);
149 size_t count = 0;
150
151 for (auto& entry : shared_pool_) {
152 count += entry.first.size();
153 }
154
155 return count;
156}
157
159 base::MutexGuard guard(&mutex_);
160 size_t count = 0;
161
162 for (auto& entry : shared_pool_) {
163 count += entry.first.size();
164 }
165
166 for (auto& entry : local_pools) {
167 count += entry.second.size();
168 }
169
170 return count;
171}
172
174 // This method is called only on the main thread and only during the
175 // atomic pause so a lock is not needed.
176 DCHECK_NOT_NULL(chunk);
178 DCHECK(!chunk->Chunk()->IsLargePage());
179 DCHECK(!chunk->Chunk()->IsTrusted());
180 DCHECK_NE(chunk->Chunk()->executable(), EXECUTABLE);
182 base::MutexGuard guard(&mutex_);
183 local_pools[isolate].push_back(chunk);
184}
185
187 base::MutexGuard guard(&mutex_);
188
189 // Try to get a page from the page pool for the given isolate first.
190 auto it = local_pools.find(isolate);
191
192 if (it == local_pools.end()) {
193 // Pages in this pool will be flushed soon. Take them first.
194 if (!shared_pool_.empty()) {
195 auto& group = shared_pool_.back().first;
196 MutablePageMetadata* page = group.back();
197 group.pop_back();
198 if (group.empty()) {
199 shared_pool_.pop_back();
200 }
201 return page;
202 }
203
204 // Otherwise steal from some other isolate's local pool.
205 it = local_pools.begin();
206 }
207
208 if (it != local_pools.end()) {
209 std::vector<MutablePageMetadata*>& pages = it->second;
210 DCHECK(!pages.empty());
211
212 MutablePageMetadata* result = pages.back();
213 pages.pop_back();
214
215 if (pages.empty()) {
216 local_pools.erase(it);
217 }
218
219 return result;
220 }
221
222 return nullptr;
223}
224
225} // namespace internal
226} // namespace v8
static constexpr TimeDelta FromSeconds(int64_t seconds)
Definition time.h:81
double InSecondsF() const
Definition time.cc:210
static void DeleteMemoryChunk(MutablePageMetadata *metadata)
Executability executable() const
std::vector< std::pair< std::vector< MutablePageMetadata * >, size_t > > shared_pool_
Definition page-pool.h:66
V8_EXPORT_PRIVATE void ReleaseImmediately(Isolate *isolate)
Definition page-pool.cc:80
void ReleaseOnTearDown(Isolate *isolate)
Definition page-pool.cc:43
size_t GetSharedCount() const
Definition page-pool.cc:147
size_t GetCount(Isolate *isolate) const
Definition page-pool.cc:137
MutablePageMetadata * Remove(Isolate *isolate)
Definition page-pool.cc:186
size_t GetTotalCount() const
Definition page-pool.cc:158
void Add(Isolate *isolate, MutablePageMetadata *chunk)
Definition page-pool.cc:173
absl::flat_hash_map< Isolate *, std::vector< MutablePageMetadata * > > local_pools
Definition page-pool.h:62
size_t ReleaseUpTo(size_t id)
Definition page-pool.cc:110
ReleasePooledChunksTask(Isolate *isolate, PagePool *pool, size_t id)
Definition page-pool.cc:22
~ReleasePooledChunksTask() override=default
ReleasePooledChunksTask(const ReleasePooledChunksTask &)=delete
ReleasePooledChunksTask & operator=(const ReleasePooledChunksTask &)=delete
BasePage * page
Definition sweeper.cc:218
uint32_t count
Isolate * isolate
ZoneVector< RpoNumber > & result
V8_EXPORT_PRIVATE FlagValues v8_flags
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293