blob: 831531bbee4b4bec7e287846eb6546bc5dc77ca0 [file] [log] [blame]
// 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 "base/compiler_specific.h"
#include "base/lazy_instance.h"
#include "third_party/blink/renderer/platform/heap/blink_gc.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/thread_specific.h"
#include "third_party/blink/renderer/platform/wtf/threading.h"
#include "v8-profiler.h"
#include "v8/include/cppgc/heap-consistency.h"
#include "v8/include/cppgc/prefinalizer.h"
#include "v8/include/v8-cppgc.h"
#include "v8/include/v8.h"
namespace v8 {
class CppHeap;
} // namespace v8
namespace cppgc {
class AllocationHandle;
} // namespace cppgc
namespace v8 {
class EmbedderGraph;
} // namespace v8
namespace blink {
#define USING_PRE_FINALIZER(Class, PreFinalizer) \
CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer)
// 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*);
class PLATFORM_EXPORT ThreadState final {
public:
class NoAllocationScope;
static ALWAYS_INLINE ThreadState* Current() {
return *(thread_specific_.Get());
}
static ALWAYS_INLINE ThreadState* MainThreadState() {
return reinterpret_cast<ThreadState*>(main_thread_state_storage_);
}
// Attaches a ThreadState to the main-thread.
static ThreadState* AttachMainThread();
// Attaches a ThreadState to the currently running thread. Must not be the
// main thread and must be called after AttachMainThread().
static ThreadState* AttachCurrentThread();
static void DetachCurrentThread();
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_; }
// Forced garbage collection for testing:
//
// Collects garbage as long as live memory decreases (capped at 5).
void CollectAllGarbageForTesting(
BlinkGC::StackState stack_state =
BlinkGC::StackState::kNoHeapPointersOnStack);
void SafePoint(BlinkGC::StackState);
bool IsMainThread() const { return this == MainThreadState(); }
bool IsCreationThread() const { return thread_id_ == CurrentThread(); }
void NotifyGarbageCollection(v8::GCType, v8::GCCallbackFlags);
bool InAtomicSweepingPause() const {
auto& heap_handle = cpp_heap().GetHeapHandle();
return cppgc::subtle::HeapState::IsInAtomicPause(heap_handle) &&
cppgc::subtle::HeapState::IsSweeping(heap_handle);
}
bool IsAllocationAllowed() const {
return cppgc::subtle::DisallowGarbageCollectionScope::
IsGarbageCollectionAllowed(cpp_heap().GetHeapHandle());
}
// Waits until sweeping is done and invokes the given callback with
// the total sizes of live objects in Node and CSS arenas.
void CollectNodeAndCssStatistics(
base::OnceCallback<void(size_t allocated_node_bytes,
size_t allocated_css_bytes)>);
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_[];
// Storage for all ThreadState objects. This includes the main-thread
// ThreadState as well.
static base::LazyInstance<WTF::ThreadSpecific<ThreadState*>>::Leaky
thread_specific_;
explicit ThreadState();
~ThreadState();
std::unique_ptr<v8::CppHeap> cpp_heap_;
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_V8_WRAPPER_THREAD_STATE_H_