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 #include "include/cppgc/internal/pointer-policies.h"
6
7 #include "include/cppgc/internal/caged-heap-local-data.h"
8 #include "include/cppgc/internal/persistent-node.h"
9 #include "src/base/logging.h"
10 #include "src/base/macros.h"
11 #include "src/base/platform/platform.h"
12 #include "src/heap/cppgc/heap-object-header.h"
13 #include "src/heap/cppgc/heap-page.h"
14 #include "src/heap/cppgc/heap.h"
15 #include "src/heap/cppgc/page-memory.h"
16 #include "src/heap/cppgc/prefinalizer-handler.h"
17 #include "src/heap/cppgc/process-heap.h"
18
19 namespace cppgc {
20 namespace internal {
21
22 namespace {
23
24 #if defined(DEBUG)
IsOnStack(const void * address)25 bool IsOnStack(const void* address) {
26 return v8::base::Stack::GetCurrentStackPosition() <= address &&
27 address < v8::base::Stack::GetStackStart();
28 }
29 #endif // defined(DEBUG)
30
31 } // namespace
32
CheckPointerImpl(const void * ptr,bool points_to_payload,bool check_off_heap_assignments)33 void SameThreadEnabledCheckingPolicyBase::CheckPointerImpl(
34 const void* ptr, bool points_to_payload, bool check_off_heap_assignments) {
35 // `ptr` must not reside on stack.
36 DCHECK(!IsOnStack(ptr));
37 // Check for the most commonly used wrong sentinel value (-1).
38 DCHECK_NE(reinterpret_cast<void*>(-1), ptr);
39 auto* base_page = BasePage::FromPayload(ptr);
40 // Large objects do not support mixins. This also means that `base_page` is
41 // valid for large objects.
42 DCHECK_IMPLIES(base_page->is_large(), points_to_payload);
43
44 // References cannot change their heap association which means that state is
45 // immutable once it is set.
46 bool is_on_heap = true;
47 if (!heap_) {
48 heap_ = &base_page->heap();
49 if (!heap_->page_backend()->Lookup(reinterpret_cast<Address>(this))) {
50 // If `this` is not contained within the heap of `ptr`, we must deal with
51 // an on-stack or off-heap reference. For both cases there should be no
52 // heap registered.
53 is_on_heap = false;
54 CHECK(!HeapRegistry::TryFromManagedPointer(this));
55 }
56 }
57
58 // Member references should never mix heaps.
59 DCHECK_EQ(heap_, &base_page->heap());
60
61 DCHECK_EQ(heap_->GetCreationThreadId(), v8::base::OS::GetCurrentThreadId());
62
63 // Header checks.
64 const HeapObjectHeader* header = nullptr;
65 if (points_to_payload) {
66 header = &HeapObjectHeader::FromObject(ptr);
67 } else {
68 // Mixin case. Access the ObjectStartBitmap atomically since sweeping can be
69 // in progress.
70 header = &base_page->ObjectHeaderFromInnerAddress<AccessMode::kAtomic>(ptr);
71 DCHECK_LE(header->ObjectStart(), ptr);
72 DCHECK_GT(header->ObjectEnd(), ptr);
73 }
74 if (header) {
75 DCHECK(!header->IsFree());
76 }
77
78 #ifdef CPPGC_VERIFY_HEAP
79 if (check_off_heap_assignments || is_on_heap) {
80 if (heap_->prefinalizer_handler()->IsInvokingPreFinalizers()) {
81 // Slot can be in a large object.
82 const auto* slot_page = BasePage::FromInnerAddress(heap_, this);
83 // Off-heap slots (from other heaps or on-stack) are considered live.
84 bool slot_is_live =
85 !slot_page ||
86 slot_page->ObjectHeaderFromInnerAddress(this).IsMarked();
87 // During prefinalizers invocation, check that if the slot is live then
88 // |ptr| refers to a live object.
89 DCHECK_IMPLIES(slot_is_live, header->IsMarked());
90 USE(slot_is_live);
91 }
92 }
93 #else
94 USE(is_on_heap);
95 #endif // CPPGC_VERIFY_HEAP
96 }
97
GetPersistentRegion(const void * object)98 PersistentRegion& StrongPersistentPolicy::GetPersistentRegion(
99 const void* object) {
100 return BasePage::FromPayload(object)->heap().GetStrongPersistentRegion();
101 }
102
GetPersistentRegion(const void * object)103 PersistentRegion& WeakPersistentPolicy::GetPersistentRegion(
104 const void* object) {
105 return BasePage::FromPayload(object)->heap().GetWeakPersistentRegion();
106 }
107
108 CrossThreadPersistentRegion&
GetPersistentRegion(const void * object)109 StrongCrossThreadPersistentPolicy::GetPersistentRegion(const void* object) {
110 return BasePage::FromPayload(object)
111 ->heap()
112 .GetStrongCrossThreadPersistentRegion();
113 }
114
115 CrossThreadPersistentRegion&
GetPersistentRegion(const void * object)116 WeakCrossThreadPersistentPolicy::GetPersistentRegion(const void* object) {
117 return BasePage::FromPayload(object)
118 ->heap()
119 .GetWeakCrossThreadPersistentRegion();
120 }
121
122 } // namespace internal
123 } // namespace cppgc
124