blob: b2734080686566f6c71a47d420314bf225d46794 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// 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 "base/compiler_specific.h"
#include "base/functional/callback_forward.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/bindings/active_script_wrappable_manager.h"
#include "third_party/blink/renderer/platform/heap/forward.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/threading.h"
#include "v8/include/cppgc/common.h" // IWYU pragma: export (for ThreadState::StackState alias)
#include "v8/include/cppgc/heap-consistency.h"
#include "v8/include/v8-callbacks.h"
#include "v8/include/v8-cppgc.h"
#include "v8/include/v8-profiler.h"
namespace v8 {
class CppHeap;
class EmbedderRootsHandler;
} // namespace v8
namespace blink {
class ActiveScriptWrappableManager;
class BlinkGCMemoryDumpProvider;
// ThreadState manages garbage collections together with V8. This includes the
// setup and teardown of the GC wiring as well as custom weakness and clearing
// logic. The state is aware of which Isolate it is attached to and the
// ownership of the underlying CppHeap.
class PLATFORM_EXPORT ThreadState final {
public:
class GCForbiddenScope;
class NoAllocationScope;
using StackState = cppgc::EmbedderStackState;
using DevToolsCountersCallback = void (*)(v8::Isolate*);
ALWAYS_INLINE static ThreadState* Current() {
return &ThreadStateStorage::Current()->thread_state();
}
// 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();
// Attaches custom GC handling to an Isolate. CppHeap is already owned by the
// Isolate at this point.
void AttachToIsolate(v8::Isolate* isolate, DevToolsCountersCallback);
// Detaches custom GC handling from an Isolate. CppHeap is still owned by the
// Isolate afterwards.
void DetachFromIsolate();
// Releases ownership of the CppHeap which is transferred to the v8::Isolate.
std::unique_ptr<v8::CppHeap> ReleaseCppHeap();
ALWAYS_INLINE cppgc::HeapHandle& heap_handle() const { return heap_handle_; }
ALWAYS_INLINE v8::CppHeap& cpp_heap() const { return *cpp_heap_; }
bool IsMainThread() const {
return this ==
&ThreadStateStorage::MainThreadStateStorage()->thread_state();
}
bool IsCreationThread() const { return thread_id_ == CurrentThread(); }
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)>);
// Returns true if incremental marking is currently running, and false
// otherwise.
bool IsIncrementalMarking() const;
// Returns true if the current thread is currently sweeping, i.e., whether the
// caller is invoked from a destructor, and false otherwise.
bool IsSweepingOnOwningThread() const;
// Returns true during heap snapshot generation, and false otherwise.
bool IsTakingHeapSnapshot() const;
// Copies a string into the V8 heap profiler, and returns a pointer to the
// copy. Only valid while taking a heap snapshot.
const char* CopyNameForHeapSnapshot(const char* name) const;
ActiveScriptWrappableManager* GetActiveScriptWrappableManager() {
return active_script_wrappable_manager_.Get();
}
static ThreadState* AttachMainThreadForTesting(v8::Platform*);
static ThreadState* AttachCurrentThreadForTesting(v8::Platform*);
// Forced garbage collection for testing.
//
// Collects garbage as long as live memory decreases (capped at 5).
void CollectAllGarbageForTesting(
StackState stack_state = StackState::kNoHeapPointers);
// Perform stop-the-world garbage collection in young generation for testing.
void CollectGarbageInYoungGenerationForTesting(
StackState stack_state = StackState::kNoHeapPointers);
void EnableDetachedGarbageCollectionsForTesting();
// Transfers ownership of a CppHeap back to ThreadState on Isolate teardown.
// Only used in test drivers.
void RecoverCppHeapAfterIsolateTearDownForTesting();
// Takes a heap snapshot that can be loaded into DevTools. Requires that
// `ThreadState` is attached to a `v8::Isolate`.
//
// `filename` specifies the path on the system to store the snapshot. If no
// filename is provided, the snapshot will be emitted to `stdout`.
//
// Writing to a file requires a disabled sandbox.
void TakeHeapSnapshotForTesting(const char* filename) const;
private:
static void RecoverCppHeapTrampoline(std::unique_ptr<v8::CppHeap>);
// Prologue and epilogue callbacks for unified heap garbage collections. Set
// and released during `AttachToIsolate()` and `DetachFromIsolate()`,
// respectively.
static void GcPrologue(v8::Isolate*, v8::GCType, v8::GCCallbackFlags);
static void GcEpilogue(v8::Isolate*, v8::GCType, v8::GCCallbackFlags);
explicit ThreadState(v8::Platform*);
~ThreadState();
void RecoverCppHeap(std::unique_ptr<v8::CppHeap>);
// During setup of a page ThreadState owns CppHeap. The ownership is
// transferred to the v8::Isolate on its creation.
std::unique_ptr<v8::CppHeap> owning_cpp_heap_;
// Even when not owning the CppHeap (as the heap is owned by a v8::Isolate),
// this pointer will keep a reference to the current CppHeap.
v8::CppHeap* cpp_heap_;
std::unique_ptr<v8::EmbedderRootsHandler> embedder_roots_handler_;
cppgc::HeapHandle& heap_handle_;
v8::Isolate* isolate_ = nullptr;
base::PlatformThreadId thread_id_;
size_t gc_callback_depth_ = 0;
Persistent<ActiveScriptWrappableManager> active_script_wrappable_manager_;
// TODO(mlippautz): Refactor to proper base::CheckedObserver once there's more
// users that want to listen to GC events.
DevToolsCountersCallback dev_tools_counters_callback_;
friend class BlinkGCMemoryDumpProvider;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_