diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-03-12 09:13:00 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-03-16 09:58:26 +0000 |
commit | 03561cae90f1d99b5c54b1ef3be69f10e882b25e (patch) | |
tree | cc5f0958e823c044e7ae51cc0117fe51432abe5e /chromium/third_party/blink/renderer/platform/heap | |
parent | fa98118a45f7e169f8846086dc2c22c49a8ba310 (diff) | |
download | qtwebengine-chromium-03561cae90f1d99b5c54b1ef3be69f10e882b25e.tar.gz |
BASELINE: Update Chromium to 88.0.4324.208
Change-Id: I3ae87d23e4eff4b4a469685658740a213600c667
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/heap')
96 files changed, 6222 insertions, 5643 deletions
diff --git a/chromium/third_party/blink/renderer/platform/heap/BUILD.gn b/chromium/third_party/blink/renderer/platform/heap/BUILD.gn index 7647b413521..52b0679d553 100644 --- a/chromium/third_party/blink/renderer/platform/heap/BUILD.gn +++ b/chromium/third_party/blink/renderer/platform/heap/BUILD.gn @@ -16,6 +16,7 @@ buildflag_header("blink_heap_buildflags") { flags = [ "BLINK_HEAP_VERIFICATION=$enable_blink_heap_verification", "BLINK_HEAP_YOUNG_GENERATION=$enable_blink_heap_young_generation", + "BLINK_HEAP_USE_V8_OILPAN=$enable_blink_heap_use_v8_oilpan", ] } @@ -29,11 +30,18 @@ source_set("heap_unsanitized") { # std::atomic<>:: functions must be inlined. configs -= [ "//build/config/compiler:default_optimization" ] configs += [ "//build/config/compiler:optimize_max" ] + if (using_mismatched_sample_profile) { + configs -= [ "//build/config/compiler:afdo_optimize_size" ] + } - sources = [ - "unsanitized_atomic.cc", - "unsanitized_atomic.h", - ] + if (!enable_blink_heap_use_v8_oilpan) { + sources = [ + "impl/unsanitized_atomic.cc", + "impl/unsanitized_atomic.h", + ] + } else { + sources = [] + } deps = [ "//base", @@ -43,65 +51,30 @@ source_set("heap_unsanitized") { } blink_platform_sources("heap") { + configs += [ "//build/config/compiler:noshadowing" ] + sources = [ - "atomic_entry_flag.h", - "blink_gc.cc", - "blink_gc.h", - "blink_gc_memory_dump_provider.cc", "blink_gc_memory_dump_provider.h", "collection_support/heap_hash_table_backing.h", "collection_support/heap_linked_stack.h", "collection_support/heap_vector_backing.h", "disallow_new_wrapper.h", - "finalizer_traits.h", "garbage_collected.h", - "gc_info.cc", - "gc_info.h", "gc_task_runner.h", "handle.h", - "heap.cc", "heap.h", - "heap_allocator.cc", "heap_allocator.h", - "heap_compact.cc", - "heap_compact.h", - "heap_page.cc", - "heap_page.h", - "heap_stats_collector.cc", "heap_stats_collector.h", "heap_traits.h", - "marking_scheduling_oracle.cc", - "marking_scheduling_oracle.h", - "marking_verifier.cc", - "marking_verifier.h", - "marking_visitor.cc", - "marking_visitor.h", "member.h", - "name_traits.h", - "page_bloom_filter.h", - "page_memory.cc", - "page_memory.h", - "page_pool.cc", - "page_pool.h", "persistent.h", - "persistent_node.cc", - "persistent_node.h", - "process_heap.cc", "process_heap.h", "self_keep_alive.h", - "thread_state.cc", "thread_state.h", "thread_state_scopes.h", - "thread_state_statistics.cc", - "thread_state_statistics.h", - "threading_traits.h", - "trace_traits.h", - "unified_heap_controller.cc", "unified_heap_controller.h", - "unified_heap_marking_visitor.cc", "unified_heap_marking_visitor.h", "visitor.h", - "worklist.h", ] deps = [ @@ -114,9 +87,91 @@ blink_platform_sources("heap") { "//v8", ] + if (enable_blink_heap_use_v8_oilpan) { + sources += [ + "v8_wrapper/blink_gc.h", + "v8_wrapper/blink_gc_memory_dump_provider.h", + "v8_wrapper/disallow_new_wrapper.h", + "v8_wrapper/garbage_collected.h", + "v8_wrapper/gc_task_runner.h", + "v8_wrapper/heap.h", + "v8_wrapper/heap_allocator.h", + "v8_wrapper/heap_stats_collector.h", + "v8_wrapper/heap_traits.h", + "v8_wrapper/member.h", + "v8_wrapper/persistent.h", + "v8_wrapper/process_heap.h", + "v8_wrapper/thread_state.h", + "v8_wrapper/thread_state_scopes.h", + "v8_wrapper/unified_heap_controller.h", + "v8_wrapper/unified_heap_marking_visitor.h", + "v8_wrapper/visitor.h", + ] + + deps += [ "//v8:cppgc" ] + } else { + sources += [ + "impl/atomic_entry_flag.h", + "impl/blink_gc.cc", + "impl/blink_gc.h", + "impl/blink_gc_memory_dump_provider.cc", + "impl/blink_gc_memory_dump_provider.h", + "impl/disallow_new_wrapper.h", + "impl/finalizer_traits.h", + "impl/garbage_collected.h", + "impl/gc_info.cc", + "impl/gc_info.h", + "impl/gc_task_runner.h", + "impl/heap.cc", + "impl/heap.h", + "impl/heap_allocator.cc", + "impl/heap_allocator.h", + "impl/heap_compact.cc", + "impl/heap_compact.h", + "impl/heap_page.cc", + "impl/heap_page.h", + "impl/heap_stats_collector.cc", + "impl/heap_stats_collector.h", + "impl/heap_traits.h", + "impl/marking_scheduling_oracle.cc", + "impl/marking_scheduling_oracle.h", + "impl/marking_verifier.cc", + "impl/marking_verifier.h", + "impl/marking_visitor.cc", + "impl/marking_visitor.h", + "impl/member.h", + "impl/name_traits.h", + "impl/page_bloom_filter.h", + "impl/page_memory.cc", + "impl/page_memory.h", + "impl/page_pool.cc", + "impl/page_pool.h", + "impl/persistent.h", + "impl/persistent_node.cc", + "impl/persistent_node.h", + "impl/process_heap.cc", + "impl/process_heap.h", + "impl/thread_state.cc", + "impl/thread_state.h", + "impl/thread_state_scopes.h", + "impl/thread_state_statistics.cc", + "impl/thread_state_statistics.h", + "impl/threading_traits.h", + "impl/trace_traits.h", + "impl/unified_heap_controller.cc", + "impl/unified_heap_controller.h", + "impl/unified_heap_marking_visitor.cc", + "impl/unified_heap_marking_visitor.h", + "impl/visitor.h", + "impl/worklist.h", + ] + } + if (!is_debug && !optimize_for_size) { configs -= [ "//build/config/compiler:default_optimization" ] configs += [ "//build/config/compiler:optimize_max" ] + } else if (using_mismatched_sample_profile) { + configs -= [ "//build/config/compiler:afdo_optimize_size" ] } visibility = [ diff --git a/chromium/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md b/chromium/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md index 2ccf1b181f8..b2c71f1c037 100644 --- a/chromium/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md +++ b/chromium/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md @@ -239,7 +239,7 @@ It may take some time for the pointer in a `WeakMember<T>` to become `nullptr` a because this rewrite is only done within Blink GC's garbage collection period. ```c++ -class SomeGarbageCollectedClass : public GarbageCollected<GarbageCollectedSomething> { +class SomeGarbageCollectedClass : public GarbageCollected<SomeGarbageCollectedClass> { ... private: Member<AnotherGarbageCollectedClass> another_; // OK, retained by Member<T>. diff --git a/chromium/third_party/blink/renderer/platform/heap/blink_gc.h b/chromium/third_party/blink/renderer/platform/heap/blink_gc.h index e6a47ee9bdf..bba521667cf 100644 --- a/chromium/third_party/blink/renderer/platform/heap/blink_gc.h +++ b/chromium/third_party/blink/renderer/platform/heap/blink_gc.h @@ -1,126 +1,16 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_ -// BlinkGC.h is a file that defines common things used by Blink GC. +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -#include "third_party/blink/renderer/platform/platform_export.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" - -#define PRINT_HEAP_STATS 0 // Enable this macro to print heap stats to stderr. - -namespace blink { - -class LivenessBroker; -class MarkingVisitor; -class Visitor; - -using Address = uint8_t*; -using ConstAddress = const uint8_t*; - -using VisitorCallback = void (*)(Visitor*, const void*); -using MarkingVisitorCallback = void (*)(MarkingVisitor*, const void*); -using TraceCallback = VisitorCallback; -using WeakCallback = void (*)(const LivenessBroker&, const void*); -using EphemeronCallback = VisitorCallback; - -// Simple alias to avoid heap compaction type signatures turning into -// a sea of generic |void*|s. -using MovableReference = const void*; - -// List of all arenas. Includes typed arenas as well. -#define FOR_EACH_ARENA(H) \ - H(NormalPage1) \ - H(NormalPage2) \ - H(NormalPage3) \ - H(NormalPage4) \ - H(Vector) \ - H(HashTable) \ - H(Node) \ - H(CSSValue) \ - H(LargeObject) - -class PLATFORM_EXPORT WorklistTaskId { - public: - static constexpr int MutatorThread = 0; - static constexpr int ConcurrentThreadBase = 1; -}; - -class PLATFORM_EXPORT BlinkGC final { - STATIC_ONLY(BlinkGC); - - public: - // CollectionType represents generational collection. kMinor collects objects - // in the young generation (i.e. allocated since the previous collection - // cycle, since we use sticky bits), kMajor collects the entire heap. - enum class CollectionType { kMinor, kMajor }; - - // When garbage collecting we need to know whether or not there - // can be pointers to Blink GC managed objects on the stack for - // each thread. When threads reach a safe point they record - // whether or not they have pointers on the stack. - enum StackState { kNoHeapPointersOnStack, kHeapPointersOnStack }; - - enum MarkingType { - // The marking completes synchronously. - kAtomicMarking, - // The marking task is split and executed in chunks (either on the mutator - // thread or concurrently). - kIncrementalAndConcurrentMarking - }; - - enum SweepingType { - // The sweeping task is split into chunks and scheduled lazily and - // concurrently. - kConcurrentAndLazySweeping, - // The sweeping task executes synchronously right after marking. - kEagerSweeping, - }; - - // Commented out reasons have been used in the past but are not used any - // longer. We keep them here as the corresponding UMA histograms cannot be - // changed. - enum class GCReason { - // kIdleGC = 0 - // kPreciseGC = 1 - // kConservativeGC = 2 - kForcedGCForTesting = 3, - // kMemoryPressureGC = 4 - // kPageNavigationGC = 5 - kThreadTerminationGC = 6, - // kTesting = 7 - // kIncrementalIdleGC = 8 - // kIncrementalV8FollowupGC = 9 - kUnifiedHeapGC = 10, - kUnifiedHeapForMemoryReductionGC = 11, - kUnifiedHeapForcedForTestingGC = 12, - // Used by UMA_HISTOGRAM_ENUMERATION macro. - kMaxValue = kUnifiedHeapForcedForTestingGC, - }; - -#define DeclareArenaIndex(name) k##name##ArenaIndex, - enum ArenaIndices { - FOR_EACH_ARENA(DeclareArenaIndex) - // Values used for iteration of heap segments. - kNumberOfArenas, - }; -#undef DeclareArenaIndex - - enum V8GCType { - kV8MinorGC, - kV8MajorGC, - }; - - static const char* ToString(GCReason); - static const char* ToString(MarkingType); - static const char* ToString(StackState); - static const char* ToString(SweepingType); - static const char* ToString(ArenaIndices); -}; - -} // namespace blink +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/blink_gc.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h b/chromium/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h index 42be7084019..e3216e12529 100644 --- a/chromium/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h +++ b/chromium/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h @@ -1,47 +1,16 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_ -#include "base/trace_event/memory_dump_provider.h" -#include "third_party/blink/renderer/platform/heap/blink_gc.h" -#include "third_party/blink/renderer/platform/platform_export.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -namespace base { -class SingleThreadTaskRunner; -} // namespace base - -namespace blink { - -class ThreadState; - -class PLATFORM_EXPORT BlinkGCMemoryDumpProvider final - : public base::trace_event::MemoryDumpProvider { - USING_FAST_MALLOC(BlinkGCMemoryDumpProvider); - - public: - enum class HeapType { kBlinkMainThread, kBlinkWorkerThread }; - - ~BlinkGCMemoryDumpProvider() final; - BlinkGCMemoryDumpProvider( - ThreadState* thread_state, - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - HeapType heap_type); - - // MemoryDumpProvider implementation. - bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&, - base::trace_event::ProcessMemoryDump*) final; - - private: - ThreadState* const thread_state_; - const HeapType heap_type_; - const std::string dump_base_name_; -}; - -} // namespace blink +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_BLINK_GC_MEMORY_DUMP_PROVIDER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h index e91e2e194a3..27460c3acca 100644 --- a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h +++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h @@ -5,9 +5,9 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_HASH_TABLE_BACKING_H_ -#include "third_party/blink/renderer/platform/heap/heap_page.h" -#include "third_party/blink/renderer/platform/heap/threading_traits.h" -#include "third_party/blink/renderer/platform/heap/trace_traits.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_page.h" +#include "third_party/blink/renderer/platform/heap/impl/threading_traits.h" +#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/conditional_destructor.h" @@ -199,7 +199,8 @@ class ConcurrentBucket { private: // Alignment is needed for atomic accesses to |buf_| and to assure |buf_| // can be accessed the same as objects of type T - alignas(std::max(alignof(T), sizeof(size_t))) char buf_[sizeof(T)]; + static constexpr size_t boundary = std::max(alignof(T), sizeof(size_t)); + alignas(boundary) char buf_[sizeof(T)]; }; template <typename Key, typename Value> @@ -223,7 +224,8 @@ class ConcurrentBucket<KeyValuePair<Key, Value>> { private: // Alignment is needed for atomic accesses to |buf_| and to assure |buf_| // can be accessed the same as objects of type Key - alignas(std::max(alignof(Key), sizeof(size_t))) char buf_[sizeof(Key)]; + static constexpr size_t boundary = std::max(alignof(Key), sizeof(size_t)); + alignas(boundary) char buf_[sizeof(Key)]; const Value* value_; }; @@ -339,11 +341,7 @@ struct TraceKeyValuePairInCollectionTrait { // The following passes on kNoWeakHandling for tracing value as the value // callback is only invoked to keep value alive iff key is alive, // following ephemeron semantics. - visitor->TraceEphemeron( - *helper.key, helper.value, - blink::TraceCollectionIfEnabled< - kNoWeakHandling, typename EphemeronHelper::ValueType, - typename EphemeronHelper::ValueTraits>::Trace); + visitor->TraceEphemeron(*helper.key, helper.value); } }; diff --git a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h index 07c97e2e068..12b72b78ee9 100644 --- a/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h +++ b/chromium/third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h @@ -6,13 +6,13 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_COLLECTION_SUPPORT_HEAP_VECTOR_BACKING_H_ #include "base/check_op.h" -#include "third_party/blink/renderer/platform/heap/finalizer_traits.h" -#include "third_party/blink/renderer/platform/heap/gc_info.h" #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap_allocator.h" +#include "third_party/blink/renderer/platform/heap/impl/finalizer_traits.h" +#include "third_party/blink/renderer/platform/heap/impl/gc_info.h" +#include "third_party/blink/renderer/platform/heap/impl/threading_traits.h" +#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h" #include "third_party/blink/renderer/platform/heap/thread_state.h" -#include "third_party/blink/renderer/platform/heap/threading_traits.h" -#include "third_party/blink/renderer/platform/heap/trace_traits.h" #include "third_party/blink/renderer/platform/wtf/conditional_destructor.h" #include "third_party/blink/renderer/platform/wtf/vector.h" diff --git a/chromium/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h b/chromium/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h index 1d3b1f3031f..9d60caf37f6 100644 --- a/chromium/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h +++ b/chromium/third_party/blink/renderer/platform/heap/disallow_new_wrapper.h @@ -1,53 +1,16 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_DISALLOW_NEW_WRAPPER_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_DISALLOW_NEW_WRAPPER_H_ -#include "third_party/blink/renderer/platform/heap/garbage_collected.h" -#include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/heap/visitor.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -namespace blink { - -// DisallowNewWrapper wraps a disallow new type in a GarbageCollected class. -template <typename T> -class DisallowNewWrapper final - : public GarbageCollected<DisallowNewWrapper<T>> { - public: - explicit DisallowNewWrapper(const T& value) : value_(value) { - static_assert(WTF::IsDisallowNew<T>::value, - "T needs to be a disallow new type"); - static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable"); - } - explicit DisallowNewWrapper(T&& value) : value_(std::forward<T>(value)) { - static_assert(WTF::IsDisallowNew<T>::value, - "T needs to be a disallow new type"); - static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable"); - } - - const T& Value() const { return value_; } - T&& TakeValue() { return std::move(value_); } - - void Trace(Visitor* visitor) const { visitor->Trace(value_); } - - private: - T value_; -}; - -// Wraps a disallow new type in a GarbageCollected class, making it possible to -// be referenced off heap from a Persistent. -template <typename T> -DisallowNewWrapper<T>* WrapDisallowNew(const T& value) { - return MakeGarbageCollected<DisallowNewWrapper<T>>(value); -} - -template <typename T> -DisallowNewWrapper<T>* WrapDisallowNew(T&& value) { - return MakeGarbageCollected<DisallowNewWrapper<T>>(std::forward<T>(value)); -} - -} // namespace blink +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_DISALLOW_NEW_WRAPPER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h b/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h index dfd6a12c930..93715933385 100644 --- a/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h +++ b/chromium/third_party/blink/renderer/platform/heap/garbage_collected.h @@ -1,117 +1,16 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_ -#include "base/macros.h" -#include "third_party/blink/renderer/platform/heap/thread_state.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/assertions.h" -#include "third_party/blink/renderer/platform/wtf/type_traits.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -namespace blink { +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/garbage_collected.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN -template <typename T> -class GarbageCollected; - -// GC_PLUGIN_IGNORE is used to make the plugin ignore a particular class or -// field when checking for proper usage. When using GC_PLUGIN_IGNORE -// a bug-number should be provided as an argument where the bug describes -// what needs to happen to remove the GC_PLUGIN_IGNORE again. -#if defined(__clang__) -#define GC_PLUGIN_IGNORE(bug) \ - __attribute__((annotate("blink_gc_plugin_ignore"))) -#else -#define GC_PLUGIN_IGNORE(bug) -#endif - -// Template to determine if a class is a GarbageCollectedMixin by checking if it -// has IsGarbageCollectedMixinMarker -template <typename T> -struct IsGarbageCollectedMixin { - private: - typedef char YesType; - struct NoType { - char padding[8]; - }; - - template <typename U> - static YesType CheckMarker(typename U::IsGarbageCollectedMixinMarker*); - template <typename U> - static NoType CheckMarker(...); - - public: - static const bool value = sizeof(CheckMarker<T>(nullptr)) == sizeof(YesType); -}; - -// TraceDescriptor is used to describe how to trace an object. -struct TraceDescriptor { - STACK_ALLOCATED(); - - public: - // The adjusted base pointer of the object that should be traced. - const void* base_object_payload; - // A callback for tracing the object. - TraceCallback callback; -}; - -// The GarbageCollectedMixin interface can be used to automatically define -// TraceTrait/ObjectAliveTrait on non-leftmost deriving classes which need -// to be garbage collected. -class PLATFORM_EXPORT GarbageCollectedMixin { - public: - typedef int IsGarbageCollectedMixinMarker; - virtual void Trace(Visitor*) const {} -}; - -// Base class for objects allocated in the Blink garbage-collected heap. -// -// Instances of GarbageCollected will be finalized if they are non-trivially -// destructible. -template <typename T> -class GarbageCollected; - -template <typename T, - bool = WTF::IsSubclassOfTemplate<typename std::remove_const<T>::type, - GarbageCollected>::value> -class NeedsAdjustPointer; - -template <typename T> -class NeedsAdjustPointer<T, true> { - static_assert(sizeof(T), "T must be fully defined"); - - public: - static const bool value = false; -}; - -template <typename T> -class NeedsAdjustPointer<T, false> { - static_assert(sizeof(T), "T must be fully defined"); - - public: - static const bool value = - IsGarbageCollectedMixin<typename std::remove_const<T>::type>::value; -}; - -// TODO(sof): migrate to wtf/TypeTraits.h -template <typename T> -class IsFullyDefined { - using TrueType = char; - struct FalseType { - char dummy[2]; - }; - - template <typename U, size_t sz = sizeof(U)> - static TrueType IsSizeofKnown(U*); - static FalseType IsSizeofKnown(...); - static T& t_; - - public: - static const bool value = sizeof(TrueType) == sizeof(IsSizeofKnown(&t_)); -}; - -} // namespace blink - -#endif +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/gc_task_runner.h b/chromium/third_party/blink/renderer/platform/heap/gc_task_runner.h index b00f3b24d1f..758506b7e07 100644 --- a/chromium/third_party/blink/renderer/platform/heap/gc_task_runner.h +++ b/chromium/third_party/blink/renderer/platform/heap/gc_task_runner.h @@ -1,90 +1,16 @@ -/* - * Copyright (C) 2014 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_TASK_RUNNER_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_TASK_RUNNER_H_ -#include <memory> -#include "base/location.h" -#include "third_party/blink/renderer/platform/heap/thread_state.h" -#include "third_party/blink/renderer/platform/scheduler/public/thread.h" -#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -namespace blink { +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/gc_task_runner.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN -class GCTaskObserver final : public Thread::TaskObserver { - USING_FAST_MALLOC(GCTaskObserver); - - public: - GCTaskObserver() : nesting_(0) {} - - ~GCTaskObserver() override { - // m_nesting can be 1 if this was unregistered in a task and - // didProcessTask was not called. - DCHECK(!nesting_ || nesting_ == 1); - } - - void WillProcessTask(const base::PendingTask&, bool) override { nesting_++; } - - void DidProcessTask(const base::PendingTask&) override { - // In the production code WebKit::initialize is called from inside the - // message loop so we can get didProcessTask() without corresponding - // willProcessTask once. This is benign. - if (nesting_) - nesting_--; - - ThreadState::Current()->SafePoint(nesting_ - ? BlinkGC::kHeapPointersOnStack - : BlinkGC::kNoHeapPointersOnStack); - } - - private: - int nesting_; -}; - -class GCTaskRunner final { - USING_FAST_MALLOC(GCTaskRunner); - - public: - explicit GCTaskRunner(Thread* thread) - : gc_task_observer_(std::make_unique<GCTaskObserver>()), thread_(thread) { - thread_->AddTaskObserver(gc_task_observer_.get()); - } - - ~GCTaskRunner() { thread_->RemoveTaskObserver(gc_task_observer_.get()); } - - private: - std::unique_ptr<GCTaskObserver> gc_task_observer_; - Thread* thread_; -}; - -} // namespace blink - -#endif +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_TASK_RUNNER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/handle.h b/chromium/third_party/blink/renderer/platform/heap/handle.h index 9df15cc43d6..ee07268f578 100644 --- a/chromium/third_party/blink/renderer/platform/heap/handle.h +++ b/chromium/third_party/blink/renderer/platform/heap/handle.h @@ -38,7 +38,6 @@ #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/heap/thread_state.h" #include "third_party/blink/renderer/platform/heap/thread_state_scopes.h" -#include "third_party/blink/renderer/platform/heap/trace_traits.h" #include "third_party/blink/renderer/platform/heap/visitor.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" diff --git a/chromium/third_party/blink/renderer/platform/heap/heap.h b/chromium/third_party/blink/renderer/platform/heap/heap.h index f27916bac06..7cbe94f71ec 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap.h +++ b/chromium/third_party/blink/renderer/platform/heap/heap.h @@ -1,732 +1,16 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_ -#include <limits> -#include <memory> +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -#include "base/macros.h" -#include "build/build_config.h" -#include "third_party/blink/renderer/platform/heap/finalizer_traits.h" -#include "third_party/blink/renderer/platform/heap/gc_info.h" -#include "third_party/blink/renderer/platform/heap/heap_page.h" -#include "third_party/blink/renderer/platform/heap/process_heap.h" -#include "third_party/blink/renderer/platform/heap/thread_state.h" -#include "third_party/blink/renderer/platform/heap/thread_state_statistics.h" -#include "third_party/blink/renderer/platform/heap/visitor.h" -#include "third_party/blink/renderer/platform/heap/worklist.h" -#include "third_party/blink/renderer/platform/platform_export.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/assertions.h" -#include "third_party/blink/renderer/platform/wtf/forward.h" -#include "third_party/blink/renderer/platform/wtf/sanitizers.h" - -namespace blink { - -namespace incremental_marking_test { -class IncrementalMarkingScopeBase; -} // namespace incremental_marking_test - -class ConcurrentMarkingVisitor; -class ThreadHeapStatsCollector; -class PageBloomFilter; -class PagePool; -class ProcessHeapReporter; -class RegionTree; -class MarkingSchedulingOracle; - -using MarkingItem = TraceDescriptor; -using NotFullyConstructedItem = const void*; - -struct EphemeronPairItem { - const void* key; - const void* value; - TraceCallback value_trace_callback; -}; - -struct CustomCallbackItem { - WeakCallback callback; - const void* parameter; -}; - -struct NotSafeToConcurrentlyTraceItem { - TraceDescriptor desc; - size_t bailout_size; -}; - -using V8Reference = const TraceWrapperV8Reference<v8::Value>*; - -// Segment size of 512 entries necessary to avoid throughput regressions. Since -// the work list is currently a temporary object this is not a problem. -using MarkingWorklist = Worklist<MarkingItem, 512 /* local entries */>; -using WriteBarrierWorklist = Worklist<HeapObjectHeader*, 64>; -using NotFullyConstructedWorklist = - Worklist<NotFullyConstructedItem, 16 /* local entries */>; -using WeakCallbackWorklist = - Worklist<CustomCallbackItem, 64 /* local entries */>; -// Using large local segments here (sized 512 entries) to avoid throughput -// regressions. -using MovableReferenceWorklist = - Worklist<const MovableReference*, 256 /* local entries */>; -using EphemeronPairsWorklist = - Worklist<EphemeronPairItem, 64 /* local entries */>; -using V8ReferencesWorklist = Worklist<V8Reference, 16 /* local entries */>; -using NotSafeToConcurrentlyTraceWorklist = - Worklist<NotSafeToConcurrentlyTraceItem, 64 /* local entries */>; - -class PLATFORM_EXPORT HeapAllocHooks { - STATIC_ONLY(HeapAllocHooks); - - public: - // TODO(hajimehoshi): Pass a type name of the allocated object. - typedef void AllocationHook(Address, size_t, const char*); - typedef void FreeHook(Address); - - // Sets allocation hook. Only one hook is supported. - static void SetAllocationHook(AllocationHook* hook) { - CHECK(!allocation_hook_ || !hook); - allocation_hook_ = hook; - } - - // Sets free hook. Only one hook is supported. - static void SetFreeHook(FreeHook* hook) { - CHECK(!free_hook_ || !hook); - free_hook_ = hook; - } - - static void AllocationHookIfEnabled(Address address, - size_t size, - const char* type_name) { - AllocationHook* allocation_hook = allocation_hook_; - if (UNLIKELY(!!allocation_hook)) - allocation_hook(address, size, type_name); - } - - static void FreeHookIfEnabled(Address address) { - FreeHook* free_hook = free_hook_; - if (UNLIKELY(!!free_hook)) - free_hook(address); - } - - private: - static AllocationHook* allocation_hook_; - static FreeHook* free_hook_; -}; - -class HeapCompact; -template <typename T> -class Member; -template <typename T> -class WeakMember; -template <typename T> -class UntracedMember; - -namespace internal { - -class LivenessBrokerFactory; - -template <typename T, bool = NeedsAdjustPointer<T>::value> -class ObjectAliveTrait; - -template <typename T> -class ObjectAliveTrait<T, false> { - STATIC_ONLY(ObjectAliveTrait); - - public: - static bool IsHeapObjectAlive(const T* object) { - static_assert(sizeof(T), "T must be fully defined"); - return HeapObjectHeader::FromPayload(object)->IsMarked(); - } -}; - -template <typename T> -class ObjectAliveTrait<T, true> { - STATIC_ONLY(ObjectAliveTrait); - - public: - NO_SANITIZE_ADDRESS - static bool IsHeapObjectAlive(const T* object) { - static_assert(sizeof(T), "T must be fully defined"); - const HeapObjectHeader* header = HeapObjectHeader::FromPayload( - TraceTrait<T>::GetTraceDescriptor(object).base_object_payload); - DCHECK(!header->IsInConstruction() || header->IsMarked()); - return header->IsMarked(); - } -}; - -template <typename T, typename = int> -struct IsGarbageCollectedContainer : std::false_type {}; - -template <typename T> -struct IsGarbageCollectedContainer< - T, - typename T::IsGarbageCollectedCollectionTypeMarker> : std::true_type {}; - -} // namespace internal - -class PLATFORM_EXPORT ThreadHeap { - USING_FAST_MALLOC(ThreadHeap); - - using EphemeronProcessing = ThreadState::EphemeronProcessing; - - public: - explicit ThreadHeap(ThreadState*); - ~ThreadHeap(); - - MarkingWorklist* GetMarkingWorklist() const { - return marking_worklist_.get(); - } - - WriteBarrierWorklist* GetWriteBarrierWorklist() const { - return write_barrier_worklist_.get(); - } - - NotFullyConstructedWorklist* GetNotFullyConstructedWorklist() const { - return not_fully_constructed_worklist_.get(); - } - - NotFullyConstructedWorklist* GetPreviouslyNotFullyConstructedWorklist() - const { - return previously_not_fully_constructed_worklist_.get(); - } - - WeakCallbackWorklist* GetWeakCallbackWorklist() const { - return weak_callback_worklist_.get(); - } - - MovableReferenceWorklist* GetMovableReferenceWorklist() const { - return movable_reference_worklist_.get(); - } - - EphemeronPairsWorklist* GetDiscoveredEphemeronPairsWorklist() const { - return discovered_ephemeron_pairs_worklist_.get(); - } - - EphemeronPairsWorklist* GetEphemeronPairsToProcessWorklist() const { - return ephemeron_pairs_to_process_worklist_.get(); - } - - V8ReferencesWorklist* GetV8ReferencesWorklist() const { - return v8_references_worklist_.get(); - } - - NotSafeToConcurrentlyTraceWorklist* GetNotSafeToConcurrentlyTraceWorklist() - const { - return not_safe_to_concurrently_trace_worklist_.get(); - } - // Register an ephemeron table for fixed-point iteration. - void RegisterWeakTable(void* container_object, - EphemeronCallback); - - // Heap compaction registration methods: - - // Checks whether we need to register |addr| as a backing store or a slot - // containing reference to it. - bool ShouldRegisterMovingAddress(); - - RegionTree* GetRegionTree() { return region_tree_.get(); } - - static inline size_t AllocationSizeFromSize(size_t size) { - // Add space for header. - size_t allocation_size = size + sizeof(HeapObjectHeader); - // The allocation size calculation can overflow for large sizes. - CHECK_GT(allocation_size, size); - // Align size with allocation granularity. - allocation_size = (allocation_size + kAllocationMask) & ~kAllocationMask; - return allocation_size; - } - Address AllocateOnArenaIndex(ThreadState*, - size_t, - int arena_index, - uint32_t gc_info_index, - const char* type_name); - template <typename T> - static Address Allocate(size_t); - - void WeakProcessing(MarkingVisitor*); - - // Moves not fully constructed objects to previously not fully constructed - // objects. Such objects can be iterated using the Trace() method and do - // not need to rely on conservative handling. - void FlushNotFullyConstructedObjects(); - - // Moves ephemeron pairs from |discovered_ephemeron_pairs_worklist_| to - // |ephemeron_pairs_to_process_worklist_| - void FlushEphemeronPairs(EphemeronProcessing); - - // Marks not fully constructed objects. - void MarkNotFullyConstructedObjects(MarkingVisitor*); - // Marks the transitive closure including ephemerons. - bool AdvanceMarking(MarkingVisitor*, base::TimeTicks, EphemeronProcessing); - void VerifyMarking(); - - // Returns true if concurrent markers will have work to steal - bool HasWorkForConcurrentMarking() const; - // Returns the amount of work currently available for stealing (there could be - // work remaining even if this is 0). - size_t ConcurrentMarkingGlobalWorkSize() const; - // Returns true if marker is done - bool AdvanceConcurrentMarking(ConcurrentMarkingVisitor*, - base::JobDelegate*, - MarkingSchedulingOracle* marking_scheduler); - - // Conservatively checks whether an address is a pointer in any of the - // thread heaps. If so marks the object pointed to as live. - Address CheckAndMarkPointer(MarkingVisitor*, Address); - - // Visits remembered sets. - void VisitRememberedSets(MarkingVisitor*); - - size_t ObjectPayloadSizeForTesting(); - void ResetAllocationPointForTesting(); - - PagePool* GetFreePagePool() { return free_page_pool_.get(); } - - // This look-up uses the region search tree and a negative contains cache to - // provide an efficient mapping from arbitrary addresses to the containing - // heap-page if one exists. - BasePage* LookupPageForAddress(ConstAddress); - - HeapCompact* Compaction(); - - // Get one of the heap structures for this thread. - // The thread heap is split into multiple heap parts based on object types - // and object sizes. - BaseArena* Arena(int arena_index) const { - DCHECK_LE(0, arena_index); - DCHECK_LT(arena_index, BlinkGC::kNumberOfArenas); - return arenas_[arena_index]; - } - - static bool IsVectorArenaIndex(int arena_index) { - return BlinkGC::kVectorArenaIndex == arena_index; - } - static bool IsNormalArenaIndex(int); - - void MakeConsistentForGC(); - // MakeConsistentForMutator() drops marks from marked objects and rebuild - // free lists. This is called after taking a snapshot and before resuming - // the executions of mutators. - void MakeConsistentForMutator(); - - // Unmarks all objects in the entire heap. This is supposed to be called in - // the beginning of major GC. - void Unmark(); - - void Compact(); - - bool AdvanceLazySweep(base::TimeTicks deadline); - bool AdvanceConcurrentSweep(base::JobDelegate*); - - void PrepareForSweep(BlinkGC::CollectionType); - void RemoveAllPages(); - void InvokeFinalizersOnSweptPages(); - void CompleteSweep(); - - void CollectStatistics(ThreadState::Statistics* statistics); - - ThreadHeapStatsCollector* stats_collector() const { - return heap_stats_collector_.get(); - } - -#if defined(ADDRESS_SANITIZER) - void PoisonUnmarkedObjects(); -#endif - -#if DCHECK_IS_ON() - // Infrastructure to determine if an address is within one of the - // address ranges for the Blink heap. If the address is in the Blink - // heap the containing heap page is returned. - BasePage* FindPageFromAddress(Address); - BasePage* FindPageFromAddress(const void* pointer) { - return FindPageFromAddress( - reinterpret_cast<Address>(const_cast<void*>(pointer))); - } -#endif - - PageBloomFilter* page_bloom_filter() { return page_bloom_filter_.get(); } - - bool IsInLastAllocatedRegion(Address address) const; - void SetLastAllocatedRegion(Address start, size_t length); - - private: - struct LastAllocatedRegion { - Address start = nullptr; - size_t length = 0; - }; - - static int ArenaIndexForObjectSize(size_t); - - void SetupWorklists(bool); - void DestroyMarkingWorklists(BlinkGC::StackState); - void DestroyCompactionWorklists(); - - bool InvokeEphemeronCallbacks(EphemeronProcessing, - MarkingVisitor*, - base::TimeTicks); - - bool FlushV8References(base::TimeTicks); - - ThreadState* thread_state_; - std::unique_ptr<ThreadHeapStatsCollector> heap_stats_collector_; - std::unique_ptr<RegionTree> region_tree_; - std::unique_ptr<PageBloomFilter> page_bloom_filter_; - std::unique_ptr<PagePool> free_page_pool_; - std::unique_ptr<ProcessHeapReporter> process_heap_reporter_; - - // All objects on this worklist have been fully initialized and assigned a - // trace callback for iterating the body of the object. This worklist should - // contain almost all objects. - std::unique_ptr<MarkingWorklist> marking_worklist_; - - // Objects on this worklist have been collected in the write barrier. The - // worklist is different from |marking_worklist_| to minimize execution in the - // path where a write barrier is executed. - std::unique_ptr<WriteBarrierWorklist> write_barrier_worklist_; - - // Objects on this worklist were observed to be in construction (in their - // constructor) and thus have been delayed for processing. They have not yet - // been assigned a valid header and trace callback. - std::unique_ptr<NotFullyConstructedWorklist> not_fully_constructed_worklist_; - - // Objects on this worklist were previously in construction but have been - // moved here upon observing a safepoint, i.e., processing without stack. They - // have not yet been assigned a valid header and trace callback but are fully - // specified and can thus be iterated using the trace callback (which can be - // looked up dynamically). - std::unique_ptr<NotFullyConstructedWorklist> - previously_not_fully_constructed_worklist_; - - // Worklist of weak callbacks accumulated for objects. Such callbacks are - // processed after finishing marking objects. - std::unique_ptr<WeakCallbackWorklist> weak_callback_worklist_; - - // The worklist is to remember slots that are traced during - // marking phases. The mapping between the slots and the backing stores are - // created at the atomic pause phase. - std::unique_ptr<MovableReferenceWorklist> movable_reference_worklist_; - - // Worklist of ephemeron callbacks. Used to pass new callbacks from - // MarkingVisitor to ThreadHeap. - std::unique_ptr<EphemeronPairsWorklist> discovered_ephemeron_pairs_worklist_; - std::unique_ptr<EphemeronPairsWorklist> ephemeron_pairs_to_process_worklist_; - - // Worklist for storing the V8 references until ThreadHeap can flush them - // to V8. - std::unique_ptr<V8ReferencesWorklist> v8_references_worklist_; - - std::unique_ptr<NotSafeToConcurrentlyTraceWorklist> - not_safe_to_concurrently_trace_worklist_; - - std::unique_ptr<HeapCompact> compaction_; - - LastAllocatedRegion last_allocated_region_; - - BaseArena* arenas_[BlinkGC::kNumberOfArenas]; - - static ThreadHeap* main_thread_heap_; - - static constexpr size_t kStepsBeforeEphemeronPairsFlush = 4u; - size_t steps_since_last_ephemeron_pairs_flush_ = 0; - static constexpr size_t kStepsBeforeEphemeronProcessing = 16u; - size_t steps_since_last_ephemeron_processing_ = 0; - - friend class incremental_marking_test::IncrementalMarkingScopeBase; - template <typename T> - friend class Member; - friend class ThreadState; -}; - -template <typename T> -class GarbageCollected { - IS_GARBAGE_COLLECTED_TYPE(); - - public: - using ParentMostGarbageCollectedType = T; - - // Must use MakeGarbageCollected. - void* operator new(size_t) = delete; - void* operator new[](size_t) = delete; - // The garbage collector is taking care of reclaiming the object. Also, - // virtual destructor requires an unambiguous, accessible 'operator delete'. - void operator delete(void*) { NOTREACHED(); } - void operator delete[](void*) = delete; - - template <typename Derived> - static void* AllocateObject(size_t size) { - return ThreadHeap::Allocate<GCInfoFoldedType<Derived>>(size); - } - - protected: - // This trait in theory can be moved to gc_info.h, but that would cause - // significant memory bloat caused by huge number of ThreadHeap::Allocate<> - // instantiations, which linker is not able to fold. - template <typename Derived> - class GCInfoFolded { - static constexpr bool is_virtual_destructor_at_base = - std::has_virtual_destructor<ParentMostGarbageCollectedType>::value; - static constexpr bool both_trivially_destructible = - std::is_trivially_destructible<ParentMostGarbageCollectedType>::value && - std::is_trivially_destructible<Derived>::value; - static constexpr bool has_custom_dispatch_at_base = - internal::HasFinalizeGarbageCollectedObject< - ParentMostGarbageCollectedType>::value; - - public: - using Type = std::conditional_t<is_virtual_destructor_at_base || - both_trivially_destructible || - has_custom_dispatch_at_base, - ParentMostGarbageCollectedType, - Derived>; - }; - - template <typename Derived> - using GCInfoFoldedType = typename GCInfoFolded<Derived>::Type; - - GarbageCollected() = default; - - DISALLOW_COPY_AND_ASSIGN(GarbageCollected); -}; - -// Used for passing custom sizes to MakeGarbageCollected. -struct AdditionalBytes { - explicit AdditionalBytes(size_t bytes) : value(bytes) {} - const size_t value; -}; - -template <typename T> -struct MakeGarbageCollectedTrait { - template <typename... Args> - static T* Call(Args&&... args) { - static_assert(WTF::IsGarbageCollectedType<T>::value, - "T needs to be a garbage collected object"); - static_assert( - std::is_trivially_destructible<T>::value || - std::has_virtual_destructor<T>::value || std::is_final<T>::value || - internal::IsGarbageCollectedContainer<T>::value || - internal::HasFinalizeGarbageCollectedObject<T>::value, - "Finalized GarbageCollected class should either have a virtual " - "destructor or be marked as final"); - static_assert(!IsGarbageCollectedMixin<T>::value || - sizeof(T) <= kLargeObjectSizeThreshold, - "GarbageCollectedMixin may not be a large object"); - void* memory = T::template AllocateObject<T>(sizeof(T)); - HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory); - // Placement new as regular operator new() is deleted. - T* object = ::new (memory) T(std::forward<Args>(args)...); - header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>(); - return object; - } - - template <typename... Args> - static T* Call(AdditionalBytes additional_bytes, Args&&... args) { - static_assert(WTF::IsGarbageCollectedType<T>::value, - "T needs to be a garbage collected object"); - static_assert( - std::is_trivially_destructible<T>::value || - std::has_virtual_destructor<T>::value || std::is_final<T>::value || - internal::IsGarbageCollectedContainer<T>::value || - internal::HasFinalizeGarbageCollectedObject<T>::value, - "Finalized GarbageCollected class should either have a virtual " - "destructor or be marked as final."); - const size_t size = sizeof(T) + additional_bytes.value; - if (IsGarbageCollectedMixin<T>::value) { - // Ban large mixin so we can use PageFromObject() on them. - CHECK_GE(kLargeObjectSizeThreshold, size) - << "GarbageCollectedMixin may not be a large object"; - } - void* memory = T::template AllocateObject<T>(size); - HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory); - // Placement new as regular operator new() is deleted. - T* object = ::new (memory) T(std::forward<Args>(args)...); - header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>(); - return object; - } -}; - -template <typename T, typename = void> -struct PostConstructionHookTrait { - static void Call(T*) {} -}; - -// Default MakeGarbageCollected: Constructs an instance of T, which is a garbage -// collected type. -template <typename T, typename... Args> -T* MakeGarbageCollected(Args&&... args) { - T* object = MakeGarbageCollectedTrait<T>::Call(std::forward<Args>(args)...); - PostConstructionHookTrait<T>::Call(object); - return object; -} - -// Constructs an instance of T, which is a garbage collected type. This special -// version takes size which enables constructing inline objects. -template <typename T, typename... Args> -T* MakeGarbageCollected(AdditionalBytes additional_bytes, Args&&... args) { - T* object = MakeGarbageCollectedTrait<T>::Call(additional_bytes, - std::forward<Args>(args)...); - PostConstructionHookTrait<T>::Call(object); - return object; -} - -// Assigning class types to their arenas. -// -// We use sized arenas for most 'normal' objects to improve memory locality. -// It seems that the same type of objects are likely to be accessed together, -// which means that we want to group objects by type. That's one reason -// why we provide dedicated arenas for popular types (e.g., Node, CSSValue), -// but it's not practical to prepare dedicated arenas for all types. -// Thus we group objects by their sizes, hoping that this will approximately -// group objects by their types. -// - -inline int ThreadHeap::ArenaIndexForObjectSize(size_t size) { - if (size < 64) { - if (size < 32) - return BlinkGC::kNormalPage1ArenaIndex; - return BlinkGC::kNormalPage2ArenaIndex; - } - if (size < 128) - return BlinkGC::kNormalPage3ArenaIndex; - return BlinkGC::kNormalPage4ArenaIndex; -} - -inline bool ThreadHeap::IsNormalArenaIndex(int index) { - return index >= BlinkGC::kNormalPage1ArenaIndex && - index <= BlinkGC::kNormalPage4ArenaIndex; -} - -inline Address ThreadHeap::AllocateOnArenaIndex(ThreadState* state, - size_t size, - int arena_index, - uint32_t gc_info_index, - const char* type_name) { - DCHECK(state->IsAllocationAllowed()); - DCHECK_NE(arena_index, BlinkGC::kLargeObjectArenaIndex); - NormalPageArena* arena = static_cast<NormalPageArena*>(Arena(arena_index)); - Address address = - arena->AllocateObject(AllocationSizeFromSize(size), gc_info_index); - HeapAllocHooks::AllocationHookIfEnabled(address, size, type_name); - return address; -} - -template <typename T> -Address ThreadHeap::Allocate(size_t size) { - ThreadState* state = ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState(); - const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(T); - return state->Heap().AllocateOnArenaIndex( - state, size, ThreadHeap::ArenaIndexForObjectSize(size), - GCInfoTrait<T>::Index(), type_name); -} - -inline bool ThreadHeap::IsInLastAllocatedRegion(Address address) const { - return last_allocated_region_.start <= address && - address < - (last_allocated_region_.start + last_allocated_region_.length); -} - -inline void ThreadHeap::SetLastAllocatedRegion(Address start, size_t length) { - last_allocated_region_.start = start; - last_allocated_region_.length = length; -} - -class PLATFORM_EXPORT LivenessBroker final { - public: - template <typename T> - bool IsHeapObjectAlive(const T*) const; - template <typename T> - bool IsHeapObjectAlive(const WeakMember<T>&) const; - template <typename T> - bool IsHeapObjectAlive(const UntracedMember<T>&) const; - - private: - LivenessBroker() = default; - friend class internal::LivenessBrokerFactory; -}; - -template <typename T> -bool LivenessBroker::IsHeapObjectAlive(const T* object) const { - static_assert(sizeof(T), "T must be fully defined"); - // The strongification of collections relies on the fact that once a - // collection has been strongified, there is no way that it can contain - // non-live entries, so no entries will be removed. Since you can't set - // the mark bit on a null pointer, that means that null pointers are - // always 'alive'. - if (!object) - return true; - // TODO(keishi): some tests create CrossThreadPersistent on non attached - // threads. - if (!ThreadState::Current()) - return true; - DCHECK(&ThreadState::Current()->Heap() == - &PageFromObject(object)->Arena()->GetThreadState()->Heap()); - return internal::ObjectAliveTrait<T>::IsHeapObjectAlive(object); -} - -template <typename T> -bool LivenessBroker::IsHeapObjectAlive(const WeakMember<T>& weak_member) const { - return IsHeapObjectAlive(weak_member.Get()); -} - -template <typename T> -bool LivenessBroker::IsHeapObjectAlive( - const UntracedMember<T>& untraced_member) const { - return IsHeapObjectAlive(untraced_member.Get()); -} - -template <typename T> -void Visitor::HandleWeakCell(const LivenessBroker& broker, const void* object) { - WeakMember<T>* weak_member = - reinterpret_cast<WeakMember<T>*>(const_cast<void*>(object)); - if (weak_member->Get()) { - if (weak_member->IsHashTableDeletedValue()) { - // This can happen when weak fields are deleted while incremental marking - // is running. Deleted values need to be preserved to avoid reviving - // objects in containers. - return; - } - if (!broker.IsHeapObjectAlive(weak_member->Get())) - weak_member->Clear(); - } -} - -namespace internal { - -class LivenessBrokerFactory final { - public: - static LivenessBroker Create() { return LivenessBroker(); } -}; - -} // namespace internal - -} // namespace blink +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/heap.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h b/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h index 1d49586e4b3..c90f1fc3535 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h +++ b/chromium/third_party/blink/renderer/platform/heap/heap_allocator.h @@ -1,919 +1,16 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_ -#include <type_traits> - -#include "build/build_config.h" -#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h" -#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h" -#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -#include "third_party/blink/renderer/platform/heap/marking_visitor.h" -#include "third_party/blink/renderer/platform/heap/thread_state_scopes.h" -#include "third_party/blink/renderer/platform/heap/trace_traits.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/assertions.h" -#include "third_party/blink/renderer/platform/wtf/construct_traits.h" -#include "third_party/blink/renderer/platform/wtf/deque.h" -#include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h" -#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h" -#include "third_party/blink/renderer/platform/wtf/hash_map.h" -#include "third_party/blink/renderer/platform/wtf/hash_set.h" -#include "third_party/blink/renderer/platform/wtf/hash_table.h" -#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h" -#include "third_party/blink/renderer/platform/wtf/list_hash_set.h" -#include "third_party/blink/renderer/platform/wtf/type_traits.h" -#include "third_party/blink/renderer/platform/wtf/vector.h" - -namespace blink { - -#define DISALLOW_IN_CONTAINER() \ - public: \ - using IsDisallowedInContainerMarker = int; \ - \ - private: \ - friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro - -// IsAllowedInContainer returns true if some type T supports being nested -// arbitrarily in other containers. This is relevant for collections where some -// collections assume that they are placed on a non-moving arena. -template <typename T, typename = int> -struct IsAllowedInContainer : std::true_type {}; -template <typename T> -struct IsAllowedInContainer<T, typename T::IsDisallowedInContainerMarker> - : std::false_type {}; - -// This is a static-only class used as a trait on collections to make them heap -// allocated. However see also HeapListHashSetAllocator. -class PLATFORM_EXPORT HeapAllocator { - STATIC_ONLY(HeapAllocator); - - public: - using LivenessBroker = blink::LivenessBroker; - using Visitor = blink::Visitor; - static constexpr bool kIsGarbageCollected = true; - - template <typename T> - static size_t MaxElementCountInBackingStore() { - return kMaxHeapObjectSize / sizeof(T); - } - - template <typename T> - static size_t QuantizedSize(size_t count) { - CHECK(count <= MaxElementCountInBackingStore<T>()); - return ThreadHeap::AllocationSizeFromSize(count * sizeof(T)) - - sizeof(HeapObjectHeader); - } - template <typename T> - static T* AllocateVectorBacking(size_t size) { - return reinterpret_cast<T*>( - MakeGarbageCollected<HeapVectorBacking<T>>(size / sizeof(T))); - } - static void FreeVectorBacking(void*); - static bool ExpandVectorBacking(void*, size_t); - static bool ShrinkVectorBacking(void* address, - size_t quantized_current_size, - size_t quantized_shrunk_size); - - template <typename T, typename HashTable> - static T* AllocateHashTableBacking(size_t size) { - return reinterpret_cast<T*>( - MakeGarbageCollected<HeapHashTableBacking<HashTable>>( - size / sizeof(typename HashTable::ValueType))); - } - template <typename T, typename HashTable> - static T* AllocateZeroedHashTableBacking(size_t size) { - return AllocateHashTableBacking<T, HashTable>(size); - } - static void FreeHashTableBacking(void* address); - static bool ExpandHashTableBacking(void*, size_t); - - static void TraceBackingStoreIfMarked(const void* address) { - // Trace backing store elements only if backing store was marked. The - // sweeper may be active on the backing store which requires atomic mark bit - // access. A precise filter is performed in - // MarkingVisitor::TraceMarkedBackingStore. - if (HeapObjectHeader::FromPayload(address) - ->IsMarked<HeapObjectHeader::AccessMode::kAtomic>()) { - MarkingVisitor::TraceMarkedBackingStore(address); - } - } - - template <typename T> - static void BackingWriteBarrier(T** slot) { - MarkingVisitor::WriteBarrier(slot); - } - - template <typename Return, typename Metadata> - static Return Malloc(size_t size, const char* type_name) { - return reinterpret_cast<Return>( - MarkAsConstructed(ThreadHeap::Allocate<Metadata>(size))); - } - - // Compilers sometimes eagerly instantiates the unused 'operator delete', so - // we provide a version that asserts and fails at run-time if used. - static void Free(void*) { NOTREACHED(); } - - template <typename T> - static void* NewArray(size_t bytes) { - NOTREACHED(); - return nullptr; - } - - static void DeleteArray(void* ptr) { NOTREACHED(); } - - static bool IsAllocationAllowed() { - return ThreadState::Current()->IsAllocationAllowed(); - } - - static bool IsSweepForbidden() { - return ThreadState::Current()->SweepForbidden(); - } - - static bool IsIncrementalMarking() { - return ThreadState::IsAnyIncrementalMarking() && - ThreadState::Current()->IsIncrementalMarking(); - } - - template <typename T, typename Traits> - static void Trace(Visitor* visitor, const T& t) { - TraceCollectionIfEnabled<WTF::WeakHandlingTrait<T>::value, T, - Traits>::Trace(visitor, &t); - } - - static void EnterGCForbiddenScope() { - ThreadState::Current()->EnterGCForbiddenScope(); - } - - static void LeaveGCForbiddenScope() { - ThreadState::Current()->LeaveGCForbiddenScope(); - } - - template <typename T, typename Traits> - static void NotifyNewObject(T* object) { -#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION) - ThreadState* const thread_state = ThreadState::Current(); - if (!thread_state->IsIncrementalMarking()) { - MarkingVisitor::GenerationalBarrier(reinterpret_cast<Address>(object), - thread_state); - return; - } -#else - if (!ThreadState::IsAnyIncrementalMarking()) - return; - // The object may have been in-place constructed as part of a large object. - // It is not safe to retrieve the page from the object here. - ThreadState* const thread_state = ThreadState::Current(); - if (!thread_state->IsIncrementalMarking()) { - return; - } -#endif // BLINK_HEAP_YOUNG_GENERATION - // Eagerly trace the object ensuring that the object and all its children - // are discovered by the marker. - ThreadState::NoAllocationScope no_allocation_scope(thread_state); - DCHECK(thread_state->CurrentVisitor()); - // No weak handling for write barriers. Modifying weakly reachable objects - // strongifies them for the current cycle. - DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*object)); - TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace( - thread_state->CurrentVisitor(), object); - } - - template <typename T, typename Traits> - static void NotifyNewObjects(T* array, size_t len) { -#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION) - ThreadState* const thread_state = ThreadState::Current(); - if (!thread_state->IsIncrementalMarking()) { - MarkingVisitor::GenerationalBarrier(reinterpret_cast<Address>(array), - thread_state); - return; - } -#else - if (!ThreadState::IsAnyIncrementalMarking()) - return; - // The object may have been in-place constructed as part of a large object. - // It is not safe to retrieve the page from the object here. - ThreadState* const thread_state = ThreadState::Current(); - if (!thread_state->IsIncrementalMarking()) { - return; - } -#endif // BLINK_HEAP_YOUNG_GENERATION - // See |NotifyNewObject| for details. - ThreadState::NoAllocationScope no_allocation_scope(thread_state); - DCHECK(thread_state->CurrentVisitor()); - // No weak handling for write barriers. Modifying weakly reachable objects - // strongifies them for the current cycle. - while (len-- > 0) { - DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*array)); - TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace( - thread_state->CurrentVisitor(), array); - array++; - } - } - - template <typename T> - static void TraceVectorBacking(Visitor* visitor, - const T* backing, - const T* const* backing_slot) { - visitor->TraceMovablePointer(backing_slot); - visitor->Trace(reinterpret_cast<const HeapVectorBacking<T>*>(backing)); - } - - template <typename T, typename HashTable> - static void TraceHashTableBackingStrongly(Visitor* visitor, - const T* backing, - const T* const* backing_slot) { - visitor->TraceMovablePointer(backing_slot); - visitor->Trace( - reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing)); - } - - template <typename T, typename HashTable> - static void TraceHashTableBackingWeakly(Visitor* visitor, - const T* backing, - const T* const* backing_slot, - WeakCallback callback, - const void* parameter) { - visitor->TraceMovablePointer(backing_slot); - visitor->TraceWeakContainer( - reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing), - reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>( - backing_slot), - TraceTrait<HeapHashTableBacking<HashTable>>::GetTraceDescriptor( - backing), - TraceTrait<HeapHashTableBacking<HashTable>>::GetWeakTraceDescriptor( - backing), - callback, parameter); - } - - private: - static Address MarkAsConstructed(Address address) { - HeapObjectHeader::FromPayload(reinterpret_cast<void*>(address)) - ->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>(); - return address; - } - - static void BackingFree(void*); - static bool BackingExpand(void*, size_t); - static bool BackingShrink(void*, - size_t quantized_current_size, - size_t quantized_shrunk_size); - - template <typename T, wtf_size_t u, typename V> - friend class WTF::Vector; - template <typename T, typename U, typename V, typename W> - friend class WTF::HashSet; - template <typename T, - typename U, - typename V, - typename W, - typename X, - typename Y> - friend class WTF::HashMap; -}; - -template <typename VisitorDispatcher, typename Value> -static void TraceListHashSetValue(VisitorDispatcher visitor, - const Value& value) { - // We use the default hash traits for the value in the node, because - // ListHashSet does not let you specify any specific ones. - // We don't allow ListHashSet of WeakMember, so we set that one false - // (there's an assert elsewhere), but we have to specify some value for the - // strongify template argument, so we specify WTF::WeakPointersActWeak, - // arbitrarily. - TraceCollectionIfEnabled<WTF::kNoWeakHandling, Value, - WTF::HashTraits<Value>>::Trace(visitor, &value); -} - -// The inline capacity is just a dummy template argument to match the off-heap -// allocator. -// This inherits from the static-only HeapAllocator trait class, but we do -// declare pointers to instances. These pointers are always null, and no -// objects are instantiated. -template <typename ValueArg, wtf_size_t inlineCapacity> -class HeapListHashSetAllocator : public HeapAllocator { - DISALLOW_NEW(); - - public: - using TableAllocator = HeapAllocator; - using Node = WTF::ListHashSetNode<ValueArg, HeapListHashSetAllocator>; - - class AllocatorProvider { - DISALLOW_NEW(); - - public: - // For the heap allocation we don't need an actual allocator object, so - // we just return null. - HeapListHashSetAllocator* Get() const { return nullptr; } - - // No allocator object is needed. - void CreateAllocatorIfNeeded() {} - void ReleaseAllocator() {} - - // There is no allocator object in the HeapListHashSet (unlike in the - // regular ListHashSet) so there is nothing to swap. - void Swap(AllocatorProvider& other) {} - }; - - void Deallocate(void* dummy) {} - - // This is not a static method even though it could be, because it needs to - // match the one that the (off-heap) ListHashSetAllocator has. The 'this' - // pointer will always be null. - void* AllocateNode() { - // Consider using a LinkedHashSet instead if this compile-time assert fails: - static_assert(!WTF::IsWeak<ValueArg>::value, - "weak pointers in a ListHashSet will result in null entries " - "in the set"); - - return Malloc<void*, Node>( - sizeof(Node), - nullptr /* Oilpan does not use the heap profiler at the moment. */); - } - - template <typename VisitorDispatcher> - static void TraceValue(VisitorDispatcher visitor, const Node* node) { - TraceListHashSetValue(visitor, node->value_); - } -}; - -namespace internal { - -template <typename T> -constexpr bool IsMember = WTF::IsSubclassOfTemplate<T, Member>::value; - -template <typename T> -constexpr bool IsMemberOrWeakMemberType = - WTF::IsSubclassOfTemplate<T, Member>::value || - WTF::IsSubclassOfTemplate<T, WeakMember>::value; - -} // namespace internal - -template <typename KeyArg, - typename MappedArg, - typename HashArg = typename DefaultHash<KeyArg>::Hash, - typename KeyTraitsArg = HashTraits<KeyArg>, - typename MappedTraitsArg = HashTraits<MappedArg>> -class HeapHashMap : public HashMap<KeyArg, - MappedArg, - HashArg, - KeyTraitsArg, - MappedTraitsArg, - HeapAllocator> { - IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); - DISALLOW_NEW(); - - static void CheckType() { - static_assert(std::is_trivially_destructible<HeapHashMap>::value, - "HeapHashMap must be trivially destructible."); - static_assert( - IsAllowedInContainer<KeyArg>::value, - "Not allowed to directly nest type. Use Member<> indirection instead."); - static_assert( - IsAllowedInContainer<MappedArg>::value, - "Not allowed to directly nest type. Use Member<> indirection instead."); - static_assert( - WTF::IsTraceable<KeyArg>::value || WTF::IsTraceable<MappedArg>::value, - "For hash maps without traceable elements, use HashMap<> " - "instead of HeapHashMap<>."); - static_assert(internal::IsMemberOrWeakMemberType<KeyArg> || - !WTF::IsTraceable<KeyArg>::value, - "HeapHashMap supports only Member, WeakMember and " - "non-traceable types as keys."); - static_assert(internal::IsMemberOrWeakMemberType<MappedArg> || - !WTF::IsTraceable<MappedArg>::value || - WTF::IsSubclassOfTemplate<MappedArg, - TraceWrapperV8Reference>::value, - "HeapHashMap supports only Member, WeakMember, " - "TraceWrapperV8Reference and " - "non-traceable types as values."); - } - - public: - template <typename> - static void* AllocateObject(size_t size) { - return ThreadHeap::Allocate< - HeapHashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>>( - size); - } - - HeapHashMap() { CheckType(); } -}; - -template <typename T, typename U, typename V, typename W, typename X> -struct GCInfoTrait<HeapHashMap<T, U, V, W, X>> - : public GCInfoTrait<HashMap<T, U, V, W, X, HeapAllocator>> {}; - -template <typename ValueArg, - typename HashArg = typename DefaultHash<ValueArg>::Hash, - typename TraitsArg = HashTraits<ValueArg>> -class HeapHashSet - : public HashSet<ValueArg, HashArg, TraitsArg, HeapAllocator> { - IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); - DISALLOW_NEW(); - - static void CheckType() { - static_assert(internal::IsMemberOrWeakMemberType<ValueArg>, - "HeapHashSet supports only Member and WeakMember."); - static_assert(std::is_trivially_destructible<HeapHashSet>::value, - "HeapHashSet must be trivially destructible."); - static_assert( - IsAllowedInContainer<ValueArg>::value, - "Not allowed to directly nest type. Use Member<> indirection instead."); - static_assert(WTF::IsTraceable<ValueArg>::value, - "For hash sets without traceable elements, use HashSet<> " - "instead of HeapHashSet<>."); - } - - public: - template <typename> - static void* AllocateObject(size_t size) { - return ThreadHeap::Allocate<HeapHashSet<ValueArg, HashArg, TraitsArg>>( - size); - } - - HeapHashSet() { CheckType(); } -}; - -template <typename T, typename U, typename V> -struct GCInfoTrait<HeapHashSet<T, U, V>> - : public GCInfoTrait<HashSet<T, U, V, HeapAllocator>> {}; - -template <typename ValueArg, typename TraitsArg = HashTraits<ValueArg>> -class HeapLinkedHashSet - : public LinkedHashSet<ValueArg, TraitsArg, HeapAllocator> { - IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); - DISALLOW_NEW(); - - static void CheckType() { - static_assert(internal::IsMemberOrWeakMemberType<ValueArg>, - "HeapLinkedHashSet supports only Member and WeakMember."); - // If not trivially destructible, we have to add a destructor which will - // hinder performance. - static_assert(std::is_trivially_destructible<HeapLinkedHashSet>::value, - "HeapLinkedHashSet must be trivially destructible."); - static_assert( - IsAllowedInContainer<ValueArg>::value, - "Not allowed to directly nest type. Use Member<> indirection instead."); - static_assert(WTF::IsTraceable<ValueArg>::value, - "For sets without traceable elements, use LinkedHashSet<> " - "instead of HeapLinkedHashSet<>."); - } - - public: - template <typename> - static void* AllocateObject(size_t size) { - return ThreadHeap::Allocate<HeapLinkedHashSet<ValueArg, TraitsArg>>(size); - } - - HeapLinkedHashSet() { CheckType(); } -}; - -template <typename T, typename U> -struct GCInfoTrait<HeapLinkedHashSet<T, U>> - : public GCInfoTrait<LinkedHashSet<T, U, HeapAllocator>> {}; - -template <typename ValueArg, - wtf_size_t inlineCapacity = - 0, // The inlineCapacity is just a dummy to - // match ListHashSet (off-heap). - typename HashArg = typename DefaultHash<ValueArg>::Hash> -class HeapListHashSet - : public ListHashSet<ValueArg, - inlineCapacity, - HashArg, - HeapListHashSetAllocator<ValueArg, inlineCapacity>> { - IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); - DISALLOW_NEW(); - - static void CheckType() { - static_assert(internal::IsMemberOrWeakMemberType<ValueArg>, - "HeapListHashSet supports only Member and WeakMember."); - static_assert(std::is_trivially_destructible<HeapListHashSet>::value, - "HeapListHashSet must be trivially destructible."); - static_assert( - IsAllowedInContainer<ValueArg>::value, - "Not allowed to directly nest type. Use Member<> indirection instead."); - static_assert(WTF::IsTraceable<ValueArg>::value, - "For sets without traceable elements, use ListHashSet<> " - "instead of HeapListHashSet<>."); - } - - public: - template <typename> - static void* AllocateObject(size_t size) { - return ThreadHeap::Allocate< - HeapListHashSet<ValueArg, inlineCapacity, HashArg>>(size); - } - - HeapListHashSet() { CheckType(); } -}; - -template <typename T, wtf_size_t inlineCapacity, typename U> -struct GCInfoTrait<HeapListHashSet<T, inlineCapacity, U>> - : public GCInfoTrait< - ListHashSet<T, - inlineCapacity, - U, - HeapListHashSetAllocator<T, inlineCapacity>>> {}; - -template <typename Value, - typename HashFunctions = typename DefaultHash<Value>::Hash, - typename Traits = HashTraits<Value>> -class HeapHashCountedSet - : public HashCountedSet<Value, HashFunctions, Traits, HeapAllocator> { - IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); - DISALLOW_NEW(); - - static void CheckType() { - static_assert(internal::IsMemberOrWeakMemberType<Value>, - "HeapHashCountedSet supports only Member and WeakMember."); - static_assert(std::is_trivially_destructible<HeapHashCountedSet>::value, - "HeapHashCountedSet must be trivially destructible."); - static_assert( - IsAllowedInContainer<Value>::value, - "Not allowed to directly nest type. Use Member<> indirection instead."); - static_assert(WTF::IsTraceable<Value>::value, - "For counted sets without traceable elements, use " - "HashCountedSet<> instead of HeapHashCountedSet<>."); - } - - public: - template <typename> - static void* AllocateObject(size_t size) { - return ThreadHeap::Allocate< - HeapHashCountedSet<Value, HashFunctions, Traits>>(size); - } - - HeapHashCountedSet() { CheckType(); } -}; - -template <typename T, typename U, typename V> -struct GCInfoTrait<HeapHashCountedSet<T, U, V>> - : public GCInfoTrait<HashCountedSet<T, U, V, HeapAllocator>> {}; - -template <typename T, wtf_size_t inlineCapacity = 0> -class HeapVector : public Vector<T, inlineCapacity, HeapAllocator> { - IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); - DISALLOW_NEW(); - - static void CheckType() { - static_assert( - std::is_trivially_destructible<HeapVector>::value || inlineCapacity, - "HeapVector must be trivially destructible."); - static_assert( - IsAllowedInContainer<T>::value, - "Not allowed to directly nest type. Use Member<> indirection instead."); - static_assert(WTF::IsTraceable<T>::value, - "For vectors without traceable elements, use Vector<> " - "instead of HeapVector<>."); - static_assert(!WTF::IsWeak<T>::value, - "Weak types are not allowed in HeapVector."); - static_assert(WTF::IsTraceableInCollectionTrait<VectorTraits<T>>::value, - "Type must be traceable in collection"); - } - - public: - template <typename> - static void* AllocateObject(size_t size) { - // On-heap HeapVectors generally should not have inline capacity, but it is - // hard to avoid when using a type alias. Hence we only disallow the - // VectorTraits<T>::kNeedsDestruction case for now. - static_assert(inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction, - "on-heap HeapVector<> should not have an inline capacity"); - return ThreadHeap::Allocate<HeapVector<T, inlineCapacity>>(size); - } - - HeapVector() { CheckType(); } - - explicit HeapVector(wtf_size_t size) - : Vector<T, inlineCapacity, HeapAllocator>(size) { - CheckType(); - } - - HeapVector(wtf_size_t size, const T& val) - : Vector<T, inlineCapacity, HeapAllocator>(size, val) { - CheckType(); - } - - template <wtf_size_t otherCapacity> - HeapVector(const HeapVector<T, otherCapacity>& other) - : Vector<T, inlineCapacity, HeapAllocator>(other) { - CheckType(); - } - - HeapVector(std::initializer_list<T> elements) - : Vector<T, inlineCapacity, HeapAllocator>(elements) { - CheckType(); - } -}; - -template <typename T, wtf_size_t inlineCapacity> -struct GCInfoTrait<HeapVector<T, inlineCapacity>> - : public GCInfoTrait<Vector<T, inlineCapacity, HeapAllocator>> {}; - -template <typename T> -class HeapDeque : public Deque<T, 0, HeapAllocator> { - IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); - DISALLOW_NEW(); - - static void CheckType() { - static_assert(internal::IsMember<T>, "HeapDeque supports only Member."); - static_assert(std::is_trivially_destructible<HeapDeque>::value, - "HeapDeque must be trivially destructible."); - static_assert( - IsAllowedInContainer<T>::value, - "Not allowed to directly nest type. Use Member<> indirection instead."); - static_assert(WTF::IsTraceable<T>::value, - "For vectors without traceable elements, use Deque<> instead " - "of HeapDeque<>"); - } - - public: - template <typename> - static void* AllocateObject(size_t size) { - return ThreadHeap::Allocate<HeapDeque<T>>(size); - } - - HeapDeque() { CheckType(); } - - explicit HeapDeque(wtf_size_t size) : Deque<T, 0, HeapAllocator>(size) { - CheckType(); - } - - HeapDeque(wtf_size_t size, const T& val) - : Deque<T, 0, HeapAllocator>(size, val) { - CheckType(); - } - - HeapDeque& operator=(const HeapDeque& other) { - HeapDeque<T> copy(other); - Deque<T, 0, HeapAllocator>::Swap(copy); - return *this; - } - - HeapDeque(const HeapDeque<T>& other) : Deque<T, 0, HeapAllocator>(other) {} -}; - -template <typename T> -struct GCInfoTrait<HeapDeque<T>> - : public GCInfoTrait<Deque<T, 0, HeapAllocator>> {}; - -} // namespace blink - -namespace WTF { - -template <typename T> -struct VectorTraits<blink::Member<T>> : VectorTraitsBase<blink::Member<T>> { - STATIC_ONLY(VectorTraits); - static const bool kNeedsDestruction = false; - static const bool kCanInitializeWithMemset = true; - static const bool kCanClearUnusedSlotsWithMemset = true; - static const bool kCanCopyWithMemcpy = true; - static const bool kCanMoveWithMemcpy = true; - - static constexpr bool kCanTraceConcurrently = true; -}; - -// These traits are used in VectorBackedLinkedList to support WeakMember in -// HeapLinkedHashSet though HeapVector<WeakMember> usage is still banned. -// (See the discussion in https://crrev.com/c/2246014) -template <typename T> -struct VectorTraits<blink::WeakMember<T>> - : VectorTraitsBase<blink::WeakMember<T>> { - STATIC_ONLY(VectorTraits); - static const bool kNeedsDestruction = false; - static const bool kCanInitializeWithMemset = true; - static const bool kCanClearUnusedSlotsWithMemset = true; - static const bool kCanCopyWithMemcpy = true; - static const bool kCanMoveWithMemcpy = true; - - static constexpr bool kCanTraceConcurrently = true; -}; - -template <typename T> -struct VectorTraits<blink::UntracedMember<T>> - : VectorTraitsBase<blink::UntracedMember<T>> { - STATIC_ONLY(VectorTraits); - static const bool kNeedsDestruction = false; - static const bool kCanInitializeWithMemset = true; - static const bool kCanClearUnusedSlotsWithMemset = true; - static const bool kCanMoveWithMemcpy = true; -}; - -template <typename T> -struct VectorTraits<blink::HeapVector<T, 0>> - : VectorTraitsBase<blink::HeapVector<T, 0>> { - STATIC_ONLY(VectorTraits); - static const bool kNeedsDestruction = false; - static const bool kCanInitializeWithMemset = true; - static const bool kCanClearUnusedSlotsWithMemset = true; - static const bool kCanMoveWithMemcpy = true; -}; - -template <typename T> -struct VectorTraits<blink::HeapDeque<T>> - : VectorTraitsBase<blink::HeapDeque<T>> { - STATIC_ONLY(VectorTraits); - static const bool kNeedsDestruction = false; - static const bool kCanInitializeWithMemset = true; - static const bool kCanClearUnusedSlotsWithMemset = true; - static const bool kCanMoveWithMemcpy = true; -}; - -template <typename T, wtf_size_t inlineCapacity> -struct VectorTraits<blink::HeapVector<T, inlineCapacity>> - : VectorTraitsBase<blink::HeapVector<T, inlineCapacity>> { - STATIC_ONLY(VectorTraits); - static const bool kNeedsDestruction = VectorTraits<T>::kNeedsDestruction; - static const bool kCanInitializeWithMemset = - VectorTraits<T>::kCanInitializeWithMemset; - static const bool kCanClearUnusedSlotsWithMemset = - VectorTraits<T>::kCanClearUnusedSlotsWithMemset; - static const bool kCanMoveWithMemcpy = VectorTraits<T>::kCanMoveWithMemcpy; -}; - -template <typename T> -struct HashTraits<blink::Member<T>> : SimpleClassHashTraits<blink::Member<T>> { - STATIC_ONLY(HashTraits); - // FIXME: Implement proper const'ness for iterator types. Requires support - // in the marking Visitor. - using PeekInType = T*; - using IteratorGetType = blink::Member<T>*; - using IteratorConstGetType = const blink::Member<T>*; - using IteratorReferenceType = blink::Member<T>&; - using IteratorConstReferenceType = const blink::Member<T>&; - static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { - return *x; - } - static IteratorConstReferenceType GetToReferenceConstConversion( - IteratorConstGetType x) { - return *x; - } - - using PeekOutType = T*; - - template <typename U> - static void Store(const U& value, blink::Member<T>& storage) { - storage = value; - } - - static PeekOutType Peek(const blink::Member<T>& value) { return value; } - - static void ConstructDeletedValue(blink::Member<T>& slot, bool) { - slot = WTF::kHashTableDeletedValue; - } - - static constexpr bool kCanTraceConcurrently = true; -}; - -template <typename T> -struct HashTraits<blink::WeakMember<T>> - : SimpleClassHashTraits<blink::WeakMember<T>> { - STATIC_ONLY(HashTraits); - static const bool kNeedsDestruction = false; - // FIXME: Implement proper const'ness for iterator types. Requires support - // in the marking Visitor. - using PeekInType = T*; - using IteratorGetType = blink::WeakMember<T>*; - using IteratorConstGetType = const blink::WeakMember<T>*; - using IteratorReferenceType = blink::WeakMember<T>&; - using IteratorConstReferenceType = const blink::WeakMember<T>&; - static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { - return *x; - } - static IteratorConstReferenceType GetToReferenceConstConversion( - IteratorConstGetType x) { - return *x; - } - - using PeekOutType = T*; - - template <typename U> - static void Store(const U& value, blink::WeakMember<T>& storage) { - storage = value; - } - - static PeekOutType Peek(const blink::WeakMember<T>& value) { return value; } - - static void ConstructDeletedValue(blink::WeakMember<T>& slot, bool) { - slot = WTF::kHashTableDeletedValue; - } - - static constexpr bool kCanTraceConcurrently = true; -}; - -template <typename T> -struct HashTraits<blink::UntracedMember<T>> - : SimpleClassHashTraits<blink::UntracedMember<T>> { - STATIC_ONLY(HashTraits); - static const bool kNeedsDestruction = false; - // FIXME: Implement proper const'ness for iterator types. - using PeekInType = T*; - using IteratorGetType = blink::UntracedMember<T>*; - using IteratorConstGetType = const blink::UntracedMember<T>*; - using IteratorReferenceType = blink::UntracedMember<T>&; - using IteratorConstReferenceType = const blink::UntracedMember<T>&; - static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { - return *x; - } - static IteratorConstReferenceType GetToReferenceConstConversion( - IteratorConstGetType x) { - return *x; - } - using PeekOutType = T*; - - template <typename U> - static void Store(const U& value, blink::UntracedMember<T>& storage) { - storage = value; - } - - static PeekOutType Peek(const blink::UntracedMember<T>& value) { - return value; - } -}; - -template <typename T, wtf_size_t inlineCapacity> -struct IsTraceable< - ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>*> { - STATIC_ONLY(IsTraceable); - static_assert(sizeof(T), "T must be fully defined"); - // All heap allocated node pointers need visiting to keep the nodes alive, - // regardless of whether they contain pointers to other heap allocated - // objects. - static const bool value = true; -}; - -template <typename T, wtf_size_t inlineCapacity> -struct IsGarbageCollectedType< - ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>> { - static const bool value = true; -}; - -template <typename Set> -struct IsGarbageCollectedType<ListHashSetIterator<Set>> { - static const bool value = IsGarbageCollectedType<Set>::value; -}; - -template <typename Set> -struct IsGarbageCollectedType<ListHashSetConstIterator<Set>> { - static const bool value = IsGarbageCollectedType<Set>::value; -}; - -template <typename Set> -struct IsGarbageCollectedType<ListHashSetReverseIterator<Set>> { - static const bool value = IsGarbageCollectedType<Set>::value; -}; - -template <typename Set> -struct IsGarbageCollectedType<ListHashSetConstReverseIterator<Set>> { - static const bool value = IsGarbageCollectedType<Set>::value; -}; - -template <typename T, typename H> -struct HandleHashTraits : SimpleClassHashTraits<H> { - STATIC_ONLY(HandleHashTraits); - // TODO: Implement proper const'ness for iterator types. Requires support - // in the marking Visitor. - using PeekInType = T*; - using IteratorGetType = H*; - using IteratorConstGetType = const H*; - using IteratorReferenceType = H&; - using IteratorConstReferenceType = const H&; - static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { - return *x; - } - static IteratorConstReferenceType GetToReferenceConstConversion( - IteratorConstGetType x) { - return *x; - } - - using PeekOutType = T*; - - template <typename U> - static void Store(const U& value, H& storage) { - storage = value; - } - - static PeekOutType Peek(const H& value) { return value; } -}; - -template <typename Value, - typename HashFunctions, - typename Traits, - typename VectorType> -inline void CopyToVector( - const blink::HeapHashCountedSet<Value, HashFunctions, Traits>& set, - VectorType& vector) { - CopyToVector(static_cast<const HashCountedSet<Value, HashFunctions, Traits, - blink::HeapAllocator>&>(set), - vector); -} -} // namespace WTF +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/heap_allocator.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN -#endif +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_ALLOCATOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_stats_collector.h b/chromium/third_party/blink/renderer/platform/heap/heap_stats_collector.h index 344d4394be6..1a6a45c023d 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap_stats_collector.h +++ b/chromium/third_party/blink/renderer/platform/heap/heap_stats_collector.h @@ -1,469 +1,16 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_ -#include <stddef.h> +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -#include "base/atomicops.h" -#include "third_party/blink/renderer/platform/heap/blink_gc.h" -#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" -#include "third_party/blink/renderer/platform/platform_export.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" - -namespace blink { - -// Interface for observing changes to heap sizing. -class PLATFORM_EXPORT ThreadHeapStatsObserver { - public: - // Called upon allocating/releasing chunks of memory that contain objects. - // - // Must not trigger GC or allocate. - virtual void IncreaseAllocatedSpace(size_t) = 0; - virtual void DecreaseAllocatedSpace(size_t) = 0; - - // Called once per GC cycle with the accurate number of live |bytes|. - // - // Must not trigger GC or allocate. - virtual void ResetAllocatedObjectSize(size_t bytes) = 0; - - // Called after observing at least - // |ThreadHeapStatsCollector::kUpdateThreshold| changed bytes through - // allocation or explicit free. Reports both, negative and positive - // increments, to allow observer to decide whether absolute values or only the - // deltas is interesting. - // - // May trigger GC but most not allocate. - virtual void IncreaseAllocatedObjectSize(size_t) = 0; - virtual void DecreaseAllocatedObjectSize(size_t) = 0; -}; - -#define FOR_ALL_SCOPES(V) \ - V(AtomicPauseCompaction) \ - V(AtomicPauseMarkEpilogue) \ - V(AtomicPauseMarkPrologue) \ - V(AtomicPauseMarkRoots) \ - V(AtomicPauseMarkTransitiveClosure) \ - V(AtomicPauseSweepAndCompact) \ - V(CompleteSweep) \ - V(IncrementalMarkingFinalize) \ - V(IncrementalMarkingStartMarking) \ - V(IncrementalMarkingStep) \ - V(IncrementalMarkingWithDeadline) \ - V(InvokePreFinalizers) \ - V(LazySweepInIdle) \ - V(LazySweepOnAllocation) \ - V(MarkBailOutObjects) \ - V(MarkInvokeEphemeronCallbacks) \ - V(MarkFlushV8References) \ - V(MarkFlushEphemeronPairs) \ - V(MarkProcessWorklists) \ - V(MarkProcessMarkingWorklist) \ - V(MarkProcessWriteBarrierWorklist) \ - V(MarkProcessNotFullyconstructeddWorklist) \ - V(MarkNotFullyConstructedObjects) \ - V(MarkWeakProcessing) \ - V(UnifiedMarkingStep) \ - V(VisitCrossThreadPersistents) \ - V(VisitPersistentRoots) \ - V(VisitPersistents) \ - V(VisitRoots) \ - V(VisitStackRoots) \ - V(VisitRememberedSets) - -#define FOR_ALL_CONCURRENT_SCOPES(V) \ - V(ConcurrentMarkInvokeEphemeronCallbacks) \ - V(ConcurrentMarkingStep) \ - V(ConcurrentSweepingStep) - -// Manages counters and statistics across garbage collection cycles. -// -// Usage: -// ThreadHeapStatsCollector stats_collector; -// stats_collector.NotifyMarkingStarted(<BlinkGC::CollectionType>, -// <BlinkGC::GCReason>); -// // Use tracer. -// stats_collector.NotifySweepingCompleted(); -// // Previous event is available using stats_collector.previous(). -class PLATFORM_EXPORT ThreadHeapStatsCollector { - USING_FAST_MALLOC(ThreadHeapStatsCollector); - - public: - // These ids will form human readable names when used in Scopes. - enum Id { -#define DECLARE_ENUM(name) k##name, - FOR_ALL_SCOPES(DECLARE_ENUM) -#undef DECLARE_ENUM - kNumScopeIds, - }; - - enum ConcurrentId { -#define DECLARE_ENUM(name) k##name, - FOR_ALL_CONCURRENT_SCOPES(DECLARE_ENUM) -#undef DECLARE_ENUM - kNumConcurrentScopeIds - }; - - constexpr static const char* ToString(Id id, BlinkGC::CollectionType type) { - switch (id) { -#define CASE(name) \ - case k##name: \ - return type == BlinkGC::CollectionType::kMajor ? "BlinkGC." #name \ - : "BlinkGC." #name \ - ".Minor"; - FOR_ALL_SCOPES(CASE) -#undef CASE - default: - NOTREACHED(); - } - return nullptr; - } - - constexpr static const char* ToString(ConcurrentId id, - BlinkGC::CollectionType type) { - switch (id) { -#define CASE(name) \ - case k##name: \ - return type == BlinkGC::CollectionType::kMajor ? "BlinkGC." #name \ - : "BlinkGC." #name \ - ".Minor"; - FOR_ALL_CONCURRENT_SCOPES(CASE) -#undef CASE - default: - NOTREACHED(); - } - return nullptr; - } - - enum TraceCategory { kEnabled, kDisabled }; - enum ScopeContext { kMutatorThread, kConcurrentThread }; - - // Trace a particular scope. Will emit a trace event and record the time in - // the corresponding ThreadHeapStatsCollector. - template <TraceCategory trace_category = kDisabled, - ScopeContext scope_category = kMutatorThread> - class PLATFORM_EXPORT InternalScope { - DISALLOW_NEW(); - DISALLOW_COPY_AND_ASSIGN(InternalScope); - - using IdType = - std::conditional_t<scope_category == kMutatorThread, Id, ConcurrentId>; - - public: - template <typename... Args> - InternalScope(ThreadHeapStatsCollector* tracer, IdType id, Args... args) - : tracer_(tracer), start_time_(base::TimeTicks::Now()), id_(id) { - StartTrace(args...); - } - - ~InternalScope() { - StopTrace(); - IncreaseScopeTime(id_); - } - - private: - inline constexpr static const char* TraceCategory(); - - inline void StartTrace(); - template <typename Value1> - inline void StartTrace(const char* k1, Value1 v1); - template <typename Value1, typename Value2> - inline void StartTrace(const char* k1, - Value1 v1, - const char* k2, - Value2 v2); - inline void StopTrace(); - - inline void IncreaseScopeTime(Id); - inline void IncreaseScopeTime(ConcurrentId); - - ThreadHeapStatsCollector* const tracer_; - const base::TimeTicks start_time_; - const IdType id_; - }; - - using Scope = InternalScope<kDisabled>; - using EnabledScope = InternalScope<kEnabled>; - using ConcurrentScope = InternalScope<kDisabled, kConcurrentThread>; - using EnabledConcurrentScope = InternalScope<kEnabled, kConcurrentThread>; - - // BlinkGCInV8Scope keeps track of time spent in Blink's GC when called by V8. - // This is necessary to avoid double-accounting of Blink's time when computing - // the overall time (V8 + Blink) spent in GC on the main thread. - class PLATFORM_EXPORT BlinkGCInV8Scope { - DISALLOW_NEW(); - DISALLOW_COPY_AND_ASSIGN(BlinkGCInV8Scope); - - public: - template <typename... Args> - BlinkGCInV8Scope(ThreadHeapStatsCollector* tracer) - : tracer_(tracer), start_time_(base::TimeTicks::Now()) {} - - ~BlinkGCInV8Scope() { - if (tracer_) - tracer_->gc_nested_in_v8_ += base::TimeTicks::Now() - start_time_; - } - - private: - ThreadHeapStatsCollector* const tracer_; - const base::TimeTicks start_time_; - }; - - // POD to hold interesting data accumulated during a garbage collection cycle. - // The event is always fully populated when looking at previous events but - // is only be partially populated when looking at the current event. See - // members on when they are available. - // - // Note that all getters include time for stand-alone as well as unified heap - // GCs. E.g., |atomic_marking_time()| report the marking time of the atomic - // phase, independent of whether the GC was a stand-alone or unified heap GC. - struct PLATFORM_EXPORT Event { - Event(); - - // Overall time spent in the GC cycle. This includes marking time as well as - // sweeping time. - base::TimeDelta gc_cycle_time() const; - - // Time spent in the final atomic pause of a GC cycle. - base::TimeDelta atomic_pause_time() const; - - // Time spent in the final atomic pause for marking the heap. - base::TimeDelta atomic_marking_time() const; - - // Time spent in the final atomic pause in sweeping and compacting the heap. - base::TimeDelta atomic_sweep_and_compact_time() const; - - // Time spent marking the roots. - base::TimeDelta roots_marking_time() const; - - // Time spent incrementally marking the heap. - base::TimeDelta incremental_marking_time() const; - - // Time spent processing worklist in the foreground thread. - base::TimeDelta worklist_processing_time_foreground() const; - - // Time spent flushing v8 references (this is done only in the foreground) - base::TimeDelta flushing_v8_references_time() const; - - // Time spent in foreground tasks marking the heap. - base::TimeDelta foreground_marking_time() const; - - // Time spent in background tasks marking the heap. - base::TimeDelta background_marking_time() const; - - // Overall time spent marking the heap. - base::TimeDelta marking_time() const; - - // Time spent in foreground tasks sweeping the heap. - base::TimeDelta foreground_sweeping_time() const; - - // Time spent in background tasks sweeping the heap. - base::TimeDelta background_sweeping_time() const; - - // Overall time spent sweeping the heap. - base::TimeDelta sweeping_time() const; - - // Marked bytes collected during sweeping. - size_t unique_id = -1; - size_t marked_bytes = 0; - size_t compaction_freed_bytes = 0; - size_t compaction_freed_pages = 0; - bool compaction_recorded_events = false; - base::TimeDelta scope_data[kNumScopeIds]; - base::subtle::Atomic32 concurrent_scope_data[kNumConcurrentScopeIds]{0}; - BlinkGC::GCReason reason = static_cast<BlinkGC::GCReason>(0); - BlinkGC::CollectionType collection_type = BlinkGC::CollectionType::kMajor; - size_t object_size_in_bytes_before_sweeping = 0; - size_t allocated_space_in_bytes_before_sweeping = 0; - size_t partition_alloc_bytes_before_sweeping = 0; - double live_object_rate = 0; - base::TimeDelta gc_nested_in_v8; - bool is_forced_gc = true; - }; - - // Indicates a new garbage collection cycle. - void NotifyMarkingStarted(BlinkGC::CollectionType, - BlinkGC::GCReason, - bool is_forced_gc); - - // Indicates that marking of the current garbage collection cycle is - // completed. - void NotifyMarkingCompleted(size_t marked_bytes); - - // Indicates the end of a garbage collection cycle. This means that sweeping - // is finished at this point. - void NotifySweepingCompleted(); - - void IncreaseScopeTime(Id id, base::TimeDelta time) { - DCHECK(is_started_); - current_.scope_data[id] += time; - } - - void IncreaseConcurrentScopeTime(ConcurrentId id, base::TimeDelta time) { - using Atomic32 = base::subtle::Atomic32; - DCHECK(is_started_); - const int64_t ms = time.InMicroseconds(); - DCHECK(ms <= std::numeric_limits<Atomic32>::max()); - base::subtle::NoBarrier_AtomicIncrement(¤t_.concurrent_scope_data[id], - static_cast<Atomic32>(ms)); - } - - void UpdateReason(BlinkGC::GCReason); - void IncreaseCompactionFreedSize(size_t); - void IncreaseCompactionFreedPages(size_t); - void IncreaseAllocatedObjectSize(size_t); - void DecreaseAllocatedObjectSize(size_t); - void IncreaseAllocatedSpace(size_t); - void DecreaseAllocatedSpace(size_t); - void IncreaseWrapperCount(size_t); - void DecreaseWrapperCount(size_t); - void IncreaseCollectedWrapperCount(size_t); - - // Called by the GC when it hits a point where allocated memory may be - // reported and garbage collection is possible. This is necessary, as - // increments and decrements are reported as close to their actual - // allocation/reclamation as possible. - void AllocatedObjectSizeSafepoint(); - - // Size of objects on the heap. Based on marked bytes in the previous cycle - // and newly allocated bytes since the previous cycle. - size_t object_size_in_bytes() const; - - size_t marked_bytes() const; - base::TimeDelta marking_time_so_far() const; - - base::TimeDelta worklist_processing_time_foreground() const; - - base::TimeDelta flushing_v8_references_time() const; - - int64_t allocated_bytes_since_prev_gc() const; - - size_t allocated_space_bytes() const; - - size_t wrapper_count() const; - size_t collected_wrapper_count() const; - - bool is_started() const { return is_started_; } - - // Statistics for the previously running garbage collection. - const Event& previous() const { return previous_; } - - void RegisterObserver(ThreadHeapStatsObserver* observer); - void UnregisterObserver(ThreadHeapStatsObserver* observer); - - void IncreaseAllocatedObjectSizeForTesting(size_t); - void DecreaseAllocatedObjectSizeForTesting(size_t); - - private: - // Observers are implemented using virtual calls. Avoid notifications below - // reasonably interesting sizes. - static constexpr int64_t kUpdateThreshold = 1024; - - // Invokes |callback| for all registered observers. - template <typename Callback> - void ForAllObservers(Callback callback); - - void AllocatedObjectSizeSafepointImpl(); - - // Statistics for the currently running garbage collection. Note that the - // Event may not be fully populated yet as some phase may not have been run. - const Event& current() const { return current_; } - - Event current_; - Event previous_; - - // Allocated bytes since the last garbage collection. These bytes are reset - // after marking as they are accounted in marked_bytes then. - int64_t allocated_bytes_since_prev_gc_ = 0; - int64_t pos_delta_allocated_bytes_since_prev_gc_ = 0; - int64_t neg_delta_allocated_bytes_since_prev_gc_ = 0; - - // Allocated space in bytes for all arenas. - size_t allocated_space_bytes_ = 0; - - bool is_started_ = false; - - // base::TimeDelta for RawScope. These don't need to be nested within a - // garbage collection cycle to make them easier to use. - base::TimeDelta gc_nested_in_v8_; - - Vector<ThreadHeapStatsObserver*> observers_; - - FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, InitialEmpty); - FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, IncreaseScopeTime); - FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, StopResetsCurrent); -}; - -template <ThreadHeapStatsCollector::TraceCategory trace_category, - ThreadHeapStatsCollector::ScopeContext scope_category> -constexpr const char* -ThreadHeapStatsCollector::InternalScope<trace_category, - scope_category>::TraceCategory() { - switch (trace_category) { - case kEnabled: - return "blink_gc,devtools.timeline"; - case kDisabled: - return TRACE_DISABLED_BY_DEFAULT("blink_gc"); - } -} - -template <ThreadHeapStatsCollector::TraceCategory trace_category, - ThreadHeapStatsCollector::ScopeContext scope_category> -void ThreadHeapStatsCollector::InternalScope<trace_category, - scope_category>::StartTrace() { - TRACE_EVENT_BEGIN0(TraceCategory(), - ToString(id_, tracer_->current_.collection_type)); -} - -template <ThreadHeapStatsCollector::TraceCategory trace_category, - ThreadHeapStatsCollector::ScopeContext scope_category> -template <typename Value1> -void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>:: - StartTrace(const char* k1, Value1 v1) { - TRACE_EVENT_BEGIN1(TraceCategory(), - ToString(id_, tracer_->current_.collection_type), k1, v1); -} - -template <ThreadHeapStatsCollector::TraceCategory trace_category, - ThreadHeapStatsCollector::ScopeContext scope_category> -template <typename Value1, typename Value2> -void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>:: - StartTrace(const char* k1, Value1 v1, const char* k2, Value2 v2) { - TRACE_EVENT_BEGIN2(TraceCategory(), - ToString(id_, tracer_->current_.collection_type), k1, v1, - k2, v2); -} - -template <ThreadHeapStatsCollector::TraceCategory trace_category, - ThreadHeapStatsCollector::ScopeContext scope_category> -void ThreadHeapStatsCollector::InternalScope<trace_category, - scope_category>::StopTrace() { - TRACE_EVENT_END2(TraceCategory(), - ToString(id_, tracer_->current_.collection_type), "epoch", - tracer_->current_.unique_id, "forced", - tracer_->current_.is_forced_gc); -} - -template <ThreadHeapStatsCollector::TraceCategory trace_category, - ThreadHeapStatsCollector::ScopeContext scope_category> -void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>:: - IncreaseScopeTime(Id) { - tracer_->IncreaseScopeTime(id_, base::TimeTicks::Now() - start_time_); -} - -template <ThreadHeapStatsCollector::TraceCategory trace_category, - ThreadHeapStatsCollector::ScopeContext scope_category> -void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>:: - IncreaseScopeTime(ConcurrentId) { - tracer_->IncreaseConcurrentScopeTime(id_, - base::TimeTicks::Now() - start_time_); -} - -#undef FOR_ALL_SCOPES -#undef FOR_ALL_CONCURRENT_SCOPES - -} // namespace blink +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_STATS_COLLECTOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.cc b/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.cc index 4bf47d69328..3373e840c7c 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.cc +++ b/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.cc @@ -7,7 +7,7 @@ #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h" #include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/heap/heap_compact.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h b/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h index e4e3a4c4b51..f9214bbf8ed 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h +++ b/chromium/third_party/blink/renderer/platform/heap/heap_test_utilities.h @@ -14,7 +14,7 @@ #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/heap/trace_traits.h" +#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h" #include "third_party/blink/renderer/platform/heap/visitor.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_traits.h b/chromium/third_party/blink/renderer/platform/heap/heap_traits.h index f72489def15..43245200945 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap_traits.h +++ b/chromium/third_party/blink/renderer/platform/heap/heap_traits.h @@ -1,40 +1,16 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TRAITS_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TRAITS_H_ -#include <type_traits> -#include "third_party/blink/renderer/platform/heap/heap_allocator.h" -#include "third_party/blink/renderer/platform/heap/member.h" -#include "third_party/blink/renderer/platform/wtf/type_traits.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -namespace blink { - -// Given a type T, returns a type that is either Member<T> or just T depending -// on whether T is a garbage-collected type. -template <typename T> -using AddMemberIfNeeded = - std::conditional_t<WTF::IsGarbageCollectedType<T>::value, Member<T>, T>; - -// Given a type T, returns a type that is either HeapVector<T>, -// HeapVector<Member<T>> or Vector<T> depending on T. -template <typename T> -using VectorOf = std::conditional_t<WTF::IsTraceable<T>::value, - HeapVector<AddMemberIfNeeded<T>>, - Vector<T>>; - -// Given types T and U, returns a type that is one of the following: -// - HeapVector<std::pair<V, X>> -// (where V is either T or Member<T> and X is either U or Member<U>) -// - Vector<std::pair<T, U>> -template <typename T, typename U> -using VectorOfPairs = std::conditional_t< - WTF::IsTraceable<T>::value || WTF::IsTraceable<U>::value, - HeapVector<std::pair<AddMemberIfNeeded<T>, AddMemberIfNeeded<U>>>, - Vector<std::pair<T, U>>>; - -} // namespace blink +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/heap_traits.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_TRAITS_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/atomic_entry_flag.h b/chromium/third_party/blink/renderer/platform/heap/impl/atomic_entry_flag.h index 07f013a5984..46342d94529 100644 --- a/chromium/third_party/blink/renderer/platform/heap/atomic_entry_flag.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/atomic_entry_flag.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_ATOMIC_ENTRY_FLAG_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_ATOMIC_ENTRY_FLAG_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_ATOMIC_ENTRY_FLAG_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_ATOMIC_ENTRY_FLAG_H_ #include <atomic> @@ -48,4 +48,4 @@ class AtomicEntryFlag { } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_ATOMIC_ENTRY_FLAG_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_ATOMIC_ENTRY_FLAG_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/blink_gc.cc b/chromium/third_party/blink/renderer/platform/heap/impl/blink_gc.cc index 65881c15dca..58c86eb7a12 100644 --- a/chromium/third_party/blink/renderer/platform/heap/blink_gc.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/blink_gc.cc @@ -4,7 +4,6 @@ #include "third_party/blink/renderer/platform/heap/blink_gc.h" - namespace blink { const char* BlinkGC::ToString(BlinkGC::GCReason reason) { diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/blink_gc.h b/chromium/third_party/blink/renderer/platform/heap/impl/blink_gc.h new file mode 100644 index 00000000000..1aa6ec6ad8c --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/blink_gc.h @@ -0,0 +1,126 @@ +// Copyright 2015 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_H_ + +// BlinkGC.h is a file that defines common things used by Blink GC. + +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" + +#define PRINT_HEAP_STATS 0 // Enable this macro to print heap stats to stderr. + +namespace blink { + +class LivenessBroker; +class MarkingVisitor; +class Visitor; + +using Address = uint8_t*; +using ConstAddress = const uint8_t*; + +using VisitorCallback = void (*)(Visitor*, const void*); +using MarkingVisitorCallback = void (*)(MarkingVisitor*, const void*); +using TraceCallback = VisitorCallback; +using WeakCallback = void (*)(const LivenessBroker&, const void*); +using EphemeronCallback = VisitorCallback; + +// Simple alias to avoid heap compaction type signatures turning into +// a sea of generic |void*|s. +using MovableReference = const void*; + +// List of all arenas. Includes typed arenas as well. +#define FOR_EACH_ARENA(H) \ + H(NormalPage1) \ + H(NormalPage2) \ + H(NormalPage3) \ + H(NormalPage4) \ + H(Vector) \ + H(HashTable) \ + H(Node) \ + H(CSSValue) \ + H(LargeObject) + +class PLATFORM_EXPORT WorklistTaskId { + public: + static constexpr int MutatorThread = 0; + static constexpr int ConcurrentThreadBase = 1; +}; + +class PLATFORM_EXPORT BlinkGC final { + STATIC_ONLY(BlinkGC); + + public: + // CollectionType represents generational collection. kMinor collects objects + // in the young generation (i.e. allocated since the previous collection + // cycle, since we use sticky bits), kMajor collects the entire heap. + enum class CollectionType { kMinor, kMajor }; + + // When garbage collecting we need to know whether or not there + // can be pointers to Blink GC managed objects on the stack for + // each thread. When threads reach a safe point they record + // whether or not they have pointers on the stack. + enum StackState { kNoHeapPointersOnStack, kHeapPointersOnStack }; + + enum MarkingType { + // The marking completes synchronously. + kAtomicMarking, + // The marking task is split and executed in chunks (either on the mutator + // thread or concurrently). + kIncrementalAndConcurrentMarking + }; + + enum SweepingType { + // The sweeping task is split into chunks and scheduled lazily and + // concurrently. + kConcurrentAndLazySweeping, + // The sweeping task executes synchronously right after marking. + kEagerSweeping, + }; + + // Commented out reasons have been used in the past but are not used any + // longer. We keep them here as the corresponding UMA histograms cannot be + // changed. + enum class GCReason { + // kIdleGC = 0 + // kPreciseGC = 1 + // kConservativeGC = 2 + kForcedGCForTesting = 3, + // kMemoryPressureGC = 4 + // kPageNavigationGC = 5 + kThreadTerminationGC = 6, + // kTesting = 7 + // kIncrementalIdleGC = 8 + // kIncrementalV8FollowupGC = 9 + kUnifiedHeapGC = 10, + kUnifiedHeapForMemoryReductionGC = 11, + kUnifiedHeapForcedForTestingGC = 12, + // Used by UMA_HISTOGRAM_ENUMERATION macro. + kMaxValue = kUnifiedHeapForcedForTestingGC, + }; + +#define DeclareArenaIndex(name) k##name##ArenaIndex, + enum ArenaIndices { + FOR_EACH_ARENA(DeclareArenaIndex) + // Values used for iteration of heap segments. + kNumberOfArenas, + }; +#undef DeclareArenaIndex + + enum V8GCType { + kV8MinorGC, + kV8MajorGC, + }; + + static const char* ToString(GCReason); + static const char* ToString(MarkingType); + static const char* ToString(StackState); + static const char* ToString(SweepingType); + static const char* ToString(ArenaIndices); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.cc b/chromium/third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.cc index d4105605814..cb8ce725ffa 100644 --- a/chromium/third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.cc @@ -11,8 +11,8 @@ #include "base/trace_event/process_memory_dump.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h" #include "third_party/blink/renderer/platform/heap/thread_state.h" -#include "third_party/blink/renderer/platform/heap/thread_state_statistics.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/web_memory_allocator_dump.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/threading.h" diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.h b/chromium/third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.h new file mode 100644 index 00000000000..e730f8d58f0 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/blink_gc_memory_dump_provider.h @@ -0,0 +1,47 @@ +// Copyright 2015 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_MEMORY_DUMP_PROVIDER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_MEMORY_DUMP_PROVIDER_H_ + +#include "base/trace_event/memory_dump_provider.h" +#include "third_party/blink/renderer/platform/heap/blink_gc.h" +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace base { +class SingleThreadTaskRunner; +} // namespace base + +namespace blink { + +class ThreadState; + +class PLATFORM_EXPORT BlinkGCMemoryDumpProvider final + : public base::trace_event::MemoryDumpProvider { + USING_FAST_MALLOC(BlinkGCMemoryDumpProvider); + + public: + enum class HeapType { kBlinkMainThread, kBlinkWorkerThread }; + + ~BlinkGCMemoryDumpProvider() final; + BlinkGCMemoryDumpProvider( + ThreadState* thread_state, + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + HeapType heap_type); + + // MemoryDumpProvider implementation. + bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&, + base::trace_event::ProcessMemoryDump*) final; + + private: + ThreadState* const thread_state_; + const HeapType heap_type_; + const std::string dump_base_name_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_BLINK_GC_MEMORY_DUMP_PROVIDER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h b/chromium/third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h new file mode 100644 index 00000000000..b6562e440e3 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/disallow_new_wrapper.h @@ -0,0 +1,53 @@ +// Copyright 2019 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_DISALLOW_NEW_WRAPPER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_DISALLOW_NEW_WRAPPER_H_ + +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/heap/heap.h" +#include "third_party/blink/renderer/platform/heap/visitor.h" + +namespace blink { + +// DisallowNewWrapper wraps a disallow new type in a GarbageCollected class. +template <typename T> +class DisallowNewWrapper final + : public GarbageCollected<DisallowNewWrapper<T>> { + public: + explicit DisallowNewWrapper(const T& value) : value_(value) { + static_assert(WTF::IsDisallowNew<T>::value, + "T needs to be a disallow new type"); + static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable"); + } + explicit DisallowNewWrapper(T&& value) : value_(std::forward<T>(value)) { + static_assert(WTF::IsDisallowNew<T>::value, + "T needs to be a disallow new type"); + static_assert(WTF::IsTraceable<T>::value, "T needs to be traceable"); + } + + const T& Value() const { return value_; } + T&& TakeValue() { return std::move(value_); } + + void Trace(Visitor* visitor) const { visitor->Trace(value_); } + + private: + T value_; +}; + +// Wraps a disallow new type in a GarbageCollected class, making it possible to +// be referenced off heap from a Persistent. +template <typename T> +DisallowNewWrapper<T>* WrapDisallowNew(const T& value) { + return MakeGarbageCollected<DisallowNewWrapper<T>>(value); +} + +template <typename T> +DisallowNewWrapper<T>* WrapDisallowNew(T&& value) { + return MakeGarbageCollected<DisallowNewWrapper<T>>(std::forward<T>(value)); +} + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_DISALLOW_NEW_WRAPPER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/finalizer_traits.h b/chromium/third_party/blink/renderer/platform/heap/impl/finalizer_traits.h index 1a450a480de..2f0e0ee9f44 100644 --- a/chromium/third_party/blink/renderer/platform/heap/finalizer_traits.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/finalizer_traits.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_FINALIZER_TRAITS_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_FINALIZER_TRAITS_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_FINALIZER_TRAITS_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_FINALIZER_TRAITS_H_ #include <type_traits> @@ -92,4 +92,4 @@ struct FinalizerTrait { } // namespace internal } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_FINALIZER_TRAITS_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_FINALIZER_TRAITS_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/garbage_collected.h b/chromium/third_party/blink/renderer/platform/heap/impl/garbage_collected.h new file mode 100644 index 00000000000..b7af662ed5d --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/garbage_collected.h @@ -0,0 +1,117 @@ +// Copyright 2015 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GARBAGE_COLLECTED_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GARBAGE_COLLECTED_H_ + +#include "base/macros.h" +#include "third_party/blink/renderer/platform/heap/thread_state.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/assertions.h" +#include "third_party/blink/renderer/platform/wtf/type_traits.h" + +namespace blink { + +template <typename T> +class GarbageCollected; + +// GC_PLUGIN_IGNORE is used to make the plugin ignore a particular class or +// field when checking for proper usage. When using GC_PLUGIN_IGNORE +// a bug-number should be provided as an argument where the bug describes +// what needs to happen to remove the GC_PLUGIN_IGNORE again. +#if defined(__clang__) +#define GC_PLUGIN_IGNORE(bug) \ + __attribute__((annotate("blink_gc_plugin_ignore"))) +#else +#define GC_PLUGIN_IGNORE(bug) +#endif + +// Template to determine if a class is a GarbageCollectedMixin by checking if it +// has IsGarbageCollectedMixinMarker +template <typename T> +struct IsGarbageCollectedMixin { + private: + typedef char YesType; + struct NoType { + char padding[8]; + }; + + template <typename U> + static YesType CheckMarker(typename U::IsGarbageCollectedMixinMarker*); + template <typename U> + static NoType CheckMarker(...); + + public: + static const bool value = sizeof(CheckMarker<T>(nullptr)) == sizeof(YesType); +}; + +// TraceDescriptor is used to describe how to trace an object. +struct TraceDescriptor { + STACK_ALLOCATED(); + + public: + // The adjusted base pointer of the object that should be traced. + const void* base_object_payload; + // A callback for tracing the object. + TraceCallback callback; +}; + +// The GarbageCollectedMixin interface can be used to automatically define +// TraceTrait/ObjectAliveTrait on non-leftmost deriving classes which need +// to be garbage collected. +class PLATFORM_EXPORT GarbageCollectedMixin { + public: + typedef int IsGarbageCollectedMixinMarker; + virtual void Trace(Visitor*) const {} +}; + +// Base class for objects allocated in the Blink garbage-collected heap. +// +// Instances of GarbageCollected will be finalized if they are non-trivially +// destructible. +template <typename T> +class GarbageCollected; + +template <typename T, + bool = WTF::IsSubclassOfTemplate<typename std::remove_const<T>::type, + GarbageCollected>::value> +class NeedsAdjustPointer; + +template <typename T> +class NeedsAdjustPointer<T, true> { + static_assert(sizeof(T), "T must be fully defined"); + + public: + static const bool value = false; +}; + +template <typename T> +class NeedsAdjustPointer<T, false> { + static_assert(sizeof(T), "T must be fully defined"); + + public: + static const bool value = + IsGarbageCollectedMixin<typename std::remove_const<T>::type>::value; +}; + +// TODO(sof): migrate to wtf/TypeTraits.h +template <typename T> +class IsFullyDefined { + using TrueType = char; + struct FalseType { + char dummy[2]; + }; + + template <typename U, size_t sz = sizeof(U)> + static TrueType IsSizeofKnown(U*); + static FalseType IsSizeofKnown(...); + static T& t_; + + public: + static const bool value = sizeof(TrueType) == sizeof(IsSizeofKnown(&t_)); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GARBAGE_COLLECTED_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/gc_info.cc b/chromium/third_party/blink/renderer/platform/heap/impl/gc_info.cc index a3187825c6d..14361c26f3c 100644 --- a/chromium/third_party/blink/renderer/platform/heap/gc_info.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/gc_info.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/platform/heap/gc_info.h" +#include "third_party/blink/renderer/platform/heap/impl/gc_info.h" #include "base/allocator/partition_allocator/page_allocator.h" #include "base/bits.h" diff --git a/chromium/third_party/blink/renderer/platform/heap/gc_info.h b/chromium/third_party/blink/renderer/platform/heap/impl/gc_info.h index 155b9164a4a..bec05ee6c1b 100644 --- a/chromium/third_party/blink/renderer/platform/heap/gc_info.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/gc_info.h @@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_INFO_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GC_INFO_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_INFO_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_INFO_H_ #include <atomic> #include "base/gtest_prod_util.h" #include "third_party/blink/renderer/platform/heap/blink_gc.h" -#include "third_party/blink/renderer/platform/heap/finalizer_traits.h" -#include "third_party/blink/renderer/platform/heap/name_traits.h" +#include "third_party/blink/renderer/platform/heap/impl/finalizer_traits.h" +#include "third_party/blink/renderer/platform/heap/impl/name_traits.h" #include "third_party/blink/renderer/platform/wtf/threading_primitives.h" namespace blink { @@ -125,4 +125,4 @@ class GCInfoTrait<const U> : public GCInfoTrait<U> {}; } // namespace blink -#endif +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_INFO_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/gc_task_runner.h b/chromium/third_party/blink/renderer/platform/heap/impl/gc_task_runner.h new file mode 100644 index 00000000000..1e93f7fcac5 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/gc_task_runner.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_TASK_RUNNER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_TASK_RUNNER_H_ + +#include <memory> +#include "base/location.h" +#include "third_party/blink/renderer/platform/heap/thread_state.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" +#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" + +namespace blink { + +class GCTaskObserver final : public Thread::TaskObserver { + USING_FAST_MALLOC(GCTaskObserver); + + public: + GCTaskObserver() : nesting_(0) {} + + ~GCTaskObserver() override { + // m_nesting can be 1 if this was unregistered in a task and + // didProcessTask was not called. + DCHECK(!nesting_ || nesting_ == 1); + } + + void WillProcessTask(const base::PendingTask&, bool) override { nesting_++; } + + void DidProcessTask(const base::PendingTask&) override { + // In the production code WebKit::initialize is called from inside the + // message loop so we can get didProcessTask() without corresponding + // willProcessTask once. This is benign. + if (nesting_) + nesting_--; + + ThreadState::Current()->SafePoint(nesting_ + ? BlinkGC::kHeapPointersOnStack + : BlinkGC::kNoHeapPointersOnStack); + } + + private: + int nesting_; +}; + +class GCTaskRunner final { + USING_FAST_MALLOC(GCTaskRunner); + + public: + explicit GCTaskRunner(Thread* thread) + : gc_task_observer_(std::make_unique<GCTaskObserver>()), thread_(thread) { + thread_->AddTaskObserver(gc_task_observer_.get()); + } + + ~GCTaskRunner() { thread_->RemoveTaskObserver(gc_task_observer_.get()); } + + private: + std::unique_ptr<GCTaskObserver> gc_task_observer_; + Thread* thread_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_GC_TASK_RUNNER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/heap.cc b/chromium/third_party/blink/renderer/platform/heap/impl/heap.cc index 2a5b1790935..2fa56d7d1d9 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap.cc @@ -40,13 +40,13 @@ #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h" #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h" #include "third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h" -#include "third_party/blink/renderer/platform/heap/heap_compact.h" #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h" -#include "third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h" -#include "third_party/blink/renderer/platform/heap/marking_visitor.h" -#include "third_party/blink/renderer/platform/heap/page_bloom_filter.h" -#include "third_party/blink/renderer/platform/heap/page_memory.h" -#include "third_party/blink/renderer/platform/heap/page_pool.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h" +#include "third_party/blink/renderer/platform/heap/impl/page_bloom_filter.h" +#include "third_party/blink/renderer/platform/heap/impl/page_memory.h" +#include "third_party/blink/renderer/platform/heap/impl/page_pool.h" #include "third_party/blink/renderer/platform/heap/thread_state_scopes.h" #include "third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h" #include "third_party/blink/renderer/platform/instrumentation/histogram.h" @@ -180,6 +180,7 @@ void ThreadHeap::SetupWorklists(bool should_initialize_compaction_worklists) { v8_references_worklist_ = std::make_unique<V8ReferencesWorklist>(); not_safe_to_concurrently_trace_worklist_ = std::make_unique<NotSafeToConcurrentlyTraceWorklist>(); + weak_containers_worklist_ = std::make_unique<WeakContainersWorklist>(); if (should_initialize_compaction_worklists) { movable_reference_worklist_ = std::make_unique<MovableReferenceWorklist>(); } @@ -193,6 +194,7 @@ void ThreadHeap::DestroyMarkingWorklists(BlinkGC::StackState stack_state) { ephemeron_pairs_to_process_worklist_.reset(); v8_references_worklist_.reset(); not_safe_to_concurrently_trace_worklist_.reset(); + weak_containers_worklist_.reset(); // The fixed point iteration may have found not-fully-constructed objects. // Such objects should have already been found through the stack scan though // and should thus already be marked. @@ -376,8 +378,7 @@ bool ThreadHeap::InvokeEphemeronCallbacks( return DrainWorklistWithDeadline( deadline, ephemeron_pairs_to_process_worklist_.get(), [visitor](EphemeronPairItem& item) { - visitor->VisitEphemeron(item.key, item.value, - item.value_trace_callback); + visitor->VisitEphemeron(item.key, item.value_desc); }, WorklistTaskId::MutatorThread); } @@ -579,14 +580,12 @@ bool ThreadHeap::AdvanceConcurrentMarking( // Callbacks found by the concurrent marking will be flushed eventually // by the mutator thread and then invoked either concurrently or by the // mutator thread (in the atomic pause at latest). - finished = - DrainWorklist<kDefaultConcurrentDeadlineCheckInterval>( - ephemeron_pairs_to_process_worklist_.get(), - [visitor](EphemeronPairItem& item) { - visitor->VisitEphemeron(item.key, item.value, - item.value_trace_callback); - }, - should_yield_callback, visitor->task_id()); + finished = DrainWorklist<kDefaultConcurrentDeadlineCheckInterval>( + ephemeron_pairs_to_process_worklist_.get(), + [visitor](EphemeronPairItem& item) { + visitor->VisitEphemeron(item.key, item.value_desc); + }, + should_yield_callback, visitor->task_id()); if (!finished) break; } @@ -711,8 +710,8 @@ void ThreadHeap::CompleteSweep() { } void ThreadHeap::InvokeFinalizersOnSweptPages() { - for (size_t i = BlinkGC::kNormalPage1ArenaIndex; - i < BlinkGC::kNumberOfArenas; i++) + for (size_t i = BlinkGC::kNormalPage1ArenaIndex; i < BlinkGC::kNumberOfArenas; + i++) arenas_[i]->InvokeFinalizersOnSweptPages(); } diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap.h new file mode 100644 index 00000000000..f1740aaa3e2 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap.h @@ -0,0 +1,757 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_H_ + +#include <limits> +#include <memory> +#include <unordered_set> + +#include "base/macros.h" +#include "build/build_config.h" +#include "third_party/blink/renderer/platform/heap/impl/gc_info.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_page.h" +#include "third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h" +#include "third_party/blink/renderer/platform/heap/impl/worklist.h" +#include "third_party/blink/renderer/platform/heap/process_heap.h" +#include "third_party/blink/renderer/platform/heap/thread_state.h" +#include "third_party/blink/renderer/platform/heap/visitor.h" +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/assertions.h" +#include "third_party/blink/renderer/platform/wtf/forward.h" +#include "third_party/blink/renderer/platform/wtf/sanitizers.h" +#include "third_party/blink/renderer/platform/wtf/threading_primitives.h" + +namespace blink { + +namespace incremental_marking_test { +class IncrementalMarkingScopeBase; +} // namespace incremental_marking_test + +class ConcurrentMarkingVisitor; +class ThreadHeapStatsCollector; +class PageBloomFilter; +class PagePool; +class ProcessHeapReporter; +class RegionTree; +class MarkingSchedulingOracle; + +using MarkingItem = TraceDescriptor; +using NotFullyConstructedItem = const void*; + +struct EphemeronPairItem { + const void* key; + TraceDescriptor value_desc; +}; + +struct CustomCallbackItem { + WeakCallback callback; + const void* parameter; +}; + +struct NotSafeToConcurrentlyTraceItem { + TraceDescriptor desc; + size_t bailout_size; +}; + +using V8Reference = const TraceWrapperV8Reference<v8::Value>*; + +// Segment size of 512 entries necessary to avoid throughput regressions. Since +// the work list is currently a temporary object this is not a problem. +using MarkingWorklist = Worklist<MarkingItem, 512 /* local entries */>; +using WriteBarrierWorklist = Worklist<HeapObjectHeader*, 64>; +using NotFullyConstructedWorklist = + Worklist<NotFullyConstructedItem, 16 /* local entries */>; +using WeakCallbackWorklist = + Worklist<CustomCallbackItem, 64 /* local entries */>; +// Using large local segments here (sized 512 entries) to avoid throughput +// regressions. +using MovableReferenceWorklist = + Worklist<const MovableReference*, 256 /* local entries */>; +using EphemeronPairsWorklist = + Worklist<EphemeronPairItem, 64 /* local entries */>; +using V8ReferencesWorklist = Worklist<V8Reference, 16 /* local entries */>; +using NotSafeToConcurrentlyTraceWorklist = + Worklist<NotSafeToConcurrentlyTraceItem, 64 /* local entries */>; + +class WeakContainersWorklist { + public: + inline void Push(const HeapObjectHeader* object) { + DCHECK(object); + WTF::MutexLocker locker(lock_); + objects_.insert(object); + } + + inline bool Contains(const HeapObjectHeader* object) { + // This method is called only during atomic pause, so lock is not needed. + DCHECK(object); + return objects_.find(object) != objects_.end(); + } + + private: + WTF::Mutex lock_; + std::unordered_set<const HeapObjectHeader*> objects_; +}; + +class PLATFORM_EXPORT HeapAllocHooks { + STATIC_ONLY(HeapAllocHooks); + + public: + // TODO(hajimehoshi): Pass a type name of the allocated object. + typedef void AllocationHook(Address, size_t, const char*); + typedef void FreeHook(Address); + + // Sets allocation hook. Only one hook is supported. + static void SetAllocationHook(AllocationHook* hook) { + CHECK(!allocation_hook_ || !hook); + allocation_hook_ = hook; + } + + // Sets free hook. Only one hook is supported. + static void SetFreeHook(FreeHook* hook) { + CHECK(!free_hook_ || !hook); + free_hook_ = hook; + } + + static void AllocationHookIfEnabled(Address address, + size_t size, + const char* type_name) { + AllocationHook* allocation_hook = allocation_hook_; + if (UNLIKELY(!!allocation_hook)) + allocation_hook(address, size, type_name); + } + + static void FreeHookIfEnabled(Address address) { + FreeHook* free_hook = free_hook_; + if (UNLIKELY(!!free_hook)) + free_hook(address); + } + + private: + static AllocationHook* allocation_hook_; + static FreeHook* free_hook_; +}; + +class HeapCompact; +template <typename T> +class Member; +template <typename T> +class WeakMember; +template <typename T> +class UntracedMember; + +namespace internal { + +class LivenessBrokerFactory; + +template <typename T, bool = NeedsAdjustPointer<T>::value> +class ObjectAliveTrait; + +template <typename T> +class ObjectAliveTrait<T, false> { + STATIC_ONLY(ObjectAliveTrait); + + public: + static bool IsHeapObjectAlive(const T* object) { + static_assert(sizeof(T), "T must be fully defined"); + return HeapObjectHeader::FromPayload(object)->IsMarked(); + } +}; + +template <typename T> +class ObjectAliveTrait<T, true> { + STATIC_ONLY(ObjectAliveTrait); + + public: + NO_SANITIZE_ADDRESS + static bool IsHeapObjectAlive(const T* object) { + static_assert(sizeof(T), "T must be fully defined"); + const HeapObjectHeader* header = HeapObjectHeader::FromPayload( + TraceTrait<T>::GetTraceDescriptor(object).base_object_payload); + DCHECK(!header->IsInConstruction() || header->IsMarked()); + return header->IsMarked(); + } +}; + +template <typename T, typename = int> +struct IsGarbageCollectedContainer : std::false_type {}; + +template <typename T> +struct IsGarbageCollectedContainer< + T, + typename T::IsGarbageCollectedCollectionTypeMarker> : std::true_type {}; + +} // namespace internal + +class PLATFORM_EXPORT ThreadHeap { + USING_FAST_MALLOC(ThreadHeap); + + using EphemeronProcessing = ThreadState::EphemeronProcessing; + + public: + explicit ThreadHeap(ThreadState*); + ~ThreadHeap(); + + MarkingWorklist* GetMarkingWorklist() const { + return marking_worklist_.get(); + } + + WriteBarrierWorklist* GetWriteBarrierWorklist() const { + return write_barrier_worklist_.get(); + } + + NotFullyConstructedWorklist* GetNotFullyConstructedWorklist() const { + return not_fully_constructed_worklist_.get(); + } + + NotFullyConstructedWorklist* GetPreviouslyNotFullyConstructedWorklist() + const { + return previously_not_fully_constructed_worklist_.get(); + } + + WeakCallbackWorklist* GetWeakCallbackWorklist() const { + return weak_callback_worklist_.get(); + } + + MovableReferenceWorklist* GetMovableReferenceWorklist() const { + return movable_reference_worklist_.get(); + } + + EphemeronPairsWorklist* GetDiscoveredEphemeronPairsWorklist() const { + return discovered_ephemeron_pairs_worklist_.get(); + } + + EphemeronPairsWorklist* GetEphemeronPairsToProcessWorklist() const { + return ephemeron_pairs_to_process_worklist_.get(); + } + + V8ReferencesWorklist* GetV8ReferencesWorklist() const { + return v8_references_worklist_.get(); + } + + NotSafeToConcurrentlyTraceWorklist* GetNotSafeToConcurrentlyTraceWorklist() + const { + return not_safe_to_concurrently_trace_worklist_.get(); + } + + WeakContainersWorklist* GetWeakContainersWorklist() const { + return weak_containers_worklist_.get(); + } + + // Register an ephemeron table for fixed-point iteration. + void RegisterWeakTable(void* container_object, EphemeronCallback); + + // Heap compaction registration methods: + + // Checks whether we need to register |addr| as a backing store or a slot + // containing reference to it. + bool ShouldRegisterMovingAddress(); + + RegionTree* GetRegionTree() { return region_tree_.get(); } + + static inline size_t AllocationSizeFromSize(size_t size) { + // Add space for header. + size_t allocation_size = size + sizeof(HeapObjectHeader); + // The allocation size calculation can overflow for large sizes. + CHECK_GT(allocation_size, size); + // Align size with allocation granularity. + allocation_size = (allocation_size + kAllocationMask) & ~kAllocationMask; + return allocation_size; + } + Address AllocateOnArenaIndex(ThreadState*, + size_t, + int arena_index, + uint32_t gc_info_index, + const char* type_name); + template <typename T> + static Address Allocate(size_t); + + void WeakProcessing(MarkingVisitor*); + + // Moves not fully constructed objects to previously not fully constructed + // objects. Such objects can be iterated using the Trace() method and do + // not need to rely on conservative handling. + void FlushNotFullyConstructedObjects(); + + // Moves ephemeron pairs from |discovered_ephemeron_pairs_worklist_| to + // |ephemeron_pairs_to_process_worklist_| + void FlushEphemeronPairs(EphemeronProcessing); + + // Marks not fully constructed objects. + void MarkNotFullyConstructedObjects(MarkingVisitor*); + // Marks the transitive closure including ephemerons. + bool AdvanceMarking(MarkingVisitor*, base::TimeTicks, EphemeronProcessing); + void VerifyMarking(); + + // Returns true if concurrent markers will have work to steal + bool HasWorkForConcurrentMarking() const; + // Returns the amount of work currently available for stealing (there could be + // work remaining even if this is 0). + size_t ConcurrentMarkingGlobalWorkSize() const; + // Returns true if marker is done + bool AdvanceConcurrentMarking(ConcurrentMarkingVisitor*, + base::JobDelegate*, + MarkingSchedulingOracle* marking_scheduler); + + // Conservatively checks whether an address is a pointer in any of the + // thread heaps. If so marks the object pointed to as live. + Address CheckAndMarkPointer(MarkingVisitor*, Address); + + // Visits remembered sets. + void VisitRememberedSets(MarkingVisitor*); + + size_t ObjectPayloadSizeForTesting(); + void ResetAllocationPointForTesting(); + + PagePool* GetFreePagePool() { return free_page_pool_.get(); } + + // This look-up uses the region search tree and a negative contains cache to + // provide an efficient mapping from arbitrary addresses to the containing + // heap-page if one exists. + BasePage* LookupPageForAddress(ConstAddress); + + HeapCompact* Compaction(); + + // Get one of the heap structures for this thread. + // The thread heap is split into multiple heap parts based on object types + // and object sizes. + BaseArena* Arena(int arena_index) const { + DCHECK_LE(0, arena_index); + DCHECK_LT(arena_index, BlinkGC::kNumberOfArenas); + return arenas_[arena_index]; + } + + static bool IsVectorArenaIndex(int arena_index) { + return BlinkGC::kVectorArenaIndex == arena_index; + } + static bool IsNormalArenaIndex(int); + + void MakeConsistentForGC(); + // MakeConsistentForMutator() drops marks from marked objects and rebuild + // free lists. This is called after taking a snapshot and before resuming + // the executions of mutators. + void MakeConsistentForMutator(); + + // Unmarks all objects in the entire heap. This is supposed to be called in + // the beginning of major GC. + void Unmark(); + + void Compact(); + + bool AdvanceLazySweep(base::TimeTicks deadline); + bool AdvanceConcurrentSweep(base::JobDelegate*); + + void PrepareForSweep(BlinkGC::CollectionType); + void RemoveAllPages(); + void InvokeFinalizersOnSweptPages(); + void CompleteSweep(); + + void CollectStatistics(ThreadState::Statistics* statistics); + + ThreadHeapStatsCollector* stats_collector() const { + return heap_stats_collector_.get(); + } + +#if defined(ADDRESS_SANITIZER) + void PoisonUnmarkedObjects(); +#endif + +#if DCHECK_IS_ON() + // Infrastructure to determine if an address is within one of the + // address ranges for the Blink heap. If the address is in the Blink + // heap the containing heap page is returned. + BasePage* FindPageFromAddress(Address); + BasePage* FindPageFromAddress(const void* pointer) { + return FindPageFromAddress( + reinterpret_cast<Address>(const_cast<void*>(pointer))); + } +#endif + + PageBloomFilter* page_bloom_filter() { return page_bloom_filter_.get(); } + + bool IsInLastAllocatedRegion(Address address) const; + void SetLastAllocatedRegion(Address start, size_t length); + + private: + struct LastAllocatedRegion { + Address start = nullptr; + size_t length = 0; + }; + + static int ArenaIndexForObjectSize(size_t); + + void SetupWorklists(bool); + void DestroyMarkingWorklists(BlinkGC::StackState); + void DestroyCompactionWorklists(); + + bool InvokeEphemeronCallbacks(EphemeronProcessing, + MarkingVisitor*, + base::TimeTicks); + + bool FlushV8References(base::TimeTicks); + + ThreadState* thread_state_; + std::unique_ptr<ThreadHeapStatsCollector> heap_stats_collector_; + std::unique_ptr<RegionTree> region_tree_; + std::unique_ptr<PageBloomFilter> page_bloom_filter_; + std::unique_ptr<PagePool> free_page_pool_; + std::unique_ptr<ProcessHeapReporter> process_heap_reporter_; + + // All objects on this worklist have been fully initialized and assigned a + // trace callback for iterating the body of the object. This worklist should + // contain almost all objects. + std::unique_ptr<MarkingWorklist> marking_worklist_; + + // Objects on this worklist have been collected in the write barrier. The + // worklist is different from |marking_worklist_| to minimize execution in the + // path where a write barrier is executed. + std::unique_ptr<WriteBarrierWorklist> write_barrier_worklist_; + + // Objects on this worklist were observed to be in construction (in their + // constructor) and thus have been delayed for processing. They have not yet + // been assigned a valid header and trace callback. + std::unique_ptr<NotFullyConstructedWorklist> not_fully_constructed_worklist_; + + // Objects on this worklist were previously in construction but have been + // moved here upon observing a safepoint, i.e., processing without stack. They + // have not yet been assigned a valid header and trace callback but are fully + // specified and can thus be iterated using the trace callback (which can be + // looked up dynamically). + std::unique_ptr<NotFullyConstructedWorklist> + previously_not_fully_constructed_worklist_; + + // Worklist of weak callbacks accumulated for objects. Such callbacks are + // processed after finishing marking objects. + std::unique_ptr<WeakCallbackWorklist> weak_callback_worklist_; + + // The worklist is to remember slots that are traced during + // marking phases. The mapping between the slots and the backing stores are + // created at the atomic pause phase. + std::unique_ptr<MovableReferenceWorklist> movable_reference_worklist_; + + // Worklist of ephemeron callbacks. Used to pass new callbacks from + // MarkingVisitor to ThreadHeap. + std::unique_ptr<EphemeronPairsWorklist> discovered_ephemeron_pairs_worklist_; + std::unique_ptr<EphemeronPairsWorklist> ephemeron_pairs_to_process_worklist_; + + // Worklist for storing the V8 references until ThreadHeap can flush them + // to V8. + std::unique_ptr<V8ReferencesWorklist> v8_references_worklist_; + + std::unique_ptr<NotSafeToConcurrentlyTraceWorklist> + not_safe_to_concurrently_trace_worklist_; + + std::unique_ptr<WeakContainersWorklist> weak_containers_worklist_; + + std::unique_ptr<HeapCompact> compaction_; + + LastAllocatedRegion last_allocated_region_; + + BaseArena* arenas_[BlinkGC::kNumberOfArenas]; + + static ThreadHeap* main_thread_heap_; + + static constexpr size_t kStepsBeforeEphemeronPairsFlush = 4u; + size_t steps_since_last_ephemeron_pairs_flush_ = 0; + static constexpr size_t kStepsBeforeEphemeronProcessing = 16u; + size_t steps_since_last_ephemeron_processing_ = 0; + + friend class incremental_marking_test::IncrementalMarkingScopeBase; + template <typename T> + friend class Member; + friend class ThreadState; +}; + +template <typename T> +class GarbageCollected { + IS_GARBAGE_COLLECTED_TYPE(); + + public: + using ParentMostGarbageCollectedType = T; + + // Must use MakeGarbageCollected. + void* operator new(size_t) = delete; + void* operator new[](size_t) = delete; + // The garbage collector is taking care of reclaiming the object. Also, + // virtual destructor requires an unambiguous, accessible 'operator delete'. + void operator delete(void*) { NOTREACHED(); } + void operator delete[](void*) = delete; + + template <typename Derived> + static void* AllocateObject(size_t size) { + return ThreadHeap::Allocate<GCInfoFoldedType<Derived>>(size); + } + + protected: + // This trait in theory can be moved to gc_info.h, but that would cause + // significant memory bloat caused by huge number of ThreadHeap::Allocate<> + // instantiations, which linker is not able to fold. + template <typename Derived> + class GCInfoFolded { + static constexpr bool is_virtual_destructor_at_base = + std::has_virtual_destructor<ParentMostGarbageCollectedType>::value; + static constexpr bool both_trivially_destructible = + std::is_trivially_destructible<ParentMostGarbageCollectedType>::value && + std::is_trivially_destructible<Derived>::value; + static constexpr bool has_custom_dispatch_at_base = + internal::HasFinalizeGarbageCollectedObject< + ParentMostGarbageCollectedType>::value; + + public: + using Type = std::conditional_t<is_virtual_destructor_at_base || + both_trivially_destructible || + has_custom_dispatch_at_base, + ParentMostGarbageCollectedType, + Derived>; + }; + + template <typename Derived> + using GCInfoFoldedType = typename GCInfoFolded<Derived>::Type; + + GarbageCollected() = default; + + DISALLOW_COPY_AND_ASSIGN(GarbageCollected); +}; + +// Used for passing custom sizes to MakeGarbageCollected. +struct AdditionalBytes { + explicit AdditionalBytes(size_t bytes) : value(bytes) {} + const size_t value; +}; + +template <typename T> +struct MakeGarbageCollectedTrait { + template <typename... Args> + static T* Call(Args&&... args) { + static_assert(WTF::IsGarbageCollectedType<T>::value, + "T needs to be a garbage collected object"); + static_assert( + std::is_trivially_destructible<T>::value || + std::has_virtual_destructor<T>::value || std::is_final<T>::value || + internal::IsGarbageCollectedContainer<T>::value || + internal::HasFinalizeGarbageCollectedObject<T>::value, + "Finalized GarbageCollected class should either have a virtual " + "destructor or be marked as final"); + static_assert(!IsGarbageCollectedMixin<T>::value || + sizeof(T) <= kLargeObjectSizeThreshold, + "GarbageCollectedMixin may not be a large object"); + void* memory = T::template AllocateObject<T>(sizeof(T)); + HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory); + // Placement new as regular operator new() is deleted. + T* object = ::new (memory) T(std::forward<Args>(args)...); + header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>(); + return object; + } + + template <typename... Args> + static T* Call(AdditionalBytes additional_bytes, Args&&... args) { + static_assert(WTF::IsGarbageCollectedType<T>::value, + "T needs to be a garbage collected object"); + static_assert( + std::is_trivially_destructible<T>::value || + std::has_virtual_destructor<T>::value || std::is_final<T>::value || + internal::IsGarbageCollectedContainer<T>::value || + internal::HasFinalizeGarbageCollectedObject<T>::value, + "Finalized GarbageCollected class should either have a virtual " + "destructor or be marked as final."); + const size_t size = sizeof(T) + additional_bytes.value; + if (IsGarbageCollectedMixin<T>::value) { + // Ban large mixin so we can use PageFromObject() on them. + CHECK_GE(kLargeObjectSizeThreshold, size) + << "GarbageCollectedMixin may not be a large object"; + } + void* memory = T::template AllocateObject<T>(size); + HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory); + // Placement new as regular operator new() is deleted. + T* object = ::new (memory) T(std::forward<Args>(args)...); + header->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>(); + return object; + } +}; + +template <typename T, typename = void> +struct PostConstructionHookTrait { + static void Call(T*) {} +}; + +// Default MakeGarbageCollected: Constructs an instance of T, which is a garbage +// collected type. +template <typename T, typename... Args> +T* MakeGarbageCollected(Args&&... args) { + T* object = MakeGarbageCollectedTrait<T>::Call(std::forward<Args>(args)...); + PostConstructionHookTrait<T>::Call(object); + return object; +} + +// Constructs an instance of T, which is a garbage collected type. This special +// version takes size which enables constructing inline objects. +template <typename T, typename... Args> +T* MakeGarbageCollected(AdditionalBytes additional_bytes, Args&&... args) { + T* object = MakeGarbageCollectedTrait<T>::Call(additional_bytes, + std::forward<Args>(args)...); + PostConstructionHookTrait<T>::Call(object); + return object; +} + +// Assigning class types to their arenas. +// +// We use sized arenas for most 'normal' objects to improve memory locality. +// It seems that the same type of objects are likely to be accessed together, +// which means that we want to group objects by type. That's one reason +// why we provide dedicated arenas for popular types (e.g., Node, CSSValue), +// but it's not practical to prepare dedicated arenas for all types. +// Thus we group objects by their sizes, hoping that this will approximately +// group objects by their types. +// + +inline int ThreadHeap::ArenaIndexForObjectSize(size_t size) { + if (size < 64) { + if (size < 32) + return BlinkGC::kNormalPage1ArenaIndex; + return BlinkGC::kNormalPage2ArenaIndex; + } + if (size < 128) + return BlinkGC::kNormalPage3ArenaIndex; + return BlinkGC::kNormalPage4ArenaIndex; +} + +inline bool ThreadHeap::IsNormalArenaIndex(int index) { + return index >= BlinkGC::kNormalPage1ArenaIndex && + index <= BlinkGC::kNormalPage4ArenaIndex; +} + +inline Address ThreadHeap::AllocateOnArenaIndex(ThreadState* state, + size_t size, + int arena_index, + uint32_t gc_info_index, + const char* type_name) { + DCHECK(state->IsAllocationAllowed()); + DCHECK_NE(arena_index, BlinkGC::kLargeObjectArenaIndex); + NormalPageArena* arena = static_cast<NormalPageArena*>(Arena(arena_index)); + Address address = + arena->AllocateObject(AllocationSizeFromSize(size), gc_info_index); + HeapAllocHooks::AllocationHookIfEnabled(address, size, type_name); + return address; +} + +template <typename T> +Address ThreadHeap::Allocate(size_t size) { + ThreadState* state = ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState(); + const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(T); + return state->Heap().AllocateOnArenaIndex( + state, size, ThreadHeap::ArenaIndexForObjectSize(size), + GCInfoTrait<T>::Index(), type_name); +} + +inline bool ThreadHeap::IsInLastAllocatedRegion(Address address) const { + return last_allocated_region_.start <= address && + address < + (last_allocated_region_.start + last_allocated_region_.length); +} + +inline void ThreadHeap::SetLastAllocatedRegion(Address start, size_t length) { + last_allocated_region_.start = start; + last_allocated_region_.length = length; +} + +class PLATFORM_EXPORT LivenessBroker final { + public: + template <typename T> + bool IsHeapObjectAlive(const T*) const; + template <typename T> + bool IsHeapObjectAlive(const WeakMember<T>&) const; + template <typename T> + bool IsHeapObjectAlive(const UntracedMember<T>&) const; + + private: + LivenessBroker() = default; + friend class internal::LivenessBrokerFactory; +}; + +template <typename T> +bool LivenessBroker::IsHeapObjectAlive(const T* object) const { + static_assert(sizeof(T), "T must be fully defined"); + // The strongification of collections relies on the fact that once a + // collection has been strongified, there is no way that it can contain + // non-live entries, so no entries will be removed. Since you can't set + // the mark bit on a null pointer, that means that null pointers are + // always 'alive'. + if (!object) + return true; + // TODO(keishi): some tests create CrossThreadPersistent on non attached + // threads. + if (!ThreadState::Current()) + return true; + DCHECK(&ThreadState::Current()->Heap() == + &PageFromObject(object)->Arena()->GetThreadState()->Heap()); + return internal::ObjectAliveTrait<T>::IsHeapObjectAlive(object); +} + +template <typename T> +bool LivenessBroker::IsHeapObjectAlive(const WeakMember<T>& weak_member) const { + return IsHeapObjectAlive(weak_member.Get()); +} + +template <typename T> +bool LivenessBroker::IsHeapObjectAlive( + const UntracedMember<T>& untraced_member) const { + return IsHeapObjectAlive(untraced_member.Get()); +} + +template <typename T> +void Visitor::HandleWeakCell(const LivenessBroker& broker, const void* object) { + WeakMember<T>* weak_member = + reinterpret_cast<WeakMember<T>*>(const_cast<void*>(object)); + if (weak_member->Get()) { + if (weak_member->IsHashTableDeletedValue()) { + // This can happen when weak fields are deleted while incremental marking + // is running. Deleted values need to be preserved to avoid reviving + // objects in containers. + return; + } + if (!broker.IsHeapObjectAlive(weak_member->Get())) + weak_member->Clear(); + } +} + +namespace internal { + +class LivenessBrokerFactory final { + public: + static LivenessBroker Create() { return LivenessBroker(); } +}; + +} // namespace internal + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_allocator.cc b/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.cc index f4e2745e671..f4e2745e671 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap_allocator.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.cc diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.h new file mode 100644 index 00000000000..8fc46cb2a62 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_allocator.h @@ -0,0 +1,909 @@ +// Copyright 2015 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_H_ + +#include <type_traits> + +#include "build/build_config.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h" +#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h" +#include "third_party/blink/renderer/platform/heap/heap.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h" +#include "third_party/blink/renderer/platform/heap/impl/trace_traits.h" +#include "third_party/blink/renderer/platform/heap/thread_state_scopes.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/assertions.h" +#include "third_party/blink/renderer/platform/wtf/construct_traits.h" +#include "third_party/blink/renderer/platform/wtf/deque.h" +#include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h" +#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h" +#include "third_party/blink/renderer/platform/wtf/hash_map.h" +#include "third_party/blink/renderer/platform/wtf/hash_set.h" +#include "third_party/blink/renderer/platform/wtf/hash_table.h" +#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h" +#include "third_party/blink/renderer/platform/wtf/list_hash_set.h" +#include "third_party/blink/renderer/platform/wtf/type_traits.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" + +namespace blink { + +#define DISALLOW_IN_CONTAINER() \ + public: \ + using IsDisallowedInContainerMarker = int; \ + \ + private: \ + friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro + +// IsAllowedInContainer returns true if some type T supports being nested +// arbitrarily in other containers. This is relevant for collections where some +// collections assume that they are placed on a non-moving arena. +template <typename T, typename = int> +struct IsAllowedInContainer : std::true_type {}; +template <typename T> +struct IsAllowedInContainer<T, typename T::IsDisallowedInContainerMarker> + : std::false_type {}; + +// This is a static-only class used as a trait on collections to make them heap +// allocated. However see also HeapListHashSetAllocator. +class PLATFORM_EXPORT HeapAllocator { + STATIC_ONLY(HeapAllocator); + + public: + using LivenessBroker = blink::LivenessBroker; + using Visitor = blink::Visitor; + static constexpr bool kIsGarbageCollected = true; + + template <typename T> + static size_t MaxElementCountInBackingStore() { + return kMaxHeapObjectSize / sizeof(T); + } + + template <typename T> + static size_t QuantizedSize(size_t count) { + CHECK(count <= MaxElementCountInBackingStore<T>()); + return ThreadHeap::AllocationSizeFromSize(count * sizeof(T)) - + sizeof(HeapObjectHeader); + } + template <typename T> + static T* AllocateVectorBacking(size_t size) { + return reinterpret_cast<T*>( + MakeGarbageCollected<HeapVectorBacking<T>>(size / sizeof(T))); + } + static void FreeVectorBacking(void*); + static bool ExpandVectorBacking(void*, size_t); + static bool ShrinkVectorBacking(void* address, + size_t quantized_current_size, + size_t quantized_shrunk_size); + + template <typename T, typename HashTable> + static T* AllocateHashTableBacking(size_t size) { + return reinterpret_cast<T*>( + MakeGarbageCollected<HeapHashTableBacking<HashTable>>( + size / sizeof(typename HashTable::ValueType))); + } + template <typename T, typename HashTable> + static T* AllocateZeroedHashTableBacking(size_t size) { + return AllocateHashTableBacking<T, HashTable>(size); + } + static void FreeHashTableBacking(void* address); + static bool ExpandHashTableBacking(void*, size_t); + + static void TraceBackingStoreIfMarked(const void* address) { + // Trace backing store elements only if backing store was marked. The + // sweeper may be active on the backing store which requires atomic mark bit + // access. A precise filter is performed in + // MarkingVisitor::TraceMarkedBackingStore. + if (HeapObjectHeader::FromPayload(address) + ->IsMarked<HeapObjectHeader::AccessMode::kAtomic>()) { + MarkingVisitor::TraceMarkedBackingStore(address); + } + } + + template <typename T> + static void BackingWriteBarrier(T** slot) { + MarkingVisitor::WriteBarrier(slot); + } + + template <typename Return, typename Metadata> + static Return Malloc(size_t size, const char* type_name) { + return reinterpret_cast<Return>( + MarkAsConstructed(ThreadHeap::Allocate<Metadata>(size))); + } + + // Compilers sometimes eagerly instantiates the unused 'operator delete', so + // we provide a version that asserts and fails at run-time if used. + static void Free(void*) { NOTREACHED(); } + + template <typename T> + static void* NewArray(size_t bytes) { + NOTREACHED(); + return nullptr; + } + + static void DeleteArray(void* ptr) { NOTREACHED(); } + + static bool IsAllocationAllowed() { + return ThreadState::Current()->IsAllocationAllowed(); + } + + static bool IsIncrementalMarking() { + return ThreadState::IsAnyIncrementalMarking() && + ThreadState::Current()->IsIncrementalMarking(); + } + + template <typename T, typename Traits> + static void Trace(Visitor* visitor, const T& t) { + TraceCollectionIfEnabled<WTF::WeakHandlingTrait<T>::value, T, + Traits>::Trace(visitor, &t); + } + + static void EnterGCForbiddenScope() { + ThreadState::Current()->EnterGCForbiddenScope(); + } + + static void LeaveGCForbiddenScope() { + ThreadState::Current()->LeaveGCForbiddenScope(); + } + + template <typename T, typename Traits> + static void NotifyNewObject(T* object) { +#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION) + ThreadState* const thread_state = ThreadState::Current(); + if (!thread_state->IsIncrementalMarking()) { + MarkingVisitor::GenerationalBarrier(reinterpret_cast<Address>(object), + thread_state); + return; + } +#else + if (!ThreadState::IsAnyIncrementalMarking()) + return; + // The object may have been in-place constructed as part of a large object. + // It is not safe to retrieve the page from the object here. + ThreadState* const thread_state = ThreadState::Current(); + if (!thread_state->IsIncrementalMarking()) { + return; + } +#endif // BLINK_HEAP_YOUNG_GENERATION + // Eagerly trace the object ensuring that the object and all its children + // are discovered by the marker. + ThreadState::NoAllocationScope no_allocation_scope(thread_state); + DCHECK(thread_state->CurrentVisitor()); + // No weak handling for write barriers. Modifying weakly reachable objects + // strongifies them for the current cycle. + DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*object)); + TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace( + thread_state->CurrentVisitor(), object); + } + + template <typename T, typename Traits> + static void NotifyNewObjects(T* array, size_t len) { +#if BUILDFLAG(BLINK_HEAP_YOUNG_GENERATION) + ThreadState* const thread_state = ThreadState::Current(); + if (!thread_state->IsIncrementalMarking()) { + MarkingVisitor::GenerationalBarrier(reinterpret_cast<Address>(array), + thread_state); + return; + } +#else + if (!ThreadState::IsAnyIncrementalMarking()) + return; + // The object may have been in-place constructed as part of a large object. + // It is not safe to retrieve the page from the object here. + ThreadState* const thread_state = ThreadState::Current(); + if (!thread_state->IsIncrementalMarking()) { + return; + } +#endif // BLINK_HEAP_YOUNG_GENERATION + // See |NotifyNewObject| for details. + ThreadState::NoAllocationScope no_allocation_scope(thread_state); + DCHECK(thread_state->CurrentVisitor()); + // No weak handling for write barriers. Modifying weakly reachable objects + // strongifies them for the current cycle. + while (len-- > 0) { + DCHECK(!Traits::kCanHaveDeletedValue || !Traits::IsDeletedValue(*array)); + TraceCollectionIfEnabled<WTF::kNoWeakHandling, T, Traits>::Trace( + thread_state->CurrentVisitor(), array); + array++; + } + } + + template <typename T> + static void TraceVectorBacking(Visitor* visitor, + const T* backing, + const T* const* backing_slot) { + visitor->TraceMovablePointer(backing_slot); + visitor->Trace(reinterpret_cast<const HeapVectorBacking<T>*>(backing)); + } + + template <typename T, typename HashTable> + static void TraceHashTableBackingStrongly(Visitor* visitor, + const T* backing, + const T* const* backing_slot) { + visitor->TraceMovablePointer(backing_slot); + visitor->Trace( + reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing)); + } + + template <typename T, typename HashTable> + static void TraceHashTableBackingWeakly(Visitor* visitor, + const T* backing, + const T* const* backing_slot, + WeakCallback callback, + const void* parameter) { + visitor->TraceMovablePointer(backing_slot); + visitor->TraceWeakContainer( + reinterpret_cast<const HeapHashTableBacking<HashTable>*>(backing), + reinterpret_cast<const HeapHashTableBacking<HashTable>* const*>( + backing_slot), + TraceTrait<HeapHashTableBacking<HashTable>>::GetTraceDescriptor( + backing), + TraceTrait<HeapHashTableBacking<HashTable>>::GetWeakTraceDescriptor( + backing), + callback, parameter); + } + + private: + static Address MarkAsConstructed(Address address) { + HeapObjectHeader::FromPayload(reinterpret_cast<void*>(address)) + ->MarkFullyConstructed<HeapObjectHeader::AccessMode::kAtomic>(); + return address; + } + + static void BackingFree(void*); + static bool BackingExpand(void*, size_t); + static bool BackingShrink(void*, + size_t quantized_current_size, + size_t quantized_shrunk_size); + + template <typename T, wtf_size_t u, typename V> + friend class WTF::Vector; + template <typename T, typename U, typename V, typename W> + friend class WTF::HashSet; + template <typename T, + typename U, + typename V, + typename W, + typename X, + typename Y> + friend class WTF::HashMap; +}; + +template <typename VisitorDispatcher, typename Value> +static void TraceListHashSetValue(VisitorDispatcher visitor, + const Value& value) { + // We use the default hash traits for the value in the node, because + // ListHashSet does not let you specify any specific ones. + // We don't allow ListHashSet of WeakMember, so we set that one false + // (there's an assert elsewhere), but we have to specify some value for the + // strongify template argument, so we specify WTF::WeakPointersActWeak, + // arbitrarily. + TraceCollectionIfEnabled<WTF::kNoWeakHandling, Value, + WTF::HashTraits<Value>>::Trace(visitor, &value); +} + +// The inline capacity is just a dummy template argument to match the off-heap +// allocator. +// This inherits from the static-only HeapAllocator trait class, but we do +// declare pointers to instances. These pointers are always null, and no +// objects are instantiated. +template <typename ValueArg, wtf_size_t inlineCapacity> +class HeapListHashSetAllocator : public HeapAllocator { + DISALLOW_NEW(); + + public: + using TableAllocator = HeapAllocator; + using Node = WTF::ListHashSetNode<ValueArg, HeapListHashSetAllocator>; + + class AllocatorProvider { + DISALLOW_NEW(); + + public: + // For the heap allocation we don't need an actual allocator object, so + // we just return null. + HeapListHashSetAllocator* Get() const { return nullptr; } + + // No allocator object is needed. + void CreateAllocatorIfNeeded() {} + void ReleaseAllocator() {} + + // There is no allocator object in the HeapListHashSet (unlike in the + // regular ListHashSet) so there is nothing to swap. + void Swap(AllocatorProvider& other) {} + }; + + void Deallocate(void* dummy) {} + + // This is not a static method even though it could be, because it needs to + // match the one that the (off-heap) ListHashSetAllocator has. The 'this' + // pointer will always be null. + void* AllocateNode() { + // Consider using a LinkedHashSet instead if this compile-time assert fails: + static_assert(!WTF::IsWeak<ValueArg>::value, + "weak pointers in a ListHashSet will result in null entries " + "in the set"); + + return Malloc<void*, Node>( + sizeof(Node), + nullptr /* Oilpan does not use the heap profiler at the moment. */); + } + + template <typename VisitorDispatcher> + static void TraceValue(VisitorDispatcher visitor, const Node* node) { + TraceListHashSetValue(visitor, node->value_); + } +}; + +namespace internal { + +template <typename T> +constexpr bool IsMember = WTF::IsSubclassOfTemplate<T, Member>::value; + +} // namespace internal + +template <typename KeyArg, + typename MappedArg, + typename HashArg = typename DefaultHash<KeyArg>::Hash, + typename KeyTraitsArg = HashTraits<KeyArg>, + typename MappedTraitsArg = HashTraits<MappedArg>> +class HeapHashMap : public HashMap<KeyArg, + MappedArg, + HashArg, + KeyTraitsArg, + MappedTraitsArg, + HeapAllocator> { + IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); + DISALLOW_NEW(); + + static void CheckType() { + static_assert(std::is_trivially_destructible<HeapHashMap>::value, + "HeapHashMap must be trivially destructible."); + static_assert( + IsAllowedInContainer<KeyArg>::value, + "Not allowed to directly nest type. Use Member<> indirection instead."); + static_assert( + IsAllowedInContainer<MappedArg>::value, + "Not allowed to directly nest type. Use Member<> indirection instead."); + static_assert( + WTF::IsTraceable<KeyArg>::value || WTF::IsTraceable<MappedArg>::value, + "For hash maps without traceable elements, use HashMap<> " + "instead of HeapHashMap<>."); + static_assert(WTF::IsMemberOrWeakMemberType<KeyArg>::value || + !WTF::IsTraceable<KeyArg>::value, + "HeapHashMap supports only Member, WeakMember and " + "non-traceable types as keys."); + static_assert(WTF::IsMemberOrWeakMemberType<MappedArg>::value || + !WTF::IsTraceable<MappedArg>::value || + WTF::IsSubclassOfTemplate<MappedArg, + TraceWrapperV8Reference>::value, + "HeapHashMap supports only Member, WeakMember, " + "TraceWrapperV8Reference and " + "non-traceable types as values."); + } + + public: + template <typename> + static void* AllocateObject(size_t size) { + return ThreadHeap::Allocate< + HeapHashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>>( + size); + } + + HeapHashMap() { CheckType(); } +}; + +template <typename T, typename U, typename V, typename W, typename X> +struct GCInfoTrait<HeapHashMap<T, U, V, W, X>> + : public GCInfoTrait<HashMap<T, U, V, W, X, HeapAllocator>> {}; + +template <typename ValueArg, + typename HashArg = typename DefaultHash<ValueArg>::Hash, + typename TraitsArg = HashTraits<ValueArg>> +class HeapHashSet + : public HashSet<ValueArg, HashArg, TraitsArg, HeapAllocator> { + IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); + DISALLOW_NEW(); + + static void CheckType() { + static_assert(WTF::IsMemberOrWeakMemberType<ValueArg>::value, + "HeapHashSet supports only Member and WeakMember."); + static_assert(std::is_trivially_destructible<HeapHashSet>::value, + "HeapHashSet must be trivially destructible."); + static_assert( + IsAllowedInContainer<ValueArg>::value, + "Not allowed to directly nest type. Use Member<> indirection instead."); + static_assert(WTF::IsTraceable<ValueArg>::value, + "For hash sets without traceable elements, use HashSet<> " + "instead of HeapHashSet<>."); + } + + public: + template <typename> + static void* AllocateObject(size_t size) { + return ThreadHeap::Allocate<HeapHashSet<ValueArg, HashArg, TraitsArg>>( + size); + } + + HeapHashSet() { CheckType(); } +}; + +template <typename T, typename U, typename V> +struct GCInfoTrait<HeapHashSet<T, U, V>> + : public GCInfoTrait<HashSet<T, U, V, HeapAllocator>> {}; + +template <typename ValueArg, typename TraitsArg = HashTraits<ValueArg>> +class HeapLinkedHashSet + : public LinkedHashSet<ValueArg, TraitsArg, HeapAllocator> { + IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); + DISALLOW_NEW(); + + static void CheckType() { + static_assert(WTF::IsMemberOrWeakMemberType<ValueArg>::value, + "HeapLinkedHashSet supports only Member and WeakMember."); + // If not trivially destructible, we have to add a destructor which will + // hinder performance. + static_assert(std::is_trivially_destructible<HeapLinkedHashSet>::value, + "HeapLinkedHashSet must be trivially destructible."); + static_assert( + IsAllowedInContainer<ValueArg>::value, + "Not allowed to directly nest type. Use Member<> indirection instead."); + static_assert(WTF::IsTraceable<ValueArg>::value, + "For sets without traceable elements, use LinkedHashSet<> " + "instead of HeapLinkedHashSet<>."); + } + + public: + template <typename> + static void* AllocateObject(size_t size) { + return ThreadHeap::Allocate<HeapLinkedHashSet<ValueArg, TraitsArg>>(size); + } + + HeapLinkedHashSet() { CheckType(); } +}; + +template <typename T, typename U> +struct GCInfoTrait<HeapLinkedHashSet<T, U>> + : public GCInfoTrait<LinkedHashSet<T, U, HeapAllocator>> {}; + +template <typename ValueArg, + wtf_size_t inlineCapacity = 0, // The inlineCapacity is just a dummy + // to match ListHashSet (off-heap). + typename HashArg = typename DefaultHash<ValueArg>::Hash> +class HeapListHashSet + : public ListHashSet<ValueArg, + inlineCapacity, + HashArg, + HeapListHashSetAllocator<ValueArg, inlineCapacity>> { + IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); + DISALLOW_NEW(); + + static void CheckType() { + static_assert(WTF::IsMemberOrWeakMemberType<ValueArg>::value, + "HeapListHashSet supports only Member and WeakMember."); + static_assert(std::is_trivially_destructible<HeapListHashSet>::value, + "HeapListHashSet must be trivially destructible."); + static_assert( + IsAllowedInContainer<ValueArg>::value, + "Not allowed to directly nest type. Use Member<> indirection instead."); + static_assert(WTF::IsTraceable<ValueArg>::value, + "For sets without traceable elements, use ListHashSet<> " + "instead of HeapListHashSet<>."); + } + + public: + template <typename> + static void* AllocateObject(size_t size) { + return ThreadHeap::Allocate< + HeapListHashSet<ValueArg, inlineCapacity, HashArg>>(size); + } + + HeapListHashSet() { CheckType(); } +}; + +template <typename T, wtf_size_t inlineCapacity, typename U> +struct GCInfoTrait<HeapListHashSet<T, inlineCapacity, U>> + : public GCInfoTrait< + ListHashSet<T, + inlineCapacity, + U, + HeapListHashSetAllocator<T, inlineCapacity>>> {}; + +template <typename Value, + typename HashFunctions = typename DefaultHash<Value>::Hash, + typename Traits = HashTraits<Value>> +class HeapHashCountedSet + : public HashCountedSet<Value, HashFunctions, Traits, HeapAllocator> { + IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); + DISALLOW_NEW(); + + static void CheckType() { + static_assert(WTF::IsMemberOrWeakMemberType<Value>::value, + "HeapHashCountedSet supports only Member and WeakMember."); + static_assert(std::is_trivially_destructible<HeapHashCountedSet>::value, + "HeapHashCountedSet must be trivially destructible."); + static_assert( + IsAllowedInContainer<Value>::value, + "Not allowed to directly nest type. Use Member<> indirection instead."); + static_assert(WTF::IsTraceable<Value>::value, + "For counted sets without traceable elements, use " + "HashCountedSet<> instead of HeapHashCountedSet<>."); + } + + public: + template <typename> + static void* AllocateObject(size_t size) { + return ThreadHeap::Allocate< + HeapHashCountedSet<Value, HashFunctions, Traits>>(size); + } + + HeapHashCountedSet() { CheckType(); } +}; + +template <typename T, typename U, typename V> +struct GCInfoTrait<HeapHashCountedSet<T, U, V>> + : public GCInfoTrait<HashCountedSet<T, U, V, HeapAllocator>> {}; + +template <typename T, wtf_size_t inlineCapacity = 0> +class HeapVector : public Vector<T, inlineCapacity, HeapAllocator> { + IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); + DISALLOW_NEW(); + + static void CheckType() { + static_assert( + std::is_trivially_destructible<HeapVector>::value || inlineCapacity, + "HeapVector must be trivially destructible."); + static_assert( + IsAllowedInContainer<T>::value, + "Not allowed to directly nest type. Use Member<> indirection instead."); + static_assert(WTF::IsTraceable<T>::value, + "For vectors without traceable elements, use Vector<> " + "instead of HeapVector<>."); + static_assert(!WTF::IsWeak<T>::value, + "Weak types are not allowed in HeapVector."); + static_assert(WTF::IsTraceableInCollectionTrait<VectorTraits<T>>::value, + "Type must be traceable in collection"); + } + + public: + template <typename> + static void* AllocateObject(size_t size) { + // On-heap HeapVectors generally should not have inline capacity, but it is + // hard to avoid when using a type alias. Hence we only disallow the + // VectorTraits<T>::kNeedsDestruction case for now. + static_assert(inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction, + "on-heap HeapVector<> should not have an inline capacity"); + return ThreadHeap::Allocate<HeapVector<T, inlineCapacity>>(size); + } + + HeapVector() { CheckType(); } + + explicit HeapVector(wtf_size_t size) + : Vector<T, inlineCapacity, HeapAllocator>(size) { + CheckType(); + } + + HeapVector(wtf_size_t size, const T& val) + : Vector<T, inlineCapacity, HeapAllocator>(size, val) { + CheckType(); + } + + template <wtf_size_t otherCapacity> + HeapVector(const HeapVector<T, otherCapacity>& other) + : Vector<T, inlineCapacity, HeapAllocator>(other) { + CheckType(); + } + + HeapVector(std::initializer_list<T> elements) + : Vector<T, inlineCapacity, HeapAllocator>(elements) { + CheckType(); + } +}; + +template <typename T, wtf_size_t inlineCapacity> +struct GCInfoTrait<HeapVector<T, inlineCapacity>> + : public GCInfoTrait<Vector<T, inlineCapacity, HeapAllocator>> {}; + +template <typename T> +class HeapDeque : public Deque<T, 0, HeapAllocator> { + IS_GARBAGE_COLLECTED_CONTAINER_TYPE(); + DISALLOW_NEW(); + + static void CheckType() { + static_assert(internal::IsMember<T>, "HeapDeque supports only Member."); + static_assert(std::is_trivially_destructible<HeapDeque>::value, + "HeapDeque must be trivially destructible."); + static_assert( + IsAllowedInContainer<T>::value, + "Not allowed to directly nest type. Use Member<> indirection instead."); + static_assert(WTF::IsTraceable<T>::value, + "For vectors without traceable elements, use Deque<> instead " + "of HeapDeque<>"); + } + + public: + template <typename> + static void* AllocateObject(size_t size) { + return ThreadHeap::Allocate<HeapDeque<T>>(size); + } + + HeapDeque() { CheckType(); } + + explicit HeapDeque(wtf_size_t size) : Deque<T, 0, HeapAllocator>(size) { + CheckType(); + } + + HeapDeque(wtf_size_t size, const T& val) + : Deque<T, 0, HeapAllocator>(size, val) { + CheckType(); + } + + HeapDeque& operator=(const HeapDeque& other) { + HeapDeque<T> copy(other); + Deque<T, 0, HeapAllocator>::Swap(copy); + return *this; + } + + HeapDeque(const HeapDeque<T>& other) : Deque<T, 0, HeapAllocator>(other) {} +}; + +template <typename T> +struct GCInfoTrait<HeapDeque<T>> + : public GCInfoTrait<Deque<T, 0, HeapAllocator>> {}; + +} // namespace blink + +namespace WTF { + +template <typename T> +struct VectorTraits<blink::Member<T>> : VectorTraitsBase<blink::Member<T>> { + STATIC_ONLY(VectorTraits); + static const bool kNeedsDestruction = false; + static const bool kCanInitializeWithMemset = true; + static const bool kCanClearUnusedSlotsWithMemset = true; + static const bool kCanCopyWithMemcpy = true; + static const bool kCanMoveWithMemcpy = true; + + static constexpr bool kCanTraceConcurrently = true; +}; + +// These traits are used in VectorBackedLinkedList to support WeakMember in +// HeapLinkedHashSet though HeapVector<WeakMember> usage is still banned. +// (See the discussion in https://crrev.com/c/2246014) +template <typename T> +struct VectorTraits<blink::WeakMember<T>> + : VectorTraitsBase<blink::WeakMember<T>> { + STATIC_ONLY(VectorTraits); + static const bool kNeedsDestruction = false; + static const bool kCanInitializeWithMemset = true; + static const bool kCanClearUnusedSlotsWithMemset = true; + static const bool kCanCopyWithMemcpy = true; + static const bool kCanMoveWithMemcpy = true; + + static constexpr bool kCanTraceConcurrently = true; +}; + +template <typename T> +struct VectorTraits<blink::UntracedMember<T>> + : VectorTraitsBase<blink::UntracedMember<T>> { + STATIC_ONLY(VectorTraits); + static const bool kNeedsDestruction = false; + static const bool kCanInitializeWithMemset = true; + static const bool kCanClearUnusedSlotsWithMemset = true; + static const bool kCanMoveWithMemcpy = true; +}; + +template <typename T> +struct VectorTraits<blink::HeapVector<T, 0>> + : VectorTraitsBase<blink::HeapVector<T, 0>> { + STATIC_ONLY(VectorTraits); + static const bool kNeedsDestruction = false; + static const bool kCanInitializeWithMemset = true; + static const bool kCanClearUnusedSlotsWithMemset = true; + static const bool kCanMoveWithMemcpy = true; +}; + +template <typename T> +struct VectorTraits<blink::HeapDeque<T>> + : VectorTraitsBase<blink::HeapDeque<T>> { + STATIC_ONLY(VectorTraits); + static const bool kNeedsDestruction = false; + static const bool kCanInitializeWithMemset = true; + static const bool kCanClearUnusedSlotsWithMemset = true; + static const bool kCanMoveWithMemcpy = true; +}; + +template <typename T, wtf_size_t inlineCapacity> +struct VectorTraits<blink::HeapVector<T, inlineCapacity>> + : VectorTraitsBase<blink::HeapVector<T, inlineCapacity>> { + STATIC_ONLY(VectorTraits); + static const bool kNeedsDestruction = VectorTraits<T>::kNeedsDestruction; + static const bool kCanInitializeWithMemset = + VectorTraits<T>::kCanInitializeWithMemset; + static const bool kCanClearUnusedSlotsWithMemset = + VectorTraits<T>::kCanClearUnusedSlotsWithMemset; + static const bool kCanMoveWithMemcpy = VectorTraits<T>::kCanMoveWithMemcpy; +}; + +template <typename T> +struct HashTraits<blink::Member<T>> : SimpleClassHashTraits<blink::Member<T>> { + STATIC_ONLY(HashTraits); + // FIXME: Implement proper const'ness for iterator types. Requires support + // in the marking Visitor. + using PeekInType = T*; + using IteratorGetType = blink::Member<T>*; + using IteratorConstGetType = const blink::Member<T>*; + using IteratorReferenceType = blink::Member<T>&; + using IteratorConstReferenceType = const blink::Member<T>&; + static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { + return *x; + } + static IteratorConstReferenceType GetToReferenceConstConversion( + IteratorConstGetType x) { + return *x; + } + + using PeekOutType = T*; + + template <typename U> + static void Store(const U& value, blink::Member<T>& storage) { + storage = value; + } + + static PeekOutType Peek(const blink::Member<T>& value) { return value; } + + static void ConstructDeletedValue(blink::Member<T>& slot, bool) { + slot = WTF::kHashTableDeletedValue; + } + + static constexpr bool kCanTraceConcurrently = true; +}; + +template <typename T> +struct HashTraits<blink::WeakMember<T>> + : SimpleClassHashTraits<blink::WeakMember<T>> { + STATIC_ONLY(HashTraits); + static const bool kNeedsDestruction = false; + // FIXME: Implement proper const'ness for iterator types. Requires support + // in the marking Visitor. + using PeekInType = T*; + using IteratorGetType = blink::WeakMember<T>*; + using IteratorConstGetType = const blink::WeakMember<T>*; + using IteratorReferenceType = blink::WeakMember<T>&; + using IteratorConstReferenceType = const blink::WeakMember<T>&; + static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { + return *x; + } + static IteratorConstReferenceType GetToReferenceConstConversion( + IteratorConstGetType x) { + return *x; + } + + using PeekOutType = T*; + + template <typename U> + static void Store(const U& value, blink::WeakMember<T>& storage) { + storage = value; + } + + static PeekOutType Peek(const blink::WeakMember<T>& value) { return value; } + + static void ConstructDeletedValue(blink::WeakMember<T>& slot, bool) { + slot = WTF::kHashTableDeletedValue; + } + + static constexpr bool kCanTraceConcurrently = true; +}; + +template <typename T> +struct HashTraits<blink::UntracedMember<T>> + : SimpleClassHashTraits<blink::UntracedMember<T>> { + STATIC_ONLY(HashTraits); + static const bool kNeedsDestruction = false; + // FIXME: Implement proper const'ness for iterator types. + using PeekInType = T*; + using IteratorGetType = blink::UntracedMember<T>*; + using IteratorConstGetType = const blink::UntracedMember<T>*; + using IteratorReferenceType = blink::UntracedMember<T>&; + using IteratorConstReferenceType = const blink::UntracedMember<T>&; + static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { + return *x; + } + static IteratorConstReferenceType GetToReferenceConstConversion( + IteratorConstGetType x) { + return *x; + } + using PeekOutType = T*; + + template <typename U> + static void Store(const U& value, blink::UntracedMember<T>& storage) { + storage = value; + } + + static PeekOutType Peek(const blink::UntracedMember<T>& value) { + return value; + } +}; + +template <typename T, wtf_size_t inlineCapacity> +struct IsTraceable< + ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>*> { + STATIC_ONLY(IsTraceable); + static_assert(sizeof(T), "T must be fully defined"); + // All heap allocated node pointers need visiting to keep the nodes alive, + // regardless of whether they contain pointers to other heap allocated + // objects. + static const bool value = true; +}; + +template <typename T, wtf_size_t inlineCapacity> +struct IsGarbageCollectedType< + ListHashSetNode<T, blink::HeapListHashSetAllocator<T, inlineCapacity>>> { + static const bool value = true; +}; + +template <typename Set> +struct IsGarbageCollectedType<ListHashSetIterator<Set>> { + static const bool value = IsGarbageCollectedType<Set>::value; +}; + +template <typename Set> +struct IsGarbageCollectedType<ListHashSetConstIterator<Set>> { + static const bool value = IsGarbageCollectedType<Set>::value; +}; + +template <typename Set> +struct IsGarbageCollectedType<ListHashSetReverseIterator<Set>> { + static const bool value = IsGarbageCollectedType<Set>::value; +}; + +template <typename Set> +struct IsGarbageCollectedType<ListHashSetConstReverseIterator<Set>> { + static const bool value = IsGarbageCollectedType<Set>::value; +}; + +template <typename T, typename H> +struct HandleHashTraits : SimpleClassHashTraits<H> { + STATIC_ONLY(HandleHashTraits); + // TODO: Implement proper const'ness for iterator types. Requires support + // in the marking Visitor. + using PeekInType = T*; + using IteratorGetType = H*; + using IteratorConstGetType = const H*; + using IteratorReferenceType = H&; + using IteratorConstReferenceType = const H&; + static IteratorReferenceType GetToReferenceConversion(IteratorGetType x) { + return *x; + } + static IteratorConstReferenceType GetToReferenceConstConversion( + IteratorConstGetType x) { + return *x; + } + + using PeekOutType = T*; + + template <typename U> + static void Store(const U& value, H& storage) { + storage = value; + } + + static PeekOutType Peek(const H& value) { return value; } +}; + +template <typename Value, + typename HashFunctions, + typename Traits, + typename VectorType> +inline void CopyToVector( + const blink::HeapHashCountedSet<Value, HashFunctions, Traits>& set, + VectorType& vector) { + CopyToVector(static_cast<const HashCountedSet<Value, HashFunctions, Traits, + blink::HeapAllocator>&>(set), + vector); +} + +} // namespace WTF + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_ALLOCATOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_compact.cc b/chromium/third_party/blink/renderer/platform/heap/impl/heap_compact.cc index f750406477e..411ea513c3e 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap_compact.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_compact.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/platform/heap/heap_compact.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h" #include <memory> @@ -170,70 +170,70 @@ void HeapCompact::MovableObjectFixups::AddOrFilter( void HeapCompact::MovableObjectFixups::Relocate(Address from, Address to) { #if DCHECK_IS_ON() - moved_objects_.insert(from); + moved_objects_.insert(from); #endif // DCHECK_IS_ON() - const HeapObjectHeader* header = HeapObjectHeader::FromPayload(to); - const size_t size = header->PayloadSize(); + const HeapObjectHeader* header = HeapObjectHeader::FromPayload(to); + const size_t size = header->PayloadSize(); - // Interior slots always need to be processed for moved objects. - // Consider an object A with slot A.x pointing to value B where A is - // allocated on a movable page itself. When B is finally moved, it needs to - // find the corresponding slot A.x. Object A may be moved already and the - // memory may have been freed, which would result in a crash. - if (!interior_fixups_.empty()) { - RelocateInteriorFixups(from, to, size); - } + // Interior slots always need to be processed for moved objects. + // Consider an object A with slot A.x pointing to value B where A is + // allocated on a movable page itself. When B is finally moved, it needs to + // find the corresponding slot A.x. Object A may be moved already and the + // memory may have been freed, which would result in a crash. + if (!interior_fixups_.empty()) { + RelocateInteriorFixups(from, to, size); + } - auto it = fixups_.find(from); - // This means that there is no corresponding slot for a live backing store. - // This may happen because a mutator may change the slot to point to a - // different backing store because e.g. incremental marking marked a backing - // store as live that was later on replaced. - if (it == fixups_.end()) { - return; - } + auto it = fixups_.find(from); + // This means that there is no corresponding slot for a live backing store. + // This may happen because a mutator may change the slot to point to a + // different backing store because e.g. incremental marking marked a backing + // store as live that was later on replaced. + if (it == fixups_.end()) { + return; + } #if DCHECK_IS_ON() - BasePage* from_page = PageFromObject(from); - DCHECK(relocatable_pages_.Contains(from_page)); + BasePage* from_page = PageFromObject(from); + DCHECK(relocatable_pages_.Contains(from_page)); #endif - // If the object is referenced by a slot that is contained on a compacted - // area itself, check whether it can be updated already. - MovableReference* slot = it->value; - auto interior_it = interior_fixups_.find(slot); - if (interior_it != interior_fixups_.end()) { - MovableReference* slot_location = - reinterpret_cast<MovableReference*>(interior_it->second); - if (!slot_location) { - interior_it->second = to; + // If the object is referenced by a slot that is contained on a compacted + // area itself, check whether it can be updated already. + MovableReference* slot = it->value; + auto interior_it = interior_fixups_.find(slot); + if (interior_it != interior_fixups_.end()) { + MovableReference* slot_location = + reinterpret_cast<MovableReference*>(interior_it->second); + if (!slot_location) { + interior_it->second = to; #if DCHECK_IS_ON() - // Check that the containing object has not been moved yet. - auto reverse_it = interior_slot_to_object_.find(slot); - DCHECK(interior_slot_to_object_.end() != reverse_it); - DCHECK(moved_objects_.end() == moved_objects_.find(reverse_it->value)); + // Check that the containing object has not been moved yet. + auto reverse_it = interior_slot_to_object_.find(slot); + DCHECK(interior_slot_to_object_.end() != reverse_it); + DCHECK(moved_objects_.end() == moved_objects_.find(reverse_it->value)); #endif // DCHECK_IS_ON() - } else { - LOG_HEAP_COMPACTION() - << "Redirected slot: " << slot << " => " << slot_location; - slot = slot_location; - } - } - - // If the slot has subsequently been updated, e.g. a destructor having - // mutated and expanded/shrunk the collection, do not update and relocate - // the slot -- |from| is no longer valid and referenced. - if (UNLIKELY(*slot != from)) { + } else { LOG_HEAP_COMPACTION() - << "No relocation: slot = " << slot << ", *slot = " << *slot - << ", from = " << from << ", to = " << to; - VerifyUpdatedSlot(slot); - return; + << "Redirected slot: " << slot << " => " << slot_location; + slot = slot_location; } + } + + // If the slot has subsequently been updated, e.g. a destructor having + // mutated and expanded/shrunk the collection, do not update and relocate + // the slot -- |from| is no longer valid and referenced. + if (UNLIKELY(*slot != from)) { + LOG_HEAP_COMPACTION() << "No relocation: slot = " << slot + << ", *slot = " << *slot << ", from = " << from + << ", to = " << to; + VerifyUpdatedSlot(slot); + return; + } - // Update the slots new value. - *slot = to; + // Update the slots new value. + *slot = to; } void HeapCompact::MovableObjectFixups::RelocateInteriorFixups(Address from, diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_compact.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap_compact.h index b241471ba4b..e39c9c57b88 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap_compact.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_compact.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_COMPACT_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_COMPACT_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_COMPACT_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_COMPACT_H_ #include <memory> @@ -164,4 +164,4 @@ class PLATFORM_EXPORT HeapCompact final { #define LOG_HEAP_FREELIST_VERBOSE() EAT_STREAM_PARAMETERS #endif -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_COMPACT_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_COMPACT_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_page.cc b/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.cc index 9ba8a2fac3a..1949d5c9921 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap_page.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.cc @@ -28,7 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "third_party/blink/renderer/platform/heap/heap_page.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_page.h" #include "base/allocator/partition_allocator/page_allocator.h" #include "base/auto_reset.h" @@ -36,12 +36,12 @@ #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h" #include "third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h" -#include "third_party/blink/renderer/platform/heap/heap_compact.h" #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h" -#include "third_party/blink/renderer/platform/heap/marking_verifier.h" -#include "third_party/blink/renderer/platform/heap/page_bloom_filter.h" -#include "third_party/blink/renderer/platform/heap/page_memory.h" -#include "third_party/blink/renderer/platform/heap/page_pool.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_verifier.h" +#include "third_party/blink/renderer/platform/heap/impl/page_bloom_filter.h" +#include "third_party/blink/renderer/platform/heap/impl/page_memory.h" +#include "third_party/blink/renderer/platform/heap/impl/page_pool.h" #include "third_party/blink/renderer/platform/heap/thread_state.h" #include "third_party/blink/renderer/platform/instrumentation/histogram.h" #include "third_party/blink/renderer/platform/instrumentation/memory_pressure_listener.h" diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_page.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.h index 98abc6bca72..1c26d4ffe20 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap_page.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_page.h @@ -28,8 +28,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_PAGE_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_PAGE_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_PAGE_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_PAGE_H_ #include <stdint.h> #include <array> @@ -40,11 +40,11 @@ #include "build/build_config.h" #include "third_party/blink/renderer/platform/heap/blink_gc.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" -#include "third_party/blink/renderer/platform/heap/gc_info.h" #include "third_party/blink/renderer/platform/heap/heap_buildflags.h" +#include "third_party/blink/renderer/platform/heap/impl/gc_info.h" +#include "third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h" +#include "third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.h" #include "third_party/blink/renderer/platform/heap/thread_state.h" -#include "third_party/blink/renderer/platform/heap/thread_state_statistics.h" -#include "third_party/blink/renderer/platform/heap/unsanitized_atomic.h" #include "third_party/blink/renderer/platform/heap/visitor.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" @@ -968,9 +968,7 @@ class PLATFORM_EXPORT LargeObjectPage final : public BasePage { #endif // Remembers the page as containing inter-generational pointers. - void SetRemembered(bool remembered) { - is_remembered_ = remembered; - } + void SetRemembered(bool remembered) { is_remembered_ = remembered; } bool IsRemembered() const { return is_remembered_; } private: @@ -1613,4 +1611,4 @@ inline void NormalPage::MarkCard(Address address) { } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_HEAP_PAGE_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_PAGE_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/heap_stats_collector.cc b/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.cc index 97590b912b2..97590b912b2 100644 --- a/chromium/third_party/blink/renderer/platform/heap/heap_stats_collector.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.cc diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h new file mode 100644 index 00000000000..cbac7c3b8ac --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_stats_collector.h @@ -0,0 +1,469 @@ +// Copyright 2018 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_STATS_COLLECTOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_STATS_COLLECTOR_H_ + +#include <stddef.h> + +#include "base/atomicops.h" +#include "third_party/blink/renderer/platform/heap/blink_gc.h" +#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" + +namespace blink { + +// Interface for observing changes to heap sizing. +class PLATFORM_EXPORT ThreadHeapStatsObserver { + public: + // Called upon allocating/releasing chunks of memory that contain objects. + // + // Must not trigger GC or allocate. + virtual void IncreaseAllocatedSpace(size_t) = 0; + virtual void DecreaseAllocatedSpace(size_t) = 0; + + // Called once per GC cycle with the accurate number of live |bytes|. + // + // Must not trigger GC or allocate. + virtual void ResetAllocatedObjectSize(size_t bytes) = 0; + + // Called after observing at least + // |ThreadHeapStatsCollector::kUpdateThreshold| changed bytes through + // allocation or explicit free. Reports both, negative and positive + // increments, to allow observer to decide whether absolute values or only the + // deltas is interesting. + // + // May trigger GC but most not allocate. + virtual void IncreaseAllocatedObjectSize(size_t) = 0; + virtual void DecreaseAllocatedObjectSize(size_t) = 0; +}; + +#define FOR_ALL_SCOPES(V) \ + V(AtomicPauseCompaction) \ + V(AtomicPauseMarkEpilogue) \ + V(AtomicPauseMarkPrologue) \ + V(AtomicPauseMarkRoots) \ + V(AtomicPauseMarkTransitiveClosure) \ + V(AtomicPauseSweepAndCompact) \ + V(CompleteSweep) \ + V(IncrementalMarkingFinalize) \ + V(IncrementalMarkingStartMarking) \ + V(IncrementalMarkingStep) \ + V(IncrementalMarkingWithDeadline) \ + V(InvokePreFinalizers) \ + V(LazySweepInIdle) \ + V(LazySweepOnAllocation) \ + V(MarkBailOutObjects) \ + V(MarkInvokeEphemeronCallbacks) \ + V(MarkFlushV8References) \ + V(MarkFlushEphemeronPairs) \ + V(MarkProcessWorklists) \ + V(MarkProcessMarkingWorklist) \ + V(MarkProcessWriteBarrierWorklist) \ + V(MarkProcessNotFullyconstructeddWorklist) \ + V(MarkNotFullyConstructedObjects) \ + V(MarkWeakProcessing) \ + V(UnifiedMarkingStep) \ + V(VisitCrossThreadPersistents) \ + V(VisitPersistentRoots) \ + V(VisitPersistents) \ + V(VisitRoots) \ + V(VisitStackRoots) \ + V(VisitRememberedSets) + +#define FOR_ALL_CONCURRENT_SCOPES(V) \ + V(ConcurrentMarkInvokeEphemeronCallbacks) \ + V(ConcurrentMarkingStep) \ + V(ConcurrentSweepingStep) + +// Manages counters and statistics across garbage collection cycles. +// +// Usage: +// ThreadHeapStatsCollector stats_collector; +// stats_collector.NotifyMarkingStarted(<BlinkGC::CollectionType>, +// <BlinkGC::GCReason>); +// // Use tracer. +// stats_collector.NotifySweepingCompleted(); +// // Previous event is available using stats_collector.previous(). +class PLATFORM_EXPORT ThreadHeapStatsCollector { + USING_FAST_MALLOC(ThreadHeapStatsCollector); + + public: + // These ids will form human readable names when used in Scopes. + enum Id { +#define DECLARE_ENUM(name) k##name, + FOR_ALL_SCOPES(DECLARE_ENUM) +#undef DECLARE_ENUM + kNumScopeIds, + }; + + enum ConcurrentId { +#define DECLARE_ENUM(name) k##name, + FOR_ALL_CONCURRENT_SCOPES(DECLARE_ENUM) +#undef DECLARE_ENUM + kNumConcurrentScopeIds + }; + + constexpr static const char* ToString(Id id, BlinkGC::CollectionType type) { + switch (id) { +#define CASE(name) \ + case k##name: \ + return type == BlinkGC::CollectionType::kMajor ? "BlinkGC." #name \ + : "BlinkGC." #name \ + ".Minor"; + FOR_ALL_SCOPES(CASE) +#undef CASE + default: + NOTREACHED(); + } + return nullptr; + } + + constexpr static const char* ToString(ConcurrentId id, + BlinkGC::CollectionType type) { + switch (id) { +#define CASE(name) \ + case k##name: \ + return type == BlinkGC::CollectionType::kMajor ? "BlinkGC." #name \ + : "BlinkGC." #name \ + ".Minor"; + FOR_ALL_CONCURRENT_SCOPES(CASE) +#undef CASE + default: + NOTREACHED(); + } + return nullptr; + } + + enum TraceCategory { kEnabled, kDisabled }; + enum ScopeContext { kMutatorThread, kConcurrentThread }; + + // Trace a particular scope. Will emit a trace event and record the time in + // the corresponding ThreadHeapStatsCollector. + template <TraceCategory trace_category = kDisabled, + ScopeContext scope_category = kMutatorThread> + class PLATFORM_EXPORT InternalScope { + DISALLOW_NEW(); + DISALLOW_COPY_AND_ASSIGN(InternalScope); + + using IdType = + std::conditional_t<scope_category == kMutatorThread, Id, ConcurrentId>; + + public: + template <typename... Args> + InternalScope(ThreadHeapStatsCollector* tracer, IdType id, Args... args) + : tracer_(tracer), start_time_(base::TimeTicks::Now()), id_(id) { + StartTrace(args...); + } + + ~InternalScope() { + StopTrace(); + IncreaseScopeTime(id_); + } + + private: + inline constexpr static const char* TraceCategory(); + + inline void StartTrace(); + template <typename Value1> + inline void StartTrace(const char* k1, Value1 v1); + template <typename Value1, typename Value2> + inline void StartTrace(const char* k1, + Value1 v1, + const char* k2, + Value2 v2); + inline void StopTrace(); + + inline void IncreaseScopeTime(Id); + inline void IncreaseScopeTime(ConcurrentId); + + ThreadHeapStatsCollector* const tracer_; + const base::TimeTicks start_time_; + const IdType id_; + }; + + using Scope = InternalScope<kDisabled>; + using EnabledScope = InternalScope<kEnabled>; + using ConcurrentScope = InternalScope<kDisabled, kConcurrentThread>; + using EnabledConcurrentScope = InternalScope<kEnabled, kConcurrentThread>; + + // BlinkGCInV8Scope keeps track of time spent in Blink's GC when called by V8. + // This is necessary to avoid double-accounting of Blink's time when computing + // the overall time (V8 + Blink) spent in GC on the main thread. + class PLATFORM_EXPORT BlinkGCInV8Scope { + DISALLOW_NEW(); + DISALLOW_COPY_AND_ASSIGN(BlinkGCInV8Scope); + + public: + template <typename... Args> + BlinkGCInV8Scope(ThreadHeapStatsCollector* tracer) + : tracer_(tracer), start_time_(base::TimeTicks::Now()) {} + + ~BlinkGCInV8Scope() { + if (tracer_) + tracer_->gc_nested_in_v8_ += base::TimeTicks::Now() - start_time_; + } + + private: + ThreadHeapStatsCollector* const tracer_; + const base::TimeTicks start_time_; + }; + + // POD to hold interesting data accumulated during a garbage collection cycle. + // The event is always fully populated when looking at previous events but + // is only be partially populated when looking at the current event. See + // members on when they are available. + // + // Note that all getters include time for stand-alone as well as unified heap + // GCs. E.g., |atomic_marking_time()| report the marking time of the atomic + // phase, independent of whether the GC was a stand-alone or unified heap GC. + struct PLATFORM_EXPORT Event { + Event(); + + // Overall time spent in the GC cycle. This includes marking time as well as + // sweeping time. + base::TimeDelta gc_cycle_time() const; + + // Time spent in the final atomic pause of a GC cycle. + base::TimeDelta atomic_pause_time() const; + + // Time spent in the final atomic pause for marking the heap. + base::TimeDelta atomic_marking_time() const; + + // Time spent in the final atomic pause in sweeping and compacting the heap. + base::TimeDelta atomic_sweep_and_compact_time() const; + + // Time spent marking the roots. + base::TimeDelta roots_marking_time() const; + + // Time spent incrementally marking the heap. + base::TimeDelta incremental_marking_time() const; + + // Time spent processing worklist in the foreground thread. + base::TimeDelta worklist_processing_time_foreground() const; + + // Time spent flushing v8 references (this is done only in the foreground) + base::TimeDelta flushing_v8_references_time() const; + + // Time spent in foreground tasks marking the heap. + base::TimeDelta foreground_marking_time() const; + + // Time spent in background tasks marking the heap. + base::TimeDelta background_marking_time() const; + + // Overall time spent marking the heap. + base::TimeDelta marking_time() const; + + // Time spent in foreground tasks sweeping the heap. + base::TimeDelta foreground_sweeping_time() const; + + // Time spent in background tasks sweeping the heap. + base::TimeDelta background_sweeping_time() const; + + // Overall time spent sweeping the heap. + base::TimeDelta sweeping_time() const; + + // Marked bytes collected during sweeping. + size_t unique_id = -1; + size_t marked_bytes = 0; + size_t compaction_freed_bytes = 0; + size_t compaction_freed_pages = 0; + bool compaction_recorded_events = false; + base::TimeDelta scope_data[kNumScopeIds]; + base::subtle::Atomic32 concurrent_scope_data[kNumConcurrentScopeIds]{0}; + BlinkGC::GCReason reason = static_cast<BlinkGC::GCReason>(0); + BlinkGC::CollectionType collection_type = BlinkGC::CollectionType::kMajor; + size_t object_size_in_bytes_before_sweeping = 0; + size_t allocated_space_in_bytes_before_sweeping = 0; + size_t partition_alloc_bytes_before_sweeping = 0; + double live_object_rate = 0; + base::TimeDelta gc_nested_in_v8; + bool is_forced_gc = true; + }; + + // Indicates a new garbage collection cycle. + void NotifyMarkingStarted(BlinkGC::CollectionType, + BlinkGC::GCReason, + bool is_forced_gc); + + // Indicates that marking of the current garbage collection cycle is + // completed. + void NotifyMarkingCompleted(size_t marked_bytes); + + // Indicates the end of a garbage collection cycle. This means that sweeping + // is finished at this point. + void NotifySweepingCompleted(); + + void IncreaseScopeTime(Id id, base::TimeDelta time) { + DCHECK(is_started_); + current_.scope_data[id] += time; + } + + void IncreaseConcurrentScopeTime(ConcurrentId id, base::TimeDelta time) { + using Atomic32 = base::subtle::Atomic32; + DCHECK(is_started_); + const int64_t ms = time.InMicroseconds(); + DCHECK(ms <= std::numeric_limits<Atomic32>::max()); + base::subtle::NoBarrier_AtomicIncrement(¤t_.concurrent_scope_data[id], + static_cast<Atomic32>(ms)); + } + + void UpdateReason(BlinkGC::GCReason); + void IncreaseCompactionFreedSize(size_t); + void IncreaseCompactionFreedPages(size_t); + void IncreaseAllocatedObjectSize(size_t); + void DecreaseAllocatedObjectSize(size_t); + void IncreaseAllocatedSpace(size_t); + void DecreaseAllocatedSpace(size_t); + void IncreaseWrapperCount(size_t); + void DecreaseWrapperCount(size_t); + void IncreaseCollectedWrapperCount(size_t); + + // Called by the GC when it hits a point where allocated memory may be + // reported and garbage collection is possible. This is necessary, as + // increments and decrements are reported as close to their actual + // allocation/reclamation as possible. + void AllocatedObjectSizeSafepoint(); + + // Size of objects on the heap. Based on marked bytes in the previous cycle + // and newly allocated bytes since the previous cycle. + size_t object_size_in_bytes() const; + + size_t marked_bytes() const; + base::TimeDelta marking_time_so_far() const; + + base::TimeDelta worklist_processing_time_foreground() const; + + base::TimeDelta flushing_v8_references_time() const; + + int64_t allocated_bytes_since_prev_gc() const; + + size_t allocated_space_bytes() const; + + size_t wrapper_count() const; + size_t collected_wrapper_count() const; + + bool is_started() const { return is_started_; } + + // Statistics for the previously running garbage collection. + const Event& previous() const { return previous_; } + + void RegisterObserver(ThreadHeapStatsObserver* observer); + void UnregisterObserver(ThreadHeapStatsObserver* observer); + + void IncreaseAllocatedObjectSizeForTesting(size_t); + void DecreaseAllocatedObjectSizeForTesting(size_t); + + private: + // Observers are implemented using virtual calls. Avoid notifications below + // reasonably interesting sizes. + static constexpr int64_t kUpdateThreshold = 1024; + + // Invokes |callback| for all registered observers. + template <typename Callback> + void ForAllObservers(Callback callback); + + void AllocatedObjectSizeSafepointImpl(); + + // Statistics for the currently running garbage collection. Note that the + // Event may not be fully populated yet as some phase may not have been run. + const Event& current() const { return current_; } + + Event current_; + Event previous_; + + // Allocated bytes since the last garbage collection. These bytes are reset + // after marking as they are accounted in marked_bytes then. + int64_t allocated_bytes_since_prev_gc_ = 0; + int64_t pos_delta_allocated_bytes_since_prev_gc_ = 0; + int64_t neg_delta_allocated_bytes_since_prev_gc_ = 0; + + // Allocated space in bytes for all arenas. + size_t allocated_space_bytes_ = 0; + + bool is_started_ = false; + + // base::TimeDelta for RawScope. These don't need to be nested within a + // garbage collection cycle to make them easier to use. + base::TimeDelta gc_nested_in_v8_; + + Vector<ThreadHeapStatsObserver*> observers_; + + FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, InitialEmpty); + FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, IncreaseScopeTime); + FRIEND_TEST_ALL_PREFIXES(ThreadHeapStatsCollectorTest, StopResetsCurrent); +}; + +template <ThreadHeapStatsCollector::TraceCategory trace_category, + ThreadHeapStatsCollector::ScopeContext scope_category> +constexpr const char* +ThreadHeapStatsCollector::InternalScope<trace_category, + scope_category>::TraceCategory() { + switch (trace_category) { + case kEnabled: + return "blink_gc,devtools.timeline"; + case kDisabled: + return TRACE_DISABLED_BY_DEFAULT("blink_gc"); + } +} + +template <ThreadHeapStatsCollector::TraceCategory trace_category, + ThreadHeapStatsCollector::ScopeContext scope_category> +void ThreadHeapStatsCollector::InternalScope<trace_category, + scope_category>::StartTrace() { + TRACE_EVENT_BEGIN0(TraceCategory(), + ToString(id_, tracer_->current_.collection_type)); +} + +template <ThreadHeapStatsCollector::TraceCategory trace_category, + ThreadHeapStatsCollector::ScopeContext scope_category> +template <typename Value1> +void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>:: + StartTrace(const char* k1, Value1 v1) { + TRACE_EVENT_BEGIN1(TraceCategory(), + ToString(id_, tracer_->current_.collection_type), k1, v1); +} + +template <ThreadHeapStatsCollector::TraceCategory trace_category, + ThreadHeapStatsCollector::ScopeContext scope_category> +template <typename Value1, typename Value2> +void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>:: + StartTrace(const char* k1, Value1 v1, const char* k2, Value2 v2) { + TRACE_EVENT_BEGIN2(TraceCategory(), + ToString(id_, tracer_->current_.collection_type), k1, v1, + k2, v2); +} + +template <ThreadHeapStatsCollector::TraceCategory trace_category, + ThreadHeapStatsCollector::ScopeContext scope_category> +void ThreadHeapStatsCollector::InternalScope<trace_category, + scope_category>::StopTrace() { + TRACE_EVENT_END2(TraceCategory(), + ToString(id_, tracer_->current_.collection_type), "epoch", + tracer_->current_.unique_id, "forced", + tracer_->current_.is_forced_gc); +} + +template <ThreadHeapStatsCollector::TraceCategory trace_category, + ThreadHeapStatsCollector::ScopeContext scope_category> +void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>:: + IncreaseScopeTime(Id) { + tracer_->IncreaseScopeTime(id_, base::TimeTicks::Now() - start_time_); +} + +template <ThreadHeapStatsCollector::TraceCategory trace_category, + ThreadHeapStatsCollector::ScopeContext scope_category> +void ThreadHeapStatsCollector::InternalScope<trace_category, scope_category>:: + IncreaseScopeTime(ConcurrentId) { + tracer_->IncreaseConcurrentScopeTime(id_, + base::TimeTicks::Now() - start_time_); +} + +#undef FOR_ALL_SCOPES +#undef FOR_ALL_CONCURRENT_SCOPES + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_STATS_COLLECTOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/heap_traits.h b/chromium/third_party/blink/renderer/platform/heap/impl/heap_traits.h new file mode 100644 index 00000000000..36ac20e5710 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/heap_traits.h @@ -0,0 +1,40 @@ +// Copyright (c) 2018 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TRAITS_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TRAITS_H_ + +#include <type_traits> +#include "third_party/blink/renderer/platform/heap/heap_allocator.h" +#include "third_party/blink/renderer/platform/heap/member.h" +#include "third_party/blink/renderer/platform/wtf/type_traits.h" + +namespace blink { + +// Given a type T, returns a type that is either Member<T> or just T depending +// on whether T is a garbage-collected type. +template <typename T> +using AddMemberIfNeeded = + std::conditional_t<WTF::IsGarbageCollectedType<T>::value, Member<T>, T>; + +// Given a type T, returns a type that is either HeapVector<T>, +// HeapVector<Member<T>> or Vector<T> depending on T. +template <typename T> +using VectorOf = std::conditional_t<WTF::IsTraceable<T>::value, + HeapVector<AddMemberIfNeeded<T>>, + Vector<T>>; + +// Given types T and U, returns a type that is one of the following: +// - HeapVector<std::pair<V, X>> +// (where V is either T or Member<T> and X is either U or Member<U>) +// - Vector<std::pair<T, U>> +template <typename T, typename U> +using VectorOfPairs = std::conditional_t< + WTF::IsTraceable<T>::value || WTF::IsTraceable<U>::value, + HeapVector<std::pair<AddMemberIfNeeded<T>, AddMemberIfNeeded<U>>>, + Vector<std::pair<T, U>>>; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_HEAP_TRAITS_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc b/chromium/third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.cc index b140239e02c..8b05de2df81 100644 --- a/chromium/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h" #include "base/numerics/ranges.h" diff --git a/chromium/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h b/chromium/third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h index f8634c45c89..19c9e0b68a0 100644 --- a/chromium/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_SCHEDULING_ORACLE_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_SCHEDULING_ORACLE_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_SCHEDULING_ORACLE_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_SCHEDULING_ORACLE_H_ #include <atomic> @@ -62,4 +62,4 @@ class PLATFORM_EXPORT MarkingSchedulingOracle { } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_SCHEDULING_ORACLE_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_SCHEDULING_ORACLE_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/marking_verifier.cc b/chromium/third_party/blink/renderer/platform/heap/impl/marking_verifier.cc index 45067dfe9c4..58b049ef54a 100644 --- a/chromium/third_party/blink/renderer/platform/heap/marking_verifier.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/marking_verifier.cc @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/platform/heap/marking_verifier.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_verifier.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" -#include "third_party/blink/renderer/platform/heap/heap_page.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_page.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/platform/heap/marking_verifier.h b/chromium/third_party/blink/renderer/platform/heap/impl/marking_verifier.h index f7ce363bf6c..ee4266a53f1 100644 --- a/chromium/third_party/blink/renderer/platform/heap/marking_verifier.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/marking_verifier.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VERIFIER_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VERIFIER_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VERIFIER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VERIFIER_H_ #include "third_party/blink/renderer/platform/heap/visitor.h" @@ -40,4 +40,4 @@ class MarkingVerifier final : public Visitor { } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VERIFIER_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VERIFIER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/marking_visitor.cc b/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.cc index df3d97ef8c9..aca7b715e65 100644 --- a/chromium/third_party/blink/renderer/platform/heap/marking_visitor.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.cc @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/platform/heap/marking_visitor.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h" #include "third_party/blink/renderer/platform/heap/blink_gc.h" #include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/heap/heap_page.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_page.h" #include "third_party/blink/renderer/platform/heap/thread_state.h" namespace blink { @@ -28,6 +28,7 @@ MarkingVisitorBase::MarkingVisitorBase(ThreadState* state, ephemeron_pairs_to_process_worklist_( Heap().GetEphemeronPairsToProcessWorklist(), task_id), + weak_containers_worklist_(Heap().GetWeakContainersWorklist()), marking_mode_(marking_mode), task_id_(task_id) {} @@ -69,19 +70,17 @@ void MarkingVisitorBase::VisitWeak(const void* object, } void MarkingVisitorBase::VisitEphemeron(const void* key, - const void* value, - TraceCallback value_trace_callback) { + TraceDescriptor value_desc) { HeapObjectHeader* key_header = HeapObjectHeader::FromPayload(key); if (!key_header->IsInConstruction<HeapObjectHeader::AccessMode::kAtomic>() && !key_header->IsMarked<HeapObjectHeader::AccessMode::kAtomic>()) { // In construction keys are considered as marked because they are // guaranteed to be marked by the end of GC (e.g. by write barrier // on insertion to HashTable). - discovered_ephemeron_pairs_worklist_.Push( - {key, value, value_trace_callback}); + discovered_ephemeron_pairs_worklist_.Push({key, value_desc}); return; } - value_trace_callback(this, value); + value_desc.callback(this, value_desc.base_object_payload); } void MarkingVisitorBase::VisitWeakContainer( @@ -117,6 +116,7 @@ void MarkingVisitorBase::VisitWeakContainer( // non-empty/deleted buckets have been moved to the new backing store. MarkHeaderNoTracing(header); AccountMarkedBytes(header); + weak_containers_worklist_->Push(header); // Register final weak processing of the backing store. RegisterWeakCallback(weak_callback, weak_callback_parameter); @@ -228,6 +228,24 @@ void MarkingVisitor::TraceMarkedBackingStoreSlow(const void* value) { .trace(thread_state->CurrentVisitor(), value); } +constexpr size_t MarkingVisitor::RecentlyRetracedWeakContainers::kMaxCacheSize; + +bool MarkingVisitor::RecentlyRetracedWeakContainers::Contains( + const HeapObjectHeader* header) { + return std::find(recently_retraced_cache_.begin(), + recently_retraced_cache_.end(), + header) != recently_retraced_cache_.end(); +} + +void MarkingVisitor::RecentlyRetracedWeakContainers::Insert( + const HeapObjectHeader* header) { + last_used_index_ = (last_used_index_ + 1) % kMaxCacheSize; + if (recently_retraced_cache_.size() <= last_used_index_) + recently_retraced_cache_.push_back(header); + else + recently_retraced_cache_[last_used_index_] = header; +} + MarkingVisitor::MarkingVisitor(ThreadState* state, MarkingMode marking_mode) : MarkingVisitorBase(state, marking_mode, WorklistTaskId::MutatorThread) { DCHECK(state->InAtomicMarkingPause()); @@ -244,8 +262,24 @@ void MarkingVisitor::ConservativelyMarkAddress(BasePage* page, ? static_cast<LargeObjectPage*>(page)->ObjectHeader() : static_cast<NormalPage*>(page)->ConservativelyFindHeaderFromAddress( address); - if (!header || header->IsMarked()) + if (!header) + return; + if (header->IsMarked()) { + // Weak containers found through conservative GC need to be strongified. In + // case the container was previously marked and weakly traced, it should be + // retraced strongly now. Previously marked/traced weak containers are + // marked using the |weak_containers_worklist_|. Other marked object can be + // skipped. + if (weak_containers_worklist_->Contains(header) && + !recently_retraced_weak_containers_.Contains(header)) { + DCHECK(!header->IsInConstruction()); + // Record the weak container backing store to avoid retracing it again. + recently_retraced_weak_containers_.Insert(header); + marking_worklist_.Push( + {header->Payload(), GCInfo::From(header->GcInfoIndex()).trace}); + } return; + } // Simple case for fully constructed objects. This just adds the object to the // regular marking worklist. diff --git a/chromium/third_party/blink/renderer/platform/heap/marking_visitor.h b/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.h index 6b472bde7a6..df17247076f 100644 --- a/chromium/third_party/blink/renderer/platform/heap/marking_visitor.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/marking_visitor.h @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VISITOR_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VISITOR_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VISITOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VISITOR_H_ #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -#include "third_party/blink/renderer/platform/heap/heap_page.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_page.h" #include "third_party/blink/renderer/platform/heap/visitor.h" namespace blink { @@ -42,7 +42,7 @@ class PLATFORM_EXPORT MarkingVisitorBase : public Visitor { TraceDescriptor, WeakCallback, const void*) final; - void VisitEphemeron(const void*, const void*, TraceCallback) final; + void VisitEphemeron(const void*, TraceDescriptor) final; // Marks an object dynamically using any address within its body and adds a // tracing callback for processing of the object. The object is not allowed @@ -86,6 +86,7 @@ class PLATFORM_EXPORT MarkingVisitorBase : public Visitor { MovableReferenceWorklist::View movable_reference_worklist_; EphemeronPairsWorklist::View discovered_ephemeron_pairs_worklist_; EphemeronPairsWorklist::View ephemeron_pairs_to_process_worklist_; + WeakContainersWorklist* const weak_containers_worklist_; size_t marked_bytes_ = 0; const MarkingMode marking_mode_; int task_id_; @@ -173,6 +174,22 @@ class PLATFORM_EXPORT MarkingVisitor : public MarkingVisitorBase { static bool MarkValue(void*, BasePage*, ThreadState*); static void TraceMarkedBackingStoreSlow(const void*); + // Weak containers are strongly retraced during conservative stack scanning. + // Stack scanning happens once per GC at the start of the atomic pause. + // Because the visitor is not retained between GCs, there is no need to clear + // the set at the end of GC. + class RecentlyRetracedWeakContainers { + static constexpr size_t kMaxCacheSize = 8; + + public: + bool Contains(const HeapObjectHeader*); + void Insert(const HeapObjectHeader*); + + private: + std::vector<const HeapObjectHeader*> recently_retraced_cache_; + size_t last_used_index_ = -1; + } recently_retraced_weak_containers_; + friend class HeapAllocator; template <typename T, TracenessMemberConfiguration tracenessConfiguration> friend class MemberBase; @@ -261,4 +278,4 @@ class PLATFORM_EXPORT ConcurrentMarkingVisitor : public MarkingVisitorBase { } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VISITOR_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MARKING_VISITOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/member.h b/chromium/third_party/blink/renderer/platform/heap/impl/member.h new file mode 100644 index 00000000000..caf60bf1b23 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/member.h @@ -0,0 +1,577 @@ +// Copyright 2016 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MEMBER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MEMBER_H_ + +#include "third_party/blink/renderer/platform/heap/heap.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_page.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/hash_functions.h" +#include "third_party/blink/renderer/platform/wtf/hash_traits.h" + +namespace WTF { +template <typename P, typename Traits, typename Allocator> +class MemberConstructTraits; +} // namespace WTF + +namespace blink { + +template <typename T> +class Persistent; + +enum class TracenessMemberConfiguration { + kTraced, + kUntraced, +}; + +template <typename T, + TracenessMemberConfiguration tracenessConfiguration = + TracenessMemberConfiguration::kTraced> +class MemberPointerVerifier { + public: + MemberPointerVerifier() = default; + + void SaveCreationThreadState(T* pointer) { + if (tracenessConfiguration == TracenessMemberConfiguration::kUntraced) { + creation_thread_state_ = nullptr; + } else { + creation_thread_state_ = ThreadState::Current(); + // Members should be created in an attached thread. But an empty + // value Member may be created on an unattached thread by a heap + // collection iterator. + DCHECK(creation_thread_state_ || !pointer); + } + } + + void CheckPointer(T* pointer) { + if (!pointer) + return; + + ThreadState* current = ThreadState::Current(); + DCHECK(current); + if (tracenessConfiguration != TracenessMemberConfiguration::kUntraced) { + // creation_thread_state_ may be null when this is used in a heap + // collection which initialized the Member with memset and the + // constructor wasn't called. + if (creation_thread_state_) { + // Member should point to objects that belong in the same ThreadHeap. + DCHECK(creation_thread_state_->IsOnThreadHeap(pointer)); + // Member should point to objects that belong in the same ThreadHeap. + DCHECK_EQ(¤t->Heap(), &creation_thread_state_->Heap()); + } else { + DCHECK(current->IsOnThreadHeap(pointer)); + } + } + + if (current->IsSweepingInProgress()) { + // During sweeping the object start bitmap is invalid. Check the header + // when the type is available and not pointing to a mixin. + if (IsFullyDefined<T>::value && !IsGarbageCollectedMixin<T>::value) + HeapObjectHeader::CheckFromPayload(pointer); + } else { + DCHECK(HeapObjectHeader::FromInnerAddress< + HeapObjectHeader::AccessMode::kAtomic>(pointer)); + } + } + + private: + const ThreadState* creation_thread_state_; +}; + +template <typename T, + TracenessMemberConfiguration tracenessConfiguration = + TracenessMemberConfiguration::kTraced> +class MemberBase { + DISALLOW_NEW(); + + public: + MemberBase() : raw_(nullptr) { SaveCreationThreadState(); } + + MemberBase(std::nullptr_t) : raw_(nullptr) { SaveCreationThreadState(); } + + explicit MemberBase(T* raw) : raw_(raw) { + SaveCreationThreadState(); + CheckPointer(); + // No write barrier for initializing stores. + } + + explicit MemberBase(T& raw) : raw_(&raw) { + SaveCreationThreadState(); + CheckPointer(); + // No write barrier for initializing stores. + } + + MemberBase(WTF::HashTableDeletedValueType) + : raw_(reinterpret_cast<T*>(kHashTableDeletedRawValue)) { + SaveCreationThreadState(); + } + + MemberBase(const MemberBase& other) : raw_(other) { + SaveCreationThreadState(); + CheckPointer(); + // No write barrier for initializing stores. + } + + template <typename U> + MemberBase(const Persistent<U>& other) : raw_(other) { + SaveCreationThreadState(); + CheckPointer(); + // No write barrier for initializing stores. + } + + template <typename U> + MemberBase(const MemberBase<U>& other) : raw_(other) { + SaveCreationThreadState(); + CheckPointer(); + // No write barrier for initializing stores. + } + + template <typename U> + MemberBase& operator=(const Persistent<U>& other) { + SetRaw(other); + CheckPointer(); + WriteBarrier(); + return *this; + } + + MemberBase& operator=(const MemberBase& other) { + SetRaw(other); + CheckPointer(); + WriteBarrier(); + return *this; + } + + template <typename U> + MemberBase& operator=(const MemberBase<U>& other) { + SetRaw(other); + CheckPointer(); + WriteBarrier(); + return *this; + } + + template <typename U> + MemberBase& operator=(U* other) { + SetRaw(other); + CheckPointer(); + WriteBarrier(); + return *this; + } + + MemberBase& operator=(WTF::HashTableDeletedValueType) { + SetRaw(reinterpret_cast<T*>(-1)); + return *this; + } + + MemberBase& operator=(std::nullptr_t) { + SetRaw(nullptr); + return *this; + } + + void Swap(MemberBase<T>& other) { + T* tmp = GetRaw(); + SetRaw(other.GetRaw()); + other.SetRaw(tmp); + CheckPointer(); + WriteBarrier(); + other.WriteBarrier(); + } + + explicit operator bool() const { return GetRaw(); } + operator T*() const { return GetRaw(); } + T* operator->() const { return GetRaw(); } + T& operator*() const { return *GetRaw(); } + + T* Get() const { return GetRaw(); } + + void Clear() { SetRaw(nullptr); } + + T* Release() { + T* result = GetRaw(); + SetRaw(nullptr); + return result; + } + + static bool IsMemberHashTableDeletedValue(const T* t) { + return t == reinterpret_cast<T*>(kHashTableDeletedRawValue); + } + + bool IsHashTableDeletedValue() const { + return IsMemberHashTableDeletedValue(GetRaw()); + } + + protected: + static constexpr intptr_t kHashTableDeletedRawValue = -1; + + enum class AtomicCtorTag { Atomic }; + + // MemberBase ctors that use atomic write to set raw_. + + MemberBase(AtomicCtorTag, T* raw) { + SetRaw(raw); + SaveCreationThreadState(); + CheckPointer(); + // No write barrier for initializing stores. + } + + MemberBase(AtomicCtorTag, T& raw) { + SetRaw(&raw); + SaveCreationThreadState(); + CheckPointer(); + // No write barrier for initializing stores. + } + + void WriteBarrier() const { + MarkingVisitor::WriteBarrier(const_cast<std::remove_const_t<T>**>(&raw_)); + } + + void CheckPointer() { +#if DCHECK_IS_ON() + // Should not be called for deleted hash table values. A value can be + // propagated here if a MemberBase containing the deleted value is copied. + if (IsHashTableDeletedValue()) + return; + pointer_verifier_.CheckPointer(GetRaw()); +#endif // DCHECK_IS_ON() + } + + void SaveCreationThreadState() { +#if DCHECK_IS_ON() + pointer_verifier_.SaveCreationThreadState(GetRaw()); +#endif // DCHECK_IS_ON() + } + + ALWAYS_INLINE void SetRaw(T* raw) { + if (tracenessConfiguration == TracenessMemberConfiguration::kUntraced) + raw_ = raw; + else + WTF::AsAtomicPtr(&raw_)->store(raw, std::memory_order_relaxed); + } + ALWAYS_INLINE T* GetRaw() const { return raw_; } + + private: + // Thread safe version of Get() for marking visitors. + // This is used to prevent data races between concurrent marking visitors + // and writes on the main thread. + const T* GetSafe() const { + // TOOD(omerkatz): replace this cast with std::atomic_ref (C++20) once it + // becomes available + return WTF::AsAtomicPtr(&raw_)->load(std::memory_order_relaxed); + } + + T* raw_; +#if DCHECK_IS_ON() + MemberPointerVerifier<T, tracenessConfiguration> pointer_verifier_; +#endif // DCHECK_IS_ON() + + friend class Visitor; +}; + +// Members are used in classes to contain strong pointers to other oilpan heap +// allocated objects. +// All Member fields of a class must be traced in the class' trace method. +// During the mark phase of the GC all live objects are marked as live and +// all Member fields of a live object will be traced marked as live as well. +template <typename T> +class Member : public MemberBase<T, TracenessMemberConfiguration::kTraced> { + DISALLOW_NEW(); + typedef MemberBase<T, TracenessMemberConfiguration::kTraced> Parent; + + public: + Member() : Parent() {} + Member(std::nullptr_t) : Parent(nullptr) {} + Member(T* raw) : Parent(raw) {} + Member(T& raw) : Parent(raw) {} + Member(WTF::HashTableDeletedValueType x) : Parent(x) {} + + Member(const Member& other) : Parent(other) {} + + template <typename U> + Member(const Member<U>& other) : Parent(other) {} + + template <typename U> + Member(const Persistent<U>& other) : Parent(other) {} + + template <typename U> + Member& operator=(const Persistent<U>& other) { + Parent::operator=(other); + return *this; + } + + Member& operator=(const Member& other) { + Parent::operator=(other); + return *this; + } + + template <typename U> + Member& operator=(const Member<U>& other) { + Parent::operator=(other); + return *this; + } + + template <typename U> + Member& operator=(const WeakMember<U>& other) { + Parent::operator=(other); + return *this; + } + + template <typename U> + Member& operator=(U* other) { + Parent::operator=(other); + return *this; + } + + Member& operator=(WTF::HashTableDeletedValueType x) { + Parent::operator=(x); + return *this; + } + + Member& operator=(std::nullptr_t) { + Parent::operator=(nullptr); + return *this; + } + + private: + using typename Parent::AtomicCtorTag; + Member(AtomicCtorTag atomic, T* raw) : Parent(atomic, raw) {} + Member(AtomicCtorTag atomic, T& raw) : Parent(atomic, raw) {} + + template <typename P, typename Traits, typename Allocator> + friend class WTF::MemberConstructTraits; +}; + +// WeakMember is similar to Member in that it is used to point to other oilpan +// heap allocated objects. +// However instead of creating a strong pointer to the object, the WeakMember +// creates a weak pointer, which does not keep the pointee alive. Hence if all +// pointers to to a heap allocated object are weak the object will be garbage +// collected. At the time of GC the weak pointers will automatically be set to +// null. +template <typename T> +class WeakMember : public MemberBase<T, TracenessMemberConfiguration::kTraced> { + typedef MemberBase<T, TracenessMemberConfiguration::kTraced> Parent; + + public: + WeakMember() : Parent() {} + + WeakMember(std::nullptr_t) : Parent(nullptr) {} + + WeakMember(T* raw) : Parent(raw) {} + + WeakMember(WTF::HashTableDeletedValueType x) : Parent(x) {} + + template <typename U> + WeakMember(const Persistent<U>& other) : Parent(other) {} + + template <typename U> + WeakMember(const Member<U>& other) : Parent(other) {} + + template <typename U> + WeakMember& operator=(const Persistent<U>& other) { + Parent::operator=(other); + return *this; + } + + template <typename U> + WeakMember& operator=(const Member<U>& other) { + Parent::operator=(other); + return *this; + } + + template <typename U> + WeakMember& operator=(U* other) { + Parent::operator=(other); + return *this; + } + + WeakMember& operator=(std::nullptr_t) { + this->SetRaw(nullptr); + return *this; + } + + private: + using typename Parent::AtomicCtorTag; + WeakMember(AtomicCtorTag atomic, T* raw) : Parent(atomic, raw) {} + WeakMember(AtomicCtorTag atomic, T& raw) : Parent(atomic, raw) {} + + template <typename P, typename Traits, typename Allocator> + friend class WTF::MemberConstructTraits; +}; + +// UntracedMember is a pointer to an on-heap object that is not traced for some +// reason. Please don't use this unless you understand what you're doing. +// Basically, all pointers to on-heap objects must be stored in either of +// Persistent, Member or WeakMember. It is not allowed to leave raw pointers to +// on-heap objects. However, there can be scenarios where you have to use raw +// pointers for some reason, and in that case you can use UntracedMember. Of +// course, it must be guaranteed that the pointing on-heap object is kept alive +// while the raw pointer is pointing to the object. +template <typename T> +class UntracedMember final + : public MemberBase<T, TracenessMemberConfiguration::kUntraced> { + typedef MemberBase<T, TracenessMemberConfiguration::kUntraced> Parent; + + public: + UntracedMember() : Parent() {} + + UntracedMember(std::nullptr_t) : Parent(nullptr) {} + + UntracedMember(T* raw) : Parent(raw) {} + + template <typename U> + UntracedMember(const Persistent<U>& other) : Parent(other) {} + + template <typename U> + UntracedMember(const Member<U>& other) : Parent(other) {} + + UntracedMember(WTF::HashTableDeletedValueType x) : Parent(x) {} + + UntracedMember& operator=(const UntracedMember& other) { + this->SetRaw(other); + this->CheckPointer(); + return *this; + } + + template <typename U> + UntracedMember& operator=(const Persistent<U>& other) { + this->SetRaw(other); + this->CheckPointer(); + return *this; + } + + template <typename U> + UntracedMember& operator=(const Member<U>& other) { + this->SetRaw(other); + this->CheckPointer(); + return *this; + } + + template <typename U> + UntracedMember& operator=(U* other) { + this->SetRaw(other); + this->CheckPointer(); + return *this; + } + + UntracedMember& operator=(std::nullptr_t) { + this->SetRaw(nullptr); + return *this; + } +}; + +template <typename T> +struct MemberTraceTraits { + STATIC_ONLY(MemberTraceTraits); + + public: + static TraceDescriptor GetTraceDescriptor(const T* ref) { + return {ref, TraceTrait<T>::Trace}; + } + + static void Trace(Visitor* visitor, const void* ref) { + visitor->Trace(*static_cast<const T*>(ref)); + } +}; + +template <typename T> +struct TraceTrait<Member<T>> : public MemberTraceTraits<Member<T>> {}; + +template <typename T> +struct TraceTrait<WeakMember<T>> : public MemberTraceTraits<WeakMember<T>> {}; + +} // namespace blink + +namespace WTF { + +// PtrHash is the default hash for hash tables with Member<>-derived elements. +template <typename T> +struct MemberHash : PtrHash<T> { + STATIC_ONLY(MemberHash); + template <typename U> + static unsigned GetHash(const U& key) { + return PtrHash<T>::GetHash(key); + } + template <typename U, typename V> + static bool Equal(const U& a, const V& b) { + return a == b; + } +}; + +template <typename T> +struct DefaultHash<blink::Member<T>> { + STATIC_ONLY(DefaultHash); + using Hash = MemberHash<T>; +}; + +template <typename T> +struct DefaultHash<blink::WeakMember<T>> { + STATIC_ONLY(DefaultHash); + using Hash = MemberHash<T>; +}; + +template <typename T> +struct DefaultHash<blink::UntracedMember<T>> { + STATIC_ONLY(DefaultHash); + using Hash = MemberHash<T>; +}; + +template <typename T> +struct IsTraceable<blink::Member<T>> { + STATIC_ONLY(IsTraceable); + static const bool value = true; +}; + +template <typename T> +struct IsWeak<blink::WeakMember<T>> : std::true_type {}; + +template <typename T> +struct IsTraceable<blink::WeakMember<T>> { + STATIC_ONLY(IsTraceable); + static const bool value = true; +}; + +template <typename T, typename Traits, typename Allocator> +class MemberConstructTraits { + STATIC_ONLY(MemberConstructTraits); + + public: + template <typename... Args> + static T* Construct(void* location, Args&&... args) { + return new (NotNull, location) T(std::forward<Args>(args)...); + } + + static void NotifyNewElement(T* element) { element->WriteBarrier(); } + + template <typename... Args> + static T* ConstructAndNotifyElement(void* location, Args&&... args) { + // ConstructAndNotifyElement updates an existing Member which might + // also be comncurrently traced while we update it. The regular ctors + // for Member don't use an atomic write which can lead to data races. + T* object = Construct(location, T::AtomicCtorTag::Atomic, + std::forward<Args>(args)...); + NotifyNewElement(object); + return object; + } + + static void NotifyNewElements(T* array, size_t len) { + while (len-- > 0) { + array->WriteBarrier(); + array++; + } + } +}; + +template <typename T, typename Traits, typename Allocator> +class ConstructTraits<blink::Member<T>, Traits, Allocator> + : public MemberConstructTraits<blink::Member<T>, Traits, Allocator> {}; + +template <typename T, typename Traits, typename Allocator> +class ConstructTraits<blink::WeakMember<T>, Traits, Allocator> + : public MemberConstructTraits<blink::WeakMember<T>, Traits, Allocator> {}; + +} // namespace WTF + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_MEMBER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/name_traits.h b/chromium/third_party/blink/renderer/platform/heap/impl/name_traits.h index 89961df0e4b..c44305ff234 100644 --- a/chromium/third_party/blink/renderer/platform/heap/name_traits.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/name_traits.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_NAME_TRAITS_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_NAME_TRAITS_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_NAME_TRAITS_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_NAME_TRAITS_H_ #include <cstring> @@ -59,4 +59,4 @@ class NameTrait { } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_NAME_TRAITS_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_NAME_TRAITS_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/page_bloom_filter.h b/chromium/third_party/blink/renderer/platform/heap/impl/page_bloom_filter.h index 5e881212d91..19263ae332e 100644 --- a/chromium/third_party/blink/renderer/platform/heap/page_bloom_filter.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/page_bloom_filter.h @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_BLOOM_FILTER_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_BLOOM_FILTER_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_BLOOM_FILTER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_BLOOM_FILTER_H_ -#include "third_party/blink/renderer/platform/heap/heap_page.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_page.h" #include "third_party/blink/renderer/platform/wtf/bloom_filter.h" namespace blink { @@ -45,4 +45,4 @@ class PageBloomFilter { } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_BLOOM_FILTER_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_BLOOM_FILTER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/page_memory.cc b/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.cc index 86445fa4d0d..4d3ffc1440d 100644 --- a/chromium/third_party/blink/renderer/platform/heap/page_memory.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/platform/heap/page_memory.h" +#include "third_party/blink/renderer/platform/heap/impl/page_memory.h" #include "base/allocator/partition_allocator/oom.h" #include "base/allocator/partition_allocator/page_allocator.h" diff --git a/chromium/third_party/blink/renderer/platform/heap/page_memory.h b/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.h index 249a1eb668c..ee13b210d59 100644 --- a/chromium/third_party/blink/renderer/platform/heap/page_memory.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/page_memory.h @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_MEMORY_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_MEMORY_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_MEMORY_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_MEMORY_H_ #include "base/atomic_ref_count.h" #include "base/containers/flat_map.h" #include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/heap/heap_page.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_page.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" @@ -183,4 +183,4 @@ class PageMemory { } // namespace blink -#endif +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_MEMORY_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/page_pool.cc b/chromium/third_party/blink/renderer/platform/heap/impl/page_pool.cc index 100a7803614..b3c31417cfb 100644 --- a/chromium/third_party/blink/renderer/platform/heap/page_pool.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/page_pool.cc @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/platform/heap/page_pool.h" +#include "third_party/blink/renderer/platform/heap/impl/page_pool.h" #include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/heap/page_memory.h" +#include "third_party/blink/renderer/platform/heap/impl/page_memory.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/platform/heap/page_pool.h b/chromium/third_party/blink/renderer/platform/heap/impl/page_pool.h index 753d2877778..fdf448f0200 100644 --- a/chromium/third_party/blink/renderer/platform/heap/page_pool.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/page_pool.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_POOL_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PAGE_POOL_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_POOL_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_POOL_H_ #include "third_party/blink/renderer/platform/heap/thread_state.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" @@ -45,4 +45,4 @@ class PagePool { } // namespace blink -#endif +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PAGE_POOL_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/persistent.h b/chromium/third_party/blink/renderer/platform/heap/impl/persistent.h new file mode 100644 index 00000000000..00cff273e2f --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/persistent.h @@ -0,0 +1,971 @@ +// Copyright 2016 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_H_ + +#include "base/bind.h" +#include "base/location.h" +#include "third_party/blink/renderer/platform/bindings/buildflags.h" +#include "third_party/blink/renderer/platform/heap/heap.h" +#include "third_party/blink/renderer/platform/heap/heap_allocator.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h" +#include "third_party/blink/renderer/platform/heap/impl/persistent_node.h" +#include "third_party/blink/renderer/platform/heap/member.h" +#include "third_party/blink/renderer/platform/heap/visitor.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h" + +namespace blink { + +template <typename T> +class CrossThreadWeakPersistent; + +// Wrapping type to force callers to go through macros that expand or drop +// base::Location. This is needed to avoid adding the strings when not needed. +// The type can be dropped once http://crbug.com/760702 is resolved and +// ENABLE_LOCATION_SOURCE is disabled for release builds. +class PersistentLocation final { + public: + PersistentLocation() = default; + explicit PersistentLocation(const base::Location& location) + : location_(location) {} + PersistentLocation(const PersistentLocation& other) = default; + + const base::Location& get() const { return location_; } + + private: + base::Location location_; +}; + +#if !BUILDFLAG(FROM_HERE_USES_LOCATION_BUILTINS) && \ + BUILDFLAG(RAW_HEAP_SNAPSHOTS) +#if !BUILDFLAG(ENABLE_LOCATION_SOURCE) +#define PERSISTENT_FROM_HERE \ + PersistentLocation(::base::Location::CreateFromHere(__FILE__)) +#else +#define PERSISTENT_FROM_HERE \ + PersistentLocation( \ + ::base::Location::CreateFromHere(__func__, __FILE__, __LINE__)) +#endif +#else +#define PERSISTENT_FROM_HERE PersistentLocation() +#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) + +template <typename T, + WeaknessPersistentConfiguration weaknessConfiguration, + CrossThreadnessPersistentConfiguration crossThreadnessConfiguration> +class PersistentBase { + USING_FAST_MALLOC(PersistentBase); + + public: + bool IsHashTableDeletedValue() const { + return raw_ == reinterpret_cast<T*>(-1); + } + + T* Release() { + T* result = raw_; + AssignSafe(nullptr); + return result; + } + + void Clear() { + // Note that this also frees up related data in the backend. + AssignSafe(nullptr); + } + + T* Get() const { + CheckPointer(); + return raw_; + } + + // TODO(https://crbug.com/653394): Consider returning a thread-safe best + // guess of validity. + bool MaybeValid() const { return true; } + + explicit operator bool() const { return Get(); } + T& operator*() const { return *Get(); } + operator T*() const { return Get(); } + T* operator->() const { return Get(); } + + // Register the persistent node as a 'static reference', + // belonging to the current thread and a persistent that must + // be cleared when the ThreadState itself is cleared out and + // destructed. + // + // Static singletons arrange for this to happen, either to ensure + // clean LSan leak reports or to register a thread-local persistent + // needing to be cleared out before the thread is terminated. + PersistentBase* RegisterAsStaticReference() { + static_assert(weaknessConfiguration == kNonWeakPersistentConfiguration, + "Can only register non-weak Persistent references as static " + "references."); + if (PersistentNode* node = persistent_node_.Get()) { + ThreadState::Current()->RegisterStaticPersistentNode(node); + LEAK_SANITIZER_IGNORE_OBJECT(this); + } + return this; + } + + NO_SANITIZE_ADDRESS + void ClearWithLockHeld() { + static_assert( + crossThreadnessConfiguration == kCrossThreadPersistentConfiguration, + "This Persistent does not require the cross-thread lock."); + PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired(); + raw_ = nullptr; + persistent_node_.ClearWithLockHeld(); + } + + void UpdateLocation(const PersistentLocation& other) { +#if BUILDFLAG(RAW_HEAP_SNAPSHOTS) + location_ = other; +#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) + } + + protected: + ~PersistentBase() { + UninitializeSafe(); + // Not resetting raw_ as it is not observable. + } + + PersistentBase() : raw_(nullptr) { + SaveCreationThreadHeap(); + // No initialization needed for empty handle. + } + PersistentBase(const PersistentLocation& location) : PersistentBase() { + UpdateLocation(location); + } + + PersistentBase(std::nullptr_t) : raw_(nullptr) { + SaveCreationThreadHeap(); + // No initialization needed for empty handle. + } + PersistentBase(const PersistentLocation& location, std::nullptr_t) + : PersistentBase(nullptr) { + UpdateLocation(location); + } + + PersistentBase(T* raw) : raw_(raw) { + SaveCreationThreadHeap(); + InitializeSafe(); + CheckPointer(); + } + PersistentBase(const PersistentLocation& location, T* raw) + : PersistentBase(raw) { + UpdateLocation(location); + } + + PersistentBase(T& raw) : raw_(&raw) { + SaveCreationThreadHeap(); + InitializeSafe(); + CheckPointer(); + } + PersistentBase(const PersistentLocation& location, T& raw) + : PersistentBase(raw) { + UpdateLocation(location); + } + + PersistentBase(const PersistentBase& other) : raw_(other) { + SaveCreationThreadHeap(); + InitializeSafe(); + CheckPointer(); + } + PersistentBase(const PersistentLocation& location, PersistentBase& other) + : PersistentBase(other) { + UpdateLocation(location); + } + + template <typename U> + PersistentBase(const PersistentBase<U, + weaknessConfiguration, + crossThreadnessConfiguration>& other) + : raw_(other) { + SaveCreationThreadHeap(); + InitializeSafe(); + CheckPointer(); + } + template <typename U> + PersistentBase(const PersistentLocation& location, + const PersistentBase<U, + weaknessConfiguration, + crossThreadnessConfiguration>& other) + : PersistentBase(other) { + UpdateLocation(location); + } + + template <typename U> + PersistentBase(const Member<U>& other) : raw_(other) { + SaveCreationThreadHeap(); + InitializeSafe(); + CheckPointer(); + } + template <typename U> + PersistentBase(const PersistentLocation& location, const Member<U>& other) + : PersistentBase(other) { + UpdateLocation(location); + } + + PersistentBase(WTF::HashTableDeletedValueType) + : raw_(reinterpret_cast<T*>(-1)) { + SaveCreationThreadHeap(); + // No initialization needed for empty handle. + } + PersistentBase(const PersistentLocation& location, + WTF::HashTableDeletedValueType) + : PersistentBase(WTF::kHashTableDeletedValue) { + UpdateLocation(location); + } + + template <typename U> + PersistentBase& operator=(U* other) { + AssignSafe(other); + return *this; + } + + PersistentBase& operator=(std::nullptr_t) { + AssignSafe(nullptr); + return *this; + } + + template <typename U> + PersistentBase& operator=(const Member<U>& other) { + AssignSafe(other); + return *this; + } + + // Using unsafe operations and assuming that caller acquires the lock for + // kCrossThreadPersistentConfiguration configuration. + PersistentBase& operator=(const PersistentBase& other) { + PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired(); + AssignUnsafe(other); + return *this; + } + + // Using unsafe operations and assuming that caller acquires the lock for + // kCrossThreadPersistentConfiguration configuration. + template <typename U> + PersistentBase& operator=( + const PersistentBase<U, + weaknessConfiguration, + crossThreadnessConfiguration>& other) { + PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired(); + AssignUnsafe(other); + return *this; + } + + // Using unsafe operations and assuming that caller acquires the lock for + // kCrossThreadPersistentConfiguration configuration. + template <typename U> + PersistentBase& operator=( + PersistentBase<U, weaknessConfiguration, crossThreadnessConfiguration>&& + other) { + PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired(); + if (persistent_node_.IsInitialized()) { + // Drop persistent node if present as it's always possible to reuse the + // node (if present) from |other|. + persistent_node_.Uninitialize(); + } + // Explicit cast enabling downcasting. + raw_ = static_cast<T*>(other.raw_); + other.raw_ = nullptr; + // Efficiently move by just rewiring the node pointer. + persistent_node_ = std::move(other.persistent_node_); + DCHECK(!other.persistent_node_.Get()); + if (persistent_node_.IsInitialized()) { + // If |raw_| points to a non-null or deleted value, just reuse the node. + TraceCallback trace_callback = + TraceMethodDelegate<PersistentBase, + &PersistentBase::TracePersistent>::Trampoline; + persistent_node_.Get()->Reinitialize(this, trace_callback); + } + CheckPointer(); + return *this; + } + + NO_SANITIZE_ADDRESS + bool IsNotNull() const { return raw_; } + + NO_SANITIZE_ADDRESS + void AssignSafe(T* ptr) { + typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock; + AssignUnsafe(ptr); + } + + NO_SANITIZE_ADDRESS + void AssignUnsafe(T* ptr) { + raw_ = ptr; + CheckPointer(); + if (raw_ && !IsHashTableDeletedValue()) { + if (!persistent_node_.IsInitialized()) + InitializeUnsafe(); + return; + } + UninitializeUnsafe(); + } + + void TracePersistent(Visitor* visitor) const { + static_assert(sizeof(T), "T must be fully defined"); + static_assert(IsGarbageCollectedType<T>::value, + "T needs to be a garbage collected object"); + DCHECK(!IsHashTableDeletedValue()); + if (weaknessConfiguration == kWeakPersistentConfiguration) { + visitor->RegisterWeakCallback(HandleWeakPersistent, this); + } else { +#if BUILDFLAG(RAW_HEAP_SNAPSHOTS) + visitor->TraceRoot(raw_, location_.get()); +#else + visitor->TraceRoot(raw_, base::Location()); +#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) + } + } + + NO_SANITIZE_ADDRESS + void InitializeSafe() { + DCHECK(!persistent_node_.IsInitialized()); + if (!raw_ || IsHashTableDeletedValue()) + return; + + TraceCallback trace_callback = + TraceMethodDelegate<PersistentBase, + &PersistentBase::TracePersistent>::Trampoline; + typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock; + persistent_node_.Initialize(this, trace_callback); + } + + NO_SANITIZE_ADDRESS + void InitializeUnsafe() { + DCHECK(!persistent_node_.IsInitialized()); + if (!raw_ || IsHashTableDeletedValue()) + return; + + TraceCallback trace_callback = + TraceMethodDelegate<PersistentBase, + &PersistentBase::TracePersistent>::Trampoline; + persistent_node_.Initialize(this, trace_callback); + } + + void UninitializeSafe() { + if (persistent_node_.IsInitialized()) { + typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock; + persistent_node_.Uninitialize(); + } + } + + void UninitializeUnsafe() { + if (persistent_node_.IsInitialized()) + persistent_node_.Uninitialize(); + } + + void CheckPointer() const { +#if DCHECK_IS_ON() + if (!raw_ || IsHashTableDeletedValue()) + return; + + if (crossThreadnessConfiguration != kCrossThreadPersistentConfiguration) { + ThreadState* current = ThreadState::Current(); + DCHECK(current); + // m_creationThreadState may be null when this is used in a heap + // collection which initialized the Persistent with memset and the + // constructor wasn't called. + if (creation_thread_state_) { + // Member should point to objects that belong in the same ThreadHeap. + DCHECK_EQ(&ThreadState::FromObject(raw_)->Heap(), + &creation_thread_state_->Heap()); + // Member should point to objects that belong in the same ThreadHeap. + DCHECK_EQ(¤t->Heap(), &creation_thread_state_->Heap()); + } + } +#endif + } + + void SaveCreationThreadHeap() { +#if DCHECK_IS_ON() + if (crossThreadnessConfiguration == kCrossThreadPersistentConfiguration) { + creation_thread_state_ = nullptr; + } else { + creation_thread_state_ = ThreadState::Current(); + DCHECK(creation_thread_state_); + } +#endif + } + + static void HandleWeakPersistent(const LivenessBroker& broker, + const void* persistent_pointer) { + using Base = + PersistentBase<typename std::remove_const<T>::type, + weaknessConfiguration, crossThreadnessConfiguration>; + Base* persistent = + reinterpret_cast<Base*>(const_cast<void*>(persistent_pointer)); + T* object = persistent->Get(); + if (object && !broker.IsHeapObjectAlive(object)) + ClearWeakPersistent(persistent); + } + + static void ClearWeakPersistent( + PersistentBase<std::remove_const_t<T>, + kWeakPersistentConfiguration, + kCrossThreadPersistentConfiguration>* persistent) { + PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired(); + persistent->ClearWithLockHeld(); + } + + static void ClearWeakPersistent( + PersistentBase<std::remove_const_t<T>, + kWeakPersistentConfiguration, + kSingleThreadPersistentConfiguration>* persistent) { + persistent->Clear(); + } + + template <typename BadPersistent> + static void ClearWeakPersistent(BadPersistent* non_weak_persistent) { + NOTREACHED(); + } + + // raw_ is accessed most, so put it at the first field. + T* raw_; + + // The pointer to the underlying persistent node. + // + // Since accesses are atomics in the cross-thread case, a different type is + // needed to prevent the compiler producing an error when it encounters + // operations that are legal on raw pointers but not on atomics, or + // vice-versa. + std::conditional_t< + crossThreadnessConfiguration == kCrossThreadPersistentConfiguration, + CrossThreadPersistentNodePtr<weaknessConfiguration>, + PersistentNodePtr<ThreadingTrait<T>::kAffinity, weaknessConfiguration>> + persistent_node_; + +#if BUILDFLAG(RAW_HEAP_SNAPSHOTS) + PersistentLocation location_; +#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) + +#if DCHECK_IS_ON() + const ThreadState* creation_thread_state_; +#endif + + template <typename F, + WeaknessPersistentConfiguration, + CrossThreadnessPersistentConfiguration> + friend class PersistentBase; +}; + +// Persistent is a way to create a strong pointer from an off-heap object +// to another on-heap object. As long as the Persistent handle is alive +// the GC will keep the object pointed to alive. The Persistent handle is +// always a GC root from the point of view of the GC. +// +// We have to construct and destruct Persistent in the same thread. +template <typename T> +class Persistent : public PersistentBase<T, + kNonWeakPersistentConfiguration, + kSingleThreadPersistentConfiguration> { + using Parent = PersistentBase<T, + kNonWeakPersistentConfiguration, + kSingleThreadPersistentConfiguration>; + + public: + Persistent() : Parent() {} + Persistent(const PersistentLocation& location) : Parent(location) {} + Persistent(std::nullptr_t) : Parent(nullptr) {} + Persistent(const PersistentLocation& location, std::nullptr_t) + : Parent(location, nullptr) {} + Persistent(T* raw) : Parent(raw) {} + Persistent(const PersistentLocation& location, T* raw) + : Parent(location, raw) {} + Persistent(T& raw) : Parent(raw) {} + Persistent(const PersistentLocation& location, T& raw) + : Parent(location, raw) {} + Persistent(const Persistent& other) : Parent(other) {} + Persistent(const PersistentLocation& location, const Persistent& other) + : Parent(location, other) {} + template <typename U> + Persistent(const Persistent<U>& other) : Parent(other) {} + template <typename U> + Persistent(const PersistentLocation& location, const Persistent<U>& other) + : Parent(location, other) {} + template <typename U> + Persistent(const Member<U>& other) : Parent(other) {} + template <typename U> + Persistent(const PersistentLocation& location, const Member<U>& other) + : Parent(location, other) {} + Persistent(WTF::HashTableDeletedValueType x) : Parent(x) {} + Persistent(const PersistentLocation& location, + WTF::HashTableDeletedValueType x) + : Parent(location, x) {} + + template <typename U> + Persistent& operator=(U* other) { + Parent::operator=(other); + return *this; + } + + Persistent& operator=(std::nullptr_t) { + Parent::operator=(nullptr); + return *this; + } + + Persistent& operator=(const Persistent& other) { + Parent::operator=(other); + return *this; + } + + template <typename U> + Persistent& operator=(const Persistent<U>& other) { + Parent::operator=(other); + return *this; + } + + template <typename U> + Persistent& operator=(const Member<U>& other) { + Parent::operator=(other); + return *this; + } +}; + +// WeakPersistent is a way to create a weak pointer from an off-heap object +// to an on-heap object. The m_raw is automatically cleared when the pointee +// gets collected. +// +// We have to construct and destruct WeakPersistent in the same thread. +// +// Note that collections of WeakPersistents are not supported. Use a collection +// of WeakMembers instead. +// +// HashSet<WeakPersistent<T>> m_set; // wrong +// Persistent<HeapHashSet<WeakMember<T>>> m_set; // correct +template <typename T> +class WeakPersistent + : public PersistentBase<T, + kWeakPersistentConfiguration, + kSingleThreadPersistentConfiguration> { + using Parent = PersistentBase<T, + kWeakPersistentConfiguration, + kSingleThreadPersistentConfiguration>; + + public: + WeakPersistent() : Parent() {} + WeakPersistent(std::nullptr_t) : Parent(nullptr) {} + WeakPersistent(T* raw) : Parent(raw) {} + WeakPersistent(T& raw) : Parent(raw) {} + WeakPersistent(const WeakPersistent& other) : Parent(other) {} + template <typename U> + WeakPersistent(const WeakPersistent<U>& other) : Parent(other) {} + template <typename U> + WeakPersistent(const Member<U>& other) : Parent(other) {} + + template <typename U> + WeakPersistent& operator=(U* other) { + Parent::operator=(other); + return *this; + } + + WeakPersistent& operator=(std::nullptr_t) { + Parent::operator=(nullptr); + return *this; + } + + WeakPersistent& operator=(const WeakPersistent& other) { + Parent::operator=(other); + return *this; + } + + template <typename U> + WeakPersistent& operator=(const WeakPersistent<U>& other) { + Parent::operator=(other); + return *this; + } + + template <typename U> + WeakPersistent& operator=(const Member<U>& other) { + Parent::operator=(other); + return *this; + } + + NO_SANITIZE_ADDRESS + bool IsClearedUnsafe() const { return this->IsNotNull(); } +}; + +// CrossThreadPersistent allows for holding onto an object strongly on a +// different thread. +// +// Thread-safe operations: +// - Construction +// - Destruction +// - Copy and move construction and assignment +// - Clearing +// - Deref if treated as immutable reference or if externally synchronized (e.g. +// mutex, task). The current implementation of Get() uses a raw load (on +// purpose) which prohibits mutation while accessing the reference on a +// different thread. +template <typename T> +class CrossThreadPersistent + : public PersistentBase<T, + kNonWeakPersistentConfiguration, + kCrossThreadPersistentConfiguration> { + using Parent = PersistentBase<T, + kNonWeakPersistentConfiguration, + kCrossThreadPersistentConfiguration>; + + public: + CrossThreadPersistent() : Parent() {} + CrossThreadPersistent(const PersistentLocation& location) + : Parent(location) {} + CrossThreadPersistent(std::nullptr_t) : Parent(nullptr) {} + CrossThreadPersistent(const PersistentLocation& location, std::nullptr_t) + : Parent(location, nullptr) {} + explicit CrossThreadPersistent(T* raw) : Parent(raw) {} + CrossThreadPersistent(const PersistentLocation& location, T* raw) + : Parent(location, raw) {} + explicit CrossThreadPersistent(T& raw) : Parent(raw) {} + CrossThreadPersistent(const PersistentLocation& location, T& raw) + : Parent(location, raw) {} + CrossThreadPersistent(const CrossThreadPersistent& other) { *this = other; } + CrossThreadPersistent(const PersistentLocation& location, + const CrossThreadPersistent& other) { + *this = other; + } + template <typename U> + CrossThreadPersistent(const CrossThreadPersistent<U>& other) { + *this = other; + } + template <typename U> + CrossThreadPersistent(const PersistentLocation& location, + const CrossThreadPersistent<U>& other) { + *this = other; + } + template <typename U> + CrossThreadPersistent(const Member<U>& other) : Parent(other) {} + template <typename U> + CrossThreadPersistent(const PersistentLocation& location, + const Member<U>& other) + : Parent(location, other) {} + CrossThreadPersistent(WTF::HashTableDeletedValueType x) : Parent(x) {} + CrossThreadPersistent(const PersistentLocation& location, + WTF::HashTableDeletedValueType x) + : Parent(location, x) {} + template <typename U> + CrossThreadPersistent(const CrossThreadWeakPersistent<U>& other) { + *this = other; + } + + // Instead of using release(), assign then clear() instead. + // Using release() with per thread heap enabled can cause the object to be + // destroyed before assigning it to a new handle. + T* Release() = delete; + + template <typename U> + CrossThreadPersistent& operator=(U* other) { + Parent::operator=(other); + return *this; + } + + CrossThreadPersistent& operator=(std::nullptr_t) { + Parent::operator=(nullptr); + return *this; + } + + CrossThreadPersistent& operator=(const CrossThreadPersistent& other) { + MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); + Parent::operator=(other); + return *this; + } + + template <typename U> + CrossThreadPersistent& operator=(const CrossThreadPersistent<U>& other) { + MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); + Parent::operator=(other); + return *this; + } + + template <typename U> + CrossThreadPersistent& operator=(const CrossThreadWeakPersistent<U>&); +}; + +// CrossThreadWeakPersistent combines behavior of CrossThreadPersistent and +// WeakPersistent, i.e., it allows holding onto an object weakly on a different +// thread. +// +// Thread-safe operations: +// - Construction +// - Destruction +// - Copy and move construction and assignment +// - Clearing +// +// Note that this does not include dereferencing and using the raw pointer as +// there is no guarantee that the object will be alive at the time it is used. +template <typename T> +class CrossThreadWeakPersistent + : public PersistentBase<T, + kWeakPersistentConfiguration, + kCrossThreadPersistentConfiguration> { + using Parent = PersistentBase<T, + kWeakPersistentConfiguration, + kCrossThreadPersistentConfiguration>; + + public: + CrossThreadWeakPersistent() : Parent() {} + explicit CrossThreadWeakPersistent(T* raw) : Parent(raw) {} + explicit CrossThreadWeakPersistent(T& raw) : Parent(raw) {} + CrossThreadWeakPersistent(const CrossThreadWeakPersistent& other) { + *this = other; + } + template <typename U> + CrossThreadWeakPersistent(const CrossThreadWeakPersistent<U>& other) { + *this = other; + } + CrossThreadWeakPersistent(CrossThreadWeakPersistent&& other) { + *this = std::move(other); + } + template <typename U> + CrossThreadWeakPersistent(CrossThreadWeakPersistent<U>&& other) { + *this = std::move(other); + } + + CrossThreadWeakPersistent& operator=(const CrossThreadWeakPersistent& other) { + MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); + Parent::operator=(other); + return *this; + } + + template <typename U> + CrossThreadWeakPersistent& operator=( + const CrossThreadWeakPersistent<U>& other) { + MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); + Parent::operator=(other); + return *this; + } + + CrossThreadWeakPersistent& operator=(CrossThreadWeakPersistent&& other) { + MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); + Parent::operator=(std::move(other)); + return *this; + } + + template <typename U> + CrossThreadWeakPersistent& operator=(CrossThreadWeakPersistent<U>&& other) { + MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); + Parent::operator=(std::move(other)); + return *this; + } + + template <typename U> + CrossThreadWeakPersistent& operator=(U* other) { + Parent::operator=(other); + return *this; + } + + // Create a CrossThreadPersistent that keeps the underlying object alive if + // there is still on set. Can be used to work with an object on a different + // thread than it was allocated. Note that CTP does not block threads from + // terminating, in which case the reference would still be invalid. + const CrossThreadPersistent<T> Lock() const { + return CrossThreadPersistent<T>(*this); + } + + // Disallow directly using CrossThreadWeakPersistent. Users must go through + // CrossThreadPersistent to access the pointee. Note that this does not + // guarantee that the object is still alive at that point. Users must check + // the state of CTP manually before invoking any calls. + T* operator->() const = delete; + T& operator*() const = delete; + operator T*() const = delete; + T* Get() const = delete; + + private: + template <typename U> + friend class CrossThreadPersistent; +}; + +template <typename T> +template <typename U> +CrossThreadPersistent<T>& CrossThreadPersistent<T>::operator=( + const CrossThreadWeakPersistent<U>& other) { + MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); + using ParentU = PersistentBase<U, kWeakPersistentConfiguration, + kCrossThreadPersistentConfiguration>; + this->AssignUnsafe(static_cast<const ParentU&>(other).Get()); + return *this; +} + +template <typename T> +Persistent<T> WrapPersistentInternal(const PersistentLocation& location, + T* value) { + return Persistent<T>(location, value); +} + +template <typename T> +Persistent<T> WrapPersistentInternal(T* value) { + return Persistent<T>(value); +} + +#if BUILDFLAG(RAW_HEAP_SNAPSHOTS) +#define WrapPersistent(value) \ + WrapPersistentInternal(PERSISTENT_FROM_HERE, value) +#else +#define WrapPersistent(value) WrapPersistentInternal(value) +#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) + +template <typename T, + typename = std::enable_if_t<WTF::IsGarbageCollectedType<T>::value>> +Persistent<T> WrapPersistentIfNeeded(T* value) { + return Persistent<T>(value); +} + +template <typename T> +T& WrapPersistentIfNeeded(T& value) { + return value; +} + +template <typename T> +WeakPersistent<T> WrapWeakPersistent(T* value) { + return WeakPersistent<T>(value); +} + +template <typename T> +CrossThreadPersistent<T> WrapCrossThreadPersistentInternal( + const PersistentLocation& location, + T* value) { + return CrossThreadPersistent<T>(location, value); +} + +template <typename T> +CrossThreadPersistent<T> WrapCrossThreadPersistentInternal(T* value) { + return CrossThreadPersistent<T>(value); +} + +#if BUILDFLAG(RAW_HEAP_SNAPSHOTS) +#define WrapCrossThreadPersistent(value) \ + WrapCrossThreadPersistentInternal(PERSISTENT_FROM_HERE, value) +#else +#define WrapCrossThreadPersistent(value) \ + WrapCrossThreadPersistentInternal(value) +#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) + +template <typename T> +CrossThreadWeakPersistent<T> WrapCrossThreadWeakPersistent(T* value) { + return CrossThreadWeakPersistent<T>(value); +} + +// Comparison operators between (Weak)Members, Persistents, and UntracedMembers. +template <typename T, typename U> +inline bool operator==(const Member<T>& a, const Member<U>& b) { + return a.Get() == b.Get(); +} +template <typename T, typename U> +inline bool operator!=(const Member<T>& a, const Member<U>& b) { + return a.Get() != b.Get(); +} +template <typename T, typename U> +inline bool operator==(const Persistent<T>& a, const Persistent<U>& b) { + return a.Get() == b.Get(); +} +template <typename T, typename U> +inline bool operator!=(const Persistent<T>& a, const Persistent<U>& b) { + return a.Get() != b.Get(); +} + +template <typename T, typename U> +inline bool operator==(const Member<T>& a, const Persistent<U>& b) { + return a.Get() == b.Get(); +} +template <typename T, typename U> +inline bool operator!=(const Member<T>& a, const Persistent<U>& b) { + return a.Get() != b.Get(); +} +template <typename T, typename U> +inline bool operator==(const Persistent<T>& a, const Member<U>& b) { + return a.Get() == b.Get(); +} +template <typename T, typename U> +inline bool operator!=(const Persistent<T>& a, const Member<U>& b) { + return a.Get() != b.Get(); +} + +} // namespace blink + +namespace WTF { + +template < + typename T, + blink::WeaknessPersistentConfiguration weaknessConfiguration, + blink::CrossThreadnessPersistentConfiguration crossThreadnessConfiguration> +struct VectorTraits<blink::PersistentBase<T, + weaknessConfiguration, + crossThreadnessConfiguration>> + : VectorTraitsBase<blink::PersistentBase<T, + weaknessConfiguration, + crossThreadnessConfiguration>> { + STATIC_ONLY(VectorTraits); + static const bool kNeedsDestruction = true; + static const bool kCanInitializeWithMemset = true; + static const bool kCanClearUnusedSlotsWithMemset = false; + static const bool kCanMoveWithMemcpy = true; +}; + +template <typename T> +struct HashTraits<blink::Persistent<T>> + : HandleHashTraits<T, blink::Persistent<T>> {}; + +template <typename T> +struct HashTraits<blink::CrossThreadPersistent<T>> + : HandleHashTraits<T, blink::CrossThreadPersistent<T>> {}; + +template <typename T> +struct DefaultHash<blink::Persistent<T>> { + STATIC_ONLY(DefaultHash); + using Hash = MemberHash<T>; +}; + +template <typename T> +struct DefaultHash<blink::WeakPersistent<T>> { + STATIC_ONLY(DefaultHash); + using Hash = MemberHash<T>; +}; + +template <typename T> +struct DefaultHash<blink::CrossThreadPersistent<T>> { + STATIC_ONLY(DefaultHash); + using Hash = MemberHash<T>; +}; + +template <typename T> +struct DefaultHash<blink::CrossThreadWeakPersistent<T>> { + STATIC_ONLY(DefaultHash); + using Hash = MemberHash<T>; +}; + +template <typename T> +struct CrossThreadCopier<blink::CrossThreadPersistent<T>> + : public CrossThreadCopierPassThrough<blink::CrossThreadPersistent<T>> { + STATIC_ONLY(CrossThreadCopier); +}; + +template <typename T> +struct CrossThreadCopier<blink::CrossThreadWeakPersistent<T>> + : public CrossThreadCopierPassThrough<blink::CrossThreadWeakPersistent<T>> { + STATIC_ONLY(CrossThreadCopier); +}; + +} // namespace WTF + +namespace base { + +template <typename T> +struct IsWeakReceiver<blink::WeakPersistent<T>> : std::true_type {}; + +template <typename T> +struct IsWeakReceiver<blink::CrossThreadWeakPersistent<T>> : std::true_type {}; + +template <typename T> +struct BindUnwrapTraits<blink::CrossThreadWeakPersistent<T>> { + static blink::CrossThreadPersistent<T> Unwrap( + const blink::CrossThreadWeakPersistent<T>& wrapped) { + return blink::CrossThreadPersistent<T>(wrapped); + } +}; +} // namespace base + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/persistent_node.cc b/chromium/third_party/blink/renderer/platform/heap/impl/persistent_node.cc index 0dd7b23ae4c..64733dc57f6 100644 --- a/chromium/third_party/blink/renderer/platform/heap/persistent_node.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/persistent_node.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/platform/heap/persistent_node.h" +#include "third_party/blink/renderer/platform/heap/impl/persistent_node.h" #include "base/debug/alias.h" #include "third_party/blink/renderer/platform/heap/handle.h" @@ -17,7 +17,7 @@ class DummyGCBase final : public GarbageCollected<DummyGCBase> { public: void Trace(Visitor* visitor) const {} }; -} +} // namespace PersistentRegionBase::~PersistentRegionBase() { PersistentNodeSlots* slots = slots_; diff --git a/chromium/third_party/blink/renderer/platform/heap/persistent_node.h b/chromium/third_party/blink/renderer/platform/heap/impl/persistent_node.h index b591db1e793..d8c2b08471e 100644 --- a/chromium/third_party/blink/renderer/platform/heap/persistent_node.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/persistent_node.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_NODE_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_NODE_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_NODE_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_NODE_H_ #include <atomic> #include <memory> @@ -382,4 +382,4 @@ void CrossThreadPersistentNodePtr<weakness_configuration>::ClearWithLockHeld() { } // namespace blink -#endif +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PERSISTENT_NODE_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/process_heap.cc b/chromium/third_party/blink/renderer/platform/heap/impl/process_heap.cc index df929e8dfd2..038a7385aad 100644 --- a/chromium/third_party/blink/renderer/platform/heap/process_heap.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/process_heap.cc @@ -6,9 +6,9 @@ #include "base/sampling_heap_profiler/poisson_allocation_sampler.h" #include "third_party/blink/public/common/features.h" -#include "third_party/blink/renderer/platform/heap/gc_info.h" #include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/heap/persistent_node.h" +#include "third_party/blink/renderer/platform/heap/impl/gc_info.h" +#include "third_party/blink/renderer/platform/heap/impl/persistent_node.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" namespace blink { diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/process_heap.h b/chromium/third_party/blink/renderer/platform/heap/impl/process_heap.h new file mode 100644 index 00000000000..91112a7c039 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/process_heap.h @@ -0,0 +1,69 @@ +// Copyright 2018 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PROCESS_HEAP_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PROCESS_HEAP_H_ + +#include <atomic> +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/threading_primitives.h" + +namespace blink { + +class CrossThreadPersistentRegion; + +class PLATFORM_EXPORT ProcessHeap { + STATIC_ONLY(ProcessHeap); + + public: + static void Init(); + + static CrossThreadPersistentRegion& GetCrossThreadPersistentRegion(); + static CrossThreadPersistentRegion& GetCrossThreadWeakPersistentRegion(); + + // Access to the CrossThreadPersistentRegion from multiple threads has to be + // prevented as allocation, freeing, and iteration of nodes may otherwise + // cause data races. + // + // Examples include: + // - Iteration of strong cross-thread Persistents. + // - Iteration and processing of weak cross-thread Persistents. The lock + // needs to span both operations as iteration of weak persistents only + // registers memory regions that are then processed afterwards. + // - Marking phase in garbage collection: The whole phase requires locking + // as CrossThreadWeakPersistents may be converted to CrossThreadPersistent + // which must observe GC as an atomic operation. + static Mutex& CrossThreadPersistentMutex(); + + static void IncreaseTotalAllocatedObjectSize(size_t delta) { + total_allocated_object_size_.fetch_add(delta, std::memory_order_relaxed); + } + static void DecreaseTotalAllocatedObjectSize(size_t delta) { + total_allocated_object_size_.fetch_sub(delta, std::memory_order_relaxed); + } + static size_t TotalAllocatedObjectSize() { + return total_allocated_object_size_.load(std::memory_order_relaxed); + } + static void IncreaseTotalAllocatedSpace(size_t delta) { + total_allocated_space_.fetch_add(delta, std::memory_order_relaxed); + } + static void DecreaseTotalAllocatedSpace(size_t delta) { + total_allocated_space_.fetch_sub(delta, std::memory_order_relaxed); + } + static size_t TotalAllocatedSpace() { + return total_allocated_space_.load(std::memory_order_relaxed); + } + static void ResetHeapCounters(); + + private: + static std::atomic_size_t total_allocated_space_; + static std::atomic_size_t total_allocated_object_size_; + + friend class ThreadState; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_PROCESS_HEAP_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/thread_state.cc b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.cc index bece34a9118..228902f91f7 100644 --- a/chromium/third_party/blink/renderer/platform/heap/thread_state.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.cc @@ -53,11 +53,11 @@ #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -#include "third_party/blink/renderer/platform/heap/heap_compact.h" #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h" -#include "third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h" -#include "third_party/blink/renderer/platform/heap/marking_visitor.h" -#include "third_party/blink/renderer/platform/heap/page_pool.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_compact.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_scheduling_oracle.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h" +#include "third_party/blink/renderer/platform/heap/impl/page_pool.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/heap/thread_state_scopes.h" #include "third_party/blink/renderer/platform/heap/unified_heap_controller.h" @@ -1153,8 +1153,8 @@ void ThreadState::IncrementalMarkingStep(BlinkGC::StackState stack_state) { skip_incremental_marking_for_testing_ = false; } else { complete = MarkPhaseAdvanceMarking( - marking_scheduling_->GetNextIncrementalStepDurationForTask( - Heap().stats_collector()->object_size_in_bytes()), + marking_scheduling_->GetNextIncrementalStepDurationForTask( + Heap().stats_collector()->object_size_in_bytes()), EphemeronProcessing::kPartialProcessing); } @@ -1638,7 +1638,6 @@ void ThreadState::MarkPhaseEpilogue(BlinkGC::MarkingType marking_type) { incremental_marking_scheduler_->Cancel(); - current_gc_data_.visitor->FlushCompactionWorklists(); current_gc_data_.visitor.reset(); diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.h b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.h new file mode 100644 index 00000000000..ee318bd64bf --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state.h @@ -0,0 +1,716 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_H_ + +#include <atomic> +#include <memory> + +#include "base/macros.h" +#include "base/synchronization/lock.h" +#include "base/task/post_job.h" +#include "third_party/blink/renderer/platform/heap/blink_gc.h" +#include "third_party/blink/renderer/platform/heap/impl/atomic_entry_flag.h" +#include "third_party/blink/renderer/platform/heap/impl/threading_traits.h" +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/forward.h" +#include "third_party/blink/renderer/platform/wtf/hash_map.h" +#include "third_party/blink/renderer/platform/wtf/hash_set.h" +#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h" +#include "third_party/blink/renderer/platform/wtf/sanitizers.h" +#include "third_party/blink/renderer/platform/wtf/thread_specific.h" +#include "third_party/blink/renderer/platform/wtf/threading.h" +#include "third_party/blink/renderer/platform/wtf/threading_primitives.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" + +namespace v8 { +class EmbedderGraph; +class Isolate; +} // namespace v8 + +namespace blink { + +namespace incremental_marking_test { +class IncrementalMarkingScope; +} // namespace incremental_marking_test + +class MarkingVisitor; +class MarkingSchedulingOracle; +class PersistentNode; +class PersistentRegion; +class ThreadHeap; +class ThreadState; +template <ThreadAffinity affinity> +class ThreadStateFor; +class UnifiedHeapController; +class Visitor; + +// Declare that a class has a pre-finalizer which gets invoked before objects +// get swept. It is thus safe to touch on-heap objects that may be collected in +// the same GC cycle. This is useful when it's not possible to avoid touching +// on-heap objects in a destructor which is forbidden. +// +// Note that: +// (a) Pre-finalizers *must* not resurrect dead objects. +// (b) Run on the same thread they are registered. +// (c) Decrease GC performance which means that they should only be used if +// absolute necessary. +// +// Usage: +// class Foo : GarbageCollected<Foo> { +// USING_PRE_FINALIZER(Foo, Dispose); +// private: +// void Dispose() { +// bar_->...; // It is safe to touch other on-heap objects. +// } +// Member<Bar> bar_; +// }; +#define USING_PRE_FINALIZER(Class, PreFinalizer) \ + public: \ + static bool InvokePreFinalizer(const LivenessBroker& info, void* object) { \ + Class* self = reinterpret_cast<Class*>(object); \ + if (info.IsHeapObjectAlive(self)) \ + return false; \ + self->Class::PreFinalizer(); \ + return true; \ + } \ + \ + private: \ + ThreadState::PrefinalizerRegistration<Class> prefinalizer_dummy_{this}; \ + using UsingPreFinalizerMacroNeedsTrailingSemiColon = char + +class PLATFORM_EXPORT BlinkGCObserver { + USING_FAST_MALLOC(BlinkGCObserver); + + public: + // The constructor automatically register this object to ThreadState's + // observer lists. The argument must not be null. + explicit BlinkGCObserver(ThreadState*); + + // The destructor automatically unregister this object from ThreadState's + // observer lists. + virtual ~BlinkGCObserver(); + + virtual void OnCompleteSweepDone() = 0; + + private: + // As a ThreadState must live when a BlinkGCObserver lives, holding a raw + // pointer is safe. + ThreadState* thread_state_; +}; + +class PLATFORM_EXPORT ThreadState final { + USING_FAST_MALLOC(ThreadState); + + public: + // Register the pre-finalizer for the |self| object. The class T be using + // USING_PRE_FINALIZER() macro. + template <typename T> + class PrefinalizerRegistration final { + DISALLOW_NEW(); + + public: + PrefinalizerRegistration(T* self) { // NOLINT + static_assert(sizeof(&T::InvokePreFinalizer) > 0, + "USING_PRE_FINALIZER(T) must be defined."); + ThreadState* state = + ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState(); +#if DCHECK_IS_ON() + DCHECK(state->CheckThread()); +#endif + DCHECK(!state->SweepForbidden()); + DCHECK(std::find(state->ordered_pre_finalizers_.begin(), + state->ordered_pre_finalizers_.end(), + PreFinalizer(self, T::InvokePreFinalizer)) == + state->ordered_pre_finalizers_.end()); + state->ordered_pre_finalizers_.emplace_back(self, T::InvokePreFinalizer); + } + }; + + // See setGCState() for possible state transitions. + enum GCState { + kNoGCScheduled, + kIncrementalMarkingStepPaused, + kIncrementalMarkingStepScheduled, + kIncrementalMarkingFinalizeScheduled, + kForcedGCForTestingScheduled, + kIncrementalGCScheduled, + }; + + // The phase that the GC is in. The GCPhase will not return kNone for mutators + // running during incremental marking and lazy sweeping. See SetGCPhase() for + // possible state transitions. + enum class GCPhase { + // GC is doing nothing. + kNone, + // GC is in marking phase. + kMarking, + // GC is in sweeping phase. + kSweeping, + }; + + enum class EphemeronProcessing { + kPartialProcessing, // Perofrm one ephemeron processing iteration every + // few step + kFullProcessing // Perofrm full fixed-point ephemeron processing on each + // step + }; + + class AtomicPauseScope; + class GCForbiddenScope; + class LsanDisabledScope; + class NoAllocationScope; + class StatisticsCollector; + struct Statistics; + class SweepForbiddenScope; + class HeapPointersOnStackScope; + + using V8BuildEmbedderGraphCallback = void (*)(v8::Isolate*, + v8::EmbedderGraph*, + void*); + + // Returns true if some thread (possibly the current thread) may be doing + // incremental marking. If false is returned, the *current* thread is + // definitely not doing incremental marking. See atomic_entry_flag.h for + // details. + // + // For an exact check, use ThreadState::IsIncrementalMarking. + ALWAYS_INLINE static bool IsAnyIncrementalMarking() { + return incremental_marking_flag_.MightBeEntered(); + } + + static ThreadState* AttachMainThread(); + + // Associate ThreadState object with the current thread. After this + // call thread can start using the garbage collected heap infrastructure. + // It also has to periodically check for safepoints. + static ThreadState* AttachCurrentThread(); + + // Disassociate attached ThreadState from the current thread. The thread + // can no longer use the garbage collected heap after this call. + // + // When ThreadState is detaching from non-main thread its heap is expected to + // be empty (because it is going away). Perform registered cleanup tasks and + // garbage collection to sweep away any objects that are left on this heap. + // + // This method asserts that no objects remain after this cleanup. If assertion + // does not hold we crash as we are potentially in the dangling pointer + // situation. + static void DetachCurrentThread(); + + static ThreadState* Current() { return **thread_specific_; } + + static ThreadState* MainThreadState() { + return reinterpret_cast<ThreadState*>(main_thread_state_storage_); + } + + static ThreadState* FromObject(const void*); + + bool IsMainThread() const { return this == MainThreadState(); } + bool CheckThread() const { return thread_ == CurrentThread(); } + + ThreadHeap& Heap() const { return *heap_; } + base::PlatformThreadId ThreadId() const { return thread_; } + + // Associates |ThreadState| with a given |v8::Isolate|, essentially tying + // there garbage collectors together. + void AttachToIsolate(v8::Isolate*, V8BuildEmbedderGraphCallback); + + // Removes the association from a potentially attached |v8::Isolate|. + void DetachFromIsolate(); + + // Returns an |UnifiedHeapController| if ThreadState is attached to a V8 + // isolate (see |AttachToIsolate|) and nullptr otherwise. + UnifiedHeapController* unified_heap_controller() const { + DCHECK(isolate_); + return unified_heap_controller_.get(); + } + + void PerformIdleLazySweep(base::TimeTicks deadline); + void PerformConcurrentSweep(base::JobDelegate*); + + void ScheduleForcedGCForTesting(); + void ScheduleGCIfNeeded(); + void SetGCState(GCState); + GCState GetGCState() const { return gc_state_; } + void SetGCPhase(GCPhase); + + // Immediately starts incremental marking and schedules further steps if + // necessary. + void StartIncrementalMarking(BlinkGC::GCReason); + + // Returns true if marking is in progress. + bool IsMarkingInProgress() const { return gc_phase_ == GCPhase::kMarking; } + + // Returns true if unified heap marking is in progress. + bool IsUnifiedGCMarkingInProgress() const { + return IsMarkingInProgress() && IsUnifiedHeapGC(); + } + + // Returns true if sweeping is in progress. + bool IsSweepingInProgress() const { return gc_phase_ == GCPhase::kSweeping; } + + // Returns true if the current GC is a memory reducing GC. + bool IsMemoryReducingGC() const { + return current_gc_data_.reason == + BlinkGC::GCReason::kUnifiedHeapForMemoryReductionGC || + current_gc_data_.reason == + BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC; + } + + bool IsUnifiedHeapGC() const { + return current_gc_data_.reason == BlinkGC::GCReason::kUnifiedHeapGC || + current_gc_data_.reason == + BlinkGC::GCReason::kUnifiedHeapForMemoryReductionGC || + current_gc_data_.reason == + BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC; + } + + bool FinishIncrementalMarkingIfRunning(BlinkGC::CollectionType, + BlinkGC::StackState, + BlinkGC::MarkingType, + BlinkGC::SweepingType, + BlinkGC::GCReason); + + void EnableIncrementalMarkingBarrier(); + void DisableIncrementalMarkingBarrier(); + + void RestartIncrementalMarkingIfPaused(); + + void CompleteSweep(); + + // Returns whether it is currently allowed to allocate an object. Mainly used + // for sanity checks asserts. + bool IsAllocationAllowed() const { + // Allocation is not allowed during atomic marking pause, but it is allowed + // during atomic sweeping pause. + return !InAtomicMarkingPause() && !no_allocation_count_; + } + + // Returns whether it is currently forbidden to trigger a GC. + bool IsGCForbidden() const { return gc_forbidden_count_; } + + // Returns whether it is currently forbidden to sweep objects. + bool SweepForbidden() const { return sweep_forbidden_; } + + bool in_atomic_pause() const { return in_atomic_pause_; } + + bool InAtomicMarkingPause() const { + return in_atomic_pause() && IsMarkingInProgress(); + } + bool InAtomicSweepingPause() const { + return in_atomic_pause() && IsSweepingInProgress(); + } + + bool IsIncrementalMarking() const { return incremental_marking_; } + void SetIncrementalMarking(bool value) { incremental_marking_ = value; } + + void SafePoint(BlinkGC::StackState); + + // A region of non-weak PersistentNodes allocated on the given thread. + PersistentRegion* GetPersistentRegion() const { + return persistent_region_.get(); + } + + // A region of PersistentNodes for WeakPersistents allocated on the given + // thread. + PersistentRegion* GetWeakPersistentRegion() const { + return weak_persistent_region_.get(); + } + + void RegisterStaticPersistentNode(PersistentNode*); + void ReleaseStaticPersistentNodes(); + void FreePersistentNode(PersistentRegion*, PersistentNode*); + + v8::Isolate* GetIsolate() const { return isolate_; } + + // Returns |true| if |object| resides on this thread's heap. + // It is well-defined to call this method on any heap allocated + // reference, provided its associated heap hasn't been detached + // and shut down. Its behavior is undefined for any other pointer + // value. + bool IsOnThreadHeap(const void* object) const { + return &FromObject(object)->Heap() == &Heap(); + } + + ALWAYS_INLINE bool IsOnStack(Address address) const { + return reinterpret_cast<Address>(start_of_stack_) >= address && + address >= (reinterpret_cast<Address>(reinterpret_cast<uintptr_t>( + WTF::GetCurrentStackPosition()))); + } + + int GcAge() const { return gc_age_; } + + MarkingVisitor* CurrentVisitor() const { + return current_gc_data_.visitor.get(); + } + + // Returns true if the marking verifier is enabled, false otherwise. + bool IsVerifyMarkingEnabled() const; + + void SkipIncrementalMarkingForTesting() { + skip_incremental_marking_for_testing_ = true; + } + + // Performs stand-alone garbage collections considering only C++ objects for + // testing. + // + // Since it only considers C++ objects this type of GC is mostly useful for + // unit tests. + void CollectGarbageForTesting(BlinkGC::CollectionType, + BlinkGC::StackState, + BlinkGC::MarkingType, + BlinkGC::SweepingType, + BlinkGC::GCReason); + + // Forced garbage collection for testing: + // - Performs unified heap garbage collections if ThreadState is attached to a + // v8::Isolate using ThreadState::AttachToIsolate. + // - Otherwise, performs stand-alone garbage collections. + // - Collects garbage as long as live memory decreases (capped at 5). + void CollectAllGarbageForTesting( + BlinkGC::StackState stack_state = + BlinkGC::StackState::kNoHeapPointersOnStack); + + // Enables compaction for next garbage collection. + void EnableCompactionForNextGCForTesting(); + + bool RequiresForcedGCForTesting() const { + return current_gc_data_.stack_state == + BlinkGC::StackState::kHeapPointersOnStack && + !forced_scheduled_gc_for_testing_; + } + + void EnterNoHeapVerificationScopeForTesting() { + ++disable_heap_verification_scope_; + } + void LeaveNoHeapVerificationScopeForTesting() { + --disable_heap_verification_scope_; + } + + private: + class IncrementalMarkingScheduler; + + // Stores whether some ThreadState is currently in incremental marking. + static AtomicEntryFlag incremental_marking_flag_; + + static WTF::ThreadSpecific<ThreadState*>* thread_specific_; + + // We can't create a static member of type ThreadState here because it will + // introduce global constructor and destructor. We would like to manage + // lifetime of the ThreadState attached to the main thread explicitly instead + // and still use normal constructor and destructor for the ThreadState class. + // For this we reserve static storage for the main ThreadState and lazily + // construct ThreadState in it using placement new. + static uint8_t main_thread_state_storage_[]; + + // Callback executed directly after pushing all callee-saved registers. + // |end_of_stack| denotes the end of the stack that can hold references to + // managed objects. + static void VisitStackAfterPushingRegisters(ThreadState*, + intptr_t* end_of_stack); + + static bool IsForcedGC(BlinkGC::GCReason reason) { + return reason == BlinkGC::GCReason::kThreadTerminationGC || + reason == BlinkGC::GCReason::kForcedGCForTesting || + reason == BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC; + } + + ThreadState(); + ~ThreadState(); + + void EnterNoAllocationScope() { no_allocation_count_++; } + void LeaveNoAllocationScope() { no_allocation_count_--; } + + void EnterAtomicPause() { + DCHECK(!in_atomic_pause_); + in_atomic_pause_ = true; + } + void LeaveAtomicPause() { + DCHECK(in_atomic_pause_); + in_atomic_pause_ = false; + } + + void EnterGCForbiddenScope() { gc_forbidden_count_++; } + void LeaveGCForbiddenScope() { + DCHECK_GT(gc_forbidden_count_, 0u); + gc_forbidden_count_--; + } + + void EnterStaticReferenceRegistrationDisabledScope(); + void LeaveStaticReferenceRegistrationDisabledScope(); + + // Performs stand-alone garbage collections considering only C++ objects. + // + // Use the public *ForTesting calls for calling GC in tests. + void CollectGarbage(BlinkGC::CollectionType, + BlinkGC::StackState, + BlinkGC::MarkingType, + BlinkGC::SweepingType, + BlinkGC::GCReason); + + // The following methods are used to compose RunAtomicPause. Public users + // should use the CollectGarbage entrypoint. Internal users should use these + // methods to compose a full garbage collection. + void AtomicPauseMarkPrologue(BlinkGC::CollectionType, + BlinkGC::StackState, + BlinkGC::MarkingType, + BlinkGC::GCReason); + void AtomicPauseMarkRoots(BlinkGC::StackState, + BlinkGC::MarkingType, + BlinkGC::GCReason); + void AtomicPauseMarkTransitiveClosure(); + void AtomicPauseMarkEpilogue(BlinkGC::MarkingType); + void AtomicPauseSweepAndCompact(BlinkGC::CollectionType, + BlinkGC::MarkingType marking_type, + BlinkGC::SweepingType sweeping_type); + void AtomicPauseEpilogue(); + + // RunAtomicPause composes the final atomic pause that finishes a mark-compact + // phase of a garbage collection. Depending on SweepingType it may also finish + // sweeping or schedule lazy/concurrent sweeping. + void RunAtomicPause(BlinkGC::CollectionType, + BlinkGC::StackState, + BlinkGC::MarkingType, + BlinkGC::SweepingType, + BlinkGC::GCReason); + + // The version is needed to be able to start incremental marking. + void MarkPhasePrologue(BlinkGC::CollectionType, + BlinkGC::StackState, + BlinkGC::MarkingType, + BlinkGC::GCReason); + void MarkPhaseEpilogue(BlinkGC::MarkingType); + void MarkPhaseVisitRoots(); + void MarkPhaseVisitNotFullyConstructedObjects(); + bool MarkPhaseAdvanceMarkingBasedOnSchedule(base::TimeDelta, + EphemeronProcessing); + bool MarkPhaseAdvanceMarking(base::TimeDelta, EphemeronProcessing); + void VerifyMarking(BlinkGC::MarkingType); + + // Visit the stack after pushing registers onto the stack. + void PushRegistersAndVisitStack(); + + // Visit local thread stack and trace all pointers conservatively. Never call + // directly but always call through |PushRegistersAndVisitStack|. + void VisitStackImpl(MarkingVisitor*, Address*, Address*); + void VisitStack(MarkingVisitor*, Address*); + void VisitUnsafeStack(MarkingVisitor*); + + // Visit the asan fake stack frame corresponding to a slot on the real machine + // stack if there is one. Never call directly but always call through + // |PushRegistersAndVisitStack|. + void VisitAsanFakeStackForPointer(MarkingVisitor*, + Address, + Address*, + Address*); + + // Visit all non-weak persistents allocated on this thread. + void VisitPersistents(Visitor*); + + // Visit all weak persistents allocated on this thread. + void VisitWeakPersistents(Visitor*); + + // Visit card tables (remembered sets) containing inter-generational pointers. + void VisitRememberedSets(MarkingVisitor*); + + // Incremental marking implementation functions. + void IncrementalMarkingStartForTesting(); + void IncrementalMarkingStart(BlinkGC::GCReason); + // Incremental marking step advance marking on the mutator thread. This method + // also reschedules concurrent marking tasks if needed. The duration parameter + // applies only to incremental marking steps on the mutator thread. + void IncrementalMarkingStep(BlinkGC::StackState); + void IncrementalMarkingFinalize(); + + // Returns true if concurrent marking is finished (i.e. all current threads + // terminated and the worklist is empty) + bool ConcurrentMarkingStep(); + void ScheduleConcurrentMarking(); + void PerformConcurrentMark(base::JobDelegate* job); + + // Schedule helpers. + void ScheduleIdleLazySweep(); + void ScheduleConcurrentAndLazySweep(); + + void NotifySweepDone(); + void PostSweep(); + + // See |DetachCurrentThread|. + void RunTerminationGC(); + + void RunScheduledGC(BlinkGC::StackState); + + void SynchronizeAndFinishConcurrentSweeping(); + + void InvokePreFinalizers(); + + // Adds the given observer to the ThreadState's observer list. This doesn't + // take ownership of the argument. The argument must not be null. The argument + // must not be registered before calling this. + void AddObserver(BlinkGCObserver*); + + // Removes the given observer from the ThreadState's observer list. This + // doesn't take ownership of the argument. The argument must not be null. + // The argument must be registered before calling this. + void RemoveObserver(BlinkGCObserver*); + + bool IsForcedGC() const { return IsForcedGC(current_gc_data_.reason); } + + // Returns whether stack scanning is forced. This is currently only used in + // platform tests where non nested tasks can be run with heap pointers on + // stack. + bool HeapPointersOnStackForced() const { + return heap_pointers_on_stack_forced_; + } + +#if defined(ADDRESS_SANITIZER) + // Poisons payload of unmarked objects. + // + // Also unpoisons memory areas for handles that may require resetting which + // can race with destructors. Note that cross-thread access still requires + // synchronization using a lock. + void PoisonUnmarkedObjects(); +#endif // ADDRESS_SANITIZER + + std::unique_ptr<ThreadHeap> heap_; + base::PlatformThreadId thread_; + std::unique_ptr<PersistentRegion> persistent_region_; + std::unique_ptr<PersistentRegion> weak_persistent_region_; + + // Start of the stack which is the boundary until conservative stack scanning + // needs to search for managed pointers. + Address* start_of_stack_; + + bool in_atomic_pause_ = false; + bool sweep_forbidden_ = false; + bool heap_pointers_on_stack_forced_ = false; + bool incremental_marking_ = false; + bool should_optimize_for_load_time_ = false; + bool forced_scheduled_gc_for_testing_ = false; + size_t no_allocation_count_ = 0; + size_t gc_forbidden_count_ = 0; + size_t static_persistent_registration_disabled_count_ = 0; + + GCState gc_state_ = GCState::kNoGCScheduled; + GCPhase gc_phase_ = GCPhase::kNone; + BlinkGC::GCReason reason_for_scheduled_gc_ = + BlinkGC::GCReason::kForcedGCForTesting; + + using PreFinalizerCallback = bool (*)(const LivenessBroker&, void*); + using PreFinalizer = std::pair<void*, PreFinalizerCallback>; + + // Pre-finalizers are called in the reverse order in which they are + // registered by the constructors (including constructors of Mixin objects) + // for an object, by processing the ordered_pre_finalizers_ back-to-front. + Deque<PreFinalizer> ordered_pre_finalizers_; + + v8::Isolate* isolate_ = nullptr; + V8BuildEmbedderGraphCallback v8_build_embedder_graph_ = nullptr; + std::unique_ptr<UnifiedHeapController> unified_heap_controller_; + +#if defined(ADDRESS_SANITIZER) + void* asan_fake_stack_; +#endif + + HashSet<BlinkGCObserver*> observers_; + + // PersistentNodes that are stored in static references; + // references that either have to be cleared upon the thread + // detaching from Oilpan and shutting down or references we + // have to clear before initiating LSan's leak detection. + HashSet<PersistentNode*> static_persistents_; + + int gc_age_ = 0; + + struct GCData { + BlinkGC::CollectionType collection_type; + BlinkGC::StackState stack_state; + BlinkGC::MarkingType marking_type; + BlinkGC::GCReason reason; + std::unique_ptr<MarkingVisitor> visitor; + }; + GCData current_gc_data_; + + std::unique_ptr<IncrementalMarkingScheduler> incremental_marking_scheduler_; + std::unique_ptr<MarkingSchedulingOracle> marking_scheduling_; + + base::JobHandle marker_handle_; + + base::JobHandle sweeper_handle_; + std::atomic_bool has_unswept_pages_{false}; + + size_t disable_heap_verification_scope_ = 0; + + bool skip_incremental_marking_for_testing_ = false; + + size_t last_concurrently_marked_bytes_ = 0; + base::TimeTicks last_concurrently_marked_bytes_update_; + bool concurrent_marking_priority_increased_ = false; + + friend class BlinkGCObserver; + friend class incremental_marking_test::IncrementalMarkingScope; + friend class IncrementalMarkingTestDriver; + friend class HeapAllocator; + template <typename T> + friend class PrefinalizerRegistration; + friend class TestGCScope; + friend class TestSupportingGC; + friend class ThreadStateSchedulingTest; + friend class UnifiedHeapController; + + DISALLOW_COPY_AND_ASSIGN(ThreadState); +}; + +template <> +class ThreadStateFor<kMainThreadOnly> { + STATIC_ONLY(ThreadStateFor); + + public: + static ThreadState* GetState() { + // This specialization must only be used from the main thread. + DCHECK(ThreadState::Current()->IsMainThread()); + return ThreadState::MainThreadState(); + } +}; + +template <> +class ThreadStateFor<kAnyThread> { + STATIC_ONLY(ThreadStateFor); + + public: + static ThreadState* GetState() { return ThreadState::Current(); } +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h new file mode 100644 index 00000000000..07e22c95cae --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h @@ -0,0 +1,128 @@ +// Copyright 2019 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_SCOPES_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_SCOPES_H_ + +#include "third_party/blink/renderer/platform/heap/thread_state.h" + +#if defined(LEAK_SANITIZER) +#include "third_party/blink/renderer/platform/wtf/leak_annotations.h" +#endif + +namespace blink { + +// The NoAllocationScope class is used in debug mode to catch unwanted +// allocations. E.g. allocations during GC. +class ThreadState::NoAllocationScope final { + STACK_ALLOCATED(); + DISALLOW_COPY_AND_ASSIGN(NoAllocationScope); + + public: + explicit NoAllocationScope(ThreadState* state) : state_(state) { + state_->EnterNoAllocationScope(); + } + ~NoAllocationScope() { state_->LeaveNoAllocationScope(); } + + private: + ThreadState* const state_; +}; + +class ThreadState::SweepForbiddenScope final { + STACK_ALLOCATED(); + DISALLOW_COPY_AND_ASSIGN(SweepForbiddenScope); + + public: + explicit SweepForbiddenScope(ThreadState* state) : state_(state) { + DCHECK(!state_->sweep_forbidden_); + state_->sweep_forbidden_ = true; + } + ~SweepForbiddenScope() { + DCHECK(state_->sweep_forbidden_); + state_->sweep_forbidden_ = false; + } + + private: + ThreadState* const state_; +}; + +class ThreadState::GCForbiddenScope final { + STACK_ALLOCATED(); + + public: + explicit GCForbiddenScope(ThreadState* thread_state) + : thread_state_(thread_state) { + thread_state_->EnterGCForbiddenScope(); + } + ~GCForbiddenScope() { thread_state_->LeaveGCForbiddenScope(); } + + private: + ThreadState* const thread_state_; +}; + +// Used to mark when we are in an atomic pause for GC. +class ThreadState::AtomicPauseScope final { + STACK_ALLOCATED(); + + public: + explicit AtomicPauseScope(ThreadState* thread_state) + : thread_state_(thread_state), gc_forbidden_scope(thread_state) { + thread_state_->EnterAtomicPause(); + } + ~AtomicPauseScope() { thread_state_->LeaveAtomicPause(); } + + private: + ThreadState* const thread_state_; + GCForbiddenScope gc_forbidden_scope; +}; + +class ThreadState::HeapPointersOnStackScope final { + STACK_ALLOCATED(); + + public: + explicit HeapPointersOnStackScope(ThreadState* state) : state_(state) { + DCHECK(!state_->heap_pointers_on_stack_forced_); + state_->heap_pointers_on_stack_forced_ = true; + } + ~HeapPointersOnStackScope() { + DCHECK(state_->heap_pointers_on_stack_forced_); + state_->heap_pointers_on_stack_forced_ = false; + } + + private: + ThreadState* const state_; +}; + +#if defined(LEAK_SANITIZER) +class ThreadState::LsanDisabledScope final { + STACK_ALLOCATED(); + DISALLOW_COPY_AND_ASSIGN(LsanDisabledScope); + + public: + explicit LsanDisabledScope(ThreadState* thread_state) + : thread_state_(thread_state) { + __lsan_disable(); + if (thread_state_) + thread_state_->EnterStaticReferenceRegistrationDisabledScope(); + } + + ~LsanDisabledScope() { + __lsan_enable(); + if (thread_state_) + thread_state_->LeaveStaticReferenceRegistrationDisabledScope(); + } + + private: + ThreadState* const thread_state_; +}; + +#define LEAK_SANITIZER_DISABLED_SCOPE \ + ThreadState::LsanDisabledScope lsan_disabled_scope(ThreadState::Current()) +#else +#define LEAK_SANITIZER_DISABLED_SCOPE +#endif + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_SCOPES_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/thread_state_statistics.cc b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.cc index 90a684cb1c7..d845f85de2e 100644 --- a/chromium/third_party/blink/renderer/platform/heap/thread_state_statistics.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/platform/heap/thread_state_statistics.h" +#include "third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h" #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h" diff --git a/chromium/third_party/blink/renderer/platform/heap/thread_state_statistics.h b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h index c2a3a6ff7b4..9eb1efa6d87 100644 --- a/chromium/third_party/blink/renderer/platform/heap/thread_state_statistics.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_STATISTICS_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_STATISTICS_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_STATISTICS_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_STATISTICS_H_ #include "third_party/blink/renderer/platform/heap/thread_state.h" @@ -64,4 +64,4 @@ class PLATFORM_EXPORT ThreadState::StatisticsCollector { } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_STATISTICS_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREAD_STATE_STATISTICS_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/threading_traits.h b/chromium/third_party/blink/renderer/platform/heap/impl/threading_traits.h index 95fa0c7e20a..bfae97b263b 100644 --- a/chromium/third_party/blink/renderer/platform/heap/threading_traits.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/threading_traits.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREADING_TRAITS_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREADING_TRAITS_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREADING_TRAITS_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREADING_TRAITS_H_ #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/deque.h" @@ -165,4 +165,4 @@ struct ThreadingTrait<HeapHashCountedSet<T, U, V>> } // namespace blink -#endif +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_THREADING_TRAITS_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/trace_traits.h b/chromium/third_party/blink/renderer/platform/heap/impl/trace_traits.h index 59c97feb72b..668da565219 100644 --- a/chromium/third_party/blink/renderer/platform/heap/trace_traits.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/trace_traits.h @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_TRACE_TRAITS_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_TRACE_TRAITS_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_TRACE_TRAITS_H_ #include "base/optional.h" -#include "third_party/blink/renderer/platform/heap/gc_info.h" #include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/heap/heap_page.h" +#include "third_party/blink/renderer/platform/heap/impl/gc_info.h" +#include "third_party/blink/renderer/platform/heap/impl/heap_page.h" #include "third_party/blink/renderer/platform/heap/visitor.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" @@ -280,31 +280,10 @@ struct TraceInCollectionTrait<kNoWeakHandling, T, Traits> { }; template <typename T, typename Traits> -struct TraceInCollectionTrait<kNoWeakHandling, blink::Member<T>, Traits> { - static bool IsAlive(const blink::LivenessBroker& info, - const blink::Member<T>& t) { - return true; - } - static void Trace(blink::Visitor* visitor, const blink::Member<T>& t) { - visitor->TraceMaybeDeleted(t); - } -}; - -template <typename T, typename Traits> -struct TraceInCollectionTrait<kWeakHandling, blink::Member<T>, Traits> { - static bool IsAlive(const blink::LivenessBroker& info, - const blink::Member<T>& t) { - return true; - } - static void Trace(blink::Visitor* visitor, const blink::Member<T>& t) { - visitor->TraceMaybeDeleted(t); - } -}; - -template <typename T, typename Traits> struct TraceInCollectionTrait<kNoWeakHandling, blink::WeakMember<T>, Traits> { static void Trace(blink::Visitor* visitor, const blink::WeakMember<T>& t) { - visitor->TraceMaybeDeleted(t); + // Extract raw pointer to avoid using the WeakMember<> overload in Visitor. + visitor->TraceStrongly(t); } }; @@ -399,4 +378,4 @@ struct TraceInCollectionTrait< } // namespace WTF -#endif +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_TRACE_TRAITS_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/unified_heap_controller.cc b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.cc index df02a2d90ec..43a4e292dbf 100644 --- a/chromium/third_party/blink/renderer/platform/heap/unified_heap_controller.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.cc @@ -12,7 +12,7 @@ #include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h" #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap_stats_collector.h" -#include "third_party/blink/renderer/platform/heap/marking_visitor.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h" #include "third_party/blink/renderer/platform/heap/thread_state.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.h b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.h new file mode 100644 index 00000000000..c42283ca6c3 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_controller.h @@ -0,0 +1,75 @@ +// Copyright 2018 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_CONTROLLER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_CONTROLLER_H_ + +#include "base/macros.h" +#include "third_party/blink/renderer/platform/heap/heap_stats_collector.h" +#include "third_party/blink/renderer/platform/platform_export.h" +#include "v8/include/v8.h" + +namespace blink { + +class ThreadState; + +// UnifiedHeapController ties V8's garbage collector to Oilpan for performing a +// garbage collection across both managed heaps. +// +// Unified heap garbage collections are triggered by V8 and mark the full +// transitive closure of V8 and Blink (Oilpan) objects. The garbage collection +// is initially triggered by V8. Both collecters report live references using +// the EmbedderHeapTracer APIs. V8 and Blink both run separate incremental +// marking steps to compute their live closures, respectively. The final atomic +// pause is then initiated by V8 and triggers a fixed-point computation between +// V8 and Blink where both GCs report live references to each other and drain +// their marking work lists until they are empty and no new references are +// found. +// +// Oilpan does not consider references from DOM wrappers (JavaScript objects on +// V8's heap) as roots for such garbage collections. +class PLATFORM_EXPORT UnifiedHeapController final + : public v8::EmbedderHeapTracer, + public ThreadHeapStatsObserver { + DISALLOW_IMPLICIT_CONSTRUCTORS(UnifiedHeapController); + + public: + explicit UnifiedHeapController(ThreadState*); + ~UnifiedHeapController() override; + + // v8::EmbedderHeapTracer implementation. + void TracePrologue(v8::EmbedderHeapTracer::TraceFlags) final; + void TraceEpilogue(v8::EmbedderHeapTracer::TraceSummary*) final; + void EnterFinalPause(EmbedderStackState) final; + void RegisterV8References(const std::vector<std::pair<void*, void*>>&) final; + bool AdvanceTracing(double) final; + bool IsTracingDone() final; + bool IsRootForNonTracingGC(const v8::TracedReference<v8::Value>&) final; + bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>&) final; + void ResetHandleInNonTracingGC(const v8::TracedReference<v8::Value>&) final; + + ThreadState* thread_state() const { return thread_state_; } + + // ThreadHeapStatsObserver implementation. + void IncreaseAllocatedObjectSize(size_t) final; + void DecreaseAllocatedObjectSize(size_t) final; + // Not needed. + void ResetAllocatedObjectSize(size_t) final {} + void IncreaseAllocatedSpace(size_t) final {} + void DecreaseAllocatedSpace(size_t) final {} + + private: + void ReportBufferedAllocatedSizeIfPossible(); + + ThreadState* const thread_state_; + // Returns whether the Blink heap has been fully processed. + bool is_tracing_done_ = false; + + // Buffered allocated size. Only positive values are forwarded to V8. + int64_t buffered_allocated_size_ = 0; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_CONTROLLER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.cc b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.cc index 00a9bc24826..00a9bc24826 100644 --- a/chromium/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.cc diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h new file mode 100644 index 00000000000..8d589b4e52b --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h @@ -0,0 +1,89 @@ +// Copyright 2018 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_MARKING_VISITOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_MARKING_VISITOR_H_ + +#include "base/macros.h" +#include "third_party/blink/renderer/platform/heap/impl/marking_visitor.h" + +namespace v8 { +class EmbedderHeapTracer; +} + +namespace blink { + +struct WrapperTypeInfo; + +// Marking visitor for unified heap garbage collections. Extends the regular +// Oilpan marking visitor by also providing write barriers and visitation +// methods that allow for announcing reachable objects to V8. Visitor can be +// used from any thread. +class PLATFORM_EXPORT UnifiedHeapMarkingVisitorBase { + public: + virtual ~UnifiedHeapMarkingVisitorBase() = default; + + protected: + UnifiedHeapMarkingVisitorBase(ThreadState*, v8::Isolate*, int); + + // Visitation methods that announce reachable wrappers to V8. + void VisitImpl(const TraceWrapperV8Reference<v8::Value>&); + + v8::Isolate* const isolate_; + v8::EmbedderHeapTracer* const controller_; + V8ReferencesWorklist::View v8_references_worklist_; + + private: + int task_id_; + + DISALLOW_COPY_AND_ASSIGN(UnifiedHeapMarkingVisitorBase); +}; + +// Same as the base visitor with the difference that it is bound to main thread. +// Also implements various sorts of write barriers that should only be called +// from the main thread. +class PLATFORM_EXPORT UnifiedHeapMarkingVisitor + : public MarkingVisitor, + public UnifiedHeapMarkingVisitorBase { + public: + // Write barriers for annotating a write during incremental marking. + static void WriteBarrier(const TraceWrapperV8Reference<v8::Value>&); + static void WriteBarrier(v8::Isolate*, const WrapperTypeInfo*, const void*); + + UnifiedHeapMarkingVisitor(ThreadState*, MarkingMode, v8::Isolate*); + ~UnifiedHeapMarkingVisitor() override = default; + + protected: + using Visitor::Visit; + void Visit(const TraceWrapperV8Reference<v8::Value>&) final; + + private: + DISALLOW_COPY_AND_ASSIGN(UnifiedHeapMarkingVisitor); +}; + +// Same as the base visitor with the difference that it is bound to a +// concurrent thread. +class PLATFORM_EXPORT ConcurrentUnifiedHeapMarkingVisitor + : public ConcurrentMarkingVisitor, + public UnifiedHeapMarkingVisitorBase { + public: + ConcurrentUnifiedHeapMarkingVisitor(ThreadState*, + MarkingMode, + v8::Isolate*, + int task_id); + ~ConcurrentUnifiedHeapMarkingVisitor() override = default; + + void FlushWorklists() override; + + protected: + using Visitor::Visit; + void Visit(const TraceWrapperV8Reference<v8::Value>&) final; + + private: + DISALLOW_COPY_AND_ASSIGN(ConcurrentUnifiedHeapMarkingVisitor); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNIFIED_HEAP_MARKING_VISITOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/unsanitized_atomic.cc b/chromium/third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.cc index c175fdb0a07..5bd25b96116 100644 --- a/chromium/third_party/blink/renderer/platform/heap/unsanitized_atomic.cc +++ b/chromium/third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "third_party/blink/renderer/platform/heap/unsanitized_atomic.h" +#include "third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.h" #include "cstdint" diff --git a/chromium/third_party/blink/renderer/platform/heap/unsanitized_atomic.h b/chromium/third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.h index 9242e9263a0..7c6828d9ee1 100644 --- a/chromium/third_party/blink/renderer/platform/heap/unsanitized_atomic.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/unsanitized_atomic.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNSANITIZED_ATOMIC_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNSANITIZED_ATOMIC_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNSANITIZED_ATOMIC_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNSANITIZED_ATOMIC_H_ #include <atomic> @@ -62,4 +62,4 @@ const auto* AsUnsanitizedAtomic(const T* ptr) { } // namespace internal } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNSANITIZED_ATOMIC_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_UNSANITIZED_ATOMIC_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/impl/visitor.h b/chromium/third_party/blink/renderer/platform/heap/impl/visitor.h new file mode 100644 index 00000000000..434bf882da7 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/impl/visitor.h @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_VISITOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_VISITOR_H_ + +#include <memory> +#include "third_party/blink/renderer/platform/heap/blink_gc.h" +#include "third_party/blink/renderer/platform/heap/garbage_collected.h" +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/assertions.h" +#include "third_party/blink/renderer/platform/wtf/forward.h" +#include "third_party/blink/renderer/platform/wtf/hash_traits.h" +#include "third_party/blink/renderer/platform/wtf/type_traits.h" + +namespace base { +class Location; +} + +namespace v8 { +class Value; +} + +namespace blink { + +class LivenessBroker; +template <typename T> +struct TraceTrait; +class ThreadState; +class Visitor; +template <typename T> +class TraceWrapperV8Reference; + +// The TraceMethodDelegate is used to convert a trace method for type T to a +// TraceCallback. This allows us to pass a type's trace method as a parameter +// to the PersistentNode constructor. The PersistentNode constructor needs the +// specific trace method due an issue with the Windows compiler which +// instantiates even unused variables. This causes problems +// in header files where we have only forward declarations of classes. +// +// This interface is safe to use on concurrent threads. All accesses (reads) +// from member are done atomically. +template <typename T, void (T::*method)(Visitor*) const> +struct TraceMethodDelegate { + STATIC_ONLY(TraceMethodDelegate); + static void Trampoline(Visitor* visitor, const void* self) { + (reinterpret_cast<const T*>(self)->*method)(visitor); + } +}; + +template <typename T, void (T::*method)(const LivenessBroker&)> +struct WeakCallbackMethodDelegate { + STATIC_ONLY(WeakCallbackMethodDelegate); + static void Trampoline(const LivenessBroker& info, const void* self) { + (reinterpret_cast<T*>(const_cast<void*>(self))->*method)(info); + } +}; + +// Visitor is used to traverse Oilpan's object graph. +class PLATFORM_EXPORT Visitor { + USING_FAST_MALLOC(Visitor); + + public: + explicit Visitor(ThreadState* state) : state_(state) {} + virtual ~Visitor() = default; + + inline ThreadState* State() const { return state_; } + inline ThreadHeap& Heap() const { return state_->Heap(); } + + // Static visitor implementation forwarding to dynamic interface. + + template <typename T> + void TraceRoot(const T* t, const base::Location& location) { + static_assert(sizeof(T), "T must be fully defined"); + static_assert(IsGarbageCollectedType<T>::value, + "T needs to be a garbage collected object"); + if (!t) + return; + VisitRoot(t, TraceDescriptorFor(t), location); + } + + template <typename T> + void Trace(const Member<T>& t) { + const T* value = t.GetSafe(); + + DCHECK(!Member<T>::IsMemberHashTableDeletedValue(value)); + + Trace(value); + } + + // TraceStrongly strongifies WeakMembers. + template <typename T> + ALWAYS_INLINE void TraceStrongly(const WeakMember<T>& t) { + const T* value = t.GetSafe(); + + DCHECK(!WeakMember<T>::IsMemberHashTableDeletedValue(value)); + + Trace<T>(value); + } + // Fallback methods used only when we need to trace raw pointers of T. This is + // the case when a member is a union where we do not support members. + template <typename T> + void Trace(T* t) { + Trace(const_cast<const T*>(t)); + } + template <typename T> + void Trace(const T* t) { + static_assert(sizeof(T), "T must be fully defined"); + static_assert(IsGarbageCollectedType<T>::value, + "T needs to be a garbage collected object"); + if (!t) + return; + Visit(t, TraceDescriptorFor(t)); + } + + // WeakMember version of the templated trace method. It doesn't keep + // the traced thing alive, but will write null to the WeakMember later + // if the pointed-to object is dead. It's lying for this to be const, + // but the overloading resolver prioritizes constness too high when + // picking the correct overload, so all these trace methods have to have + // the same constness on their argument to allow the type to decide. + template <typename T> + void Trace(const WeakMember<T>& weak_member) { + static_assert(sizeof(T), "T must be fully defined"); + static_assert(IsGarbageCollectedType<T>::value, + "T needs to be a garbage collected object"); + + const T* value = weak_member.GetSafe(); + + if (!value) + return; + + DCHECK(!WeakMember<T>::IsMemberHashTableDeletedValue(value)); + VisitWeak(value, &weak_member, TraceDescriptorFor(value), + &HandleWeakCell<T>); + } + + // Fallback trace method for part objects to allow individual trace methods + // to trace through a part object with visitor->trace(m_partObject). This + // takes a const argument, because otherwise it will match too eagerly: a + // non-const argument would match a non-const Vector<T>& argument better + // than the specialization that takes const Vector<T>&. For a similar reason, + // the other specializations take a const argument even though they are + // usually used with non-const arguments, otherwise this function would match + // too well. + template <typename T> + void Trace(const T& t) { + static_assert(sizeof(T), "T must be fully defined"); + if (std::is_polymorphic<T>::value) { + const intptr_t vtable = *reinterpret_cast<const intptr_t*>(&t); + if (!vtable) + return; + } + TraceTrait<T>::Trace(this, &t); + } + + template <typename T, typename U> + void TraceEphemeron(const WeakMember<T>& key, const U* value) { + const T* t = key.GetSafe(); + if (!t) + return; + VisitEphemeron(TraceDescriptorFor(t).base_object_payload, + TraceDescriptorFor(value)); + } + + template <typename T> + void TraceWeakContainer(const T* object, + const T* const* slot, + TraceDescriptor strong_desc, + TraceDescriptor weak_dec, + WeakCallback weak_callback, + const void* weak_callback_parameter) { + static_assert(sizeof(T), "T must be fully defined"); + static_assert(IsGarbageCollectedType<T>::value, + "T needs to be a garbage collected object"); + VisitWeakContainer(reinterpret_cast<const void*>(object), + reinterpret_cast<const void* const*>(slot), strong_desc, + weak_dec, weak_callback, weak_callback_parameter); + } + + template <typename T> + void TraceMovablePointer(const T* const* slot) { + RegisterMovableSlot(reinterpret_cast<const void* const*>(slot)); + } + + // Cross-component tracing interface. + template <typename V8Type> + void Trace(const TraceWrapperV8Reference<V8Type>& v8reference) { + Visit(v8reference.template Cast<v8::Value>()); + } + + // Dynamic visitor interface. + + // Adds a |callback| that is invoked with |parameter| after liveness has been + // computed on the whole object graph. The |callback| may use the provided + // |LivenessBroker| to determine whether an object is considered alive or + // dead. + // + // - Upon returning from the callback all references to dead objects must have + // been cleared. + // - Any operation that extends the object graph, including allocation + // or reviving objects, is prohibited. + // - Clearing out pointers is allowed. + // - Removing elements from heap collections is allowed as these collections + // are aware of custom weakness and won't resize their backings. + virtual void RegisterWeakCallback(WeakCallback callback, + const void* parameter) {} + + // Registers an instance method using |RegisterWeakCallback|. See description + // below. + template <typename T, void (T::*method)(const LivenessBroker&)> + void RegisterWeakCallbackMethod(const T* obj) { + RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>::Trampoline, + obj); + } + + // Returns whether the visitor is used in a concurrent setting. + virtual bool IsConcurrent() const { return false; } + + // Defers invoking |desc| to the main thread when running concurrently. + // Returns true if |desc| has been queued for later processing and false if + // running in a non-concurrent setting. + // + // This can be used to defer processing data structures to the main thread + // when support for concurrent processing is missing. + virtual bool DeferredTraceIfConcurrent(TraceDescriptor, size_t) { + return false; + } + + protected: + // Visits an object through a strong reference. + virtual void Visit(const void*, TraceDescriptor) {} + + // Visits an object through a weak reference. + virtual void VisitWeak(const void*, + const void*, + TraceDescriptor, + WeakCallback) {} + + // Visits cross-component references to V8. + virtual void Visit(const TraceWrapperV8Reference<v8::Value>&) {} + + virtual void VisitRoot(const void* t, + TraceDescriptor desc, + const base::Location&) { + Visit(t, desc); + } + + // Visits ephemeron pairs which are a combination of weak and strong keys and + // values. + virtual void VisitEphemeron(const void*, TraceDescriptor) {} + + // Visits a container |object| holding ephemeron pairs held from |slot|. The + // descriptor |strong_desc| can be used to enforce strong treatment of + // |object|. The |weak_desc| descriptor is invoked repeatedly until no + // more new objects are found. It is expected that |weak_desc| processing + // ultimately yields in a call to VisitEphemeron. After marking all reachable + // objects, |weak_callback| is invoked with |weak_callback_parameter|. It is + // expected that this callback is used to reset non-live entries in the + // ephemeron container. + virtual void VisitWeakContainer(const void* object, + const void* const* slot, + TraceDescriptor strong_desc, + TraceDescriptor weak_desc, + WeakCallback weak_callback, + const void* weak_callback_parameter) {} + + virtual void RegisterMovableSlot(const void* const* slot) {} + + template <typename T> + static TraceDescriptor TraceDescriptorFor(const T* traceable) { + return TraceTrait<T>::GetTraceDescriptor(traceable); + } + + private: + template <typename T> + static void HandleWeakCell(const LivenessBroker&, const void*); + + ThreadState* const state_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_VISITOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/worklist.h b/chromium/third_party/blink/renderer/platform/heap/impl/worklist.h index 6bce8f5808a..a26c61892f6 100644 --- a/chromium/third_party/blink/renderer/platform/heap/worklist.h +++ b/chromium/third_party/blink/renderer/platform/heap/impl/worklist.h @@ -8,8 +8,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WORKLIST_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WORKLIST_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_WORKLIST_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_WORKLIST_H_ #include <atomic> #include <cstddef> @@ -466,4 +466,4 @@ class Worklist { } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WORKLIST_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_IMPL_WORKLIST_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/member.h b/chromium/third_party/blink/renderer/platform/heap/member.h index 6567c77f010..4dbf5fd1c44 100644 --- a/chromium/third_party/blink/renderer/platform/heap/member.h +++ b/chromium/third_party/blink/renderer/platform/heap/member.h @@ -1,558 +1,16 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_ -#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -#include "third_party/blink/renderer/platform/heap/heap_page.h" -#include "third_party/blink/renderer/platform/heap/marking_visitor.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/hash_functions.h" -#include "third_party/blink/renderer/platform/wtf/hash_traits.h" -namespace WTF { -template <typename P, typename Traits, typename Allocator> -class MemberConstructTraits; -} // namespace WTF - -namespace blink { - -template <typename T> -class Persistent; - -enum class TracenessMemberConfiguration { - kTraced, - kUntraced, -}; - -template <typename T, - TracenessMemberConfiguration tracenessConfiguration = - TracenessMemberConfiguration::kTraced> -class MemberPointerVerifier { - public: - MemberPointerVerifier() = default; - - void SaveCreationThreadState(T* pointer) { - if (tracenessConfiguration == TracenessMemberConfiguration::kUntraced) { - creation_thread_state_ = nullptr; - } else { - creation_thread_state_ = ThreadState::Current(); - // Members should be created in an attached thread. But an empty - // value Member may be created on an unattached thread by a heap - // collection iterator. - DCHECK(creation_thread_state_ || !pointer); - } - } - - void CheckPointer(T* pointer) { - if (!pointer) - return; - - ThreadState* current = ThreadState::Current(); - DCHECK(current); - if (tracenessConfiguration != TracenessMemberConfiguration::kUntraced) { - // creation_thread_state_ may be null when this is used in a heap - // collection which initialized the Member with memset and the - // constructor wasn't called. - if (creation_thread_state_) { - // Member should point to objects that belong in the same ThreadHeap. - DCHECK(creation_thread_state_->IsOnThreadHeap(pointer)); - // Member should point to objects that belong in the same ThreadHeap. - DCHECK_EQ(¤t->Heap(), &creation_thread_state_->Heap()); - } else { - DCHECK(current->IsOnThreadHeap(pointer)); - } - } - - if (current->IsSweepingInProgress()) { - // During sweeping the object start bitmap is invalid. Check the header - // when the type is available and not pointing to a mixin. - if (IsFullyDefined<T>::value && !IsGarbageCollectedMixin<T>::value) - HeapObjectHeader::CheckFromPayload(pointer); - } else { - DCHECK(HeapObjectHeader::FromInnerAddress< - HeapObjectHeader::AccessMode::kAtomic>(pointer)); - } - } - - private: - const ThreadState* creation_thread_state_; -}; - -template <typename T, - TracenessMemberConfiguration tracenessConfiguration = - TracenessMemberConfiguration::kTraced> -class MemberBase { - DISALLOW_NEW(); - - public: - MemberBase() : raw_(nullptr) { SaveCreationThreadState(); } - - MemberBase(std::nullptr_t) : raw_(nullptr) { SaveCreationThreadState(); } - - explicit MemberBase(T* raw) : raw_(raw) { - SaveCreationThreadState(); - CheckPointer(); - // No write barrier for initializing stores. - } - - explicit MemberBase(T& raw) : raw_(&raw) { - SaveCreationThreadState(); - CheckPointer(); - // No write barrier for initializing stores. - } - - MemberBase(WTF::HashTableDeletedValueType) - : raw_(reinterpret_cast<T*>(kHashTableDeletedRawValue)) { - SaveCreationThreadState(); - } - - MemberBase(const MemberBase& other) : raw_(other) { - SaveCreationThreadState(); - CheckPointer(); - // No write barrier for initializing stores. - } - - template <typename U> - MemberBase(const Persistent<U>& other) : raw_(other) { - SaveCreationThreadState(); - CheckPointer(); - // No write barrier for initializing stores. - } - - template <typename U> - MemberBase(const MemberBase<U>& other) : raw_(other) { - SaveCreationThreadState(); - CheckPointer(); - // No write barrier for initializing stores. - } - - template <typename U> - MemberBase& operator=(const Persistent<U>& other) { - SetRaw(other); - CheckPointer(); - WriteBarrier(); - return *this; - } - - MemberBase& operator=(const MemberBase& other) { - SetRaw(other); - CheckPointer(); - WriteBarrier(); - return *this; - } - - template <typename U> - MemberBase& operator=(const MemberBase<U>& other) { - SetRaw(other); - CheckPointer(); - WriteBarrier(); - return *this; - } - - template <typename U> - MemberBase& operator=(U* other) { - SetRaw(other); - CheckPointer(); - WriteBarrier(); - return *this; - } - - MemberBase& operator=(WTF::HashTableDeletedValueType) { - SetRaw(reinterpret_cast<T*>(-1)); - return *this; - } - - MemberBase& operator=(std::nullptr_t) { - SetRaw(nullptr); - return *this; - } - - void Swap(MemberBase<T>& other) { - T* tmp = GetRaw(); - SetRaw(other.GetRaw()); - other.SetRaw(tmp); - CheckPointer(); - WriteBarrier(); - other.WriteBarrier(); - } - - explicit operator bool() const { return GetRaw(); } - operator T*() const { return GetRaw(); } - T* operator->() const { return GetRaw(); } - T& operator*() const { return *GetRaw(); } - - T* Get() const { return GetRaw(); } - - void Clear() { SetRaw(nullptr); } - - T* Release() { - T* result = GetRaw(); - SetRaw(nullptr); - return result; - } - - static bool IsMemberHashTableDeletedValue(const T* t) { - return t == reinterpret_cast<T*>(kHashTableDeletedRawValue); - } - - bool IsHashTableDeletedValue() const { - return IsMemberHashTableDeletedValue(GetRaw()); - } - - protected: - static constexpr intptr_t kHashTableDeletedRawValue = -1; - - enum class AtomicCtorTag { Atomic }; - - // MemberBase ctors that use atomic write to set raw_. - - MemberBase(AtomicCtorTag, T* raw) { - SetRaw(raw); - SaveCreationThreadState(); - CheckPointer(); - // No write barrier for initializing stores. - } - - MemberBase(AtomicCtorTag, T& raw) { - SetRaw(&raw); - SaveCreationThreadState(); - CheckPointer(); - // No write barrier for initializing stores. - } - - void WriteBarrier() const { - MarkingVisitor::WriteBarrier(const_cast<std::remove_const_t<T>**>(&raw_)); - } - - void CheckPointer() { -#if DCHECK_IS_ON() - // Should not be called for deleted hash table values. A value can be - // propagated here if a MemberBase containing the deleted value is copied. - if (IsHashTableDeletedValue()) - return; - pointer_verifier_.CheckPointer(GetRaw()); -#endif // DCHECK_IS_ON() - } - - void SaveCreationThreadState() { -#if DCHECK_IS_ON() - pointer_verifier_.SaveCreationThreadState(GetRaw()); -#endif // DCHECK_IS_ON() - } - - ALWAYS_INLINE void SetRaw(T* raw) { - if (tracenessConfiguration == TracenessMemberConfiguration::kUntraced) - raw_ = raw; - else - WTF::AsAtomicPtr(&raw_)->store(raw, std::memory_order_relaxed); - } - ALWAYS_INLINE T* GetRaw() const { return raw_; } - - private: - // Thread safe version of Get() for marking visitors. - // This is used to prevent data races between concurrent marking visitors - // and writes on the main thread. - const T* GetSafe() const { - // TOOD(omerkatz): replace this cast with std::atomic_ref (C++20) once it - // becomes available - return WTF::AsAtomicPtr(&raw_)->load(std::memory_order_relaxed); - } - - T* raw_; -#if DCHECK_IS_ON() - MemberPointerVerifier<T, tracenessConfiguration> pointer_verifier_; -#endif // DCHECK_IS_ON() - - friend class Visitor; -}; - -// Members are used in classes to contain strong pointers to other oilpan heap -// allocated objects. -// All Member fields of a class must be traced in the class' trace method. -// During the mark phase of the GC all live objects are marked as live and -// all Member fields of a live object will be traced marked as live as well. -template <typename T> -class Member : public MemberBase<T, TracenessMemberConfiguration::kTraced> { - DISALLOW_NEW(); - typedef MemberBase<T, TracenessMemberConfiguration::kTraced> Parent; - - public: - Member() : Parent() {} - Member(std::nullptr_t) : Parent(nullptr) {} - Member(T* raw) : Parent(raw) {} - Member(T& raw) : Parent(raw) {} - Member(WTF::HashTableDeletedValueType x) : Parent(x) {} - - Member(const Member& other) : Parent(other) {} - - template <typename U> - Member(const Member<U>& other) : Parent(other) { - } - - template <typename U> - Member(const Persistent<U>& other) : Parent(other) {} - - template <typename U> - Member& operator=(const Persistent<U>& other) { - Parent::operator=(other); - return *this; - } - - Member& operator=(const Member& other) { - Parent::operator=(other); - return *this; - } - - template <typename U> - Member& operator=(const Member<U>& other) { - Parent::operator=(other); - return *this; - } - - template <typename U> - Member& operator=(const WeakMember<U>& other) { - Parent::operator=(other); - return *this; - } - - template <typename U> - Member& operator=(U* other) { - Parent::operator=(other); - return *this; - } - - Member& operator=(WTF::HashTableDeletedValueType x) { - Parent::operator=(x); - return *this; - } - - Member& operator=(std::nullptr_t) { - Parent::operator=(nullptr); - return *this; - } - - private: - using typename Parent::AtomicCtorTag; - Member(AtomicCtorTag atomic, T* raw) : Parent(atomic, raw) {} - Member(AtomicCtorTag atomic, T& raw) : Parent(atomic, raw) {} - - template <typename P, typename Traits, typename Allocator> - friend class WTF::MemberConstructTraits; -}; - -// WeakMember is similar to Member in that it is used to point to other oilpan -// heap allocated objects. -// However instead of creating a strong pointer to the object, the WeakMember -// creates a weak pointer, which does not keep the pointee alive. Hence if all -// pointers to to a heap allocated object are weak the object will be garbage -// collected. At the time of GC the weak pointers will automatically be set to -// null. -template <typename T> -class WeakMember : public MemberBase<T, TracenessMemberConfiguration::kTraced> { - typedef MemberBase<T, TracenessMemberConfiguration::kTraced> Parent; - - public: - WeakMember() : Parent() {} - - WeakMember(std::nullptr_t) : Parent(nullptr) {} - - WeakMember(T* raw) : Parent(raw) {} - - WeakMember(WTF::HashTableDeletedValueType x) : Parent(x) {} - - template <typename U> - WeakMember(const Persistent<U>& other) : Parent(other) {} - - template <typename U> - WeakMember(const Member<U>& other) : Parent(other) {} - - template <typename U> - WeakMember& operator=(const Persistent<U>& other) { - Parent::operator=(other); - return *this; - } - - template <typename U> - WeakMember& operator=(const Member<U>& other) { - Parent::operator=(other); - return *this; - } - - template <typename U> - WeakMember& operator=(U* other) { - Parent::operator=(other); - return *this; - } - - WeakMember& operator=(std::nullptr_t) { - this->SetRaw(nullptr); - return *this; - } - - private: - using typename Parent::AtomicCtorTag; - WeakMember(AtomicCtorTag atomic, T* raw) : Parent(atomic, raw) {} - WeakMember(AtomicCtorTag atomic, T& raw) : Parent(atomic, raw) {} - - template <typename P, typename Traits, typename Allocator> - friend class WTF::MemberConstructTraits; -}; - -// UntracedMember is a pointer to an on-heap object that is not traced for some -// reason. Please don't use this unless you understand what you're doing. -// Basically, all pointers to on-heap objects must be stored in either of -// Persistent, Member or WeakMember. It is not allowed to leave raw pointers to -// on-heap objects. However, there can be scenarios where you have to use raw -// pointers for some reason, and in that case you can use UntracedMember. Of -// course, it must be guaranteed that the pointing on-heap object is kept alive -// while the raw pointer is pointing to the object. -template <typename T> -class UntracedMember final - : public MemberBase<T, TracenessMemberConfiguration::kUntraced> { - typedef MemberBase<T, TracenessMemberConfiguration::kUntraced> Parent; - - public: - UntracedMember() : Parent() {} - - UntracedMember(std::nullptr_t) : Parent(nullptr) {} - - UntracedMember(T* raw) : Parent(raw) {} - - template <typename U> - UntracedMember(const Persistent<U>& other) : Parent(other) {} - - template <typename U> - UntracedMember(const Member<U>& other) : Parent(other) {} - - UntracedMember(WTF::HashTableDeletedValueType x) : Parent(x) {} - - UntracedMember& operator=(const UntracedMember& other) { - this->SetRaw(other); - this->CheckPointer(); - return *this; - } - - template <typename U> - UntracedMember& operator=(const Persistent<U>& other) { - this->SetRaw(other); - this->CheckPointer(); - return *this; - } - - template <typename U> - UntracedMember& operator=(const Member<U>& other) { - this->SetRaw(other); - this->CheckPointer(); - return *this; - } - - template <typename U> - UntracedMember& operator=(U* other) { - this->SetRaw(other); - this->CheckPointer(); - return *this; - } - - UntracedMember& operator=(std::nullptr_t) { - this->SetRaw(nullptr); - return *this; - } -}; - -} // namespace blink - -namespace WTF { - -// PtrHash is the default hash for hash tables with Member<>-derived elements. -template <typename T> -struct MemberHash : PtrHash<T> { - STATIC_ONLY(MemberHash); - template <typename U> - static unsigned GetHash(const U& key) { - return PtrHash<T>::GetHash(key); - } - template <typename U, typename V> - static bool Equal(const U& a, const V& b) { - return a == b; - } -}; - -template <typename T> -struct DefaultHash<blink::Member<T>> { - STATIC_ONLY(DefaultHash); - using Hash = MemberHash<T>; -}; - -template <typename T> -struct DefaultHash<blink::WeakMember<T>> { - STATIC_ONLY(DefaultHash); - using Hash = MemberHash<T>; -}; - -template <typename T> -struct DefaultHash<blink::UntracedMember<T>> { - STATIC_ONLY(DefaultHash); - using Hash = MemberHash<T>; -}; - -template <typename T> -struct IsTraceable<blink::Member<T>> { - STATIC_ONLY(IsTraceable); - static const bool value = true; -}; - -template <typename T> -struct IsWeak<blink::WeakMember<T>> : std::true_type {}; - -template <typename T> -struct IsTraceable<blink::WeakMember<T>> { - STATIC_ONLY(IsTraceable); - static const bool value = true; -}; - -template <typename T, typename Traits, typename Allocator> -class MemberConstructTraits { - STATIC_ONLY(MemberConstructTraits); - - public: - template <typename... Args> - static T* Construct(void* location, Args&&... args) { - return new (NotNull, location) T(std::forward<Args>(args)...); - } - - static void NotifyNewElement(T* element) { element->WriteBarrier(); } - - template <typename... Args> - static T* ConstructAndNotifyElement(void* location, Args&&... args) { - // ConstructAndNotifyElement updates an existing Member which might - // also be comncurrently traced while we update it. The regular ctors - // for Member don't use an atomic write which can lead to data races. - T* object = Construct(location, T::AtomicCtorTag::Atomic, - std::forward<Args>(args)...); - NotifyNewElement(object); - return object; - } - - static void NotifyNewElements(T* array, size_t len) { - while (len-- > 0) { - array->WriteBarrier(); - array++; - } - } -}; - -template <typename T, typename Traits, typename Allocator> -class ConstructTraits<blink::Member<T>, Traits, Allocator> - : public MemberConstructTraits<blink::Member<T>, Traits, Allocator> {}; - -template <typename T, typename Traits, typename Allocator> -class ConstructTraits<blink::WeakMember<T>, Traits, Allocator> - : public MemberConstructTraits<blink::WeakMember<T>, Traits, Allocator> {}; - -} // namespace WTF +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/member.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/member.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MEMBER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/persistent.h b/chromium/third_party/blink/renderer/platform/heap/persistent.h index 32cadc008bf..77fd0d5cc7b 100644 --- a/chromium/third_party/blink/renderer/platform/heap/persistent.h +++ b/chromium/third_party/blink/renderer/platform/heap/persistent.h @@ -1,971 +1,16 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_H_ -#include "base/bind.h" -#include "base/location.h" -#include "third_party/blink/renderer/platform/bindings/buildflags.h" -#include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/heap/heap_allocator.h" -#include "third_party/blink/renderer/platform/heap/heap_compact.h" -#include "third_party/blink/renderer/platform/heap/member.h" -#include "third_party/blink/renderer/platform/heap/persistent_node.h" -#include "third_party/blink/renderer/platform/heap/visitor.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -namespace blink { - -template <typename T> -class CrossThreadWeakPersistent; - -// Wrapping type to force callers to go through macros that expand or drop -// base::Location. This is needed to avoid adding the strings when not needed. -// The type can be dropped once http://crbug.com/760702 is resolved and -// ENABLE_LOCATION_SOURCE is disabled for release builds. -class PersistentLocation final { - public: - PersistentLocation() = default; - explicit PersistentLocation(const base::Location& location) - : location_(location) {} - PersistentLocation(const PersistentLocation& other) = default; - - const base::Location& get() const { return location_; } - - private: - base::Location location_; -}; - -#if !BUILDFLAG(FROM_HERE_USES_LOCATION_BUILTINS) && \ - BUILDFLAG(RAW_HEAP_SNAPSHOTS) -#if !BUILDFLAG(ENABLE_LOCATION_SOURCE) -#define PERSISTENT_FROM_HERE \ - PersistentLocation(::base::Location::CreateFromHere(__FILE__)) -#else -#define PERSISTENT_FROM_HERE \ - PersistentLocation( \ - ::base::Location::CreateFromHere(__func__, __FILE__, __LINE__)) -#endif -#else -#define PERSISTENT_FROM_HERE PersistentLocation() -#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) - -template <typename T, - WeaknessPersistentConfiguration weaknessConfiguration, - CrossThreadnessPersistentConfiguration crossThreadnessConfiguration> -class PersistentBase { - USING_FAST_MALLOC(PersistentBase); - - public: - bool IsHashTableDeletedValue() const { - return raw_ == reinterpret_cast<T*>(-1); - } - - T* Release() { - T* result = raw_; - AssignSafe(nullptr); - return result; - } - - void Clear() { - // Note that this also frees up related data in the backend. - AssignSafe(nullptr); - } - - T* Get() const { - CheckPointer(); - return raw_; - } - - // TODO(https://crbug.com/653394): Consider returning a thread-safe best - // guess of validity. - bool MaybeValid() const { return true; } - - explicit operator bool() const { return Get(); } - T& operator*() const { return *Get(); } - operator T*() const { return Get(); } - T* operator->() const { return Get(); } - - // Register the persistent node as a 'static reference', - // belonging to the current thread and a persistent that must - // be cleared when the ThreadState itself is cleared out and - // destructed. - // - // Static singletons arrange for this to happen, either to ensure - // clean LSan leak reports or to register a thread-local persistent - // needing to be cleared out before the thread is terminated. - PersistentBase* RegisterAsStaticReference() { - static_assert(weaknessConfiguration == kNonWeakPersistentConfiguration, - "Can only register non-weak Persistent references as static " - "references."); - if (PersistentNode* node = persistent_node_.Get()) { - ThreadState::Current()->RegisterStaticPersistentNode(node); - LEAK_SANITIZER_IGNORE_OBJECT(this); - } - return this; - } - - NO_SANITIZE_ADDRESS - void ClearWithLockHeld() { - static_assert( - crossThreadnessConfiguration == kCrossThreadPersistentConfiguration, - "This Persistent does not require the cross-thread lock."); - PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired(); - raw_ = nullptr; - persistent_node_.ClearWithLockHeld(); - } - - void UpdateLocation(const PersistentLocation& other) { -#if BUILDFLAG(RAW_HEAP_SNAPSHOTS) - location_ = other; -#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) - } - - protected: - ~PersistentBase() { - UninitializeSafe(); - // Not resetting raw_ as it is not observable. - } - - PersistentBase() : raw_(nullptr) { - SaveCreationThreadHeap(); - // No initialization needed for empty handle. - } - PersistentBase(const PersistentLocation& location) : PersistentBase() { - UpdateLocation(location); - } - - PersistentBase(std::nullptr_t) : raw_(nullptr) { - SaveCreationThreadHeap(); - // No initialization needed for empty handle. - } - PersistentBase(const PersistentLocation& location, std::nullptr_t) - : PersistentBase(nullptr) { - UpdateLocation(location); - } - - PersistentBase(T* raw) : raw_(raw) { - SaveCreationThreadHeap(); - InitializeSafe(); - CheckPointer(); - } - PersistentBase(const PersistentLocation& location, T* raw) - : PersistentBase(raw) { - UpdateLocation(location); - } - - PersistentBase(T& raw) : raw_(&raw) { - SaveCreationThreadHeap(); - InitializeSafe(); - CheckPointer(); - } - PersistentBase(const PersistentLocation& location, T& raw) - : PersistentBase(raw) { - UpdateLocation(location); - } - - PersistentBase(const PersistentBase& other) : raw_(other) { - SaveCreationThreadHeap(); - InitializeSafe(); - CheckPointer(); - } - PersistentBase(const PersistentLocation& location, PersistentBase& other) - : PersistentBase(other) { - UpdateLocation(location); - } - - template <typename U> - PersistentBase(const PersistentBase<U, - weaknessConfiguration, - crossThreadnessConfiguration>& other) - : raw_(other) { - SaveCreationThreadHeap(); - InitializeSafe(); - CheckPointer(); - } - template <typename U> - PersistentBase(const PersistentLocation& location, - const PersistentBase<U, - weaknessConfiguration, - crossThreadnessConfiguration>& other) - : PersistentBase(other) { - UpdateLocation(location); - } - - template <typename U> - PersistentBase(const Member<U>& other) : raw_(other) { - SaveCreationThreadHeap(); - InitializeSafe(); - CheckPointer(); - } - template <typename U> - PersistentBase(const PersistentLocation& location, const Member<U>& other) - : PersistentBase(other) { - UpdateLocation(location); - } - - PersistentBase(WTF::HashTableDeletedValueType) - : raw_(reinterpret_cast<T*>(-1)) { - SaveCreationThreadHeap(); - // No initialization needed for empty handle. - } - PersistentBase(const PersistentLocation& location, - WTF::HashTableDeletedValueType) - : PersistentBase(WTF::kHashTableDeletedValue) { - UpdateLocation(location); - } - - template <typename U> - PersistentBase& operator=(U* other) { - AssignSafe(other); - return *this; - } - - PersistentBase& operator=(std::nullptr_t) { - AssignSafe(nullptr); - return *this; - } - - template <typename U> - PersistentBase& operator=(const Member<U>& other) { - AssignSafe(other); - return *this; - } - - // Using unsafe operations and assuming that caller acquires the lock for - // kCrossThreadPersistentConfiguration configuration. - PersistentBase& operator=(const PersistentBase& other) { - PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired(); - AssignUnsafe(other); - return *this; - } - - // Using unsafe operations and assuming that caller acquires the lock for - // kCrossThreadPersistentConfiguration configuration. - template <typename U> - PersistentBase& operator=( - const PersistentBase<U, - weaknessConfiguration, - crossThreadnessConfiguration>& other) { - PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired(); - AssignUnsafe(other); - return *this; - } - - // Using unsafe operations and assuming that caller acquires the lock for - // kCrossThreadPersistentConfiguration configuration. - template <typename U> - PersistentBase& operator=( - PersistentBase<U, weaknessConfiguration, crossThreadnessConfiguration>&& - other) { - PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired(); - if (persistent_node_.IsInitialized()) { - // Drop persistent node if present as it's always possible to reuse the - // node (if present) from |other|. - persistent_node_.Uninitialize(); - } - // Explicit cast enabling downcasting. - raw_ = static_cast<T*>(other.raw_); - other.raw_ = nullptr; - // Efficiently move by just rewiring the node pointer. - persistent_node_ = std::move(other.persistent_node_); - DCHECK(!other.persistent_node_.Get()); - if (persistent_node_.IsInitialized()) { - // If |raw_| points to a non-null or deleted value, just reuse the node. - TraceCallback trace_callback = - TraceMethodDelegate<PersistentBase, - &PersistentBase::TracePersistent>::Trampoline; - persistent_node_.Get()->Reinitialize(this, trace_callback); - } - CheckPointer(); - return *this; - } - - NO_SANITIZE_ADDRESS - bool IsNotNull() const { return raw_; } - - NO_SANITIZE_ADDRESS - void AssignSafe(T* ptr) { - typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock; - AssignUnsafe(ptr); - } - - NO_SANITIZE_ADDRESS - void AssignUnsafe(T* ptr) { - raw_ = ptr; - CheckPointer(); - if (raw_ && !IsHashTableDeletedValue()) { - if (!persistent_node_.IsInitialized()) - InitializeUnsafe(); - return; - } - UninitializeUnsafe(); - } - - void TracePersistent(Visitor* visitor) const { - static_assert(sizeof(T), "T must be fully defined"); - static_assert(IsGarbageCollectedType<T>::value, - "T needs to be a garbage collected object"); - DCHECK(!IsHashTableDeletedValue()); - if (weaknessConfiguration == kWeakPersistentConfiguration) { - visitor->RegisterWeakCallback(HandleWeakPersistent, this); - } else { -#if BUILDFLAG(RAW_HEAP_SNAPSHOTS) - visitor->TraceRoot(raw_, location_.get()); -#else - visitor->TraceRoot(raw_, base::Location()); -#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) - } - } - - NO_SANITIZE_ADDRESS - void InitializeSafe() { - DCHECK(!persistent_node_.IsInitialized()); - if (!raw_ || IsHashTableDeletedValue()) - return; - - TraceCallback trace_callback = - TraceMethodDelegate<PersistentBase, - &PersistentBase::TracePersistent>::Trampoline; - typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock; - persistent_node_.Initialize(this, trace_callback); - } - - NO_SANITIZE_ADDRESS - void InitializeUnsafe() { - DCHECK(!persistent_node_.IsInitialized()); - if (!raw_ || IsHashTableDeletedValue()) - return; - - TraceCallback trace_callback = - TraceMethodDelegate<PersistentBase, - &PersistentBase::TracePersistent>::Trampoline; - persistent_node_.Initialize(this, trace_callback); - } - - void UninitializeSafe() { - if (persistent_node_.IsInitialized()) { - typename PersistentMutexTraits<crossThreadnessConfiguration>::Locker lock; - persistent_node_.Uninitialize(); - } - } - - void UninitializeUnsafe() { - if (persistent_node_.IsInitialized()) - persistent_node_.Uninitialize(); - } - - void CheckPointer() const { -#if DCHECK_IS_ON() - if (!raw_ || IsHashTableDeletedValue()) - return; - - if (crossThreadnessConfiguration != kCrossThreadPersistentConfiguration) { - ThreadState* current = ThreadState::Current(); - DCHECK(current); - // m_creationThreadState may be null when this is used in a heap - // collection which initialized the Persistent with memset and the - // constructor wasn't called. - if (creation_thread_state_) { - // Member should point to objects that belong in the same ThreadHeap. - DCHECK_EQ(&ThreadState::FromObject(raw_)->Heap(), - &creation_thread_state_->Heap()); - // Member should point to objects that belong in the same ThreadHeap. - DCHECK_EQ(¤t->Heap(), &creation_thread_state_->Heap()); - } - } -#endif - } - - void SaveCreationThreadHeap() { -#if DCHECK_IS_ON() - if (crossThreadnessConfiguration == kCrossThreadPersistentConfiguration) { - creation_thread_state_ = nullptr; - } else { - creation_thread_state_ = ThreadState::Current(); - DCHECK(creation_thread_state_); - } -#endif - } - - static void HandleWeakPersistent(const LivenessBroker& broker, - const void* persistent_pointer) { - using Base = - PersistentBase<typename std::remove_const<T>::type, - weaknessConfiguration, crossThreadnessConfiguration>; - Base* persistent = - reinterpret_cast<Base*>(const_cast<void*>(persistent_pointer)); - T* object = persistent->Get(); - if (object && !broker.IsHeapObjectAlive(object)) - ClearWeakPersistent(persistent); - } - - static void ClearWeakPersistent( - PersistentBase<std::remove_const_t<T>, - kWeakPersistentConfiguration, - kCrossThreadPersistentConfiguration>* persistent) { - PersistentMutexTraits<crossThreadnessConfiguration>::AssertAcquired(); - persistent->ClearWithLockHeld(); - } - - static void ClearWeakPersistent( - PersistentBase<std::remove_const_t<T>, - kWeakPersistentConfiguration, - kSingleThreadPersistentConfiguration>* persistent) { - persistent->Clear(); - } - - template <typename BadPersistent> - static void ClearWeakPersistent(BadPersistent* non_weak_persistent) { - NOTREACHED(); - } - - // raw_ is accessed most, so put it at the first field. - T* raw_; - - // The pointer to the underlying persistent node. - // - // Since accesses are atomics in the cross-thread case, a different type is - // needed to prevent the compiler producing an error when it encounters - // operations that are legal on raw pointers but not on atomics, or - // vice-versa. - std::conditional_t< - crossThreadnessConfiguration == kCrossThreadPersistentConfiguration, - CrossThreadPersistentNodePtr<weaknessConfiguration>, - PersistentNodePtr<ThreadingTrait<T>::kAffinity, weaknessConfiguration>> - persistent_node_; - -#if BUILDFLAG(RAW_HEAP_SNAPSHOTS) - PersistentLocation location_; -#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) - -#if DCHECK_IS_ON() - const ThreadState* creation_thread_state_; -#endif - - template <typename F, - WeaknessPersistentConfiguration, - CrossThreadnessPersistentConfiguration> - friend class PersistentBase; -}; - -// Persistent is a way to create a strong pointer from an off-heap object -// to another on-heap object. As long as the Persistent handle is alive -// the GC will keep the object pointed to alive. The Persistent handle is -// always a GC root from the point of view of the GC. -// -// We have to construct and destruct Persistent in the same thread. -template <typename T> -class Persistent : public PersistentBase<T, - kNonWeakPersistentConfiguration, - kSingleThreadPersistentConfiguration> { - using Parent = PersistentBase<T, - kNonWeakPersistentConfiguration, - kSingleThreadPersistentConfiguration>; - - public: - Persistent() : Parent() {} - Persistent(const PersistentLocation& location) : Parent(location) {} - Persistent(std::nullptr_t) : Parent(nullptr) {} - Persistent(const PersistentLocation& location, std::nullptr_t) - : Parent(location, nullptr) {} - Persistent(T* raw) : Parent(raw) {} - Persistent(const PersistentLocation& location, T* raw) - : Parent(location, raw) {} - Persistent(T& raw) : Parent(raw) {} - Persistent(const PersistentLocation& location, T& raw) - : Parent(location, raw) {} - Persistent(const Persistent& other) : Parent(other) {} - Persistent(const PersistentLocation& location, const Persistent& other) - : Parent(location, other) {} - template <typename U> - Persistent(const Persistent<U>& other) : Parent(other) {} - template <typename U> - Persistent(const PersistentLocation& location, const Persistent<U>& other) - : Parent(location, other) {} - template <typename U> - Persistent(const Member<U>& other) : Parent(other) {} - template <typename U> - Persistent(const PersistentLocation& location, const Member<U>& other) - : Parent(location, other) {} - Persistent(WTF::HashTableDeletedValueType x) : Parent(x) {} - Persistent(const PersistentLocation& location, - WTF::HashTableDeletedValueType x) - : Parent(location, x) {} - - template <typename U> - Persistent& operator=(U* other) { - Parent::operator=(other); - return *this; - } - - Persistent& operator=(std::nullptr_t) { - Parent::operator=(nullptr); - return *this; - } - - Persistent& operator=(const Persistent& other) { - Parent::operator=(other); - return *this; - } - - template <typename U> - Persistent& operator=(const Persistent<U>& other) { - Parent::operator=(other); - return *this; - } - - template <typename U> - Persistent& operator=(const Member<U>& other) { - Parent::operator=(other); - return *this; - } -}; - -// WeakPersistent is a way to create a weak pointer from an off-heap object -// to an on-heap object. The m_raw is automatically cleared when the pointee -// gets collected. -// -// We have to construct and destruct WeakPersistent in the same thread. -// -// Note that collections of WeakPersistents are not supported. Use a collection -// of WeakMembers instead. -// -// HashSet<WeakPersistent<T>> m_set; // wrong -// Persistent<HeapHashSet<WeakMember<T>>> m_set; // correct -template <typename T> -class WeakPersistent - : public PersistentBase<T, - kWeakPersistentConfiguration, - kSingleThreadPersistentConfiguration> { - using Parent = PersistentBase<T, - kWeakPersistentConfiguration, - kSingleThreadPersistentConfiguration>; - - public: - WeakPersistent() : Parent() {} - WeakPersistent(std::nullptr_t) : Parent(nullptr) {} - WeakPersistent(T* raw) : Parent(raw) {} - WeakPersistent(T& raw) : Parent(raw) {} - WeakPersistent(const WeakPersistent& other) : Parent(other) {} - template <typename U> - WeakPersistent(const WeakPersistent<U>& other) : Parent(other) {} - template <typename U> - WeakPersistent(const Member<U>& other) : Parent(other) {} - - template <typename U> - WeakPersistent& operator=(U* other) { - Parent::operator=(other); - return *this; - } - - WeakPersistent& operator=(std::nullptr_t) { - Parent::operator=(nullptr); - return *this; - } - - WeakPersistent& operator=(const WeakPersistent& other) { - Parent::operator=(other); - return *this; - } - - template <typename U> - WeakPersistent& operator=(const WeakPersistent<U>& other) { - Parent::operator=(other); - return *this; - } - - template <typename U> - WeakPersistent& operator=(const Member<U>& other) { - Parent::operator=(other); - return *this; - } - - NO_SANITIZE_ADDRESS - bool IsClearedUnsafe() const { return this->IsNotNull(); } -}; - -// CrossThreadPersistent allows for holding onto an object strongly on a -// different thread. -// -// Thread-safe operations: -// - Construction -// - Destruction -// - Copy and move construction and assignment -// - Clearing -// - Deref if treated as immutable reference or if externally synchronized (e.g. -// mutex, task). The current implementation of Get() uses a raw load (on -// purpose) which prohibits mutation while accessing the reference on a -// different thread. -template <typename T> -class CrossThreadPersistent - : public PersistentBase<T, - kNonWeakPersistentConfiguration, - kCrossThreadPersistentConfiguration> { - using Parent = PersistentBase<T, - kNonWeakPersistentConfiguration, - kCrossThreadPersistentConfiguration>; - - public: - CrossThreadPersistent() : Parent() {} - CrossThreadPersistent(const PersistentLocation& location) - : Parent(location) {} - CrossThreadPersistent(std::nullptr_t) : Parent(nullptr) {} - CrossThreadPersistent(const PersistentLocation& location, std::nullptr_t) - : Parent(location, nullptr) {} - explicit CrossThreadPersistent(T* raw) : Parent(raw) {} - CrossThreadPersistent(const PersistentLocation& location, T* raw) - : Parent(location, raw) {} - explicit CrossThreadPersistent(T& raw) : Parent(raw) {} - CrossThreadPersistent(const PersistentLocation& location, T& raw) - : Parent(location, raw) {} - CrossThreadPersistent(const CrossThreadPersistent& other) { *this = other; } - CrossThreadPersistent(const PersistentLocation& location, - const CrossThreadPersistent& other) { - *this = other; - } - template <typename U> - CrossThreadPersistent(const CrossThreadPersistent<U>& other) { - *this = other; - } - template <typename U> - CrossThreadPersistent(const PersistentLocation& location, - const CrossThreadPersistent<U>& other) { - *this = other; - } - template <typename U> - CrossThreadPersistent(const Member<U>& other) : Parent(other) {} - template <typename U> - CrossThreadPersistent(const PersistentLocation& location, - const Member<U>& other) - : Parent(location, other) {} - CrossThreadPersistent(WTF::HashTableDeletedValueType x) : Parent(x) {} - CrossThreadPersistent(const PersistentLocation& location, - WTF::HashTableDeletedValueType x) - : Parent(location, x) {} - template <typename U> - CrossThreadPersistent(const CrossThreadWeakPersistent<U>& other) { - *this = other; - } - - // Instead of using release(), assign then clear() instead. - // Using release() with per thread heap enabled can cause the object to be - // destroyed before assigning it to a new handle. - T* Release() = delete; - - template <typename U> - CrossThreadPersistent& operator=(U* other) { - Parent::operator=(other); - return *this; - } - - CrossThreadPersistent& operator=(std::nullptr_t) { - Parent::operator=(nullptr); - return *this; - } - - CrossThreadPersistent& operator=(const CrossThreadPersistent& other) { - MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); - Parent::operator=(other); - return *this; - } - - template <typename U> - CrossThreadPersistent& operator=(const CrossThreadPersistent<U>& other) { - MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); - Parent::operator=(other); - return *this; - } - - template <typename U> - CrossThreadPersistent& operator=(const CrossThreadWeakPersistent<U>&); -}; - -// CrossThreadWeakPersistent combines behavior of CrossThreadPersistent and -// WeakPersistent, i.e., it allows holding onto an object weakly on a different -// thread. -// -// Thread-safe operations: -// - Construction -// - Destruction -// - Copy and move construction and assignment -// - Clearing -// -// Note that this does not include dereferencing and using the raw pointer as -// there is no guarantee that the object will be alive at the time it is used. -template <typename T> -class CrossThreadWeakPersistent - : public PersistentBase<T, - kWeakPersistentConfiguration, - kCrossThreadPersistentConfiguration> { - using Parent = PersistentBase<T, - kWeakPersistentConfiguration, - kCrossThreadPersistentConfiguration>; - - public: - CrossThreadWeakPersistent() : Parent() {} - explicit CrossThreadWeakPersistent(T* raw) : Parent(raw) {} - explicit CrossThreadWeakPersistent(T& raw) : Parent(raw) {} - CrossThreadWeakPersistent(const CrossThreadWeakPersistent& other) { - *this = other; - } - template <typename U> - CrossThreadWeakPersistent(const CrossThreadWeakPersistent<U>& other) { - *this = other; - } - CrossThreadWeakPersistent(CrossThreadWeakPersistent&& other) { - *this = std::move(other); - } - template <typename U> - CrossThreadWeakPersistent(CrossThreadWeakPersistent<U>&& other) { - *this = std::move(other); - } - - CrossThreadWeakPersistent& operator=(const CrossThreadWeakPersistent& other) { - MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); - Parent::operator=(other); - return *this; - } - - template <typename U> - CrossThreadWeakPersistent& operator=( - const CrossThreadWeakPersistent<U>& other) { - MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); - Parent::operator=(other); - return *this; - } - - CrossThreadWeakPersistent& operator=(CrossThreadWeakPersistent&& other) { - MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); - Parent::operator=(std::move(other)); - return *this; - } - - template <typename U> - CrossThreadWeakPersistent& operator=(CrossThreadWeakPersistent<U>&& other) { - MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); - Parent::operator=(std::move(other)); - return *this; - } - - template <typename U> - CrossThreadWeakPersistent& operator=(U* other) { - Parent::operator=(other); - return *this; - } - - // Create a CrossThreadPersistent that keeps the underlying object alive if - // there is still on set. Can be used to work with an object on a different - // thread than it was allocated. Note that CTP does not block threads from - // terminating, in which case the reference would still be invalid. - const CrossThreadPersistent<T> Lock() const { - return CrossThreadPersistent<T>(*this); - } - - // Disallow directly using CrossThreadWeakPersistent. Users must go through - // CrossThreadPersistent to access the pointee. Note that this does not - // guarantee that the object is still alive at that point. Users must check - // the state of CTP manually before invoking any calls. - T* operator->() const = delete; - T& operator*() const = delete; - operator T*() const = delete; - T* Get() const = delete; - - private: - template <typename U> - friend class CrossThreadPersistent; -}; - -template <typename T> -template <typename U> -CrossThreadPersistent<T>& CrossThreadPersistent<T>::operator=( - const CrossThreadWeakPersistent<U>& other) { - MutexLocker locker(ProcessHeap::CrossThreadPersistentMutex()); - using ParentU = PersistentBase<U, kWeakPersistentConfiguration, - kCrossThreadPersistentConfiguration>; - this->AssignUnsafe(static_cast<const ParentU&>(other).Get()); - return *this; -} - -template <typename T> -Persistent<T> WrapPersistentInternal(const PersistentLocation& location, - T* value) { - return Persistent<T>(location, value); -} - -template <typename T> -Persistent<T> WrapPersistentInternal(T* value) { - return Persistent<T>(value); -} - -#if BUILDFLAG(RAW_HEAP_SNAPSHOTS) -#define WrapPersistent(value) \ - WrapPersistentInternal(PERSISTENT_FROM_HERE, value) -#else -#define WrapPersistent(value) WrapPersistentInternal(value) -#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) - -template <typename T, - typename = std::enable_if_t<WTF::IsGarbageCollectedType<T>::value>> -Persistent<T> WrapPersistentIfNeeded(T* value) { - return Persistent<T>(value); -} - -template <typename T> -T& WrapPersistentIfNeeded(T& value) { - return value; -} - -template <typename T> -WeakPersistent<T> WrapWeakPersistent(T* value) { - return WeakPersistent<T>(value); -} - -template <typename T> -CrossThreadPersistent<T> WrapCrossThreadPersistentInternal( - const PersistentLocation& location, - T* value) { - return CrossThreadPersistent<T>(location, value); -} - -template <typename T> -CrossThreadPersistent<T> WrapCrossThreadPersistentInternal(T* value) { - return CrossThreadPersistent<T>(value); -} - -#if BUILDFLAG(RAW_HEAP_SNAPSHOTS) -#define WrapCrossThreadPersistent(value) \ - WrapCrossThreadPersistentInternal(PERSISTENT_FROM_HERE, value) -#else -#define WrapCrossThreadPersistent(value) \ - WrapCrossThreadPersistentInternal(value) -#endif // BUILDFLAG(RAW_HEAP_SNAPSHOTS) - -template <typename T> -CrossThreadWeakPersistent<T> WrapCrossThreadWeakPersistent(T* value) { - return CrossThreadWeakPersistent<T>(value); -} - -// Comparison operators between (Weak)Members, Persistents, and UntracedMembers. -template <typename T, typename U> -inline bool operator==(const Member<T>& a, const Member<U>& b) { - return a.Get() == b.Get(); -} -template <typename T, typename U> -inline bool operator!=(const Member<T>& a, const Member<U>& b) { - return a.Get() != b.Get(); -} -template <typename T, typename U> -inline bool operator==(const Persistent<T>& a, const Persistent<U>& b) { - return a.Get() == b.Get(); -} -template <typename T, typename U> -inline bool operator!=(const Persistent<T>& a, const Persistent<U>& b) { - return a.Get() != b.Get(); -} - -template <typename T, typename U> -inline bool operator==(const Member<T>& a, const Persistent<U>& b) { - return a.Get() == b.Get(); -} -template <typename T, typename U> -inline bool operator!=(const Member<T>& a, const Persistent<U>& b) { - return a.Get() != b.Get(); -} -template <typename T, typename U> -inline bool operator==(const Persistent<T>& a, const Member<U>& b) { - return a.Get() == b.Get(); -} -template <typename T, typename U> -inline bool operator!=(const Persistent<T>& a, const Member<U>& b) { - return a.Get() != b.Get(); -} - -} // namespace blink - -namespace WTF { - -template < - typename T, - blink::WeaknessPersistentConfiguration weaknessConfiguration, - blink::CrossThreadnessPersistentConfiguration crossThreadnessConfiguration> -struct VectorTraits<blink::PersistentBase<T, - weaknessConfiguration, - crossThreadnessConfiguration>> - : VectorTraitsBase<blink::PersistentBase<T, - weaknessConfiguration, - crossThreadnessConfiguration>> { - STATIC_ONLY(VectorTraits); - static const bool kNeedsDestruction = true; - static const bool kCanInitializeWithMemset = true; - static const bool kCanClearUnusedSlotsWithMemset = false; - static const bool kCanMoveWithMemcpy = true; -}; - -template <typename T> -struct HashTraits<blink::Persistent<T>> - : HandleHashTraits<T, blink::Persistent<T>> {}; - -template <typename T> -struct HashTraits<blink::CrossThreadPersistent<T>> - : HandleHashTraits<T, blink::CrossThreadPersistent<T>> {}; - -template <typename T> -struct DefaultHash<blink::Persistent<T>> { - STATIC_ONLY(DefaultHash); - using Hash = MemberHash<T>; -}; - -template <typename T> -struct DefaultHash<blink::WeakPersistent<T>> { - STATIC_ONLY(DefaultHash); - using Hash = MemberHash<T>; -}; - -template <typename T> -struct DefaultHash<blink::CrossThreadPersistent<T>> { - STATIC_ONLY(DefaultHash); - using Hash = MemberHash<T>; -}; - -template <typename T> -struct DefaultHash<blink::CrossThreadWeakPersistent<T>> { - STATIC_ONLY(DefaultHash); - using Hash = MemberHash<T>; -}; - -template <typename T> -struct CrossThreadCopier<blink::CrossThreadPersistent<T>> - : public CrossThreadCopierPassThrough<blink::CrossThreadPersistent<T>> { - STATIC_ONLY(CrossThreadCopier); -}; - -template <typename T> -struct CrossThreadCopier<blink::CrossThreadWeakPersistent<T>> - : public CrossThreadCopierPassThrough<blink::CrossThreadWeakPersistent<T>> { - STATIC_ONLY(CrossThreadCopier); -}; - -} // namespace WTF - -namespace base { - -template <typename T> -struct IsWeakReceiver<blink::WeakPersistent<T>> : std::true_type {}; - -template <typename T> -struct IsWeakReceiver<blink::CrossThreadWeakPersistent<T>> : std::true_type {}; - -template <typename T> -struct BindUnwrapTraits<blink::CrossThreadWeakPersistent<T>> { - static blink::CrossThreadPersistent<T> Unwrap( - const blink::CrossThreadWeakPersistent<T>& wrapped) { - return blink::CrossThreadPersistent<T>(wrapped); - } -}; -} +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/persistent.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PERSISTENT_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/process_heap.h b/chromium/third_party/blink/renderer/platform/heap/process_heap.h index 8217afd230d..5f8d21f5c5d 100644 --- a/chromium/third_party/blink/renderer/platform/heap/process_heap.h +++ b/chromium/third_party/blink/renderer/platform/heap/process_heap.h @@ -1,69 +1,16 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_ -#include <atomic> -#include "third_party/blink/renderer/platform/platform_export.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/threading_primitives.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -namespace blink { +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/process_heap.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN -class CrossThreadPersistentRegion; - -class PLATFORM_EXPORT ProcessHeap { - STATIC_ONLY(ProcessHeap); - - public: - static void Init(); - - static CrossThreadPersistentRegion& GetCrossThreadPersistentRegion(); - static CrossThreadPersistentRegion& GetCrossThreadWeakPersistentRegion(); - - // Access to the CrossThreadPersistentRegion from multiple threads has to be - // prevented as allocation, freeing, and iteration of nodes may otherwise - // cause data races. - // - // Examples include: - // - Iteration of strong cross-thread Persistents. - // - Iteration and processing of weak cross-thread Persistents. The lock - // needs to span both operations as iteration of weak persistents only - // registers memory regions that are then processed afterwards. - // - Marking phase in garbage collection: The whole phase requires locking - // as CrossThreadWeakPersistents may be converted to CrossThreadPersistent - // which must observe GC as an atomic operation. - static Mutex& CrossThreadPersistentMutex(); - - static void IncreaseTotalAllocatedObjectSize(size_t delta) { - total_allocated_object_size_.fetch_add(delta, std::memory_order_relaxed); - } - static void DecreaseTotalAllocatedObjectSize(size_t delta) { - total_allocated_object_size_.fetch_sub(delta, std::memory_order_relaxed); - } - static size_t TotalAllocatedObjectSize() { - return total_allocated_object_size_.load(std::memory_order_relaxed); - } - static void IncreaseTotalAllocatedSpace(size_t delta) { - total_allocated_space_.fetch_add(delta, std::memory_order_relaxed); - } - static void DecreaseTotalAllocatedSpace(size_t delta) { - total_allocated_space_.fetch_sub(delta, std::memory_order_relaxed); - } - static size_t TotalAllocatedSpace() { - return total_allocated_space_.load(std::memory_order_relaxed); - } - static void ResetHeapCounters(); - - private: - static std::atomic_size_t total_allocated_space_; - static std::atomic_size_t total_allocated_object_size_; - - friend class ThreadState; -}; - -} // namespace blink - -#endif +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_PROCESS_HEAP_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/thread_state.h b/chromium/third_party/blink/renderer/platform/heap/thread_state.h index 41499ec2c46..050bac6b39b 100644 --- a/chromium/third_party/blink/renderer/platform/heap/thread_state.h +++ b/chromium/third_party/blink/renderer/platform/heap/thread_state.h @@ -1,717 +1,16 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_ -#include <atomic> -#include <memory> +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -#include "base/macros.h" -#include "base/synchronization/lock.h" -#include "base/task/post_job.h" -#include "third_party/blink/renderer/platform/heap/atomic_entry_flag.h" -#include "third_party/blink/renderer/platform/heap/blink_gc.h" -#include "third_party/blink/renderer/platform/heap/threading_traits.h" -#include "third_party/blink/renderer/platform/platform_export.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/forward.h" -#include "third_party/blink/renderer/platform/wtf/hash_map.h" -#include "third_party/blink/renderer/platform/wtf/hash_set.h" -#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h" -#include "third_party/blink/renderer/platform/wtf/sanitizers.h" -#include "third_party/blink/renderer/platform/wtf/thread_specific.h" -#include "third_party/blink/renderer/platform/wtf/threading.h" -#include "third_party/blink/renderer/platform/wtf/threading_primitives.h" -#include "third_party/blink/renderer/platform/wtf/vector.h" - -namespace v8 { -class EmbedderGraph; -class Isolate; -} // namespace v8 - -namespace blink { - -namespace incremental_marking_test { -class IncrementalMarkingScope; -} // namespace incremental_marking_test - -class MarkingVisitor; -class MarkingSchedulingOracle; -class PersistentNode; -class PersistentRegion; -class ThreadHeap; -class ThreadState; -template <ThreadAffinity affinity> -class ThreadStateFor; -class UnifiedHeapController; -class Visitor; - -// Declare that a class has a pre-finalizer which gets invoked before objects -// get swept. It is thus safe to touch on-heap objects that may be collected in -// the same GC cycle. This is useful when it's not possible to avoid touching -// on-heap objects in a destructor which is forbidden. -// -// Note that: -// (a) Pre-finalizers *must* not resurrect dead objects. -// (b) Run on the same thread they are registered. -// (c) Decrease GC performance which means that they should only be used if -// absolute necessary. -// -// Usage: -// class Foo : GarbageCollected<Foo> { -// USING_PRE_FINALIZER(Foo, Dispose); -// private: -// void Dispose() { -// bar_->...; // It is safe to touch other on-heap objects. -// } -// Member<Bar> bar_; -// }; -#define USING_PRE_FINALIZER(Class, PreFinalizer) \ - public: \ - static bool InvokePreFinalizer(const LivenessBroker& info, void* object) { \ - Class* self = reinterpret_cast<Class*>(object); \ - if (info.IsHeapObjectAlive(self)) \ - return false; \ - self->Class::PreFinalizer(); \ - return true; \ - } \ - \ - private: \ - ThreadState::PrefinalizerRegistration<Class> prefinalizer_dummy_{this}; \ - using UsingPreFinalizerMacroNeedsTrailingSemiColon = char - -class PLATFORM_EXPORT BlinkGCObserver { - USING_FAST_MALLOC(BlinkGCObserver); - - public: - // The constructor automatically register this object to ThreadState's - // observer lists. The argument must not be null. - explicit BlinkGCObserver(ThreadState*); - - // The destructor automatically unregister this object from ThreadState's - // observer lists. - virtual ~BlinkGCObserver(); - - virtual void OnCompleteSweepDone() = 0; - - private: - // As a ThreadState must live when a BlinkGCObserver lives, holding a raw - // pointer is safe. - ThreadState* thread_state_; -}; - -class PLATFORM_EXPORT ThreadState final { - USING_FAST_MALLOC(ThreadState); - - public: - // Register the pre-finalizer for the |self| object. The class T be using - // USING_PRE_FINALIZER() macro. - template <typename T> - class PrefinalizerRegistration final { - DISALLOW_NEW(); - - public: - PrefinalizerRegistration(T* self) { // NOLINT - static_assert(sizeof(&T::InvokePreFinalizer) > 0, - "USING_PRE_FINALIZER(T) must be defined."); - ThreadState* state = - ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState(); -#if DCHECK_IS_ON() - DCHECK(state->CheckThread()); -#endif - DCHECK(!state->SweepForbidden()); - DCHECK(std::find(state->ordered_pre_finalizers_.begin(), - state->ordered_pre_finalizers_.end(), - PreFinalizer(self, T::InvokePreFinalizer)) == - state->ordered_pre_finalizers_.end()); - state->ordered_pre_finalizers_.emplace_back(self, T::InvokePreFinalizer); - } - }; - - // See setGCState() for possible state transitions. - enum GCState { - kNoGCScheduled, - kIncrementalMarkingStepPaused, - kIncrementalMarkingStepScheduled, - kIncrementalMarkingFinalizeScheduled, - kForcedGCForTestingScheduled, - kIncrementalGCScheduled, - }; - - // The phase that the GC is in. The GCPhase will not return kNone for mutators - // running during incremental marking and lazy sweeping. See SetGCPhase() for - // possible state transitions. - enum class GCPhase { - // GC is doing nothing. - kNone, - // GC is in marking phase. - kMarking, - // GC is in sweeping phase. - kSweeping, - }; - - enum class EphemeronProcessing { - kPartialProcessing, // Perofrm one ephemeron processing iteration every - // few step - kFullProcessing // Perofrm full fixed-point ephemeron processing on each - // step - }; - - class AtomicPauseScope; - class GCForbiddenScope; - class LsanDisabledScope; - class NoAllocationScope; - class StatisticsCollector; - struct Statistics; - class SweepForbiddenScope; - class HeapPointersOnStackScope; - - using V8BuildEmbedderGraphCallback = void (*)(v8::Isolate*, - v8::EmbedderGraph*, - void*); - - // Returns true if some thread (possibly the current thread) may be doing - // incremental marking. If false is returned, the *current* thread is - // definitely not doing incremental marking. See atomic_entry_flag.h for - // details. - // - // For an exact check, use ThreadState::IsIncrementalMarking. - ALWAYS_INLINE static bool IsAnyIncrementalMarking() { - return incremental_marking_flag_.MightBeEntered(); - } - - static ThreadState* AttachMainThread(); - - // Associate ThreadState object with the current thread. After this - // call thread can start using the garbage collected heap infrastructure. - // It also has to periodically check for safepoints. - static ThreadState* AttachCurrentThread(); - - // Disassociate attached ThreadState from the current thread. The thread - // can no longer use the garbage collected heap after this call. - // - // When ThreadState is detaching from non-main thread its heap is expected to - // be empty (because it is going away). Perform registered cleanup tasks and - // garbage collection to sweep away any objects that are left on this heap. - // - // This method asserts that no objects remain after this cleanup. If assertion - // does not hold we crash as we are potentially in the dangling pointer - // situation. - static void DetachCurrentThread(); - - static ThreadState* Current() { return **thread_specific_; } - - static ThreadState* MainThreadState() { - return reinterpret_cast<ThreadState*>(main_thread_state_storage_); - } - - static ThreadState* FromObject(const void*); - - bool IsMainThread() const { return this == MainThreadState(); } - bool CheckThread() const { return thread_ == CurrentThread(); } - - ThreadHeap& Heap() const { return *heap_; } - base::PlatformThreadId ThreadId() const { return thread_; } - - // Associates |ThreadState| with a given |v8::Isolate|, essentially tying - // there garbage collectors together. - void AttachToIsolate(v8::Isolate*, - V8BuildEmbedderGraphCallback); - - // Removes the association from a potentially attached |v8::Isolate|. - void DetachFromIsolate(); - - // Returns an |UnifiedHeapController| if ThreadState is attached to a V8 - // isolate (see |AttachToIsolate|) and nullptr otherwise. - UnifiedHeapController* unified_heap_controller() const { - DCHECK(isolate_); - return unified_heap_controller_.get(); - } - - void PerformIdleLazySweep(base::TimeTicks deadline); - void PerformConcurrentSweep(base::JobDelegate*); - - void ScheduleForcedGCForTesting(); - void ScheduleGCIfNeeded(); - void SetGCState(GCState); - GCState GetGCState() const { return gc_state_; } - void SetGCPhase(GCPhase); - - // Immediately starts incremental marking and schedules further steps if - // necessary. - void StartIncrementalMarking(BlinkGC::GCReason); - - // Returns true if marking is in progress. - bool IsMarkingInProgress() const { return gc_phase_ == GCPhase::kMarking; } - - // Returns true if unified heap marking is in progress. - bool IsUnifiedGCMarkingInProgress() const { - return IsMarkingInProgress() && IsUnifiedHeapGC(); - } - - // Returns true if sweeping is in progress. - bool IsSweepingInProgress() const { return gc_phase_ == GCPhase::kSweeping; } - - // Returns true if the current GC is a memory reducing GC. - bool IsMemoryReducingGC() const { - return current_gc_data_.reason == - BlinkGC::GCReason::kUnifiedHeapForMemoryReductionGC || - current_gc_data_.reason == - BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC; - } - - bool IsUnifiedHeapGC() const { - return current_gc_data_.reason == BlinkGC::GCReason::kUnifiedHeapGC || - current_gc_data_.reason == - BlinkGC::GCReason::kUnifiedHeapForMemoryReductionGC || - current_gc_data_.reason == - BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC; - } - - bool FinishIncrementalMarkingIfRunning(BlinkGC::CollectionType, - BlinkGC::StackState, - BlinkGC::MarkingType, - BlinkGC::SweepingType, - BlinkGC::GCReason); - - void EnableIncrementalMarkingBarrier(); - void DisableIncrementalMarkingBarrier(); - - void RestartIncrementalMarkingIfPaused(); - - void CompleteSweep(); - - // Returns whether it is currently allowed to allocate an object. Mainly used - // for sanity checks asserts. - bool IsAllocationAllowed() const { - // Allocation is not allowed during atomic marking pause, but it is allowed - // during atomic sweeping pause. - return !InAtomicMarkingPause() && !no_allocation_count_; - } - - // Returns whether it is currently forbidden to trigger a GC. - bool IsGCForbidden() const { return gc_forbidden_count_; } - - // Returns whether it is currently forbidden to sweep objects. - bool SweepForbidden() const { return sweep_forbidden_; } - - bool in_atomic_pause() const { return in_atomic_pause_; } - - bool InAtomicMarkingPause() const { - return in_atomic_pause() && IsMarkingInProgress(); - } - bool InAtomicSweepingPause() const { - return in_atomic_pause() && IsSweepingInProgress(); - } - - bool IsIncrementalMarking() const { return incremental_marking_; } - void SetIncrementalMarking(bool value) { incremental_marking_ = value; } - - void SafePoint(BlinkGC::StackState); - - // A region of non-weak PersistentNodes allocated on the given thread. - PersistentRegion* GetPersistentRegion() const { - return persistent_region_.get(); - } - - // A region of PersistentNodes for WeakPersistents allocated on the given - // thread. - PersistentRegion* GetWeakPersistentRegion() const { - return weak_persistent_region_.get(); - } - - void RegisterStaticPersistentNode(PersistentNode*); - void ReleaseStaticPersistentNodes(); - void FreePersistentNode(PersistentRegion*, PersistentNode*); - - v8::Isolate* GetIsolate() const { return isolate_; } - - // Returns |true| if |object| resides on this thread's heap. - // It is well-defined to call this method on any heap allocated - // reference, provided its associated heap hasn't been detached - // and shut down. Its behavior is undefined for any other pointer - // value. - bool IsOnThreadHeap(const void* object) const { - return &FromObject(object)->Heap() == &Heap(); - } - - ALWAYS_INLINE bool IsOnStack(Address address) const { - return reinterpret_cast<Address>(start_of_stack_) >= address && - address >= (reinterpret_cast<Address>(reinterpret_cast<uintptr_t>( - WTF::GetCurrentStackPosition()))); - } - - int GcAge() const { return gc_age_; } - - MarkingVisitor* CurrentVisitor() const { - return current_gc_data_.visitor.get(); - } - - // Returns true if the marking verifier is enabled, false otherwise. - bool IsVerifyMarkingEnabled() const; - - void SkipIncrementalMarkingForTesting() { - skip_incremental_marking_for_testing_ = true; - } - - // Performs stand-alone garbage collections considering only C++ objects for - // testing. - // - // Since it only considers C++ objects this type of GC is mostly useful for - // unit tests. - void CollectGarbageForTesting(BlinkGC::CollectionType, - BlinkGC::StackState, - BlinkGC::MarkingType, - BlinkGC::SweepingType, - BlinkGC::GCReason); - - // Forced garbage collection for testing: - // - Performs unified heap garbage collections if ThreadState is attached to a - // v8::Isolate using ThreadState::AttachToIsolate. - // - Otherwise, performs stand-alone garbage collections. - // - Collects garbage as long as live memory decreases (capped at 5). - void CollectAllGarbageForTesting( - BlinkGC::StackState stack_state = - BlinkGC::StackState::kNoHeapPointersOnStack); - - // Enables compaction for next garbage collection. - void EnableCompactionForNextGCForTesting(); - - bool RequiresForcedGCForTesting() const { - return current_gc_data_.stack_state == - BlinkGC::StackState::kHeapPointersOnStack && - !forced_scheduled_gc_for_testing_; - } - - void EnterNoHeapVerificationScopeForTesting() { - ++disable_heap_verification_scope_; - } - void LeaveNoHeapVerificationScopeForTesting() { - --disable_heap_verification_scope_; - } - - private: - class IncrementalMarkingScheduler; - - // Stores whether some ThreadState is currently in incremental marking. - static AtomicEntryFlag incremental_marking_flag_; - - static WTF::ThreadSpecific<ThreadState*>* thread_specific_; - - // We can't create a static member of type ThreadState here because it will - // introduce global constructor and destructor. We would like to manage - // lifetime of the ThreadState attached to the main thread explicitly instead - // and still use normal constructor and destructor for the ThreadState class. - // For this we reserve static storage for the main ThreadState and lazily - // construct ThreadState in it using placement new. - static uint8_t main_thread_state_storage_[]; - - // Callback executed directly after pushing all callee-saved registers. - // |end_of_stack| denotes the end of the stack that can hold references to - // managed objects. - static void VisitStackAfterPushingRegisters(ThreadState*, - intptr_t* end_of_stack); - - static bool IsForcedGC(BlinkGC::GCReason reason) { - return reason == BlinkGC::GCReason::kThreadTerminationGC || - reason == BlinkGC::GCReason::kForcedGCForTesting || - reason == BlinkGC::GCReason::kUnifiedHeapForcedForTestingGC; - } - - ThreadState(); - ~ThreadState(); - - void EnterNoAllocationScope() { no_allocation_count_++; } - void LeaveNoAllocationScope() { no_allocation_count_--; } - - void EnterAtomicPause() { - DCHECK(!in_atomic_pause_); - in_atomic_pause_ = true; - } - void LeaveAtomicPause() { - DCHECK(in_atomic_pause_); - in_atomic_pause_ = false; - } - - void EnterGCForbiddenScope() { gc_forbidden_count_++; } - void LeaveGCForbiddenScope() { - DCHECK_GT(gc_forbidden_count_, 0u); - gc_forbidden_count_--; - } - - void EnterStaticReferenceRegistrationDisabledScope(); - void LeaveStaticReferenceRegistrationDisabledScope(); - - // Performs stand-alone garbage collections considering only C++ objects. - // - // Use the public *ForTesting calls for calling GC in tests. - void CollectGarbage(BlinkGC::CollectionType, - BlinkGC::StackState, - BlinkGC::MarkingType, - BlinkGC::SweepingType, - BlinkGC::GCReason); - - // The following methods are used to compose RunAtomicPause. Public users - // should use the CollectGarbage entrypoint. Internal users should use these - // methods to compose a full garbage collection. - void AtomicPauseMarkPrologue(BlinkGC::CollectionType, - BlinkGC::StackState, - BlinkGC::MarkingType, - BlinkGC::GCReason); - void AtomicPauseMarkRoots(BlinkGC::StackState, - BlinkGC::MarkingType, - BlinkGC::GCReason); - void AtomicPauseMarkTransitiveClosure(); - void AtomicPauseMarkEpilogue(BlinkGC::MarkingType); - void AtomicPauseSweepAndCompact(BlinkGC::CollectionType, - BlinkGC::MarkingType marking_type, - BlinkGC::SweepingType sweeping_type); - void AtomicPauseEpilogue(); - - // RunAtomicPause composes the final atomic pause that finishes a mark-compact - // phase of a garbage collection. Depending on SweepingType it may also finish - // sweeping or schedule lazy/concurrent sweeping. - void RunAtomicPause(BlinkGC::CollectionType, - BlinkGC::StackState, - BlinkGC::MarkingType, - BlinkGC::SweepingType, - BlinkGC::GCReason); - - // The version is needed to be able to start incremental marking. - void MarkPhasePrologue(BlinkGC::CollectionType, - BlinkGC::StackState, - BlinkGC::MarkingType, - BlinkGC::GCReason); - void MarkPhaseEpilogue(BlinkGC::MarkingType); - void MarkPhaseVisitRoots(); - void MarkPhaseVisitNotFullyConstructedObjects(); - bool MarkPhaseAdvanceMarkingBasedOnSchedule(base::TimeDelta, - EphemeronProcessing); - bool MarkPhaseAdvanceMarking(base::TimeDelta, EphemeronProcessing); - void VerifyMarking(BlinkGC::MarkingType); - - // Visit the stack after pushing registers onto the stack. - void PushRegistersAndVisitStack(); - - // Visit local thread stack and trace all pointers conservatively. Never call - // directly but always call through |PushRegistersAndVisitStack|. - void VisitStackImpl(MarkingVisitor*, Address*, Address*); - void VisitStack(MarkingVisitor*, Address*); - void VisitUnsafeStack(MarkingVisitor*); - - // Visit the asan fake stack frame corresponding to a slot on the real machine - // stack if there is one. Never call directly but always call through - // |PushRegistersAndVisitStack|. - void VisitAsanFakeStackForPointer(MarkingVisitor*, - Address, - Address*, - Address*); - - // Visit all non-weak persistents allocated on this thread. - void VisitPersistents(Visitor*); - - // Visit all weak persistents allocated on this thread. - void VisitWeakPersistents(Visitor*); - - // Visit card tables (remembered sets) containing inter-generational pointers. - void VisitRememberedSets(MarkingVisitor*); - - // Incremental marking implementation functions. - void IncrementalMarkingStartForTesting(); - void IncrementalMarkingStart(BlinkGC::GCReason); - // Incremental marking step advance marking on the mutator thread. This method - // also reschedules concurrent marking tasks if needed. The duration parameter - // applies only to incremental marking steps on the mutator thread. - void IncrementalMarkingStep(BlinkGC::StackState); - void IncrementalMarkingFinalize(); - - // Returns true if concurrent marking is finished (i.e. all current threads - // terminated and the worklist is empty) - bool ConcurrentMarkingStep(); - void ScheduleConcurrentMarking(); - void PerformConcurrentMark(base::JobDelegate* job); - - // Schedule helpers. - void ScheduleIdleLazySweep(); - void ScheduleConcurrentAndLazySweep(); - - void NotifySweepDone(); - void PostSweep(); - - // See |DetachCurrentThread|. - void RunTerminationGC(); - - void RunScheduledGC(BlinkGC::StackState); - - void SynchronizeAndFinishConcurrentSweeping(); - - void InvokePreFinalizers(); - - // Adds the given observer to the ThreadState's observer list. This doesn't - // take ownership of the argument. The argument must not be null. The argument - // must not be registered before calling this. - void AddObserver(BlinkGCObserver*); - - // Removes the given observer from the ThreadState's observer list. This - // doesn't take ownership of the argument. The argument must not be null. - // The argument must be registered before calling this. - void RemoveObserver(BlinkGCObserver*); - - bool IsForcedGC() const { return IsForcedGC(current_gc_data_.reason); } - - // Returns whether stack scanning is forced. This is currently only used in - // platform tests where non nested tasks can be run with heap pointers on - // stack. - bool HeapPointersOnStackForced() const { - return heap_pointers_on_stack_forced_; - } - -#if defined(ADDRESS_SANITIZER) - // Poisons payload of unmarked objects. - // - // Also unpoisons memory areas for handles that may require resetting which - // can race with destructors. Note that cross-thread access still requires - // synchronization using a lock. - void PoisonUnmarkedObjects(); -#endif // ADDRESS_SANITIZER - - std::unique_ptr<ThreadHeap> heap_; - base::PlatformThreadId thread_; - std::unique_ptr<PersistentRegion> persistent_region_; - std::unique_ptr<PersistentRegion> weak_persistent_region_; - - // Start of the stack which is the boundary until conservative stack scanning - // needs to search for managed pointers. - Address* start_of_stack_; - - bool in_atomic_pause_ = false; - bool sweep_forbidden_ = false; - bool heap_pointers_on_stack_forced_ = false; - bool incremental_marking_ = false; - bool should_optimize_for_load_time_ = false; - bool forced_scheduled_gc_for_testing_ = false; - size_t no_allocation_count_ = 0; - size_t gc_forbidden_count_ = 0; - size_t static_persistent_registration_disabled_count_ = 0; - - GCState gc_state_ = GCState::kNoGCScheduled; - GCPhase gc_phase_ = GCPhase::kNone; - BlinkGC::GCReason reason_for_scheduled_gc_ = - BlinkGC::GCReason::kForcedGCForTesting; - - using PreFinalizerCallback = bool (*)(const LivenessBroker&, void*); - using PreFinalizer = std::pair<void*, PreFinalizerCallback>; - - // Pre-finalizers are called in the reverse order in which they are - // registered by the constructors (including constructors of Mixin objects) - // for an object, by processing the ordered_pre_finalizers_ back-to-front. - Deque<PreFinalizer> ordered_pre_finalizers_; - - v8::Isolate* isolate_ = nullptr; - V8BuildEmbedderGraphCallback v8_build_embedder_graph_ = nullptr; - std::unique_ptr<UnifiedHeapController> unified_heap_controller_; - -#if defined(ADDRESS_SANITIZER) - void* asan_fake_stack_; -#endif - - HashSet<BlinkGCObserver*> observers_; - - // PersistentNodes that are stored in static references; - // references that either have to be cleared upon the thread - // detaching from Oilpan and shutting down or references we - // have to clear before initiating LSan's leak detection. - HashSet<PersistentNode*> static_persistents_; - - int gc_age_ = 0; - - struct GCData { - BlinkGC::CollectionType collection_type; - BlinkGC::StackState stack_state; - BlinkGC::MarkingType marking_type; - BlinkGC::GCReason reason; - std::unique_ptr<MarkingVisitor> visitor; - }; - GCData current_gc_data_; - - std::unique_ptr<IncrementalMarkingScheduler> incremental_marking_scheduler_; - std::unique_ptr<MarkingSchedulingOracle> marking_scheduling_; - - base::JobHandle marker_handle_; - - base::JobHandle sweeper_handle_; - std::atomic_bool has_unswept_pages_{false}; - - size_t disable_heap_verification_scope_ = 0; - - bool skip_incremental_marking_for_testing_ = false; - - size_t last_concurrently_marked_bytes_ = 0; - base::TimeTicks last_concurrently_marked_bytes_update_; - bool concurrent_marking_priority_increased_ = false; - - friend class BlinkGCObserver; - friend class incremental_marking_test::IncrementalMarkingScope; - friend class IncrementalMarkingTestDriver; - friend class HeapAllocator; - template <typename T> - friend class PrefinalizerRegistration; - friend class TestGCScope; - friend class TestSupportingGC; - friend class ThreadStateSchedulingTest; - friend class UnifiedHeapController; - - DISALLOW_COPY_AND_ASSIGN(ThreadState); -}; - -template <> -class ThreadStateFor<kMainThreadOnly> { - STATIC_ONLY(ThreadStateFor); - - public: - static ThreadState* GetState() { - // This specialization must only be used from the main thread. - DCHECK(ThreadState::Current()->IsMainThread()); - return ThreadState::MainThreadState(); - } -}; - -template <> -class ThreadStateFor<kAnyThread> { - STATIC_ONLY(ThreadStateFor); - - public: - static ThreadState* GetState() { return ThreadState::Current(); } -}; - -} // namespace blink +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/thread_state.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/thread_state_scopes.h b/chromium/third_party/blink/renderer/platform/heap/thread_state_scopes.h index bde958dc4ad..5abe13206e6 100644 --- a/chromium/third_party/blink/renderer/platform/heap/thread_state_scopes.h +++ b/chromium/third_party/blink/renderer/platform/heap/thread_state_scopes.h @@ -1,128 +1,16 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_SCOPES_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_SCOPES_H_ -#include "third_party/blink/renderer/platform/heap/thread_state.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -#if defined(LEAK_SANITIZER) -#include "third_party/blink/renderer/platform/wtf/leak_annotations.h" -#endif - -namespace blink { - -// The NoAllocationScope class is used in debug mode to catch unwanted -// allocations. E.g. allocations during GC. -class ThreadState::NoAllocationScope final { - STACK_ALLOCATED(); - DISALLOW_COPY_AND_ASSIGN(NoAllocationScope); - - public: - explicit NoAllocationScope(ThreadState* state) : state_(state) { - state_->EnterNoAllocationScope(); - } - ~NoAllocationScope() { state_->LeaveNoAllocationScope(); } - - private: - ThreadState* const state_; -}; - -class ThreadState::SweepForbiddenScope final { - STACK_ALLOCATED(); - DISALLOW_COPY_AND_ASSIGN(SweepForbiddenScope); - - public: - explicit SweepForbiddenScope(ThreadState* state) : state_(state) { - DCHECK(!state_->sweep_forbidden_); - state_->sweep_forbidden_ = true; - } - ~SweepForbiddenScope() { - DCHECK(state_->sweep_forbidden_); - state_->sweep_forbidden_ = false; - } - - private: - ThreadState* const state_; -}; - -class ThreadState::GCForbiddenScope final { - STACK_ALLOCATED(); - - public: - explicit GCForbiddenScope(ThreadState* thread_state) - : thread_state_(thread_state) { - thread_state_->EnterGCForbiddenScope(); - } - ~GCForbiddenScope() { thread_state_->LeaveGCForbiddenScope(); } - - private: - ThreadState* const thread_state_; -}; - -// Used to mark when we are in an atomic pause for GC. -class ThreadState::AtomicPauseScope final { - STACK_ALLOCATED(); - - public: - explicit AtomicPauseScope(ThreadState* thread_state) - : thread_state_(thread_state), gc_forbidden_scope(thread_state) { - thread_state_->EnterAtomicPause(); - } - ~AtomicPauseScope() { thread_state_->LeaveAtomicPause(); } - - private: - ThreadState* const thread_state_; - GCForbiddenScope gc_forbidden_scope; -}; - -class ThreadState::HeapPointersOnStackScope final { - STACK_ALLOCATED(); - - public: - explicit HeapPointersOnStackScope(ThreadState* state) : state_(state) { - DCHECK(!state_->heap_pointers_on_stack_forced_); - state_->heap_pointers_on_stack_forced_ = true; - } - ~HeapPointersOnStackScope() { - DCHECK(state_->heap_pointers_on_stack_forced_); - state_->heap_pointers_on_stack_forced_ = false; - } - - private: - ThreadState* const state_; -}; - -#if defined(LEAK_SANITIZER) -class ThreadState::LsanDisabledScope final { - STACK_ALLOCATED(); - DISALLOW_COPY_AND_ASSIGN(LsanDisabledScope); - - public: - explicit LsanDisabledScope(ThreadState* thread_state) - : thread_state_(thread_state) { - __lsan_disable(); - if (thread_state_) - thread_state_->EnterStaticReferenceRegistrationDisabledScope(); - } - - ~LsanDisabledScope() { - __lsan_enable(); - if (thread_state_) - thread_state_->LeaveStaticReferenceRegistrationDisabledScope(); - } - - private: - ThreadState* const thread_state_; -}; - -#define LEAK_SANITIZER_DISABLED_SCOPE \ - ThreadState::LsanDisabledScope lsan_disabled_scope(ThreadState::Current()) -#else -#define LEAK_SANITIZER_DISABLED_SCOPE -#endif - -} // namespace blink +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/thread_state_scopes.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_SCOPES_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/unified_heap_controller.h b/chromium/third_party/blink/renderer/platform/heap/unified_heap_controller.h index 5ec55f91db5..9d197c495e9 100644 --- a/chromium/third_party/blink/renderer/platform/heap/unified_heap_controller.h +++ b/chromium/third_party/blink/renderer/platform/heap/unified_heap_controller.h @@ -1,75 +1,16 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_ -#include "base/macros.h" -#include "third_party/blink/renderer/platform/heap/heap_stats_collector.h" -#include "third_party/blink/renderer/platform/platform_export.h" -#include "v8/include/v8.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -namespace blink { - -class ThreadState; - -// UnifiedHeapController ties V8's garbage collector to Oilpan for performing a -// garbage collection across both managed heaps. -// -// Unified heap garbage collections are triggered by V8 and mark the full -// transitive closure of V8 and Blink (Oilpan) objects. The garbage collection -// is initially triggered by V8. Both collecters report live references using -// the EmbedderHeapTracer APIs. V8 and Blink both run separate incremental -// marking steps to compute their live closures, respectively. The final atomic -// pause is then initiated by V8 and triggers a fixed-point computation between -// V8 and Blink where both GCs report live references to each other and drain -// their marking work lists until they are empty and no new references are -// found. -// -// Oilpan does not consider references from DOM wrappers (JavaScript objects on -// V8's heap) as roots for such garbage collections. -class PLATFORM_EXPORT UnifiedHeapController final - : public v8::EmbedderHeapTracer, - public ThreadHeapStatsObserver { - DISALLOW_IMPLICIT_CONSTRUCTORS(UnifiedHeapController); - - public: - explicit UnifiedHeapController(ThreadState*); - ~UnifiedHeapController() override; - - // v8::EmbedderHeapTracer implementation. - void TracePrologue(v8::EmbedderHeapTracer::TraceFlags) final; - void TraceEpilogue(v8::EmbedderHeapTracer::TraceSummary*) final; - void EnterFinalPause(EmbedderStackState) final; - void RegisterV8References(const std::vector<std::pair<void*, void*>>&) final; - bool AdvanceTracing(double) final; - bool IsTracingDone() final; - bool IsRootForNonTracingGC(const v8::TracedReference<v8::Value>&) final; - bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>&) final; - void ResetHandleInNonTracingGC(const v8::TracedReference<v8::Value>&) final; - - ThreadState* thread_state() const { return thread_state_; } - - // ThreadHeapStatsObserver implementation. - void IncreaseAllocatedObjectSize(size_t) final; - void DecreaseAllocatedObjectSize(size_t) final; - // Not needed. - void ResetAllocatedObjectSize(size_t) final {} - void IncreaseAllocatedSpace(size_t) final {} - void DecreaseAllocatedSpace(size_t) final {} - - private: - void ReportBufferedAllocatedSizeIfPossible(); - - ThreadState* const thread_state_; - // Returns whether the Blink heap has been fully processed. - bool is_tracing_done_ = false; - - // Buffered allocated size. Only positive values are forwarded to V8. - int64_t buffered_allocated_size_ = 0; -}; - -} // namespace blink +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/unified_heap_controller.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_CONTROLLER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h b/chromium/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h index 6ff6cb6a75e..4d13146e071 100644 --- a/chromium/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h +++ b/chromium/third_party/blink/renderer/platform/heap/unified_heap_marking_visitor.h @@ -1,90 +1,16 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_ -#include "base/macros.h" -#include "third_party/blink/renderer/platform/heap/marking_visitor.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -namespace v8 { -class EmbedderHeapTracer; -} - -namespace blink { - -struct WrapperTypeInfo; - -// Marking visitor for unified heap garbage collections. Extends the regular -// Oilpan marking visitor by also providing write barriers and visitation -// methods that allow for announcing reachable objects to V8. Visitor can be -// used from any thread. -class PLATFORM_EXPORT UnifiedHeapMarkingVisitorBase { - public: - virtual ~UnifiedHeapMarkingVisitorBase() = default; - - protected: - UnifiedHeapMarkingVisitorBase(ThreadState*, v8::Isolate*, int); - - // Visitation methods that announce reachable wrappers to V8. - void VisitImpl(const TraceWrapperV8Reference<v8::Value>&); - - v8::Isolate* const isolate_; - v8::EmbedderHeapTracer* const controller_; - V8ReferencesWorklist::View v8_references_worklist_; - - private: - int task_id_; - - DISALLOW_COPY_AND_ASSIGN(UnifiedHeapMarkingVisitorBase); -}; - -// Same as the base visitor with the difference that it is bound to main thread. -// Also implements various sorts of write barriers that should only be called -// from the main thread. -class PLATFORM_EXPORT UnifiedHeapMarkingVisitor - : public MarkingVisitor, - public UnifiedHeapMarkingVisitorBase { - public: - // Write barriers for annotating a write during incremental marking. - static void WriteBarrier(const TraceWrapperV8Reference<v8::Value>&); - static void WriteBarrier(v8::Isolate*, const WrapperTypeInfo*, const void*); - - UnifiedHeapMarkingVisitor(ThreadState*, MarkingMode, v8::Isolate*); - ~UnifiedHeapMarkingVisitor() override = default; - - protected: - using Visitor::Visit; - void Visit(const TraceWrapperV8Reference<v8::Value>&) final; - - private: - DISALLOW_COPY_AND_ASSIGN(UnifiedHeapMarkingVisitor); -}; - -// Same as the base visitor with the difference that it is bound to a -// concurrent thread. -class PLATFORM_EXPORT ConcurrentUnifiedHeapMarkingVisitor - : public ConcurrentMarkingVisitor, - public UnifiedHeapMarkingVisitorBase { - public: - ConcurrentUnifiedHeapMarkingVisitor(ThreadState*, - MarkingMode, - v8::Isolate*, - int task_id); - ~ConcurrentUnifiedHeapMarkingVisitor() override = default; - - - void FlushWorklists() override; - - protected: - using Visitor::Visit; - void Visit(const TraceWrapperV8Reference<v8::Value>&) final; - - private: - DISALLOW_COPY_AND_ASSIGN(ConcurrentUnifiedHeapMarkingVisitor); -}; - -} // namespace blink +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/unified_heap_marking_visitor.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_UNIFIED_HEAP_MARKING_VISITOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h new file mode 100644 index 00000000000..bf8602168fa --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc.h @@ -0,0 +1,10 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_ + +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h new file mode 100644 index 00000000000..8773bd7af3d --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/blink_gc_memory_dump_provider.h @@ -0,0 +1,10 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_ + +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_BLINK_GC_MEMORY_DUMP_PROVIDER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h new file mode 100644 index 00000000000..17471d3fd27 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/disallow_new_wrapper.h @@ -0,0 +1,10 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_DISALLOW_NEW_WRAPPER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_DISALLOW_NEW_WRAPPER_H_ + +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_DISALLOW_NEW_WRAPPER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h new file mode 100644 index 00000000000..5867016b7a0 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/garbage_collected.h @@ -0,0 +1,9 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_ +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GARBAGE_COLLECTED_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h new file mode 100644 index 00000000000..2ef207a7c66 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/gc_task_runner.h @@ -0,0 +1,10 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GC_TASK_RUNNER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GC_TASK_RUNNER_H_ + +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_GC_TASK_RUNNER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h new file mode 100644 index 00000000000..5aecfbbbeda --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap.h @@ -0,0 +1,19 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_H_ + +#include "v8/include/cppgc/garbage-collected.h" + +namespace blink { + +template <typename T> +using GarbageCollected = cppgc::GarbageCollected<T>; + +using GarbageCollectedMixin = cppgc::GarbageCollectedMixin; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h new file mode 100644 index 00000000000..7c5cd8d4457 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_allocator.h @@ -0,0 +1,10 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_H_ + +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_ALLOCATOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h new file mode 100644 index 00000000000..042d806358e --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_stats_collector.h @@ -0,0 +1,10 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_STATS_COLLECTOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_STATS_COLLECTOR_H_ + +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_STATS_COLLECTOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h new file mode 100644 index 00000000000..59d9b9e2d4f --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/heap_traits.h @@ -0,0 +1,10 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TRAITS_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TRAITS_H_ + +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_HEAP_TRAITS_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/member.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/member.h new file mode 100644 index 00000000000..78f61452561 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/member.h @@ -0,0 +1,23 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_ + +#include "v8/include/cppgc/member.h" + +namespace blink { + +template <typename T> +using Member = cppgc::Member<T>; + +template <typename T> +using WeakMember = cppgc::WeakMember<T>; + +template <typename T> +using UntracedMember = cppgc::UntracedMember<T>; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_MEMBER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h new file mode 100644 index 00000000000..a7d0bc305f9 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/persistent.h @@ -0,0 +1,20 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_ + +#include "v8/include/cppgc/persistent.h" + +namespace blink { + +template <typename T> +using Persistent = cppgc::Persistent<T>; + +template <typename T> +using WeakPersistent = cppgc::WeakPersistent<T>; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PERSISTENT_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h new file mode 100644 index 00000000000..254f163b74b --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/process_heap.h @@ -0,0 +1,10 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_ + +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_PROCESS_HEAP_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h new file mode 100644 index 00000000000..eea17788057 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h @@ -0,0 +1,17 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_ + +#include "v8/include/cppgc/prefinalizer.h" + +namespace blink { + +#define USING_PRE_FINALIZER(Class, PreFinalizer) \ + CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer) + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h new file mode 100644 index 00000000000..8378cf6722f --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/thread_state_scopes.h @@ -0,0 +1,10 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_ + +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_THREAD_STATE_SCOPES_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h new file mode 100644 index 00000000000..36fe078e8e8 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_controller.h @@ -0,0 +1,10 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_CONTROLLER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_CONTROLLER_H_ + +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_CONTROLLER_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h new file mode 100644 index 00000000000..0a4d66e2fe4 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/unified_heap_marking_visitor.h @@ -0,0 +1,10 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_ + +// TODO(chromium:1056170): Implement wrapper. + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_UNIFIED_HEAP_MARKING_VISITOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h new file mode 100644 index 00000000000..abb9204f467 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h @@ -0,0 +1,16 @@ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_VISITOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_VISITOR_H_ + +#include "v8/include/cppgc/visitor.h" + +namespace blink { + +using Visitor = cppgc::Visitor; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_WRAPPER_VISITOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/heap/visitor.h b/chromium/third_party/blink/renderer/platform/heap/visitor.h index 7ca6427bda6..31e342005ae 100644 --- a/chromium/third_party/blink/renderer/platform/heap/visitor.h +++ b/chromium/third_party/blink/renderer/platform/heap/visitor.h @@ -1,328 +1,16 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +// Copyright 2020 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_ -#include <memory> -#include "third_party/blink/renderer/platform/heap/blink_gc.h" -#include "third_party/blink/renderer/platform/heap/garbage_collected.h" -#include "third_party/blink/renderer/platform/platform_export.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/assertions.h" -#include "third_party/blink/renderer/platform/wtf/forward.h" -#include "third_party/blink/renderer/platform/wtf/hash_traits.h" -#include "third_party/blink/renderer/platform/wtf/type_traits.h" +#include "third_party/blink/renderer/platform/heap/heap_buildflags.h" -namespace base { -class Location; -} - -namespace v8 { -class Value; -} - -namespace blink { - -template <typename T> -class GarbageCollected; -class LivenessBroker; -template <typename T> -struct TraceTrait; -class ThreadState; -class Visitor; -template <typename T> -class TraceWrapperV8Reference; - -// The TraceMethodDelegate is used to convert a trace method for type T to a -// TraceCallback. This allows us to pass a type's trace method as a parameter -// to the PersistentNode constructor. The PersistentNode constructor needs the -// specific trace method due an issue with the Windows compiler which -// instantiates even unused variables. This causes problems -// in header files where we have only forward declarations of classes. -// -// This interface is safe to use on concurrent threads. All accesses (reads) -// from member are done atomically. -template <typename T, void (T::*method)(Visitor*) const> -struct TraceMethodDelegate { - STATIC_ONLY(TraceMethodDelegate); - static void Trampoline(Visitor* visitor, const void* self) { - (reinterpret_cast<const T*>(self)->*method)(visitor); - } -}; - -template <typename T, void (T::*method)(const LivenessBroker&)> -struct WeakCallbackMethodDelegate { - STATIC_ONLY(WeakCallbackMethodDelegate); - static void Trampoline(const LivenessBroker& info, const void* self) { - (reinterpret_cast<T*>(const_cast<void*>(self))->*method)(info); - } -}; - -// Visitor is used to traverse Oilpan's object graph. -class PLATFORM_EXPORT Visitor { - USING_FAST_MALLOC(Visitor); - - public: - explicit Visitor(ThreadState* state) : state_(state) {} - virtual ~Visitor() = default; - - inline ThreadState* State() const { return state_; } - inline ThreadHeap& Heap() const { return state_->Heap(); } - - // Static visitor implementation forwarding to dynamic interface. - - template <typename T> - void TraceRoot(const T* t, const base::Location& location) { - static_assert(sizeof(T), "T must be fully defined"); - static_assert(IsGarbageCollectedType<T>::value, - "T needs to be a garbage collected object"); - if (!t) - return; - VisitRoot(t, TraceDescriptorFor(t), location); - } - - template <typename T> - void Trace(const Member<T>& t) { - const T* value = t.GetSafe(); - - DCHECK(!Member<T>::IsMemberHashTableDeletedValue(value)); - - Trace(value); - } - - template <typename T> - ALWAYS_INLINE void TraceMaybeDeleted(const Member<T>& t) { - const T* value = t.GetSafe(); - - if (Member<T>::IsMemberHashTableDeletedValue(value)) - return; - - Trace<T>(value); - } - - // TraceMayBeDeleted strongifies WeakMembers. - template <typename T> - ALWAYS_INLINE void TraceMaybeDeleted(const WeakMember<T>& t) { - const T* value = t.GetSafe(); - - if (WeakMember<T>::IsMemberHashTableDeletedValue(value)) - return; - - Trace<T>(value); - } - - // Fallback methods used only when we need to trace raw pointers of T. This is - // the case when a member is a union where we do not support members. - template <typename T> - void Trace(T* t) { - Trace(const_cast<const T*>(t)); - } - template <typename T> - void Trace(const T* t) { - static_assert(sizeof(T), "T must be fully defined"); - static_assert(IsGarbageCollectedType<T>::value, - "T needs to be a garbage collected object"); - if (!t) - return; - Visit(t, TraceDescriptorFor(t)); - } - - // WeakMember version of the templated trace method. It doesn't keep - // the traced thing alive, but will write null to the WeakMember later - // if the pointed-to object is dead. It's lying for this to be const, - // but the overloading resolver prioritizes constness too high when - // picking the correct overload, so all these trace methods have to have - // the same constness on their argument to allow the type to decide. - template <typename T> - void Trace(const WeakMember<T>& weak_member) { - static_assert(sizeof(T), "T must be fully defined"); - static_assert(IsGarbageCollectedType<T>::value, - "T needs to be a garbage collected object"); - - const T* value = weak_member.GetSafe(); - - if (!value) - return; - - DCHECK(!WeakMember<T>::IsMemberHashTableDeletedValue(value)); - VisitWeak(value, &weak_member, TraceDescriptorFor(value), - &HandleWeakCell<T>); - } - - // Fallback trace method for part objects to allow individual trace methods - // to trace through a part object with visitor->trace(m_partObject). This - // takes a const argument, because otherwise it will match too eagerly: a - // non-const argument would match a non-const Vector<T>& argument better - // than the specialization that takes const Vector<T>&. For a similar reason, - // the other specializations take a const argument even though they are - // usually used with non-const arguments, otherwise this function would match - // too well. - template <typename T> - void Trace(const T& t) { - static_assert(sizeof(T), "T must be fully defined"); - if (std::is_polymorphic<T>::value) { - const intptr_t vtable = *reinterpret_cast<const intptr_t*>(&t); - if (!vtable) - return; - } - TraceTrait<T>::Trace(this, &t); - } - - template <typename T> - void TraceEphemeron(const WeakMember<T>& key, - const void* value, - TraceCallback value_trace_callback) { - const T* t = key.GetSafe(); - if (!t) - return; - VisitEphemeron(TraceDescriptorFor(t).base_object_payload, value, - value_trace_callback); - } - - template <typename T> - void TraceWeakContainer(const T* object, - const T* const* slot, - TraceDescriptor strong_desc, - TraceDescriptor weak_dec, - WeakCallback weak_callback, - const void* weak_callback_parameter) { - static_assert(sizeof(T), "T must be fully defined"); - static_assert(IsGarbageCollectedType<T>::value, - "T needs to be a garbage collected object"); - VisitWeakContainer(reinterpret_cast<const void*>(object), - reinterpret_cast<const void* const*>(slot), strong_desc, - weak_dec, weak_callback, weak_callback_parameter); - } - - template <typename T> - void TraceMovablePointer(const T* const* slot) { - RegisterMovableSlot(reinterpret_cast<const void* const*>(slot)); - } - - // Cross-component tracing interface. - template <typename V8Type> - void Trace(const TraceWrapperV8Reference<V8Type>& v8reference) { - Visit(v8reference.template Cast<v8::Value>()); - } - - // Dynamic visitor interface. - - // Adds a |callback| that is invoked with |parameter| after liveness has been - // computed on the whole object graph. The |callback| may use the provided - // |LivenessBroker| to determine whether an object is considered alive or - // dead. - // - // - Upon returning from the callback all references to dead objects must have - // been cleared. - // - Any operation that extends the object graph, including allocation - // or reviving objects, is prohibited. - // - Clearing out pointers is allowed. - // - Removing elements from heap collections is allowed as these collections - // are aware of custom weakness and won't resize their backings. - virtual void RegisterWeakCallback(WeakCallback callback, - const void* parameter) {} - - // Registers an instance method using |RegisterWeakCallback|. See description - // below. - template <typename T, void (T::*method)(const LivenessBroker&)> - void RegisterWeakCallbackMethod(const T* obj) { - RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>::Trampoline, - obj); - } - - // Returns whether the visitor is used in a concurrent setting. - virtual bool IsConcurrent() const { return false; } - - // Defers invoking |desc| to the main thread when running concurrently. - // Returns true if |desc| has been queued for later processing and false if - // running in a non-concurrent setting. - // - // This can be used to defer processing data structures to the main thread - // when support for concurrent processing is missing. - virtual bool DeferredTraceIfConcurrent(TraceDescriptor, size_t) { - return false; - } - - protected: - // Visits an object through a strong reference. - virtual void Visit(const void*, TraceDescriptor) {} - - // Visits an object through a weak reference. - virtual void VisitWeak(const void*, - const void*, - TraceDescriptor, - WeakCallback) {} - - // Visits cross-component references to V8. - virtual void Visit(const TraceWrapperV8Reference<v8::Value>&) {} - - virtual void VisitRoot(const void* t, - TraceDescriptor desc, - const base::Location&) { - Visit(t, desc); - } - - // Visits ephemeron pairs which are a combination of weak and strong keys and - // values. - virtual void VisitEphemeron(const void*, const void*, TraceCallback) {} - - // Visits a container |object| holding ephemeron pairs held from |slot|. The - // descriptor |strong_desc| can be used to enforce strong treatment of - // |object|. The |weak_desc| descriptor is invoked repeatedly until no - // more new objects are found. It is expected that |weak_desc| processing - // ultimately yields in a call to VisitEphemeron. After marking all reachable - // objects, |weak_callback| is invoked with |weak_callback_parameter|. It is - // expected that this callback is used to reset non-live entries in the - // ephemeron container. - virtual void VisitWeakContainer(const void* object, - const void* const* slot, - TraceDescriptor strong_desc, - TraceDescriptor weak_desc, - WeakCallback weak_callback, - const void* weak_callback_parameter) {} - - virtual void RegisterMovableSlot(const void* const* slot) {} - - template <typename T> - static TraceDescriptor TraceDescriptorFor(const T* traceable) { - return TraceTrait<T>::GetTraceDescriptor(traceable); - } - - private: - template <typename T> - static void HandleWeakCell(const LivenessBroker&, const void*); - - ThreadState* const state_; -}; - -} // namespace blink +#if BUILDFLAG(BLINK_HEAP_USE_V8_OILPAN) +#include "third_party/blink/renderer/platform/heap/v8_wrapper/visitor.h" +#else // !BLINK_HEAP_USE_V8_OILPAN +#include "third_party/blink/renderer/platform/heap/impl/visitor.h" +#endif // !BLINK_HEAP_USE_V8_OILPAN #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_ |