v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
remembered-set.h
Go to the documentation of this file.
1// Copyright 2016 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_REMEMBERED_SET_H_
6#define V8_HEAP_REMEMBERED_SET_H_
7
8#include <memory>
9
10#include "src/base/bounds.h"
11#include "src/base/memory.h"
13#include "src/common/globals.h"
15#include "src/heap/heap.h"
19#include "src/heap/slot-set.h"
20#include "src/heap/spaces.h"
21
22namespace v8 {
23namespace internal {
24
26 public:
27 // Given a page and a slot in that page, this function adds the slot to the
28 // remembered set.
29 template <AccessMode access_mode>
30 static void Insert(SlotSet* slot_set, size_t slot_offset) {
31 slot_set->Insert<access_mode == v8::internal::AccessMode::ATOMIC
32 ? v8::internal::SlotSet::AccessMode::ATOMIC
33 : v8::internal::SlotSet::AccessMode::NON_ATOMIC>(
34 slot_offset);
35 }
36
37 template <AccessMode access_mode = AccessMode::ATOMIC, typename Callback>
38 static int Iterate(SlotSet* slot_set, const MutablePageMetadata* chunk,
39 Callback callback, SlotSet::EmptyBucketMode mode) {
40 int slots = 0;
41 if (slot_set != nullptr) {
42 slots += slot_set->Iterate<access_mode>(
43 chunk->ChunkAddress(), 0, chunk->BucketsInSlotSet(), callback, mode);
44 }
45 return slots;
46 }
47
48 static void Remove(SlotSet* slot_set, MutablePageMetadata* chunk,
49 Address slot_addr) {
50 if (slot_set != nullptr) {
51 uintptr_t offset = chunk->Offset(slot_addr);
52 slot_set->Remove(offset);
53 }
54 }
55
56 static void RemoveRange(SlotSet* slot_set, MutablePageMetadata* page,
59 if (slot_set != nullptr) {
60 MemoryChunk* chunk = page->Chunk();
61 uintptr_t start_offset = chunk->Offset(start);
62 uintptr_t end_offset = chunk->OffsetMaybeOutOfRange(end);
63 DCHECK_LE(start_offset, end_offset);
64 slot_set->RemoveRange(static_cast<int>(start_offset),
65 static_cast<int>(end_offset),
66 page->BucketsInSlotSet(), mode);
67 }
68 }
69
70 static void CheckNoneInRange(SlotSet* slot_set, MemoryChunk* chunk,
72 if (slot_set != nullptr) {
73 size_t start_bucket = SlotSet::BucketForSlot(chunk->Offset(start));
74 // Both 'end' and 'end_bucket' are exclusive limits, so do some index
75 // juggling to make sure we get the right bucket even if the end address
76 // is at the start of a bucket.
77 size_t end_bucket = SlotSet::BucketForSlot(
79 1;
80 slot_set->Iterate(
81 chunk->address(), start_bucket, end_bucket,
82 [start, end](MaybeObjectSlot slot) {
83 CHECK(slot.address() < start || slot.address() >= end);
84 return KEEP_SLOT;
85 },
87 }
88 }
89};
90
91template <RememberedSetType type>
92class RememberedSet : public AllStatic {
93 public:
94 // Given a page and a slot in that page, this function adds the slot to the
95 // remembered set.
96 template <AccessMode access_mode>
97 static void Insert(MutablePageMetadata* page, size_t slot_offset) {
98 SlotSet* slot_set = page->slot_set<type, access_mode>();
99 if (slot_set == nullptr) {
100 slot_set = page->AllocateSlotSet(type);
101 }
103 }
104
105 // Given a page and a slot set, this function merges the slot set to the set
106 // of the page. |other_slot_set| should not be used after calling this method.
108 SlotSet&& other_slot_set) {
109 static_assert(type == RememberedSetType::OLD_TO_NEW ||
111 SlotSet* slot_set = chunk->slot_set<type, AccessMode::NON_ATOMIC>();
112 if (slot_set == nullptr) {
113 chunk->set_slot_set<type, AccessMode::NON_ATOMIC>(&other_slot_set);
114 return;
115 }
116 slot_set->Merge(&other_slot_set, chunk->BucketsInSlotSet());
117 SlotSet::Delete(&other_slot_set);
118 }
119
120 // Given a page and a slot set, this function merges the slot set to the set
121 // of the page. |other_slot_set| should not be used after calling this method.
123 TypedSlotSet&& other_typed_slot_set) {
124 static_assert(type == RememberedSetType::OLD_TO_NEW);
125 TypedSlotSet* typed_slot_set =
127 if (typed_slot_set == nullptr) {
129 AccessMode::NON_ATOMIC>(&other_typed_slot_set);
130 return;
131 }
132 typed_slot_set->Merge(&other_typed_slot_set);
133 delete &other_typed_slot_set;
134 }
135
136 static void DeleteTyped(TypedSlotSet&& other_typed_slot_set) {
137 delete &other_typed_slot_set;
138 }
139
140 // Given a page and a slot in that page, this function returns true if
141 // the remembered set contains the slot.
142 static bool Contains(MutablePageMetadata* chunk, Address slot_addr) {
143 DCHECK(chunk->Contains(slot_addr));
144 SlotSet* slot_set = chunk->slot_set<type>();
145 if (slot_set == nullptr) {
146 return false;
147 }
148 uintptr_t offset = chunk->Offset(slot_addr);
149 return slot_set->Contains(offset);
150 }
151
153 Address end) {
154 SlotSet* slot_set = page->slot_set<type>();
155 RememberedSetOperations::CheckNoneInRange(slot_set, page->Chunk(), start,
156 end);
157 }
158
159 // Given a page and a slot in that page, this function removes the slot from
160 // the remembered set.
161 // If the slot was never added, then the function does nothing.
162 static void Remove(MutablePageMetadata* chunk, Address slot_addr) {
163 DCHECK(chunk->Contains(slot_addr));
164 SlotSet* slot_set = chunk->slot_set<type>();
165 RememberedSetOperations::Remove(slot_set, chunk, slot_addr);
166 }
167
168 // Given a page and a range of slots in that page, this function removes the
169 // slots from the remembered set.
172 SlotSet* slot_set = chunk->slot_set<type>();
173 RememberedSetOperations::RemoveRange(slot_set, chunk, start, end, mode);
174 }
175
176 // Iterates over all memory chunks that contains non-empty slot sets.
177 // The callback should take (MutablePageMetadata* chunk) and return void.
178 template <typename Callback>
179 static void IterateMemoryChunks(Heap* heap, Callback callback) {
181 MutablePageMetadata* chunk;
182 while ((chunk = it.next()) != nullptr) {
183 SlotSet* slot_set = chunk->slot_set<type>();
184 TypedSlotSet* typed_slot_set = chunk->typed_slot_set<type>();
185 if (slot_set != nullptr || typed_slot_set != nullptr) {
186 callback(chunk);
187 }
188 }
189 }
190
191 // Iterates and filters the remembered set in the given memory chunk with
192 // the given callback. The callback should take (Address slot) and return
193 // SlotCallbackResult.
194 //
195 // Notice that |mode| can only be of FREE* or PREFREE* if there are no other
196 // threads concurrently inserting slots.
197 template <AccessMode access_mode = AccessMode::ATOMIC, typename Callback>
198 static int Iterate(MutablePageMetadata* chunk, Callback callback,
200 SlotSet* slot_set = chunk->slot_set<type>();
201 return Iterate<access_mode>(slot_set, chunk, callback, mode);
202 }
203
204 template <AccessMode access_mode = AccessMode::ATOMIC, typename Callback>
205 static int Iterate(SlotSet* slot_set, const MutablePageMetadata* chunk,
206 Callback callback, SlotSet::EmptyBucketMode mode) {
208 callback, mode);
209 }
210
211 template <typename Callback>
213 MutablePageMetadata* chunk, Callback callback,
215 SlotSet* slot_set = chunk->slot_set<type>();
216 int slots = 0;
217 if (slot_set != nullptr) {
218 PossiblyEmptyBuckets* possibly_empty_buckets =
219 chunk->possibly_empty_buckets();
220 slots += slot_set->IterateAndTrackEmptyBuckets(
221 chunk->ChunkAddress(), 0, chunk->BucketsInSlotSet(), callback,
222 possibly_empty_buckets);
223 if (!possibly_empty_buckets->IsEmpty()) empty_chunks->Push(chunk);
224 }
225 return slots;
226 }
227
229 DCHECK(type == OLD_TO_NEW || type == OLD_TO_NEW_BACKGROUND);
230 SlotSet* slot_set = chunk->slot_set<type, AccessMode::NON_ATOMIC>();
231 if (slot_set != nullptr &&
233 chunk->possibly_empty_buckets())) {
234 chunk->ReleaseSlotSet(type);
235 return true;
236 }
237
238 return false;
239 }
240
241 // Given a page and a typed slot in that page, this function adds the slot
242 // to the remembered set.
243 static void InsertTyped(MutablePageMetadata* memory_chunk, SlotType slot_type,
244 uint32_t offset) {
245 TypedSlotSet* slot_set = memory_chunk->typed_slot_set<type>();
246 if (slot_set == nullptr) {
247 slot_set = memory_chunk->AllocateTypedSlotSet(type);
248 }
249 slot_set->Insert(slot_type, offset);
250 }
251
253 std::unique_ptr<TypedSlots> other) {
254 TypedSlotSet* slot_set = page->typed_slot_set<type>();
255 if (slot_set == nullptr) {
256 slot_set = page->AllocateTypedSlotSet(type);
257 }
258 slot_set->Merge(other.get());
259 }
260
261 // Given a page and a range of typed slots in that page, this function removes
262 // the slots from the remembered set.
264 Address end) {
265 TypedSlotSet* slot_set = page->typed_slot_set<type>();
266 if (slot_set != nullptr) {
267 slot_set->Iterate(
268 [=](SlotType slot_type, Address slot_addr) {
269 return start <= slot_addr && slot_addr < end ? REMOVE_SLOT
270 : KEEP_SLOT;
271 },
273 }
274 }
275
276 // Iterates and filters typed pointers in the given memory chunk with the
277 // given callback. The callback should take (SlotType slot_type, Address addr)
278 // and return SlotCallbackResult.
279 template <typename Callback>
280 static int IterateTyped(MutablePageMetadata* chunk, Callback callback) {
281 TypedSlotSet* slot_set = chunk->typed_slot_set<type>();
282 if (!slot_set) return 0;
283 return IterateTyped(slot_set, callback);
284 }
285
286 template <typename Callback>
287 static int IterateTyped(TypedSlotSet* slot_set, Callback callback) {
288 DCHECK_NOT_NULL(slot_set);
290 }
291
292 // Clear all old to old slots from the remembered set.
293 static void ClearAll(Heap* heap) {
294 static_assert(type == OLD_TO_OLD || type == TRUSTED_TO_CODE);
296 MutablePageMetadata* chunk;
297 while ((chunk = it.next()) != nullptr) {
301 }
302 }
303};
304
306 public:
307 // Updates a typed slot using an untyped slot callback where |addr| depending
308 // on slot type represents either address for respective RelocInfo or address
309 // of the uncompressed constant pool entry.
310 // The callback accepts FullMaybeObjectSlot and returns SlotCallbackResult.
311 template <typename Callback>
312 static SlotCallbackResult UpdateTypedSlot(
313 WritableJitAllocation& jit_allocation, Heap* heap, SlotType slot_type,
314 Address addr, Callback callback);
315
316 // Returns the HeapObject referenced by the given typed slot entry.
318 SlotType slot_type,
319 Address addr);
320
321 private:
322 // Updates a code entry slot using an untyped slot callback.
323 // The callback accepts FullMaybeObjectSlot and returns SlotCallbackResult.
324 template <typename Callback>
325 static SlotCallbackResult UpdateCodeEntry(Address entry_address,
326 Callback callback) {
330 SlotCallbackResult result = callback(FullMaybeObjectSlot(&code));
332 if (code != old_code) {
333 base::Memory<Address>(entry_address) = code->instruction_start();
334 }
335 return result;
336 }
337
338 // Updates a code target slot using an untyped slot callback.
339 // The callback accepts FullMaybeObjectSlot and returns SlotCallbackResult.
340 template <typename Callback>
341 static SlotCallbackResult UpdateCodeTarget(WritableRelocInfo* rinfo,
342 Callback callback) {
344 Tagged<InstructionStream> old_target =
347 SlotCallbackResult result = callback(FullMaybeObjectSlot(&new_target));
349 if (new_target != old_target) {
350 rinfo->set_target_address(
351 Cast<InstructionStream>(new_target)->instruction_start());
352 }
353 return result;
354 }
355
356 // Updates an embedded pointer slot using an untyped slot callback.
357 // The callback accepts FullMaybeObjectSlot and returns SlotCallbackResult.
358 template <typename Callback>
359 static SlotCallbackResult UpdateEmbeddedPointer(Heap* heap,
360 WritableRelocInfo* rinfo,
361 Callback callback) {
363 Tagged<HeapObject> old_target = rinfo->target_object(heap->isolate());
364 Tagged<HeapObject> new_target = old_target;
365 SlotCallbackResult result = callback(FullMaybeObjectSlot(&new_target));
367 if (new_target != old_target) {
369 }
370 return result;
371 }
372};
373
374} // namespace internal
375} // namespace v8
376
377#endif // V8_HEAP_REMEMBERED_SET_H_
static void Delete(BasicSlotSet *slot_set)
static constexpr size_t BucketForSlot(size_t slot_offset)
void Insert(size_t slot_offset)
void RemoveRange(size_t start_offset, size_t end_offset, size_t buckets, EmptyBucketMode mode)
bool Contains(size_t slot_offset)
void Remove(size_t slot_offset)
V8_INLINE void Push(EntryType entry)
Definition worklist.h:393
static Tagged< InstructionStream > FromTargetAddress(Address address)
static Tagged< InstructionStream > FromEntryAddress(Address location_of_address)
size_t OffsetMaybeOutOfRange(Address addr) const
V8_INLINE Address address() const
size_t Offset(Address addr) const
void set_typed_slot_set(TypedSlotSet *typed_slot_set)
void ReleaseTypedSlotSet(RememberedSetType type)
TypedSlotSet * AllocateTypedSlotSet(RememberedSetType type)
PossiblyEmptyBuckets * possibly_empty_buckets()
void ReleaseSlotSet(RememberedSetType type)
static constexpr bool IsCodeTargetMode(Mode mode)
Definition reloc-info.h:197
V8_INLINE Address target_address()
static constexpr bool IsEmbeddedObjectMode(Mode mode)
Definition reloc-info.h:209
V8_INLINE Tagged< HeapObject > target_object(PtrComprCageBase cage_base)
static int Iterate(SlotSet *slot_set, const MutablePageMetadata *chunk, Callback callback, SlotSet::EmptyBucketMode mode)
static void Remove(SlotSet *slot_set, MutablePageMetadata *chunk, Address slot_addr)
static void CheckNoneInRange(SlotSet *slot_set, MemoryChunk *chunk, Address start, Address end)
static void Insert(SlotSet *slot_set, size_t slot_offset)
static void RemoveRange(SlotSet *slot_set, MutablePageMetadata *page, Address start, Address end, SlotSet::EmptyBucketMode mode)
static int Iterate(SlotSet *slot_set, const MutablePageMetadata *chunk, Callback callback, SlotSet::EmptyBucketMode mode)
static void IterateMemoryChunks(Heap *heap, Callback callback)
static bool CheckPossiblyEmptyBuckets(MutablePageMetadata *chunk)
static void DeleteTyped(TypedSlotSet &&other_typed_slot_set)
static void InsertTyped(MutablePageMetadata *memory_chunk, SlotType slot_type, uint32_t offset)
static void Insert(MutablePageMetadata *page, size_t slot_offset)
static void MergeTyped(MutablePageMetadata *page, std::unique_ptr< TypedSlots > other)
static int IterateTyped(TypedSlotSet *slot_set, Callback callback)
static void ClearAll(Heap *heap)
static int IterateAndTrackEmptyBuckets(MutablePageMetadata *chunk, Callback callback, ::heap::base::Worklist< MutablePageMetadata *, 64 >::Local *empty_chunks)
static void RemoveRangeTyped(MutablePageMetadata *page, Address start, Address end)
static int IterateTyped(MutablePageMetadata *chunk, Callback callback)
static void MergeAndDelete(MutablePageMetadata *chunk, SlotSet &&other_slot_set)
static void Remove(MutablePageMetadata *chunk, Address slot_addr)
static bool Contains(MutablePageMetadata *chunk, Address slot_addr)
static void MergeAndDeleteTyped(MutablePageMetadata *chunk, TypedSlotSet &&other_typed_slot_set)
static void RemoveRange(MutablePageMetadata *chunk, Address start, Address end, SlotSet::EmptyBucketMode mode)
static void CheckNoneInRange(MutablePageMetadata *page, Address start, Address end)
static int Iterate(MutablePageMetadata *chunk, Callback callback, SlotSet::EmptyBucketMode mode)
size_t Iterate(Address chunk_start, size_t start_bucket, size_t end_bucket, Callback callback, EmptyBucketMode mode)
Definition slot-set.h:152
size_t IterateAndTrackEmptyBuckets(Address chunk_start, size_t start_bucket, size_t end_bucket, Callback callback, PossiblyEmptyBuckets *possibly_empty_buckets)
Definition slot-set.h:169
bool CheckPossiblyEmptyBuckets(size_t buckets, PossiblyEmptyBuckets *possibly_empty_buckets)
Definition slot-set.h:182
void Merge(SlotSet *other, size_t buckets)
Definition slot-set.h:209
int Iterate(Callback callback, IterationMode mode)
Definition slot-set.h:323
void Insert(SlotType type, uint32_t offset)
Definition slot-set.cc:24
void Merge(TypedSlots *other)
Definition slot-set.cc:31
static SlotCallbackResult UpdateCodeEntry(Address entry_address, Callback callback)
static SlotCallbackResult UpdateTypedSlot(WritableJitAllocation &jit_allocation, Heap *heap, SlotType slot_type, Address addr, Callback callback)
static Tagged< HeapObject > GetTargetObject(Heap *heap, SlotType slot_type, Address addr)
static SlotCallbackResult UpdateCodeTarget(WritableRelocInfo *rinfo, Callback callback)
static SlotCallbackResult UpdateEmbeddedPointer(Heap *heap, WritableRelocInfo *rinfo, Callback callback)
V8_INLINE void set_target_object(Tagged< InstructionStream > host, Tagged< HeapObject > target, WriteBarrierMode write_barrier_mode=UPDATE_WRITE_BARRIER, ICacheFlushMode icache_flush_mode=FLUSH_ICACHE_IF_NEEDED)
void set_target_address(Tagged< InstructionStream > host, Address target, WriteBarrierMode write_barrier_mode=UPDATE_WRITE_BARRIER, ICacheFlushMode icache_flush_mode=FLUSH_ICACHE_IF_NEEDED)
Handle< Code > code
int start
int end
DirectHandle< Object > new_target
Definition execution.cc:75
int32_t offset
TNode< Object > callback
ZoneVector< RpoNumber > & result
ZoneVector< int > slots
T & Memory(Address addr)
Definition memory.h:18
static V8_INLINE bool HasWeakHeapObjectTag(const Tagged< Object > value)
Definition objects.h:653
constexpr int kTaggedSize
Definition globals.h:542
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK(condition)
Definition logging.h:482
wasm::ValueType type