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
19namespace cppgc {
20namespace internal {
21
22namespace {
23
24#if defined(DEBUG)
25bool 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
33void 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
98PersistentRegion& StrongPersistentPolicy::GetPersistentRegion(
99    const void* object) {
100  return BasePage::FromPayload(object)->heap().GetStrongPersistentRegion();
101}
102
103PersistentRegion& WeakPersistentPolicy::GetPersistentRegion(
104    const void* object) {
105  return BasePage::FromPayload(object)->heap().GetWeakPersistentRegion();
106}
107
108CrossThreadPersistentRegion&
109StrongCrossThreadPersistentPolicy::GetPersistentRegion(const void* object) {
110  return BasePage::FromPayload(object)
111      ->heap()
112      .GetStrongCrossThreadPersistentRegion();
113}
114
115CrossThreadPersistentRegion&
116WeakCrossThreadPersistentPolicy::GetPersistentRegion(const void* object) {
117  return BasePage::FromPayload(object)
118      ->heap()
119      .GetWeakCrossThreadPersistentRegion();
120}
121
122}  // namespace internal
123}  // namespace cppgc
124