blob: d11b0694fe37a24b86afd63adacb1749b4a2e5d3 [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.
#include "third_party/blink/renderer/platform/heap/v8_wrapper/thread_state.h"
#include "gin/public/v8_platform.h"
#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
#include "third_party/blink/renderer/platform/heap/v8_wrapper/custom_spaces.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "v8.h"
#include "v8/include/v8-cppgc.h"
namespace blink {
// static
base::LazyInstance<WTF::ThreadSpecific<ThreadState*>>::Leaky
ThreadState::thread_specific_ = LAZY_INSTANCE_INITIALIZER;
// static
alignas(ThreadState) uint8_t
ThreadState::main_thread_state_storage_[sizeof(ThreadState)];
// static
ThreadState* ThreadState::AttachMainThread() {
return new (main_thread_state_storage_) ThreadState();
}
// static
ThreadState* ThreadState::AttachCurrentThread() {
return new ThreadState();
}
// static
void ThreadState::DetachCurrentThread() {
auto* state = ThreadState::Current();
DCHECK(state);
delete state;
}
void ThreadState::AttachToIsolate(v8::Isolate* isolate,
V8BuildEmbedderGraphCallback) {
isolate->AttachCppHeap(cpp_heap_.get());
CHECK_EQ(cpp_heap_.get(), isolate->GetCppHeap());
isolate_ = isolate;
}
void ThreadState::DetachFromIsolate() {
CHECK_EQ(cpp_heap_.get(), isolate_->GetCppHeap());
isolate_->DetachCppHeap();
isolate_ = nullptr;
}
namespace {
std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> CreateCustomSpaces() {
std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> spaces;
spaces.emplace_back(std::make_unique<HeapVectorBackingSpace>());
spaces.emplace_back(std::make_unique<HeapHashTableBackingSpace>());
spaces.emplace_back(std::make_unique<NodeSpace>());
spaces.emplace_back(std::make_unique<CSSValueSpace>());
return spaces;
}
} // namespace
ThreadState::ThreadState()
: cpp_heap_(v8::CppHeap::Create(
gin::V8Platform::Get(),
{CreateCustomSpaces(),
v8::WrapperDescriptor(kV8DOMWrapperTypeIndex,
kV8DOMWrapperObjectIndex,
gin::GinEmbedder::kEmbedderBlink)})),
allocation_handle_(cpp_heap_->GetAllocationHandle()),
heap_handle_(cpp_heap_->GetHeapHandle()),
thread_id_(CurrentThread()) {
*(thread_specific_.Get()) = this;
}
ThreadState::~ThreadState() {
DCHECK(!IsMainThread());
DCHECK(IsCreationThread());
cpp_heap_->Terminate();
}
void ThreadState::SafePoint(BlinkGC::StackState stack_state) {
DCHECK(IsCreationThread());
if (stack_state != BlinkGC::kNoHeapPointersOnStack)
return;
if (forced_scheduled_gc_for_testing_) {
CollectAllGarbageForTesting(stack_state);
forced_scheduled_gc_for_testing_ = false;
}
}
void ThreadState::NotifyGarbageCollection(v8::GCType type,
v8::GCCallbackFlags flags) {
if (flags & v8::kGCCallbackFlagForced) {
// Forces a precise GC at the end of the current event loop. This is
// required for testing code that cannot use GC internals but rather has
// to rely on window.gc(). Only schedule additional GCs if the last GC was
// using conservative stack scanning.
if (type == v8::kGCTypeScavenge) {
forced_scheduled_gc_for_testing_ = true;
} else if (type == v8::kGCTypeMarkSweepCompact) {
// TODO(1056170): Only need to schedule a forced GC if stack was scanned
// conservatively in previous GC.
forced_scheduled_gc_for_testing_ = true;
}
}
}
void ThreadState::CollectAllGarbageForTesting(BlinkGC::StackState stack_state) {
// Should only be used when attached to V8.
CHECK(isolate_);
size_t previous_live_bytes = 0;
for (size_t i = 0; i < 5; i++) {
// CppHeap registers itself as EmbedderHeapTracer internally.
isolate_->GetEmbedderHeapTracer()->GarbageCollectionForTesting(
stack_state == BlinkGC::kHeapPointersOnStack
? cppgc::EmbedderStackState::kMayContainHeapPointers
: cppgc::EmbedderStackState::kNoHeapPointers);
const size_t live_bytes =
cpp_heap()
.CollectStatistics(cppgc::HeapStatistics::kBrief)
.used_size_bytes;
if (previous_live_bytes == live_bytes) {
break;
}
previous_live_bytes = live_bytes;
}
}
void ThreadState::CollectNodeAndCssStatistics(
base::OnceCallback<void(size_t allocated_node_bytes,
size_t allocated_css_bytes)> callback) {
// TODO(1181269): Implement.
std::move(callback).Run(0u, 0u);
}
} // namespace blink