0

heap: Introduce ThreadStateStorage

Splits off the storage parts of ThreadState to allow only including
that in garbage_collected.h which is what users need to define their
GCed objects.

Follow up CLs will remove thread_state.h from anything that doesn't
need to manually invoke GC or set up the heaps.

Bug: chromium:1269227
Change-Id: I191b6fcbf7691ba600ca9567fc741005d6694bad
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3298109
Reviewed-by: Anton Bikineev <bikineev@chromium.org>
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#944879}
This commit is contained in:
Michael Lippautz
2021-11-24 09:07:55 +00:00
committed by Chromium LUCI CQ
parent 190f2afe4f
commit b462ff997a
9 changed files with 224 additions and 99 deletions

@ -77,6 +77,7 @@
#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/thread_state_storage.h"
#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@ -776,7 +777,7 @@ void V8Initializer::InitializeMainThread(
// ThreadState::isolate_ needs to be set before setting the EmbedderHeapTracer
// as setting the tracer indicates that a V8 garbage collection should trace
// over to Blink.
DCHECK(ThreadState::MainThreadState());
DCHECK(ThreadStateStorage::MainThreadStateStorage());
InitializeV8Common(isolate);

@ -52,6 +52,8 @@ blink_platform_sources("heap") {
"thread_state.cc",
"thread_state.h",
"thread_state_scopes.h",
"thread_state_storage.cc",
"thread_state_storage.h",
"trace_traits.h",
"visitor.h",
"write_barrier.h",

@ -5,11 +5,15 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_GARBAGE_COLLECTED_H_
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/heap/thread_state_storage.h"
#include "v8/include/cppgc/allocation.h"
#include "v8/include/cppgc/garbage-collected.h"
#include "v8/include/cppgc/type-traits.h"
namespace cppgc {
class Visitor;
} // namespace cppgc
namespace blink {
template <typename T>
@ -17,12 +21,14 @@ using GarbageCollected = cppgc::GarbageCollected<T>;
using GarbageCollectedMixin = cppgc::GarbageCollectedMixin;
using Visitor = cppgc::Visitor;
// Default MakeGarbageCollected: Constructs an instance of T, which is a garbage
// collected type.
template <typename T, typename... Args>
T* MakeGarbageCollected(Args&&... args) {
return cppgc::MakeGarbageCollected<T>(
ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
ThreadStateStorageFor<ThreadingTrait<T>::kAffinity>::GetState()
->allocation_handle(),
std::forward<Args>(args)...);
}
@ -34,7 +40,7 @@ using AdditionalBytes = cppgc::AdditionalBytes;
template <typename T, typename... Args>
T* MakeGarbageCollected(AdditionalBytes additional_bytes, Args&&... args) {
return cppgc::MakeGarbageCollected<T>(
ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
ThreadStateStorageFor<ThreadingTrait<T>::kAffinity>::GetState()
->allocation_handle(),
std::forward<AdditionalBytes>(additional_bytes),
std::forward<Args>(args)...);

@ -9,6 +9,7 @@
#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector_backing.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/heap/thread_state_storage.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/heap/write_barrier.h"
#include "third_party/blink/renderer/platform/platform_export.h"
@ -60,7 +61,7 @@ class PLATFORM_EXPORT HeapAllocator {
return;
HeapVectorBacking<T>::FromArray(array)->Free(
ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
ThreadStateStorageFor<ThreadingTrait<T>::kAffinity>::GetState()
->heap_handle());
}
@ -96,7 +97,7 @@ class PLATFORM_EXPORT HeapAllocator {
return;
HeapHashTableBacking<HashTable>::FromArray(array)->Free(
ThreadStateFor<ThreadingTrait<
ThreadStateStorageFor<ThreadingTrait<
HeapHashTableBacking<HashTable>>::kAffinity>::GetState()
->heap_handle());
}
@ -109,11 +110,12 @@ class PLATFORM_EXPORT HeapAllocator {
static bool IsAllocationAllowed() {
return cppgc::subtle::DisallowGarbageCollectionScope::
IsGarbageCollectionAllowed(ThreadState::Current()->heap_handle());
IsGarbageCollectionAllowed(
ThreadStateStorage::Current()->heap_handle());
}
static bool IsIncrementalMarking() {
auto& heap_handle = ThreadState::Current()->heap_handle();
auto& heap_handle = ThreadStateStorage::Current()->heap_handle();
return cppgc::subtle::HeapState::IsMarking(heap_handle) &&
!cppgc::subtle::HeapState::IsInAtomicPause(heap_handle);
}
@ -156,7 +158,7 @@ class PLATFORM_EXPORT HeapAllocator {
// garbage collected type but may be kept inline.
switch (HeapConsistency::GetWriteBarrierType(
slot_in_backing, params, []() -> cppgc::HeapHandle& {
return ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
return ThreadStateStorageFor<ThreadingTrait<T>::kAffinity>::GetState()
->heap_handle();
})) {
case HeapConsistency::WriteBarrierType::kMarking:
@ -181,7 +183,7 @@ class PLATFORM_EXPORT HeapAllocator {
// garbage collected type but may be kept inline.
switch (HeapConsistency::GetWriteBarrierType(
first_element, params, []() -> cppgc::HeapHandle& {
return ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState()
return ThreadStateStorageFor<ThreadingTrait<T>::kAffinity>::GetState()
->heap_handle();
})) {
case HeapConsistency::WriteBarrierType::kMarking:

@ -9,6 +9,7 @@
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
#include "third_party/blink/renderer/platform/heap/custom_spaces.h"
#include "third_party/blink/renderer/platform/heap/thread_state_storage.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "v8/include/cppgc/heap-consistency.h"
@ -86,39 +87,41 @@ class BlinkRootsHandler final : public v8::EmbedderRootsHandler {
} // namespace
thread_local ThreadState* g_thread_specific_ CONSTINIT
__attribute__((tls_model(BLINK_HEAP_THREAD_LOCAL_MODEL))) = nullptr;
// static
alignas(ThreadState) uint8_t
ThreadState::main_thread_state_storage_[sizeof(ThreadState)];
BLINK_HEAP_DEFINE_THREAD_LOCAL_GETTER(ThreadState::Current,
ThreadState*,
g_thread_specific_)
// static
ThreadState* ThreadState::AttachMainThread() {
return new (main_thread_state_storage_) ThreadState(gin::V8Platform::Get());
auto* thread_state = new ThreadState(gin::V8Platform::Get());
ThreadStateStorage::CreateMain(*thread_state,
thread_state->cpp_heap().GetAllocationHandle(),
thread_state->cpp_heap().GetHeapHandle());
return thread_state;
}
// static
ThreadState* ThreadState::AttachMainThreadForTesting(v8::Platform* platform) {
ThreadState* thread_state =
new (main_thread_state_storage_) ThreadState(platform);
auto* thread_state = new ThreadState(platform);
ThreadStateStorage::CreateMain(*thread_state,
thread_state->cpp_heap().GetAllocationHandle(),
thread_state->cpp_heap().GetHeapHandle());
thread_state->EnableDetachedGarbageCollectionsForTesting();
return thread_state;
}
// static
ThreadState* ThreadState::AttachCurrentThread() {
return new ThreadState(gin::V8Platform::Get());
auto* thread_state = new ThreadState(gin::V8Platform::Get());
ThreadStateStorage::Create(*thread_state,
thread_state->cpp_heap().GetAllocationHandle(),
thread_state->cpp_heap().GetHeapHandle());
return thread_state;
}
// static
ThreadState* ThreadState::AttachCurrentThreadForTesting(
v8::Platform* platform) {
ThreadState* thread_state = new ThreadState(platform);
ThreadStateStorage::Create(*thread_state,
thread_state->cpp_heap().GetAllocationHandle(),
thread_state->cpp_heap().GetHeapHandle());
thread_state->EnableDetachedGarbageCollectionsForTesting();
return thread_state;
}
@ -153,16 +156,13 @@ ThreadState::ThreadState(v8::Platform* platform)
v8::WrapperDescriptor(kV8DOMWrapperTypeIndex,
kV8DOMWrapperObjectIndex,
gin::GinEmbedder::kEmbedderBlink)})),
allocation_handle_(cpp_heap_->GetAllocationHandle()),
heap_handle_(cpp_heap_->GetHeapHandle()),
thread_id_(CurrentThread()) {
g_thread_specific_ = this;
}
thread_id_(CurrentThread()) {}
ThreadState::~ThreadState() {
DCHECK(!IsMainThread());
DCHECK(IsCreationThread());
cpp_heap_->Terminate();
delete ThreadStateStorage::Current();
}
void ThreadState::SafePoint(StackState stack_state) {

@ -8,7 +8,7 @@
#include "base/compiler_specific.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/heap/forward.h"
#include "third_party/blink/renderer/platform/heap/thread_local.h"
#include "third_party/blink/renderer/platform/heap/thread_state_storage.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/threading.h"
@ -22,10 +22,6 @@ namespace v8 {
class CppHeap;
} // namespace v8
namespace cppgc {
class AllocationHandle;
} // namespace cppgc
namespace v8 {
class EmbedderGraph;
class EmbedderRootsHandler;
@ -33,38 +29,10 @@ class EmbedderRootsHandler;
namespace blink {
// ThreadAffinity indicates which threads objects can be used on. We
// distinguish between objects that can be used on the main thread
// only and objects that can be used on any thread.
//
// For objects that can only be used on the main thread, we avoid going
// through thread-local storage to get to the thread state. This is
// important for performance.
enum ThreadAffinity {
kAnyThread,
kMainThreadOnly,
};
template <typename T, typename = void>
struct ThreadingTrait {
STATIC_ONLY(ThreadingTrait);
static constexpr ThreadAffinity kAffinity = kAnyThread;
};
template <ThreadAffinity>
class ThreadStateFor;
class ThreadState;
using V8BuildEmbedderGraphCallback = void (*)(v8::Isolate*,
v8::EmbedderGraph*,
void*);
// Storage for all ThreadState objects. This includes the main-thread
// ThreadState as well. Keep it outside the class so that PLATFORM_EXPORT
// doesn't apply to it (otherwise, clang-cl complains).
extern thread_local ThreadState* g_thread_specific_ CONSTINIT
__attribute__((tls_model(BLINK_HEAP_THREAD_LOCAL_MODEL)));
class PLATFORM_EXPORT ThreadState final {
public:
class NoAllocationScope;
@ -72,12 +40,8 @@ class PLATFORM_EXPORT ThreadState final {
using StackState = cppgc::EmbedderStackState;
BLINK_HEAP_DECLARE_THREAD_LOCAL_GETTER(Current,
ThreadState*,
g_thread_specific_)
static ALWAYS_INLINE ThreadState* MainThreadState() {
return reinterpret_cast<ThreadState*>(main_thread_state_storage_);
static ALWAYS_INLINE ThreadState* Current() {
return &ThreadStateStorage::Current()->thread_state();
}
// Attaches a ThreadState to the main-thread.
@ -90,16 +54,16 @@ class PLATFORM_EXPORT ThreadState final {
void AttachToIsolate(v8::Isolate* isolate, V8BuildEmbedderGraphCallback);
void DetachFromIsolate();
ALWAYS_INLINE cppgc::AllocationHandle& allocation_handle() const {
return allocation_handle_;
}
ALWAYS_INLINE cppgc::HeapHandle& heap_handle() const { return heap_handle_; }
ALWAYS_INLINE v8::CppHeap& cpp_heap() const { return *cpp_heap_; }
ALWAYS_INLINE v8::Isolate* GetIsolate() const { return isolate_; }
void SafePoint(StackState);
bool IsMainThread() const { return this == MainThreadState(); }
bool IsMainThread() const {
return this ==
&ThreadStateStorage::MainThreadStateStorage()->thread_state();
}
bool IsCreationThread() const { return thread_id_ == CurrentThread(); }
void NotifyGarbageCollection(v8::GCType, v8::GCCallbackFlags);
@ -135,42 +99,17 @@ class PLATFORM_EXPORT ThreadState final {
static ThreadState* AttachCurrentThreadForTesting(v8::Platform*);
private:
// Main-thread ThreadState avoids TLS completely by using a regular global.
// The object is manually managed and should not rely on global ctor/dtor.
static uint8_t main_thread_state_storage_[];
explicit ThreadState(v8::Platform*);
~ThreadState();
std::unique_ptr<v8::CppHeap> cpp_heap_;
std::unique_ptr<v8::EmbedderRootsHandler> embedder_roots_handler_;
cppgc::AllocationHandle& allocation_handle_;
cppgc::HeapHandle& heap_handle_;
v8::Isolate* isolate_ = nullptr;
base::PlatformThreadId thread_id_;
bool forced_scheduled_gc_for_testing_ = false;
};
template <>
class ThreadStateFor<kMainThreadOnly> {
STATIC_ONLY(ThreadStateFor);
public:
static ALWAYS_INLINE ThreadState* GetState() {
return ThreadState::MainThreadState();
}
};
template <>
class ThreadStateFor<kAnyThread> {
STATIC_ONLY(ThreadStateFor);
public:
static ALWAYS_INLINE ThreadState* GetState() {
return ThreadState::Current();
}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_

@ -0,0 +1,52 @@
// 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.
#include "third_party/blink/renderer/platform/heap/thread_state_storage.h"
#include <new>
namespace blink {
thread_local ThreadStateStorage* g_thread_specific_ CONSTINIT
__attribute__((tls_model(BLINK_HEAP_THREAD_LOCAL_MODEL))) = nullptr;
// static
alignas(ThreadStateStorage) uint8_t
ThreadStateStorage::main_thread_state_storage_[sizeof(ThreadStateStorage)];
BLINK_HEAP_DEFINE_THREAD_LOCAL_GETTER(ThreadStateStorage::Current,
ThreadStateStorage*,
g_thread_specific_)
// static
void ThreadStateStorage::CreateMain(ThreadState& thread_state,
cppgc::AllocationHandle& allocation_handle,
cppgc::HeapHandle& heap_handle) {
new (main_thread_state_storage_)
ThreadStateStorage(thread_state, allocation_handle, heap_handle);
}
// static
void ThreadStateStorage::Create(ThreadState& thread_state,
cppgc::AllocationHandle& allocation_handle,
cppgc::HeapHandle& heap_handle) {
new ThreadStateStorage(thread_state, allocation_handle, heap_handle);
}
ThreadStateStorage::ThreadStateStorage(
ThreadState& thread_state,
cppgc::AllocationHandle& allocation_handle,
cppgc::HeapHandle& heap_handle)
: allocation_handle_(allocation_handle),
heap_handle_(heap_handle),
thread_state_(thread_state) {
g_thread_specific_ = this;
}
ThreadStateStorage::~ThreadStateStorage() {
DCHECK(!IsMainThread());
g_thread_specific_ = nullptr;
}
} // namespace blink

@ -0,0 +1,123 @@
// 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_STORAGE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_STORAGE_H_
#include <cstdint>
#include "base/compiler_specific.h"
#include "third_party/blink/renderer/platform/heap/thread_local.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace cppgc {
class AllocationHandle;
class HeapHandle;
} // namespace cppgc
namespace blink {
class ThreadState;
class ThreadStateStorage;
// ThreadAffinity indicates which threads objects can be used on. We
// distinguish between objects that can be used on the main thread
// only and objects that can be used on any thread.
//
// For objects that can only be used on the main thread, we avoid going
// through thread-local storage to get to the thread state. This is
// important for performance.
enum ThreadAffinity {
kAnyThread,
kMainThreadOnly,
};
template <typename T, typename = void>
struct ThreadingTrait {
STATIC_ONLY(ThreadingTrait);
static constexpr ThreadAffinity kAffinity = kAnyThread;
};
// Storage for all ThreadState objects. This includes the main-thread
// ThreadState as well. Keep it outside the class so that PLATFORM_EXPORT
// doesn't apply to it (otherwise, clang-cl complains).
extern thread_local ThreadStateStorage* g_thread_specific_ CONSTINIT
__attribute__((tls_model(BLINK_HEAP_THREAD_LOCAL_MODEL)));
// ThreadStateStorage is the explicitly managed TLS- and global-backed storage
// for ThreadState.
class PLATFORM_EXPORT ThreadStateStorage final {
public:
static ALWAYS_INLINE ThreadStateStorage* MainThreadStateStorage() {
return reinterpret_cast<ThreadStateStorage*>(main_thread_state_storage_);
}
BLINK_HEAP_DECLARE_THREAD_LOCAL_GETTER(Current,
ThreadStateStorage*,
g_thread_specific_)
ALWAYS_INLINE cppgc::AllocationHandle& allocation_handle() const {
return allocation_handle_;
}
ALWAYS_INLINE cppgc::HeapHandle& heap_handle() const { return heap_handle_; }
ALWAYS_INLINE ThreadState& thread_state() const { return thread_state_; }
ALWAYS_INLINE bool IsMainThread() const {
return this == MainThreadStateStorage();
}
private:
static void CreateMain(ThreadState&,
cppgc::AllocationHandle&,
cppgc::HeapHandle&);
static void Create(ThreadState&,
cppgc::AllocationHandle&,
cppgc::HeapHandle&);
// Main-thread ThreadStateStorage avoids TLS completely by using a regular
// global. The object is manually managed and should not rely on global
// ctor/dtor.
static uint8_t main_thread_state_storage_[];
ThreadStateStorage(ThreadState&,
cppgc::AllocationHandle&,
cppgc::HeapHandle&);
~ThreadStateStorage();
cppgc::AllocationHandle& allocation_handle_;
cppgc::HeapHandle& heap_handle_;
ThreadState& thread_state_;
friend class ThreadState;
};
template <ThreadAffinity>
class ThreadStateStorageFor;
template <>
class ThreadStateStorageFor<kMainThreadOnly> {
STATIC_ONLY(ThreadStateStorageFor);
public:
static ALWAYS_INLINE ThreadStateStorage* GetState() {
return ThreadStateStorage::MainThreadStateStorage();
}
};
template <>
class ThreadStateStorageFor<kAnyThread> {
STATIC_ONLY(ThreadStateStorageFor);
public:
static ALWAYS_INLINE ThreadStateStorage* GetState() {
return ThreadStateStorage::Current();
}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_STORAGE_H_

@ -37,7 +37,7 @@
#include "mojo/core/embedder/embedder.h"
#include "mojo/core/embedder/scoped_ipc_support.h"
#include "skia/ext/test_fonts.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
namespace {