// Copyright 2020 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "include/cppgc/internal/pointer-policies.h" #include "include/cppgc/internal/caged-heap-local-data.h" #include "include/cppgc/internal/persistent-node.h" #include "src/base/logging.h" #include "src/base/macros.h" #include "src/base/platform/platform.h" #include "src/heap/cppgc/heap-object-header.h" #include "src/heap/cppgc/heap-page.h" #include "src/heap/cppgc/heap.h" #include "src/heap/cppgc/page-memory.h" #include "src/heap/cppgc/prefinalizer-handler.h" #include "src/heap/cppgc/process-heap.h" namespace cppgc { namespace internal { namespace { #if defined(DEBUG) bool IsOnStack(const void* address) { return v8::base::Stack::GetCurrentStackPosition() <= address && address < v8::base::Stack::GetStackStart(); } #endif // defined(DEBUG) } // namespace void SameThreadEnabledCheckingPolicyBase::CheckPointerImpl( const void* ptr, bool points_to_payload, bool check_off_heap_assignments) { // `ptr` must not reside on stack. DCHECK(!IsOnStack(ptr)); // Check for the most commonly used wrong sentinel value (-1). DCHECK_NE(reinterpret_cast(-1), ptr); auto* base_page = BasePage::FromPayload(ptr); // Large objects do not support mixins. This also means that `base_page` is // valid for large objects. DCHECK_IMPLIES(base_page->is_large(), points_to_payload); // References cannot change their heap association which means that state is // immutable once it is set. bool is_on_heap = true; if (!heap_) { heap_ = &base_page->heap(); if (!heap_->page_backend()->Lookup(reinterpret_cast
(this))) { // If `this` is not contained within the heap of `ptr`, we must deal with // an on-stack or off-heap reference. For both cases there should be no // heap registered. is_on_heap = false; CHECK(!HeapRegistry::TryFromManagedPointer(this)); } } // Member references should never mix heaps. DCHECK_EQ(heap_, &base_page->heap()); DCHECK_EQ(heap_->GetCreationThreadId(), v8::base::OS::GetCurrentThreadId()); // Header checks. const HeapObjectHeader* header = nullptr; if (points_to_payload) { header = &HeapObjectHeader::FromObject(ptr); } else { // Mixin case. Access the ObjectStartBitmap atomically since sweeping can be // in progress. header = &base_page->ObjectHeaderFromInnerAddress(ptr); DCHECK_LE(header->ObjectStart(), ptr); DCHECK_GT(header->ObjectEnd(), ptr); } if (header) { DCHECK(!header->IsFree()); } #ifdef CPPGC_VERIFY_HEAP if (check_off_heap_assignments || is_on_heap) { if (heap_->prefinalizer_handler()->IsInvokingPreFinalizers()) { // Slot can be in a large object. const auto* slot_page = BasePage::FromInnerAddress(heap_, this); // Off-heap slots (from other heaps or on-stack) are considered live. bool slot_is_live = !slot_page || slot_page->ObjectHeaderFromInnerAddress(this).IsMarked(); // During prefinalizers invocation, check that if the slot is live then // |ptr| refers to a live object. DCHECK_IMPLIES(slot_is_live, header->IsMarked()); USE(slot_is_live); } } #else USE(is_on_heap); #endif // CPPGC_VERIFY_HEAP } PersistentRegion& StrongPersistentPolicy::GetPersistentRegion( const void* object) { return BasePage::FromPayload(object)->heap().GetStrongPersistentRegion(); } PersistentRegion& WeakPersistentPolicy::GetPersistentRegion( const void* object) { return BasePage::FromPayload(object)->heap().GetWeakPersistentRegion(); } CrossThreadPersistentRegion& StrongCrossThreadPersistentPolicy::GetPersistentRegion(const void* object) { return BasePage::FromPayload(object) ->heap() .GetStrongCrossThreadPersistentRegion(); } CrossThreadPersistentRegion& WeakCrossThreadPersistentPolicy::GetPersistentRegion(const void* object) { return BasePage::FromPayload(object) ->heap() .GetWeakCrossThreadPersistentRegion(); } } // namespace internal } // namespace cppgc