diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/v8/include/cppgc | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/v8/include/cppgc')
23 files changed, 794 insertions, 184 deletions
diff --git a/chromium/v8/include/cppgc/allocation.h b/chromium/v8/include/cppgc/allocation.h index 49ad49c34d6..ac5062ad01a 100644 --- a/chromium/v8/include/cppgc/allocation.h +++ b/chromium/v8/include/cppgc/allocation.h @@ -11,7 +11,6 @@ #include "cppgc/custom-space.h" #include "cppgc/garbage-collected.h" -#include "cppgc/heap.h" #include "cppgc/internal/api-constants.h" #include "cppgc/internal/gc-info.h" @@ -21,6 +20,15 @@ template <typename T> class MakeGarbageCollectedTraitBase; namespace internal { +class ObjectAllocator; +} // namespace internal + +/** + * AllocationHandle is used to allocate garbage-collected objects. + */ +class AllocationHandle; + +namespace internal { class V8_EXPORT MakeGarbageCollectedTraitInternal { protected: @@ -36,9 +44,10 @@ class V8_EXPORT MakeGarbageCollectedTraitInternal { atomic_mutable_bitfield->store(value, std::memory_order_release); } - static void* Allocate(cppgc::Heap* heap, size_t size, GCInfoIndex index); - static void* Allocate(cppgc::Heap* heapx, size_t size, GCInfoIndex index, - CustomSpaceIndex space_inde); + static void* Allocate(cppgc::AllocationHandle& handle, size_t size, + GCInfoIndex index); + static void* Allocate(cppgc::AllocationHandle& handle, size_t size, + GCInfoIndex index, CustomSpaceIndex space_index); friend class HeapObjectHeader; }; @@ -58,22 +67,22 @@ class MakeGarbageCollectedTraitBase private: template <typename U, typename CustomSpace> struct SpacePolicy { - static void* Allocate(Heap* heap, size_t size) { + static void* Allocate(AllocationHandle& handle, size_t size) { // Custom space. static_assert(std::is_base_of<CustomSpaceBase, CustomSpace>::value, "Custom space must inherit from CustomSpaceBase."); return internal::MakeGarbageCollectedTraitInternal::Allocate( - heap, size, internal::GCInfoTrait<T>::Index(), + handle, size, internal::GCInfoTrait<T>::Index(), CustomSpace::kSpaceIndex); } }; template <typename U> struct SpacePolicy<U, void> { - static void* Allocate(Heap* heap, size_t size) { + static void* Allocate(AllocationHandle& handle, size_t size) { // Default space. return internal::MakeGarbageCollectedTraitInternal::Allocate( - heap, size, internal::GCInfoTrait<T>::Index()); + handle, size, internal::GCInfoTrait<T>::Index()); } }; @@ -81,12 +90,14 @@ class MakeGarbageCollectedTraitBase /** * Allocates memory for an object of type T. * - * \param heap The heap to allocate this object on. + * \param handle AllocationHandle identifying the heap to allocate the object + * on. * \param size The size that should be reserved for the object. * \returns the memory to construct an object of type T on. */ - static void* Allocate(Heap* heap, size_t size) { - return SpacePolicy<T, typename SpaceTrait<T>::Space>::Allocate(heap, size); + static void* Allocate(AllocationHandle& handle, size_t size) { + return SpacePolicy<T, typename SpaceTrait<T>::Space>::Allocate(handle, + size); } /** @@ -115,14 +126,15 @@ template <typename T> class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase<T> { public: template <typename... Args> - static T* Call(Heap* heap, Args&&... args) { + static T* Call(AllocationHandle& handle, Args&&... args) { static_assert(internal::IsGarbageCollectedType<T>::value, "T needs to be a garbage collected object"); static_assert( !internal::IsGarbageCollectedMixinType<T>::value || sizeof(T) <= internal::api_constants::kLargeObjectSizeThreshold, "GarbageCollectedMixin may not be a large object"); - void* memory = MakeGarbageCollectedTraitBase<T>::Allocate(heap, sizeof(T)); + void* memory = + MakeGarbageCollectedTraitBase<T>::Allocate(handle, sizeof(T)); T* object = ::new (memory) T(std::forward<Args>(args)...); MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object); return object; @@ -149,9 +161,9 @@ struct PostConstructionCallbackTrait { * \returns an instance of type T. */ template <typename T, typename... Args> -T* MakeGarbageCollected(Heap* heap, Args&&... args) { +T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) { T* object = - MakeGarbageCollectedTrait<T>::Call(heap, std::forward<Args>(args)...); + MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...); PostConstructionCallbackTrait<T>::Call(object); return object; } diff --git a/chromium/v8/include/cppgc/garbage-collected.h b/chromium/v8/include/cppgc/garbage-collected.h index c263a9fecf0..299b861d845 100644 --- a/chromium/v8/include/cppgc/garbage-collected.h +++ b/chromium/v8/include/cppgc/garbage-collected.h @@ -8,7 +8,6 @@ #include <type_traits> #include "cppgc/internal/api-constants.h" -#include "cppgc/macros.h" #include "cppgc/platform.h" #include "cppgc/trace-trait.h" #include "cppgc/type-traits.h" @@ -161,7 +160,7 @@ class GarbageCollectedMixin : public internal::GarbageCollectedBase { } \ \ private: \ - friend class internal::__thisIsHereToForceASemicolonAfterThisMacro + static_assert(true, "Force semicolon.") /** * Merge two or more Mixins into one. @@ -185,7 +184,7 @@ class GarbageCollectedMixin : public internal::GarbageCollectedBase { } \ \ private: \ - friend class internal::__thisIsHereToForceASemicolonAfterThisMacro + static_assert(true, "Force semicolon.") } // namespace cppgc diff --git a/chromium/v8/include/cppgc/heap.h b/chromium/v8/include/cppgc/heap.h index 90046c35055..ca0dbeca7ff 100644 --- a/chromium/v8/include/cppgc/heap.h +++ b/chromium/v8/include/cppgc/heap.h @@ -10,9 +10,21 @@ #include "cppgc/common.h" #include "cppgc/custom-space.h" +#include "cppgc/platform.h" #include "v8config.h" // NOLINT(build/include_directory) +/** + * cppgc - A C++ garbage collection library. + */ namespace cppgc { + +class AllocationHandle; + +/** + * Implementation details of cppgc. Those details are considered internal and + * may change at any point in time without notice. Users should never rely on + * the contents of this namespace. + */ namespace internal { class Heap; } // namespace internal @@ -24,7 +36,44 @@ class V8_EXPORT Heap { */ using StackState = EmbedderStackState; + /** + * Specifies whether conservative stack scanning is supported. + */ + enum class StackSupport : uint8_t { + /** + * Conservative stack scan is supported. + */ + kSupportsConservativeStackScan, + /** + * Conservative stack scan is not supported. Embedders may use this option + * when using custom infrastructure that is unsupported by the library. + */ + kNoConservativeStackScan, + }; + + /** + * Constraints for a Heap setup. + */ + struct ResourceConstraints { + /** + * Allows the heap to grow to some initial size in bytes before triggering + * garbage collections. This is useful when it is known that applications + * need a certain minimum heap to run to avoid repeatedly invoking the + * garbage collector when growing the heap. + */ + size_t initial_heap_size_bytes = 0; + }; + + /** + * Options specifying Heap properties (e.g. custom spaces) when initializing a + * heap through Heap::Create(). + */ struct HeapOptions { + /** + * Creates reasonable defaults for instantiating a Heap. + * + * \returns the HeapOptions that can be passed to Heap::Create(). + */ static HeapOptions Default() { return {}; } /** @@ -33,9 +82,34 @@ class V8_EXPORT Heap { * to the index they reside in the vector. */ std::vector<std::unique_ptr<CustomSpaceBase>> custom_spaces; + + /** + * Specifies whether conserative stack scan is supported. When conservative + * stack scan is not supported, the collector may try to invoke + * garbage collections using non-nestable task, which are guaranteed to have + * no interesting stack, through the provided Platform. If such tasks are + * not supported by the Platform, the embedder must take care of invoking + * the GC through ForceGarbageCollectionSlow(). + */ + StackSupport stack_support = StackSupport::kSupportsConservativeStackScan; + + /** + * Resource constraints specifying various properties that the internal + * GC scheduler follows. + */ + ResourceConstraints resource_constraints; }; - static std::unique_ptr<Heap> Create(HeapOptions = HeapOptions::Default()); + /** + * Creates a new heap that can be used for object allocation. + * + * \param platform implemented and provided by the embedder. + * \param options HeapOptions specifying various properties for the Heap. + * \returns a new Heap instance. + */ + static std::unique_ptr<Heap> Create( + std::shared_ptr<Platform> platform, + HeapOptions options = HeapOptions::Default()); virtual ~Heap() = default; @@ -52,6 +126,8 @@ class V8_EXPORT Heap { const char* source, const char* reason, StackState stack_state = StackState::kMayContainHeapPointers); + AllocationHandle& GetAllocationHandle(); + private: Heap() = default; diff --git a/chromium/v8/include/cppgc/internal/accessors.h b/chromium/v8/include/cppgc/internal/accessors.h deleted file mode 100644 index ee0a0042fe0..00000000000 --- a/chromium/v8/include/cppgc/internal/accessors.h +++ /dev/null @@ -1,26 +0,0 @@ -// 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. - -#ifndef INCLUDE_CPPGC_INTERNAL_ACCESSORS_H_ -#define INCLUDE_CPPGC_INTERNAL_ACCESSORS_H_ - -#include "cppgc/internal/api-constants.h" - -namespace cppgc { - -class Heap; - -namespace internal { - -inline cppgc::Heap* GetHeapFromPayload(const void* payload) { - return *reinterpret_cast<cppgc::Heap**>( - ((reinterpret_cast<uintptr_t>(payload) & api_constants::kPageBaseMask) + - api_constants::kGuardPageSize) + - api_constants::kHeapOffset); -} - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_ACCESSORS_H_ diff --git a/chromium/v8/include/cppgc/internal/api-constants.h b/chromium/v8/include/cppgc/internal/api-constants.h index ef910a48571..1303b8b861f 100644 --- a/chromium/v8/include/cppgc/internal/api-constants.h +++ b/chromium/v8/include/cppgc/internal/api-constants.h @@ -17,6 +17,11 @@ namespace internal { // Internal constants to avoid exposing internal types on the API surface. namespace api_constants { + +constexpr size_t kKB = 1024; +constexpr size_t kMB = kKB * 1024; +constexpr size_t kGB = kMB * 1024; + // Offset of the uint16_t bitfield from the payload contaning the // in-construction bit. This is subtracted from the payload pointer to get // to the right bitfield. @@ -25,17 +30,15 @@ static constexpr size_t kFullyConstructedBitFieldOffsetFromPayload = // Mask for in-construction bit. static constexpr size_t kFullyConstructedBitMask = size_t{1}; -// Page constants used to align pointers to page begin. static constexpr size_t kPageSize = size_t{1} << 17; -static constexpr size_t kPageAlignment = kPageSize; -static constexpr size_t kPageBaseMask = ~(kPageAlignment - 1); -static constexpr size_t kGuardPageSize = 4096; - -// Offset of the Heap backref. -static constexpr size_t kHeapOffset = 0; static constexpr size_t kLargeObjectSizeThreshold = kPageSize / 2; +#if defined(CPPGC_CAGED_HEAP) +constexpr size_t kCagedHeapReservationSize = static_cast<size_t>(4) * kGB; +constexpr size_t kCagedHeapReservationAlignment = kCagedHeapReservationSize; +#endif + } // namespace api_constants } // namespace internal diff --git a/chromium/v8/include/cppgc/internal/atomic-entry-flag.h b/chromium/v8/include/cppgc/internal/atomic-entry-flag.h new file mode 100644 index 00000000000..5a7d3b8f8ac --- /dev/null +++ b/chromium/v8/include/cppgc/internal/atomic-entry-flag.h @@ -0,0 +1,48 @@ +// 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. + +#ifndef INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ +#define INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ + +#include <atomic> + +namespace cppgc { +namespace internal { + +// A flag which provides a fast check whether a scope may be entered on the +// current thread, without needing to access thread-local storage or mutex. Can +// have false positives (i.e., spuriously report that it might be entered), so +// it is expected that this will be used in tandem with a precise check that the +// scope is in fact entered on that thread. +// +// Example: +// g_frobnicating_flag.MightBeEntered() && +// ThreadLocalFrobnicator().IsFrobnicating() +// +// Relaxed atomic operations are sufficient, since: +// - all accesses remain atomic +// - each thread must observe its own operations in order +// - no thread ever exits the flag more times than it enters (if used correctly) +// And so if a thread observes zero, it must be because it has observed an equal +// number of exits as entries. +class AtomicEntryFlag final { + public: + void Enter() { entries_.fetch_add(1, std::memory_order_relaxed); } + void Exit() { entries_.fetch_sub(1, std::memory_order_relaxed); } + + // Returns false only if the current thread is not between a call to Enter + // and a call to Exit. Returns true if this thread or another thread may + // currently be in the scope guarded by this flag. + bool MightBeEntered() const { + return entries_.load(std::memory_order_relaxed) != 0; + } + + private: + std::atomic_int entries_{0}; +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ diff --git a/chromium/v8/include/cppgc/internal/caged-heap-local-data.h b/chromium/v8/include/cppgc/internal/caged-heap-local-data.h new file mode 100644 index 00000000000..8c421477384 --- /dev/null +++ b/chromium/v8/include/cppgc/internal/caged-heap-local-data.h @@ -0,0 +1,67 @@ +// 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. + +#ifndef INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ +#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ + +#include <array> + +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/logging.h" +#include "cppgc/platform.h" + +namespace cppgc { +namespace internal { + +class HeapBase; + +#if defined(CPPGC_YOUNG_GENERATION) + +// AgeTable contains entries that correspond to 4KB memory regions. Each entry +// can be in one of three states: kOld, kYoung or kUnknown. +class AgeTable final { + static constexpr size_t kGranularityBits = 12; // 4KiB per byte. + + public: + enum class Age : uint8_t { kOld, kYoung, kUnknown }; + + static constexpr size_t kEntrySizeInBytes = 1 << kGranularityBits; + + Age& operator[](uintptr_t offset) { return table_[entry(offset)]; } + Age operator[](uintptr_t offset) const { return table_[entry(offset)]; } + + void Reset(PageAllocator* allocator); + + private: + static constexpr size_t kAgeTableSize = + api_constants::kCagedHeapReservationSize >> kGranularityBits; + + size_t entry(uintptr_t offset) const { + const size_t entry = offset >> kGranularityBits; + CPPGC_DCHECK(table_.size() > entry); + return entry; + } + + std::array<Age, kAgeTableSize> table_; +}; + +static_assert(sizeof(AgeTable) == 1 * api_constants::kMB, + "Size of AgeTable is 1MB"); + +#endif // CPPGC_YOUNG_GENERATION + +struct CagedHeapLocalData final { + explicit CagedHeapLocalData(HeapBase* heap_base) : heap_base(heap_base) {} + + bool is_marking_in_progress = false; + HeapBase* heap_base = nullptr; +#if defined(CPPGC_YOUNG_GENERATION) + AgeTable age_table; +#endif +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ diff --git a/chromium/v8/include/cppgc/internal/compiler-specific.h b/chromium/v8/include/cppgc/internal/compiler-specific.h index e1f5c1d57fb..c580894b35d 100644 --- a/chromium/v8/include/cppgc/internal/compiler-specific.h +++ b/chromium/v8/include/cppgc/internal/compiler-specific.h @@ -7,6 +7,12 @@ namespace cppgc { +#if defined(__has_attribute) +#define CPPGC_HAS_ATTRIBUTE(FEATURE) __has_attribute(FEATURE) +#else +#define CPPGC_HAS_ATTRIBUTE(FEATURE) 0 +#endif + #if defined(__has_cpp_attribute) #define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) __has_cpp_attribute(FEATURE) #else @@ -21,6 +27,12 @@ namespace cppgc { #define CPPGC_NO_UNIQUE_ADDRESS #endif +#if CPPGC_HAS_ATTRIBUTE(unused) // NOLINTNEXTLINE +#define CPPGC_UNUSED __attribute__((unused)) +#else +#define CPPGC_UNUSED +#endif + } // namespace cppgc #endif // INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ diff --git a/chromium/v8/include/cppgc/internal/gc-info.h b/chromium/v8/include/cppgc/internal/gc-info.h index 9aac1361c61..3d361e6d71a 100644 --- a/chromium/v8/include/cppgc/internal/gc-info.h +++ b/chromium/v8/include/cppgc/internal/gc-info.h @@ -8,6 +8,7 @@ #include <stdint.h> #include "cppgc/internal/finalizer-trait.h" +#include "cppgc/trace-trait.h" #include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { @@ -18,7 +19,7 @@ using GCInfoIndex = uint16_t; class V8_EXPORT RegisteredGCInfoIndex final { public: RegisteredGCInfoIndex(FinalizationCallback finalization_callback, - bool has_v_table); + TraceCallback trace_callback, bool has_v_table); GCInfoIndex GetIndex() const { return index_; } private: @@ -32,7 +33,8 @@ struct GCInfoTrait { static GCInfoIndex Index() { static_assert(sizeof(T), "T must be fully defined"); static const RegisteredGCInfoIndex registered_index( - FinalizerTrait<T>::kCallback, std::is_polymorphic<T>::value); + FinalizerTrait<T>::kCallback, TraceTrait<T>::Trace, + std::is_polymorphic<T>::value); return registered_index.GetIndex(); } }; diff --git a/chromium/v8/include/cppgc/internal/persistent-node.h b/chromium/v8/include/cppgc/internal/persistent-node.h index 11cf69623e8..e05efe36213 100644 --- a/chromium/v8/include/cppgc/internal/persistent-node.h +++ b/chromium/v8/include/cppgc/internal/persistent-node.h @@ -56,6 +56,11 @@ class PersistentNode final { bool IsUsed() const { return trace_; } + void* owner() const { + CPPGC_DCHECK(IsUsed()); + return owner_; + } + private: // PersistentNode acts as a designated union: // If trace_ != nullptr, owner_ points to the corresponding Persistent handle. @@ -67,11 +72,13 @@ class PersistentNode final { TraceCallback trace_ = nullptr; }; -class V8_EXPORT PersistentRegion { +class V8_EXPORT PersistentRegion final { using PersistentNodeSlots = std::array<PersistentNode, 256u>; public: PersistentRegion() = default; + // Clears Persistent fields to avoid stale pointers after heap teardown. + ~PersistentRegion(); PersistentRegion(const PersistentRegion&) = delete; PersistentRegion& operator=(const PersistentRegion&) = delete; diff --git a/chromium/v8/include/cppgc/internal/pointer-policies.h b/chromium/v8/include/cppgc/internal/pointer-policies.h index fe8d94b57a6..a6cd4e8586d 100644 --- a/chromium/v8/include/cppgc/internal/pointer-policies.h +++ b/chromium/v8/include/cppgc/internal/pointer-policies.h @@ -8,6 +8,7 @@ #include <cstdint> #include <type_traits> +#include "cppgc/internal/write-barrier.h" #include "cppgc/source-location.h" #include "v8config.h" // NOLINT(build/include_directory) @@ -26,8 +27,8 @@ struct DijkstraWriteBarrierPolicy { // Since in initializing writes the source object is always white, having no // barrier doesn't break the tri-color invariant. } - static void AssigningBarrier(const void*, const void*) { - // TODO(chromium:1056170): Add actual implementation. + static void AssigningBarrier(const void* slot, const void* value) { + WriteBarrier::MarkingBarrier(slot, value); } }; @@ -116,7 +117,7 @@ class BasicMember; struct SentinelPointer { template <typename T> operator T*() const { // NOLINT - static constexpr intptr_t kSentinelValue = -1; + static constexpr intptr_t kSentinelValue = 1; return reinterpret_cast<T*>(kSentinelValue); } // Hidden friends. diff --git a/chromium/v8/include/cppgc/internal/prefinalizer-handler.h b/chromium/v8/include/cppgc/internal/prefinalizer-handler.h index 939a9b8ff0a..ea0eca02a0e 100644 --- a/chromium/v8/include/cppgc/internal/prefinalizer-handler.h +++ b/chromium/v8/include/cppgc/internal/prefinalizer-handler.h @@ -15,14 +15,13 @@ class V8_EXPORT PreFinalizerRegistrationDispatcher final { public: using PreFinalizerCallback = bool (*)(const LivenessBroker&, void*); struct PreFinalizer { - void* object_; - PreFinalizerCallback callback_; + void* object; + PreFinalizerCallback callback; bool operator==(const PreFinalizer& other); }; - static void RegisterPrefinalizer(cppgc::Heap* heap, - PreFinalizer prefinalzier); + static void RegisterPrefinalizer(PreFinalizer pre_finalizer); }; } // namespace internal diff --git a/chromium/v8/include/cppgc/internal/process-heap.h b/chromium/v8/include/cppgc/internal/process-heap.h new file mode 100644 index 00000000000..0f742a50a9c --- /dev/null +++ b/chromium/v8/include/cppgc/internal/process-heap.h @@ -0,0 +1,34 @@ +// 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. + +#ifndef INCLUDE_CPPGC_INTERNAL_PROCESS_HEAP_H_ +#define INCLUDE_CPPGC_INTERNAL_PROCESS_HEAP_H_ + +#include "cppgc/internal/atomic-entry-flag.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +class V8_EXPORT ProcessHeap final { + public: + static void EnterIncrementalOrConcurrentMarking() { + concurrent_marking_flag_.Enter(); + } + static void ExitIncrementalOrConcurrentMarking() { + concurrent_marking_flag_.Exit(); + } + + static bool IsAnyIncrementalOrConcurrentMarking() { + return concurrent_marking_flag_.MightBeEntered(); + } + + private: + static AtomicEntryFlag concurrent_marking_flag_; +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_PROCESS_HEAP_H_ diff --git a/chromium/v8/include/cppgc/internal/write-barrier.h b/chromium/v8/include/cppgc/internal/write-barrier.h new file mode 100644 index 00000000000..5bf550b0261 --- /dev/null +++ b/chromium/v8/include/cppgc/internal/write-barrier.h @@ -0,0 +1,78 @@ +// 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. + +#ifndef INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ +#define INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ + +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/process-heap.h" +#include "v8config.h" // NOLINT(build/include_directory) + +#if defined(CPPGC_CAGED_HEAP) +#include "cppgc/internal/caged-heap-local-data.h" +#endif + +namespace cppgc { +namespace internal { + +class V8_EXPORT WriteBarrier final { + public: + static V8_INLINE void MarkingBarrier(const void* slot, const void* value) { +#if defined(CPPGC_CAGED_HEAP) + const uintptr_t start = + reinterpret_cast<uintptr_t>(value) & + ~(api_constants::kCagedHeapReservationAlignment - 1); + const uintptr_t slot_offset = reinterpret_cast<uintptr_t>(slot) - start; + if (slot_offset > api_constants::kCagedHeapReservationSize) { + // Check if slot is on stack or value is sentinel or nullptr. This relies + // on the fact that kSentinelPointer is encoded as 0x1. + return; + } + + CagedHeapLocalData* local_data = + reinterpret_cast<CagedHeapLocalData*>(start); + if (V8_UNLIKELY(local_data->is_marking_in_progress)) { + MarkingBarrierSlow(value); + return; + } +#if defined(CPPGC_YOUNG_GENERATION) + GenerationalBarrier(local_data, slot, slot_offset, + reinterpret_cast<uintptr_t>(value) - start); +#endif +#else + if (V8_LIKELY(!ProcessHeap::IsAnyIncrementalOrConcurrentMarking())) return; + + MarkingBarrierSlowWithSentinelCheck(value); +#endif // CPPGC_CAGED_HEAP + } + + private: + WriteBarrier() = delete; + + static void MarkingBarrierSlow(const void* value); + static void MarkingBarrierSlowWithSentinelCheck(const void* value); + +#if defined(CPPGC_YOUNG_GENERATION) + static V8_INLINE void GenerationalBarrier(CagedHeapLocalData* local_data, + const void* slot, + uintptr_t slot_offset, + uintptr_t value_offset) { + const AgeTable& age_table = local_data->age_table; + + // Bail out if the slot is in young generation. + if (V8_LIKELY(age_table[slot_offset] == AgeTable::Age::kYoung)) return; + + GenerationalBarrierSlow(local_data, age_table, slot, value_offset); + } + + static void GenerationalBarrierSlow(CagedHeapLocalData* local_data, + const AgeTable& ageTable, + const void* slot, uintptr_t value_offset); +#endif +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ diff --git a/chromium/v8/include/cppgc/liveness-broker.h b/chromium/v8/include/cppgc/liveness-broker.h index 69dbc11f1f4..883be46240f 100644 --- a/chromium/v8/include/cppgc/liveness-broker.h +++ b/chromium/v8/include/cppgc/liveness-broker.h @@ -16,6 +16,30 @@ namespace internal { class LivenessBrokerFactory; } // namespace internal +/** + * The broker is passed to weak callbacks to allow (temporarily) querying + * the liveness state of an object. References to non-live objects must be + * cleared when IsHeapObjectAlive() returns false. + * + * \code + * class GCedWithCustomWeakCallback final + * : public GarbageCollected<GCedWithCustomWeakCallback> { + * public: + * UntracedMember<Bar> bar; + * + * void CustomWeakCallbackMethod(const LivenessBroker& broker) { + * if (!broker.IsHeapObjectAlive(bar)) + * bar = nullptr; + * } + * + * void Trace(cppgc::Visitor* visitor) const { + * visitor->RegisterWeakCallbackMethod< + * GCedWithCustomWeakCallback, + * &GCedWithCustomWeakCallback::CustomWeakCallbackMethod>(this); + * } + * }; + * \endcode + */ class V8_EXPORT LivenessBroker final { public: template <typename T> @@ -26,12 +50,6 @@ class V8_EXPORT LivenessBroker final { } template <typename T> - bool IsHeapObjectAlive(const WeakMember<T>& weak_member) const { - return (weak_member != kSentinelPointer) && - IsHeapObjectAlive<T>(weak_member.Get()); - } - - template <typename T> bool IsHeapObjectAlive(const UntracedMember<T>& untraced_member) const { return (untraced_member != kSentinelPointer) && IsHeapObjectAlive<T>(untraced_member.Get()); diff --git a/chromium/v8/include/cppgc/macros.h b/chromium/v8/include/cppgc/macros.h index 7c7a10e433a..c0b1814e294 100644 --- a/chromium/v8/include/cppgc/macros.h +++ b/chromium/v8/include/cppgc/macros.h @@ -5,21 +5,19 @@ #ifndef INCLUDE_CPPGC_MACROS_H_ #define INCLUDE_CPPGC_MACROS_H_ -namespace cppgc { +#include "cppgc/internal/compiler-specific.h" -namespace internal { -class __thisIsHereToForceASemicolonAfterThisMacro {}; -} // namespace internal +namespace cppgc { // Use if the object is only stack allocated. -#define CPPGC_STACK_ALLOCATED() \ - public: \ - using IsStackAllocatedTypeMarker = int; \ - \ - private: \ - void* operator new(size_t) = delete; \ - void* operator new(size_t, void*) = delete; \ - friend class internal::__thisIsHereToForceASemicolonAfterThisMacro +#define CPPGC_STACK_ALLOCATED() \ + public: \ + using IsStackAllocatedTypeMarker CPPGC_UNUSED = int; \ + \ + private: \ + void* operator new(size_t) = delete; \ + void* operator new(size_t, void*) = delete; \ + static_assert(true, "Force semicolon.") } // namespace cppgc diff --git a/chromium/v8/include/cppgc/member.h b/chromium/v8/include/cppgc/member.h index a183edb96fd..22c1adc0af7 100644 --- a/chromium/v8/include/cppgc/member.h +++ b/chromium/v8/include/cppgc/member.h @@ -19,19 +19,43 @@ class Visitor; namespace internal { +class MemberBase { + protected: + MemberBase() = default; + explicit MemberBase(void* value) : raw_(value) {} + + void* const* GetRawSlot() const { return &raw_; } + void* GetRaw() const { return raw_; } + void SetRaw(void* value) { raw_ = value; } + + void* GetRawAtomic() const { + return reinterpret_cast<const std::atomic<void*>*>(&raw_)->load( + std::memory_order_relaxed); + } + void SetRawAtomic(void* value) { + reinterpret_cast<std::atomic<void*>*>(&raw_)->store( + value, std::memory_order_relaxed); + } + + void ClearFromGC() const { raw_ = nullptr; } + + private: + mutable void* raw_ = nullptr; +}; + // The basic class from which all Member classes are 'generated'. template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, typename CheckingPolicy> -class BasicMember : private CheckingPolicy { +class BasicMember final : private MemberBase, private CheckingPolicy { public: using PointeeType = T; constexpr BasicMember() = default; constexpr BasicMember(std::nullptr_t) {} // NOLINT - BasicMember(SentinelPointer s) : raw_(s) {} // NOLINT - BasicMember(T* raw) : raw_(raw) { // NOLINT + BasicMember(SentinelPointer s) : MemberBase(s) {} // NOLINT + BasicMember(T* raw) : MemberBase(raw) { // NOLINT InitializingWriteBarrier(); - this->CheckPointer(raw_); + this->CheckPointer(Get()); } BasicMember(T& raw) : BasicMember(&raw) {} // NOLINT BasicMember(const BasicMember& other) : BasicMember(other.Get()) {} @@ -106,9 +130,12 @@ class BasicMember : private CheckingPolicy { T* operator->() const { return Get(); } T& operator*() const { return *Get(); } - T* Get() const { + // CFI cast exemption to allow passing SentinelPointer through T* and support + // heterogeneous assignments between different Member and Persistent handles + // based on their actual types. + V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { // Executed by the mutator, hence non atomic load. - return raw_; + return static_cast<T*>(MemberBase::GetRaw()); } void Clear() { SetRawAtomic(nullptr); } @@ -120,25 +147,18 @@ class BasicMember : private CheckingPolicy { } private: - void SetRawAtomic(T* raw) { - reinterpret_cast<std::atomic<T*>*>(&raw_)->store(raw, - std::memory_order_relaxed); - } T* GetRawAtomic() const { - return reinterpret_cast<const std::atomic<T*>*>(&raw_)->load( - std::memory_order_relaxed); + return static_cast<T*>(MemberBase::GetRawAtomic()); } void InitializingWriteBarrier() const { - WriteBarrierPolicy::InitializingBarrier( - reinterpret_cast<const void*>(&raw_), static_cast<const void*>(raw_)); + WriteBarrierPolicy::InitializingBarrier(GetRawSlot(), GetRaw()); } void AssigningWriteBarrier() const { - WriteBarrierPolicy::AssigningBarrier(reinterpret_cast<const void*>(&raw_), - static_cast<const void*>(raw_)); + WriteBarrierPolicy::AssigningBarrier(GetRawSlot(), GetRaw()); } - T* raw_ = nullptr; + void ClearFromGC() const { MemberBase::ClearFromGC(); } friend class cppgc::Visitor; }; diff --git a/chromium/v8/include/cppgc/persistent.h b/chromium/v8/include/cppgc/persistent.h index fc6b0b9d92e..c2d8a7a5a64 100644 --- a/chromium/v8/include/cppgc/persistent.h +++ b/chromium/v8/include/cppgc/persistent.h @@ -15,14 +15,43 @@ #include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { + +class Visitor; + namespace internal { +class PersistentBase { + protected: + PersistentBase() = default; + explicit PersistentBase(void* raw) : raw_(raw) {} + + void* GetValue() const { return raw_; } + void SetValue(void* value) { raw_ = value; } + + PersistentNode* GetNode() const { return node_; } + void SetNode(PersistentNode* node) { node_ = node; } + + // Performs a shallow clear which assumes that internal persistent nodes are + // destroyed elsewhere. + void ClearFromGC() const { + raw_ = nullptr; + node_ = nullptr; + } + + private: + mutable void* raw_ = nullptr; + mutable PersistentNode* node_ = nullptr; + + friend class PersistentRegion; +}; + // The basic class from which all Persistent classes are generated. template <typename T, typename WeaknessPolicy, typename LocationPolicy, typename CheckingPolicy> -class BasicPersistent : public LocationPolicy, - private WeaknessPolicy, - private CheckingPolicy { +class BasicPersistent final : public PersistentBase, + public LocationPolicy, + private WeaknessPolicy, + private CheckingPolicy { public: using typename WeaknessPolicy::IsStrongPersistent; using PointeeType = T; @@ -38,15 +67,15 @@ class BasicPersistent : public LocationPolicy, BasicPersistent( // NOLINT SentinelPointer s, const SourceLocation& loc = SourceLocation::Current()) - : LocationPolicy(loc), raw_(s) {} + : PersistentBase(s), LocationPolicy(loc) {} - // Raw value contstructors. + // Raw value constructors. BasicPersistent(T* raw, // NOLINT const SourceLocation& loc = SourceLocation::Current()) - : LocationPolicy(loc), raw_(raw) { + : PersistentBase(raw), LocationPolicy(loc) { if (!IsValid()) return; - node_ = WeaknessPolicy::GetPersistentRegion(raw_).AllocateNode( - this, &BasicPersistent::Trace); + SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) + .AllocateNode(this, &BasicPersistent::Trace)); this->CheckPointer(Get()); } @@ -74,13 +103,11 @@ class BasicPersistent : public LocationPolicy, BasicPersistent( BasicPersistent&& other, const SourceLocation& loc = SourceLocation::Current()) noexcept - : LocationPolicy(std::move(other)), - raw_(std::move(other.raw_)), - node_(std::move(other.node_)) { + : PersistentBase(std::move(other)), LocationPolicy(std::move(other)) { if (!IsValid()) return; - node_->UpdateOwner(this); - other.raw_ = nullptr; - other.node_ = nullptr; + GetNode()->UpdateOwner(this); + other.SetValue(nullptr); + other.SetNode(nullptr); this->CheckPointer(Get()); } @@ -114,13 +141,12 @@ class BasicPersistent : public LocationPolicy, BasicPersistent& operator=(BasicPersistent&& other) { if (this == &other) return *this; Clear(); + PersistentBase::operator=(std::move(other)); LocationPolicy::operator=(std::move(other)); - raw_ = std::move(other.raw_); - node_ = std::move(other.node_); if (!IsValid()) return *this; - node_->UpdateOwner(this); - other.raw_ = nullptr; - other.node_ = nullptr; + GetNode()->UpdateOwner(this); + other.SetValue(nullptr); + other.SetNode(nullptr); this->CheckPointer(Get()); return *this; } @@ -156,7 +182,12 @@ class BasicPersistent : public LocationPolicy, T* operator->() const { return Get(); } T& operator*() const { return *Get(); } - T* Get() const { return raw_; } + // CFI cast exemption to allow passing SentinelPointer through T* and support + // heterogeneous assignments between different Member and Persistent handles + // based on their actual types. + V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { + return static_cast<T*>(GetValue()); + } void Clear() { Assign(nullptr); } @@ -176,29 +207,35 @@ class BasicPersistent : public LocationPolicy, // Ideally, handling kSentinelPointer would be done by the embedder. On the // other hand, having Persistent aware of it is beneficial since no node // gets wasted. - return raw_ != nullptr && raw_ != kSentinelPointer; + return GetValue() != nullptr && GetValue() != kSentinelPointer; } void Assign(T* ptr) { if (IsValid()) { if (ptr && ptr != kSentinelPointer) { // Simply assign the pointer reusing the existing node. - raw_ = ptr; + SetValue(ptr); this->CheckPointer(ptr); return; } - WeaknessPolicy::GetPersistentRegion(raw_).FreeNode(node_); - node_ = nullptr; + WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); + SetNode(nullptr); } - raw_ = ptr; + SetValue(ptr); if (!IsValid()) return; - node_ = WeaknessPolicy::GetPersistentRegion(raw_).AllocateNode( - this, &BasicPersistent::Trace); + SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) + .AllocateNode(this, &BasicPersistent::Trace)); this->CheckPointer(Get()); } - T* raw_ = nullptr; - PersistentNode* node_ = nullptr; + void ClearFromGC() const { + if (IsValid()) { + WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); + PersistentBase::ClearFromGC(); + } + } + + friend class cppgc::Visitor; }; template <typename T1, typename WeaknessPolicy1, typename LocationPolicy1, diff --git a/chromium/v8/include/cppgc/platform.h b/chromium/v8/include/cppgc/platform.h index 8dc5e14a7d6..72694c6ee13 100644 --- a/chromium/v8/include/cppgc/platform.h +++ b/chromium/v8/include/cppgc/platform.h @@ -10,16 +10,114 @@ namespace cppgc { -// TODO(v8:10346): Put PageAllocator in a non-V8 include header to avoid -// depending on namespace v8. +// TODO(v8:10346): Create separate includes for concepts that are not +// V8-specific. +using IdleTask = v8::IdleTask; +using JobHandle = v8::JobHandle; +using JobTask = v8::JobTask; using PageAllocator = v8::PageAllocator; +using Task = v8::Task; +using TaskPriority = v8::TaskPriority; +using TaskRunner = v8::TaskRunner; -// Initializes the garbage collector with the provided platform. Must be called -// before creating a Heap. -V8_EXPORT void InitializePlatform(PageAllocator* page_allocator); +/** + * Platform interface used by Heap. Contains allocators and executors. + */ +class V8_EXPORT Platform { + public: + virtual ~Platform() = default; -// Must be called after destroying the last used heap. -V8_EXPORT void ShutdownPlatform(); + /** + * Returns the allocator used by cppgc to allocate its heap and various + * support structures. + */ + virtual PageAllocator* GetPageAllocator() = 0; + + /** + * Monotonically increasing time in seconds from an arbitrary fixed point in + * the past. This function is expected to return at least + * millisecond-precision values. For this reason, + * it is recommended that the fixed point be no further in the past than + * the epoch. + **/ + virtual double MonotonicallyIncreasingTime() = 0; + + /** + * Foreground task runner that should be used by a Heap. + */ + virtual std::shared_ptr<TaskRunner> GetForegroundTaskRunner() { + return nullptr; + } + + /** + * Posts |job_task| to run in parallel. Returns a JobHandle associated with + * the Job, which can be joined or canceled. + * This avoids degenerate cases: + * - Calling CallOnWorkerThread() for each work item, causing significant + * overhead. + * - Fixed number of CallOnWorkerThread() calls that split the work and might + * run for a long time. This is problematic when many components post + * "num cores" tasks and all expect to use all the cores. In these cases, + * the scheduler lacks context to be fair to multiple same-priority requests + * and/or ability to request lower priority work to yield when high priority + * work comes in. + * A canonical implementation of |job_task| looks like: + * class MyJobTask : public JobTask { + * public: + * MyJobTask(...) : worker_queue_(...) {} + * // JobTask: + * void Run(JobDelegate* delegate) override { + * while (!delegate->ShouldYield()) { + * // Smallest unit of work. + * auto work_item = worker_queue_.TakeWorkItem(); // Thread safe. + * if (!work_item) return; + * ProcessWork(work_item); + * } + * } + * + * size_t GetMaxConcurrency() const override { + * return worker_queue_.GetSize(); // Thread safe. + * } + * }; + * auto handle = PostJob(TaskPriority::kUserVisible, + * std::make_unique<MyJobTask>(...)); + * handle->Join(); + * + * PostJob() and methods of the returned JobHandle/JobDelegate, must never be + * called while holding a lock that could be acquired by JobTask::Run or + * JobTask::GetMaxConcurrency -- that could result in a deadlock. This is + * because [1] JobTask::GetMaxConcurrency may be invoked while holding + * internal lock (A), hence JobTask::GetMaxConcurrency can only use a lock (B) + * if that lock is *never* held while calling back into JobHandle from any + * thread (A=>B/B=>A deadlock) and [2] JobTask::Run or + * JobTask::GetMaxConcurrency may be invoked synchronously from JobHandle + * (B=>JobHandle::foo=>B deadlock). + * + * A sufficient PostJob() implementation that uses the default Job provided in + * libplatform looks like: + * std::unique_ptr<JobHandle> PostJob( + * TaskPriority priority, std::unique_ptr<JobTask> job_task) override { + * return std::make_unique<DefaultJobHandle>( + * std::make_shared<DefaultJobState>( + * this, std::move(job_task), kNumThreads)); + * } + */ + virtual std::unique_ptr<JobHandle> PostJob( + TaskPriority priority, std::unique_ptr<JobTask> job_task) { + return nullptr; + } +}; + +/** + * Process-global initialization of the garbage collector. Must be called before + * creating a Heap. + */ +V8_EXPORT void InitializeProcess(PageAllocator*); + +/** + * Must be called after destroying the last used heap. + */ +V8_EXPORT void ShutdownProcess(); namespace internal { diff --git a/chromium/v8/include/cppgc/prefinalizer.h b/chromium/v8/include/cppgc/prefinalizer.h index 2f6d68a1dac..75764d02cde 100644 --- a/chromium/v8/include/cppgc/prefinalizer.h +++ b/chromium/v8/include/cppgc/prefinalizer.h @@ -5,11 +5,9 @@ #ifndef INCLUDE_CPPGC_PREFINALIZER_H_ #define INCLUDE_CPPGC_PREFINALIZER_H_ -#include "cppgc/internal/accessors.h" #include "cppgc/internal/compiler-specific.h" #include "cppgc/internal/prefinalizer-handler.h" #include "cppgc/liveness-broker.h" -#include "cppgc/macros.h" namespace cppgc { @@ -23,7 +21,7 @@ class PrefinalizerRegistration final { "USING_PRE_FINALIZER(T) must be defined."); cppgc::internal::PreFinalizerRegistrationDispatcher::RegisterPrefinalizer( - internal::GetHeapFromPayload(self), {self, T::InvokePreFinalizer}); + {self, T::InvokePreFinalizer}); } void* operator new(size_t, void* location) = delete; @@ -47,7 +45,7 @@ class PrefinalizerRegistration final { private: \ CPPGC_NO_UNIQUE_ADDRESS internal::PrefinalizerRegistration<Class> \ prefinalizer_dummy_{this}; \ - friend class internal::__thisIsHereToForceASemicolonAfterThisMacro + static_assert(true, "Force semicolon.") } // namespace cppgc diff --git a/chromium/v8/include/cppgc/source-location.h b/chromium/v8/include/cppgc/source-location.h index 8cc52d6a539..139c9d86c08 100644 --- a/chromium/v8/include/cppgc/source-location.h +++ b/chromium/v8/include/cppgc/source-location.h @@ -23,10 +23,16 @@ namespace cppgc { -// Encapsulates source location information. Mimics C++20's -// std::source_location. +/** + * Encapsulates source location information. Mimics C++20's + * std::source_location. + */ class V8_EXPORT SourceLocation final { public: + /** + * Construct source location information corresponding to the location of the + * call site. + */ #if CPPGC_SUPPORTS_SOURCE_LOCATION static constexpr SourceLocation Current( const char* function = __builtin_FUNCTION(), @@ -37,12 +43,38 @@ class V8_EXPORT SourceLocation final { static constexpr SourceLocation Current() { return SourceLocation(); } #endif // CPPGC_SUPPORTS_SOURCE_LOCATION + /** + * Constructs unspecified source location information. + */ constexpr SourceLocation() = default; + /** + * Returns the name of the function associated with the position represented + * by this object, if any. + * + * \returns the function name as cstring. + */ constexpr const char* Function() const { return function_; } + + /** + * Returns the name of the current source file represented by this object. + * + * \returns the file name as cstring. + */ constexpr const char* FileName() const { return file_; } + + /** + * Returns the line number represented by this object. + * + * \returns the line number. + */ constexpr size_t Line() const { return line_; } + /** + * Returns a human-readable string representing this object. + * + * \returns a human-readable string representing source location information. + */ std::string ToString() const; private: diff --git a/chromium/v8/include/cppgc/trace-trait.h b/chromium/v8/include/cppgc/trace-trait.h index e246bc53b7d..59e0b14c451 100644 --- a/chromium/v8/include/cppgc/trace-trait.h +++ b/chromium/v8/include/cppgc/trace-trait.h @@ -14,6 +14,8 @@ class Visitor; namespace internal { +// Implementation of the default TraceTrait handling GarbageCollected and +// GarbageCollectedMixin. template <typename T, bool = IsGarbageCollectedMixinTypeV<typename std::remove_const<T>::type>> @@ -21,25 +23,57 @@ struct TraceTraitImpl; } // namespace internal -using TraceCallback = void (*)(Visitor*, const void*); - -// TraceDescriptor is used to describe how to trace an object. +/** + * Callback for invoking tracing on a given object. + * + * \param visitor The visitor to dispatch to. + * \param object The object to invoke tracing on. + */ +using TraceCallback = void (*)(Visitor* visitor, const void* object); + +/** + * Describes how to trace an object, i.e., how to visit all Oilpan-relevant + * fields of an object. + */ struct TraceDescriptor { - // The adjusted base pointer of the object that should be traced. + /** + * Adjusted base pointer, i.e., the pointer to the class inheriting directly + * from GarbageCollected, of the object that is being traced. + */ const void* base_object_payload; - // A callback for tracing the object. + /** + * Callback for tracing the object. + */ TraceCallback callback; }; +/** + * Trait specifying how the garbage collector processes an object of type T. + * + * Advanced users may override handling by creating a specialization for their + * type. + */ template <typename T> struct TraceTrait { static_assert(internal::IsTraceableV<T>, "T must have a Trace() method"); + /** + * Accessor for retrieving a TraceDescriptor to process an object of type T. + * + * \param self The object to be processed. + * \returns a TraceDescriptor to process the object. + */ static TraceDescriptor GetTraceDescriptor(const void* self) { return internal::TraceTraitImpl<T>::GetTraceDescriptor( static_cast<const T*>(self)); } + /** + * Function invoking the tracing for an object of type T. + * + * \param visitor The visitor to dispatch to. + * \param self The object to invoke tracing on. + */ static void Trace(Visitor* visitor, const void* self) { static_cast<const T*>(self)->Trace(visitor); } diff --git a/chromium/v8/include/cppgc/visitor.h b/chromium/v8/include/cppgc/visitor.h index a73a4abb2bd..b70fde537bd 100644 --- a/chromium/v8/include/cppgc/visitor.h +++ b/chromium/v8/include/cppgc/visitor.h @@ -14,7 +14,11 @@ #include "cppgc/trace-trait.h" namespace cppgc { + namespace internal { +template <typename T, typename WeaknessPolicy, typename LocationPolicy, + typename CheckingPolicy> +class BasicPersistent; class VisitorBase; } // namespace internal @@ -22,10 +26,28 @@ using WeakCallback = void (*)(const LivenessBroker&, const void*); /** * Visitor passed to trace methods. All managed pointers must have called the - * visitor's trace method on them. + * Visitor's trace method on them. + * + * \code + * class Foo final : public GarbageCollected<Foo> { + * public: + * void Trace(Visitor* visitor) const { + * visitor->Trace(foo_); + * visitor->Trace(weak_foo_); + * } + * private: + * Member<Foo> foo_; + * WeakMember<Foo> weak_foo_; + * }; + * \endcode */ class Visitor { public: + /** + * Trace method for Member. + * + * \param member Member reference retaining an object. + */ template <typename T> void Trace(const Member<T>& member) { const T* value = member.GetRawAtomic(); @@ -33,11 +55,16 @@ class Visitor { Trace(value); } + /** + * Trace method for WeakMember. + * + * \param weak_member WeakMember reference weakly retaining an object. + */ template <typename T> void Trace(const WeakMember<T>& weak_member) { - static_assert(sizeof(T), "T must be fully defined"); + static_assert(sizeof(T), "Pointee type must be fully defined."); static_assert(internal::IsGarbageCollectedType<T>::value, - "T must be GarabgeCollected or GarbageCollectedMixin type"); + "T must be GarbageCollected or GarbageCollectedMixin type"); const T* value = weak_member.GetRawAtomic(); @@ -52,41 +79,42 @@ class Visitor { &HandleWeak<WeakMember<T>>, &weak_member); } - template <typename Persistent, - std::enable_if_t<Persistent::IsStrongPersistent::value>* = nullptr> - void TraceRoot(const Persistent& p, const SourceLocation& loc) { - using PointeeType = typename Persistent::PointeeType; - static_assert(sizeof(PointeeType), - "Persistent's pointee type must be fully defined"); - static_assert(internal::IsGarbageCollectedType<PointeeType>::value, - "Persisent's pointee type must be GarabgeCollected or " - "GarbageCollectedMixin"); - if (!p.Get()) { - return; - } - VisitRoot(p.Get(), TraceTrait<PointeeType>::GetTraceDescriptor(p.Get())); - } - - template < - typename WeakPersistent, - std::enable_if_t<!WeakPersistent::IsStrongPersistent::value>* = nullptr> - void TraceRoot(const WeakPersistent& p, const SourceLocation& loc) { - using PointeeType = typename WeakPersistent::PointeeType; - static_assert(sizeof(PointeeType), - "Persistent's pointee type must be fully defined"); - static_assert(internal::IsGarbageCollectedType<PointeeType>::value, - "Persisent's pointee type must be GarabgeCollected or " - "GarbageCollectedMixin"); - VisitWeakRoot(p.Get(), TraceTrait<PointeeType>::GetTraceDescriptor(p.Get()), - &HandleWeak<WeakPersistent>, &p); + /** + * Trace method for inlined objects that are not allocated themselves but + * otherwise follow managed heap layout and have a Trace() method. + * + * \param object reference of the inlined object. + */ + template <typename T> + void Trace(const T& object) { +#if V8_ENABLE_CHECKS + // This object is embedded in potentially multiple nested objects. The + // outermost object must not be in construction as such objects are (a) not + // processed immediately, and (b) only processed conservatively if not + // otherwise possible. + CheckObjectNotInConstruction(&object); +#endif // V8_ENABLE_CHECKS + TraceTrait<T>::Trace(this, &object); } + /** + * Registers a weak callback method on the object of type T. See + * LivenessBroker for an usage example. + * + * \param object of type T specifying a weak callback method. + */ template <typename T, void (T::*method)(const LivenessBroker&)> - void RegisterWeakCallbackMethod(const T* obj) { - RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>, obj); + void RegisterWeakCallbackMethod(const T* object) { + RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>, object); } - virtual void RegisterWeakCallback(WeakCallback, const void*) {} + /** + * Registers a weak callback that is invoked during garbage collection. + * + * \param callback to be invoked. + * \param data custom data that is passed to the callback. + */ + virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {} protected: virtual void Visit(const void* self, TraceDescriptor) {} @@ -108,29 +136,64 @@ class Visitor { template <typename PointerType> static void HandleWeak(const LivenessBroker& info, const void* object) { const PointerType* weak = static_cast<const PointerType*>(object); + // Sentinel values are preserved for weak pointers. + if (*weak == kSentinelPointer) return; const auto* raw = weak->Get(); - if (raw && !info.IsHeapObjectAlive(raw)) { - // Object is passed down through the marker as const. Alternatives are - // - non-const Trace method; - // - mutable pointer in MemberBase; - const_cast<PointerType*>(weak)->Clear(); + if (!info.IsHeapObjectAlive(raw)) { + weak->ClearFromGC(); } } Visitor() = default; + template <typename Persistent, + std::enable_if_t<Persistent::IsStrongPersistent::value>* = nullptr> + void TraceRoot(const Persistent& p, const SourceLocation& loc) { + using PointeeType = typename Persistent::PointeeType; + static_assert(sizeof(PointeeType), + "Persistent's pointee type must be fully defined"); + static_assert(internal::IsGarbageCollectedType<PointeeType>::value, + "Persistent's pointee type must be GarbageCollected or " + "GarbageCollectedMixin"); + if (!p.Get()) { + return; + } + VisitRoot(p.Get(), TraceTrait<PointeeType>::GetTraceDescriptor(p.Get())); + } + + template < + typename WeakPersistent, + std::enable_if_t<!WeakPersistent::IsStrongPersistent::value>* = nullptr> + void TraceRoot(const WeakPersistent& p, const SourceLocation& loc) { + using PointeeType = typename WeakPersistent::PointeeType; + static_assert(sizeof(PointeeType), + "Persistent's pointee type must be fully defined"); + static_assert(internal::IsGarbageCollectedType<PointeeType>::value, + "Persistent's pointee type must be GarbageCollected or " + "GarbageCollectedMixin"); + VisitWeakRoot(p.Get(), TraceTrait<PointeeType>::GetTraceDescriptor(p.Get()), + &HandleWeak<WeakPersistent>, &p); + } + template <typename T> void Trace(const T* t) { - static_assert(sizeof(T), "T must be fully defined"); + static_assert(sizeof(T), "Pointee type must be fully defined."); static_assert(internal::IsGarbageCollectedType<T>::value, - "T must be GarabgeCollected or GarbageCollectedMixin type"); + "T must be GarbageCollected or GarbageCollectedMixin type"); if (!t) { return; } Visit(t, TraceTrait<T>::GetTraceDescriptor(t)); } +#if V8_ENABLE_CHECKS + V8_EXPORT void CheckObjectNotInConstruction(const void* address); +#endif // V8_ENABLE_CHECKS + friend class internal::VisitorBase; + template <typename T, typename WeaknessPolicy, typename LocationPolicy, + typename CheckingPolicy> + friend class internal::BasicPersistent; }; } // namespace cppgc |