v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
conservative-stack-visitor-inl.h
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
5#ifndef V8_HEAP_CONSERVATIVE_STACK_VISITOR_INL_H_
6#define V8_HEAP_CONSERVATIVE_STACK_VISITOR_INL_H_
7
9// Include the non-inl header before the rest of the headers.
10
11#include "src/common/globals.h"
15#include "src/heap/marking.h"
18#include "src/objects/objects.h"
19#include "src/objects/tagged.h"
21
22#ifdef V8_COMPRESS_POINTERS
24#endif // V8_COMPRESS_POINTERS
25
26namespace v8 {
27namespace internal {
28
29template <typename ConcreteVisitor>
31 Isolate* isolate, RootVisitor* root_visitor)
32 : cage_base_(isolate),
33#ifdef V8_EXTERNAL_CODE_SPACE
34 code_cage_base_(isolate->code_cage_base()),
35 code_address_region_(isolate->heap()->code_region()),
36#endif
37#ifdef V8_ENABLE_SANDBOX
38 trusted_cage_base_(isolate->isolate_data()->trusted_cage_base_address()),
39#endif
40 root_visitor_(root_visitor),
41 allocator_(isolate->heap()->memory_allocator()) {
42}
43
44#ifdef V8_COMPRESS_POINTERS
45template <typename ConcreteVisitor>
47 PtrComprCageBase cage_base) const {
48 if (cage_base == cage_base_) {
49 return true;
50 }
51#ifdef V8_EXTERNAL_CODE_SPACE
52 if (cage_base == code_cage_base_) {
53 return true;
54 }
55#endif
56#ifdef V8_ENABLE_SANDBOX
57 if (cage_base == trusted_cage_base_) {
58 return true;
59 }
60#endif
61 return false;
62}
63#endif // V8_COMPRESS_POINTERS
64
65template <typename ConcreteVisitor>
67 Address maybe_inner_ptr, PtrComprCageBase cage_base) const {
68#ifdef V8_COMPRESS_POINTERS
69 DCHECK(IsInterestingCage(cage_base));
70#endif // V8_COMPRESS_POINTERS
71 // Check if the pointer is contained by a normal or large page owned by this
72 // heap. Bail out if it is not.
73 // TODO(379788114): Consider introducing a bloom filter for pages.
74 const MemoryChunk* chunk =
75 allocator_->LookupChunkContainingAddressInSafepoint(maybe_inner_ptr);
76 if (chunk == nullptr) {
77 return kNullAddress;
78 }
79 const MemoryChunkMetadata* chunk_metadata = chunk->Metadata();
80 DCHECK(chunk_metadata->Contains(maybe_inner_ptr));
81
82 if (!ConcreteVisitor::FilterPage(chunk)) {
83 return kNullAddress;
84 }
85
86 // If it is contained in a large page, we want to mark the only object on it.
87 if (chunk->IsLargePage()) {
88 // This could be simplified if we could guarantee that there are no free
89 // space or filler objects in large pages. A few cctests violate this now.
91 static_cast<const LargePageMetadata*>(chunk_metadata)->GetObject());
92 MapWord map_word = obj->map_word(cage_base, kRelaxedLoad);
93 return (!ConcreteVisitor::FilterLargeObject(obj, map_word) ||
96 : obj.address();
97 }
98
99 // Otherwise, we have a pointer inside a normal page.
100 const PageMetadata* page = static_cast<const PageMetadata*>(chunk_metadata);
101 // Try to find the address of a previous valid object on this page.
102 Address base_ptr =
103 MarkingBitmap::FindPreviousValidObject(page, maybe_inner_ptr);
104 // Iterate through the objects in the page forwards, until we find the object
105 // containing maybe_inner_ptr.
106 DCHECK_LE(base_ptr, maybe_inner_ptr);
107 MarkingBitmap* bitmap = const_cast<MarkingBitmap*>(page->marking_bitmap());
108 while (true) {
110 MapWord map_word = obj->map_word(cage_base, kRelaxedLoad);
111 if (!ConcreteVisitor::FilterNormalObject(obj, map_word, bitmap)) {
112 return kNullAddress;
113 }
114 const int size = obj->SizeFromMap(map_word.ToMap());
115 DCHECK_LT(0, size);
116 if (maybe_inner_ptr < base_ptr + size) {
117 ConcreteVisitor::HandleObjectFound(obj, size, bitmap);
118 return IsFreeSpaceOrFiller(obj, cage_base) ? kNullAddress : base_ptr;
119 }
120 base_ptr += ALIGN_TO_ALLOCATION_ALIGNMENT(size);
121 DCHECK_LT(base_ptr, page->area_end());
122 }
123}
124
125template <typename ConcreteVisitor>
127 const void* pointer) {
128 auto address = reinterpret_cast<Address>(const_cast<void*>(pointer));
129#ifdef V8_COMPRESS_POINTERS
131 cage_base_, address,
132 [this](Address ptr) { VisitConservativelyIfPointer(ptr, cage_base_); });
133 if constexpr (ConcreteVisitor::kOnlyVisitMainV8Cage) {
134 return;
135 }
136#ifdef V8_EXTERNAL_CODE_SPACE
137 ExternalCodeCompressionScheme::ProcessIntermediatePointers(
138 code_cage_base_, address, [this](Address ptr) {
139 VisitConservativelyIfPointer(ptr, code_cage_base_);
140 });
141#endif // V8_EXTERNAL_CODE_SPACE
142#ifdef V8_ENABLE_SANDBOX
144 trusted_cage_base_, address, [this](Address ptr) {
145 VisitConservativelyIfPointer(ptr, trusted_cage_base_);
146 });
147#endif // V8_ENABLE_SANDBOX
148#else // !V8_COMPRESS_POINTERS
149 VisitConservativelyIfPointer(address);
150#endif // V8_COMPRESS_POINTERS
151}
152
153template <typename ConcreteVisitor>
155 ConcreteVisitor>::VisitConservativelyIfPointer(Address address) {
156#ifdef V8_COMPRESS_POINTERS
157 // Only proceed if the address falls in one of the interesting cages,
158 // otherwise bail out.
160 cage_base_.address()) {
161 VisitConservativelyIfPointer(address, cage_base_);
162 } else if constexpr (ConcreteVisitor::kOnlyVisitMainV8Cage) {
163 return;
164#ifdef V8_EXTERNAL_CODE_SPACE
165 } else if (code_address_region_.contains(address)) {
166 VisitConservativelyIfPointer(address, code_cage_base_);
167#endif // V8_EXTERNAL_CODE_SPACE
168 }
169#ifdef V8_ENABLE_SANDBOX
171 trusted_cage_base_.address()) {
172 VisitConservativelyIfPointer(address, trusted_cage_base_);
173 }
174#endif // V8_ENABLE_SANDBOX
175#else // !V8_COMPRESS_POINTERS
176 VisitConservativelyIfPointer(address, cage_base_);
177#endif // V8_COMPRESS_POINTERS
178}
179
180template <typename ConcreteVisitor>
182 ConcreteVisitor>::VisitConservativelyIfPointer(Address address,
183 PtrComprCageBase cage_base) {
184 // Bail out immediately if the pointer is not in the space managed by the
185 // allocator.
186 if (allocator_->IsOutsideAllocatedSpace(address)) {
187 DCHECK_EQ(nullptr,
188 allocator_->LookupChunkContainingAddressInSafepoint(address));
189 return;
190 }
191 // Proceed with inner-pointer resolution.
192 Address base_ptr = FindBasePtr(address, cage_base);
193 if (base_ptr == kNullAddress) {
194 return;
195 }
197 Tagged<Object> root = obj;
199 root_visitor_->VisitRootPointer(Root::kStackRoots, nullptr,
200 FullObjectSlot(&root));
201 // Check that the root visitor did not modify the root slot.
202 DCHECK_EQ(root, obj);
203}
204
205} // namespace internal
206} // namespace v8
207
208#endif // V8_HEAP_CONSERVATIVE_STACK_VISITOR_INL_H_
RegisterAllocator * allocator_
Address FindBasePtr(Address maybe_inner_ptr, PtrComprCageBase cage_base) const
ConservativeStackVisitorBase(Isolate *isolate, RootVisitor *root_visitor)
static Tagged< HeapObject > FromAddress(Address address)
Tagged< Map > ToMap() const
static Address FindPreviousValidObject(const PageMetadata *page, Address maybe_inner_ptr)
V8_INLINE MemoryChunkMetadata * Metadata()
static V8_INLINE void ProcessIntermediatePointers(PtrComprCageBase cage_base, Address raw_value, ProcessPointerCallback callback)
static V8_INLINE constexpr Address GetPtrComprCageBaseAddress(Address on_heap_addr)
#define ALIGN_TO_ALLOCATION_ALIGNMENT(value)
Definition globals.h:1796
GraphBuildingRootVisitor & root_visitor_
V8_INLINE constexpr bool IsFreeSpaceOrFiller(InstanceType instance_type)
static constexpr Address kNullAddress
Definition v8-internal.h:53
static constexpr RelaxedLoadTag kRelaxedLoad
Definition globals.h:2909
#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
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485