Commit 1186c664 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

[bindings,heap] Prepare PerIsolateData for holding different heap tracer

- Prepare V8PerIsolateData for holding V8HeapController.
- Harden existing tests to swap in the expected visitor/controller. This way it
  is possible to test ScriptWrappableVisitor while already running on a different
  embedder heap tracer.

Change-Id: I169de233a4dd9886d153e7d97ca63e7caee0d809
Bug: chromium:843903
Reviewed-on: https://chromium-review.googlesource.com/1160656
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#580892}
parent e10124a8
...@@ -16,31 +16,123 @@ ...@@ -16,31 +16,123 @@
namespace blink { namespace blink {
static void PreciselyCollectGarbage() { namespace {
// Temporarily swaps out the underlying v8 heap controller from a given
// v8::Isolate. Gracefully finalized potentially running garbage collections.
class TemporaryV8HeapControllerScope {
WTF_MAKE_NONCOPYABLE(TemporaryV8HeapControllerScope);
STACK_ALLOCATED();
public:
TemporaryV8HeapControllerScope(v8::Isolate* isolate,
std::unique_ptr<V8HeapController> controller)
: isolate_(isolate), saved_controller_(std::move(controller)) {
SwapWithV8PerIsolateDataVisitor();
}
~TemporaryV8HeapControllerScope() { SwapWithV8PerIsolateDataVisitor(); }
V8HeapController* CurrentController() {
return V8PerIsolateData::From(isolate_)->GetV8HeapController();
}
private:
void SwapWithV8PerIsolateDataVisitor() {
V8HeapController* current = CurrentController();
if (current)
current->FinalizeAndCleanup();
V8PerIsolateData::From(isolate_)->SwapV8HeapController(saved_controller_);
isolate_->SetEmbedderHeapTracer(CurrentController());
}
v8::Isolate* const isolate_;
std::unique_ptr<V8HeapController> saved_controller_;
};
class InterceptingScriptWrappableMarkingVisitor
: public blink::ScriptWrappableMarkingVisitor {
public:
InterceptingScriptWrappableMarkingVisitor(v8::Isolate* isolate)
: ScriptWrappableMarkingVisitor(isolate),
marked_wrappers_(new size_t(0)) {}
~InterceptingScriptWrappableMarkingVisitor() override {
delete marked_wrappers_;
}
void Visit(const TraceWrapperV8Reference<v8::Value>&) override {
*marked_wrappers_ += 1;
// Do not actually mark this visitor, as this would call into v8, which
// would require executing an actual GC.
}
size_t NumberOfMarkedWrappers() const { return *marked_wrappers_; }
void Start() { TracePrologue(); }
void End() {
// Gracefully terminate tracing.
AdvanceTracing(
0,
v8::EmbedderHeapTracer::AdvanceTracingActions(
v8::EmbedderHeapTracer::ForceCompletionAction::FORCE_COMPLETION));
AbortTracing();
}
private:
size_t* marked_wrappers_; // Indirection required because of const override.
};
class InterceptingScriptWrappableMarkingVisitorScope
: public TemporaryV8HeapControllerScope {
WTF_MAKE_NONCOPYABLE(InterceptingScriptWrappableMarkingVisitorScope);
STACK_ALLOCATED();
public:
InterceptingScriptWrappableMarkingVisitorScope(v8::Isolate* isolate)
: TemporaryV8HeapControllerScope(
isolate,
std::unique_ptr<InterceptingScriptWrappableMarkingVisitor>{
new InterceptingScriptWrappableMarkingVisitor(isolate)}) {
Visitor()->Start();
}
virtual ~InterceptingScriptWrappableMarkingVisitorScope() {
Visitor()->End();
}
InterceptingScriptWrappableMarkingVisitor* Visitor() {
return static_cast<InterceptingScriptWrappableMarkingVisitor*>(
CurrentController());
}
};
void PreciselyCollectGarbage() {
ThreadState::Current()->CollectAllGarbage(); ThreadState::Current()->CollectAllGarbage();
} }
static void RunV8Scavenger(v8::Isolate* isolate) { void RunV8Scavenger(v8::Isolate* isolate) {
V8GCController::CollectGarbage(isolate, true); V8GCController::CollectGarbage(isolate, true);
} }
static void RunV8FullGc(v8::Isolate* isolate) { void RunV8FullGc(v8::Isolate* isolate) {
V8GCController::CollectGarbage(isolate, false); V8GCController::CollectGarbage(isolate, false);
} }
} // namespace
TEST(ScriptWrappableMarkingVisitorTest, TEST(ScriptWrappableMarkingVisitorTest,
ScriptWrappableMarkingVisitorTracesWrappers) { ScriptWrappableMarkingVisitorTracesWrappers) {
V8TestingScope scope; V8TestingScope testing_scope;
ScriptWrappableMarkingVisitor* visitor =
V8PerIsolateData::From(scope.GetIsolate()) // The graph needs to be set up before starting tracing as otherwise the
->GetScriptWrappableMarkingVisitor(); // conservative write barrier would trigger.
DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::Create();
DeathAwareScriptWrappable* dependency = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* dependency = DeathAwareScriptWrappable::Create();
target->SetWrappedDependency(dependency); target->SetWrappedDependency(dependency);
// The graph needs to be set up before starting tracing as otherwise the InterceptingScriptWrappableMarkingVisitorScope intercepting_scope(
// conservative write barrier would trigger. testing_scope.GetIsolate());
visitor->TracePrologue(); ScriptWrappableMarkingVisitor* visitor = intercepting_scope.Visitor();
HeapObjectHeader* target_header = HeapObjectHeader::FromPayload(target); HeapObjectHeader* target_header = HeapObjectHeader::FromPayload(target);
HeapObjectHeader* dependency_header = HeapObjectHeader* dependency_header =
...@@ -61,8 +153,6 @@ TEST(ScriptWrappableMarkingVisitorTest, ...@@ -61,8 +153,6 @@ TEST(ScriptWrappableMarkingVisitorTest,
EXPECT_EQ(visitor->MarkingDeque()->size(), 0ul); EXPECT_EQ(visitor->MarkingDeque()->size(), 0ul);
EXPECT_TRUE(target_header->IsWrapperHeaderMarked()); EXPECT_TRUE(target_header->IsWrapperHeaderMarked());
EXPECT_TRUE(dependency_header->IsWrapperHeaderMarked()); EXPECT_TRUE(dependency_header->IsWrapperHeaderMarked());
visitor->AbortTracing();
} }
TEST(ScriptWrappableMarkingVisitorTest, TEST(ScriptWrappableMarkingVisitorTest,
...@@ -145,51 +235,47 @@ TEST(ScriptWrappableMarkingVisitorTest, V8ReportsLiveObjectsDuringFullGc) { ...@@ -145,51 +235,47 @@ TEST(ScriptWrappableMarkingVisitorTest, V8ReportsLiveObjectsDuringFullGc) {
} }
TEST(ScriptWrappableMarkingVisitorTest, OilpanClearsHeadersWhenObjectDied) { TEST(ScriptWrappableMarkingVisitorTest, OilpanClearsHeadersWhenObjectDied) {
V8TestingScope scope; V8TestingScope testing_scope;
DeathAwareScriptWrappable* object = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* object = DeathAwareScriptWrappable::Create();
ScriptWrappableMarkingVisitor* visitor =
V8PerIsolateData::From(scope.GetIsolate()) // The graph needs to be set up before starting tracing as otherwise the
->GetScriptWrappableMarkingVisitor(); // conservative write barrier would trigger.
visitor->TracePrologue(); InterceptingScriptWrappableMarkingVisitorScope intercepting_scope(
testing_scope.GetIsolate());
ScriptWrappableMarkingVisitor* visitor = intercepting_scope.Visitor();
auto* header = HeapObjectHeader::FromPayload(object); auto* header = HeapObjectHeader::FromPayload(object);
visitor->headers_to_unmark_.push_back(header); visitor->headers_to_unmark_.push_back(header);
PreciselyCollectGarbage(); PreciselyCollectGarbage();
EXPECT_FALSE(visitor->headers_to_unmark_.Contains(header)); EXPECT_FALSE(visitor->headers_to_unmark_.Contains(header));
visitor->AbortTracing();
} }
TEST(ScriptWrappableMarkingVisitorTest, TEST(ScriptWrappableMarkingVisitorTest,
OilpanClearsMarkingDequeWhenObjectDied) { OilpanClearsMarkingDequeWhenObjectDied) {
V8TestingScope scope; V8TestingScope testing_scope;
DeathAwareScriptWrappable* object = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* object = DeathAwareScriptWrappable::Create();
ScriptWrappableMarkingVisitor* visitor =
V8PerIsolateData::From(scope.GetIsolate()) // The graph needs to be set up before starting tracing as otherwise the
->GetScriptWrappableMarkingVisitor(); // conservative write barrier would trigger.
visitor->TracePrologue(); InterceptingScriptWrappableMarkingVisitorScope intercepting_scope(
testing_scope.GetIsolate());
ScriptWrappableMarkingVisitor* visitor = intercepting_scope.Visitor();
visitor->TraceWithWrappers(object); visitor->TraceWithWrappers(object);
EXPECT_EQ(visitor->MarkingDeque()->front().RawObjectPointer(), object); EXPECT_EQ(visitor->MarkingDeque()->front().RawObjectPointer(), object);
PreciselyCollectGarbage(); PreciselyCollectGarbage();
EXPECT_EQ(visitor->MarkingDeque()->front().RawObjectPointer(), nullptr); EXPECT_EQ(visitor->MarkingDeque()->front().RawObjectPointer(), nullptr);
visitor->AbortTracing();
} }
TEST(ScriptWrappableMarkingVisitorTest, TEST(ScriptWrappableMarkingVisitorTest,
MarkedObjectDoesNothingOnWriteBarrierHitWhenDependencyIsMarkedToo) { MarkedObjectDoesNothingOnWriteBarrierHitWhenDependencyIsMarkedToo) {
V8TestingScope scope; V8TestingScope testing_scope;
InterceptingScriptWrappableMarkingVisitorScope intercepting_scope(
ScriptWrappableMarkingVisitor* visitor = testing_scope.GetIsolate());
V8PerIsolateData::From(scope.GetIsolate()) ScriptWrappableMarkingVisitor* visitor = intercepting_scope.Visitor();
->GetScriptWrappableMarkingVisitor();
visitor->TracePrologue();
DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::Create();
DeathAwareScriptWrappable* dependencies[] = { DeathAwareScriptWrappable* dependencies[] = {
...@@ -202,23 +288,18 @@ TEST(ScriptWrappableMarkingVisitorTest, ...@@ -202,23 +288,18 @@ TEST(ScriptWrappableMarkingVisitorTest,
} }
EXPECT_TRUE(visitor->MarkingDeque()->IsEmpty()); EXPECT_TRUE(visitor->MarkingDeque()->IsEmpty());
target->SetWrappedDependency(dependencies[0]); target->SetWrappedDependency(dependencies[0]);
target->AddWrappedVectorDependency(dependencies[1]); target->AddWrappedVectorDependency(dependencies[1]);
target->AddWrappedHashMapDependency(dependencies[2], dependencies[3]); target->AddWrappedHashMapDependency(dependencies[2], dependencies[3]);
EXPECT_TRUE(visitor->MarkingDeque()->IsEmpty()); EXPECT_TRUE(visitor->MarkingDeque()->IsEmpty());
visitor->AbortTracing();
} }
TEST(ScriptWrappableMarkingVisitorTest, TEST(ScriptWrappableMarkingVisitorTest,
MarkedObjectMarksDependencyOnWriteBarrierHitWhenNotMarked) { MarkedObjectMarksDependencyOnWriteBarrierHitWhenNotMarked) {
V8TestingScope scope; V8TestingScope testing_scope;
InterceptingScriptWrappableMarkingVisitorScope intercepting_scope(
ScriptWrappableMarkingVisitor* visitor = testing_scope.GetIsolate());
V8PerIsolateData::From(scope.GetIsolate()) ScriptWrappableMarkingVisitor* visitor = intercepting_scope.Visitor();
->GetScriptWrappableMarkingVisitor();
visitor->TracePrologue();
DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::Create();
DeathAwareScriptWrappable* dependencies[] = { DeathAwareScriptWrappable* dependencies[] = {
...@@ -236,8 +317,6 @@ TEST(ScriptWrappableMarkingVisitorTest, ...@@ -236,8 +317,6 @@ TEST(ScriptWrappableMarkingVisitorTest,
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
EXPECT_TRUE(visitor->MarkingDequeContains(dependencies[i])); EXPECT_TRUE(visitor->MarkingDequeContains(dependencies[i]));
} }
visitor->AbortTracing();
} }
namespace { namespace {
...@@ -262,63 +341,6 @@ class HandleContainer ...@@ -262,63 +341,6 @@ class HandleContainer
TraceWrapperV8Reference<v8::String> handle_; TraceWrapperV8Reference<v8::String> handle_;
}; };
class InterceptingScriptWrappableMarkingVisitor
: public blink::ScriptWrappableMarkingVisitor {
public:
InterceptingScriptWrappableMarkingVisitor(v8::Isolate* isolate)
: ScriptWrappableMarkingVisitor(isolate),
marked_wrappers_(new size_t(0)) {}
~InterceptingScriptWrappableMarkingVisitor() override {
delete marked_wrappers_;
}
void Visit(const TraceWrapperV8Reference<v8::Value>&) override {
*marked_wrappers_ += 1;
// Do not actually mark this visitor, as this would call into v8, which
// would require executing an actual GC.
}
size_t NumberOfMarkedWrappers() const { return *marked_wrappers_; }
void Start() { TracePrologue(); }
void end() {
// Gracefully terminate tracing.
AdvanceTracing(
0,
v8::EmbedderHeapTracer::AdvanceTracingActions(
v8::EmbedderHeapTracer::ForceCompletionAction::FORCE_COMPLETION));
AbortTracing();
}
private:
size_t* marked_wrappers_; // Indirection required because of const override.
};
class InterceptingScriptWrappableMarkingVisitorScope
: public V8PerIsolateData::TemporaryScriptWrappableVisitorScope {
WTF_MAKE_NONCOPYABLE(InterceptingScriptWrappableMarkingVisitorScope);
STACK_ALLOCATED();
public:
InterceptingScriptWrappableMarkingVisitorScope(v8::Isolate* isolate)
: V8PerIsolateData::TemporaryScriptWrappableVisitorScope(
isolate,
std::unique_ptr<InterceptingScriptWrappableMarkingVisitor>(
new InterceptingScriptWrappableMarkingVisitor(isolate))) {
Visitor()->Start();
}
virtual ~InterceptingScriptWrappableMarkingVisitorScope() {
Visitor()->end();
}
InterceptingScriptWrappableMarkingVisitor* Visitor() {
return reinterpret_cast<InterceptingScriptWrappableMarkingVisitor*>(
CurrentVisitor());
}
};
} // namespace } // namespace
TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnUnmarkedContainer) { TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnUnmarkedContainer) {
...@@ -356,25 +378,12 @@ TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierTriggersOnMarkedContainer) { ...@@ -356,25 +378,12 @@ TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierTriggersOnMarkedContainer) {
CHECK_EQ(1u, raw_visitor->NumberOfMarkedWrappers()); CHECK_EQ(1u, raw_visitor->NumberOfMarkedWrappers());
} }
TEST(ScriptWrappableMarkingVisitorTest, VtableAtObjectStart) {
// This test makes sure that the subobject v8::EmbedderHeapTracer is placed
// at the start of a ScriptWrappableMarkingVisitor object. We do this to
// mitigate potential problems that could be caused by LTO when passing
// v8::EmbedderHeapTracer across the API boundary.
V8TestingScope scope;
std::unique_ptr<blink::ScriptWrappableMarkingVisitor> visitor(
new ScriptWrappableMarkingVisitor(scope.GetIsolate()));
CHECK_EQ(
static_cast<void*>(visitor.get()),
static_cast<void*>(dynamic_cast<v8::EmbedderHeapTracer*>(visitor.get())));
}
TEST(ScriptWrappableMarkingVisitor, WriteBarrierForScriptWrappable) { TEST(ScriptWrappableMarkingVisitor, WriteBarrierForScriptWrappable) {
// Regression test for crbug.com/702490. // Regression test for crbug.com/702490.
V8TestingScope scope; V8TestingScope scope;
InterceptingScriptWrappableMarkingVisitorScope visitor_scope( InterceptingScriptWrappableMarkingVisitorScope intercepting_scope(
scope.GetIsolate()); scope.GetIsolate());
auto* raw_visitor = visitor_scope.Visitor(); auto* raw_visitor = intercepting_scope.Visitor();
// Mark the ScriptWrappable. // Mark the ScriptWrappable.
DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::Create();
...@@ -396,9 +405,6 @@ TEST(ScriptWrappableMarkingVisitor, WriteBarrierForScriptWrappable) { ...@@ -396,9 +405,6 @@ TEST(ScriptWrappableMarkingVisitor, WriteBarrierForScriptWrappable) {
TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnHeapVectorSwap1) { TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnHeapVectorSwap1) {
V8TestingScope scope; V8TestingScope scope;
ScriptWrappableMarkingVisitor* visitor =
V8PerIsolateData::From(scope.GetIsolate())
->GetScriptWrappableMarkingVisitor();
HeapVector<DeathAwareScriptWrappable::Wrapper> vector1; HeapVector<DeathAwareScriptWrappable::Wrapper> vector1;
DeathAwareScriptWrappable* entry1 = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* entry1 = DeathAwareScriptWrappable::Create();
...@@ -407,22 +413,18 @@ TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnHeapVectorSwap1) { ...@@ -407,22 +413,18 @@ TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnHeapVectorSwap1) {
DeathAwareScriptWrappable* entry2 = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* entry2 = DeathAwareScriptWrappable::Create();
vector2.push_back(entry2); vector2.push_back(entry2);
visitor->TracePrologue(); InterceptingScriptWrappableMarkingVisitorScope intercepting_scope(
scope.GetIsolate());
ScriptWrappableMarkingVisitor* visitor = intercepting_scope.Visitor();
EXPECT_TRUE(visitor->MarkingDeque()->IsEmpty()); EXPECT_TRUE(visitor->MarkingDeque()->IsEmpty());
swap(vector1, vector2); swap(vector1, vector2);
EXPECT_TRUE(visitor->MarkingDequeContains(entry1)); EXPECT_TRUE(visitor->MarkingDequeContains(entry1));
EXPECT_TRUE(visitor->MarkingDequeContains(entry2)); EXPECT_TRUE(visitor->MarkingDequeContains(entry2));
visitor->AbortTracing();
} }
TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnHeapVectorSwap2) { TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnHeapVectorSwap2) {
V8TestingScope scope; V8TestingScope scope;
ScriptWrappableMarkingVisitor* visitor =
V8PerIsolateData::From(scope.GetIsolate())
->GetScriptWrappableMarkingVisitor();
HeapVector<DeathAwareScriptWrappable::Wrapper> vector1; HeapVector<DeathAwareScriptWrappable::Wrapper> vector1;
DeathAwareScriptWrappable* entry1 = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* entry1 = DeathAwareScriptWrappable::Create();
...@@ -431,16 +433,15 @@ TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnHeapVectorSwap2) { ...@@ -431,16 +433,15 @@ TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnHeapVectorSwap2) {
DeathAwareScriptWrappable* entry2 = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* entry2 = DeathAwareScriptWrappable::Create();
vector2.push_back(entry2); vector2.push_back(entry2);
visitor->TracePrologue(); InterceptingScriptWrappableMarkingVisitorScope intercepting_scope(
scope.GetIsolate());
ScriptWrappableMarkingVisitor* visitor = intercepting_scope.Visitor();
EXPECT_TRUE(visitor->MarkingDeque()->IsEmpty()); EXPECT_TRUE(visitor->MarkingDeque()->IsEmpty());
swap(vector1, vector2); swap(vector1, vector2);
// Only entry2 is held alive by TraceWrapperMember, so we only expect this // Only entry2 is held alive by TraceWrapperMember, so we only expect this
// barrier to fire. // barrier to fire.
EXPECT_TRUE(visitor->MarkingDequeContains(entry2)); EXPECT_TRUE(visitor->MarkingDequeContains(entry2));
visitor->AbortTracing();
} }
namespace { namespace {
...@@ -495,9 +496,6 @@ class Base : public blink::GarbageCollected<Base>, ...@@ -495,9 +496,6 @@ class Base : public blink::GarbageCollected<Base>,
TEST(ScriptWrappableMarkingVisitorTest, MixinTracing) { TEST(ScriptWrappableMarkingVisitorTest, MixinTracing) {
V8TestingScope scope; V8TestingScope scope;
ScriptWrappableMarkingVisitor* visitor =
V8PerIsolateData::From(scope.GetIsolate())
->GetScriptWrappableMarkingVisitor();
DeathAwareScriptWrappable* base_wrapper = DeathAwareScriptWrappable::Create(); DeathAwareScriptWrappable* base_wrapper = DeathAwareScriptWrappable::Create();
DeathAwareScriptWrappable* mixin_wrapper = DeathAwareScriptWrappable* mixin_wrapper =
...@@ -510,7 +508,9 @@ TEST(ScriptWrappableMarkingVisitorTest, MixinTracing) { ...@@ -510,7 +508,9 @@ TEST(ScriptWrappableMarkingVisitorTest, MixinTracing) {
// Make sure that mixin does not point to the object header. // Make sure that mixin does not point to the object header.
EXPECT_NE(static_cast<void*>(base), static_cast<void*>(mixin)); EXPECT_NE(static_cast<void*>(base), static_cast<void*>(mixin));
visitor->TracePrologue(); InterceptingScriptWrappableMarkingVisitorScope intercepting_scope(
scope.GetIsolate());
ScriptWrappableMarkingVisitor* visitor = intercepting_scope.Visitor();
EXPECT_TRUE(visitor->MarkingDeque()->IsEmpty()); EXPECT_TRUE(visitor->MarkingDeque()->IsEmpty());
...@@ -531,7 +531,6 @@ TEST(ScriptWrappableMarkingVisitorTest, MixinTracing) { ...@@ -531,7 +531,6 @@ TEST(ScriptWrappableMarkingVisitorTest, MixinTracing) {
HeapObjectHeader::FromPayload(mixin_wrapper)->IsWrapperHeaderMarked()); HeapObjectHeader::FromPayload(mixin_wrapper)->IsWrapperHeaderMarked());
mixin_handle = nullptr; mixin_handle = nullptr;
visitor->AbortTracing();
} }
} // namespace blink } // namespace blink
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
#include "third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h" #include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
#include "third_party/blink/renderer/platform/bindings/v8_private_property.h" #include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
#include "third_party/blink/renderer/platform/heap/v8_heap_controller.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/loader/fetch/access_control_status.h" #include "third_party/blink/renderer/platform/loader/fetch/access_control_status.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
...@@ -622,12 +623,11 @@ static void HostGetImportMetaProperties(v8::Local<v8::Context> context, ...@@ -622,12 +623,11 @@ static void HostGetImportMetaProperties(v8::Local<v8::Context> context,
static void InitializeV8Common(v8::Isolate* isolate) { static void InitializeV8Common(v8::Isolate* isolate) {
isolate->AddGCPrologueCallback(V8GCController::GcPrologue); isolate->AddGCPrologueCallback(V8GCController::GcPrologue);
isolate->AddGCEpilogueCallback(V8GCController::GcEpilogue); isolate->AddGCEpilogueCallback(V8GCController::GcEpilogue);
std::unique_ptr<ScriptWrappableMarkingVisitor> visitor( V8PerIsolateData::From(isolate)->SetV8HeapController(
new ScriptWrappableMarkingVisitor(isolate)); std::unique_ptr<V8HeapController>{
V8PerIsolateData::From(isolate)->SetScriptWrappableMarkingVisitor( new ScriptWrappableMarkingVisitor(isolate)});
std::move(visitor));
isolate->SetEmbedderHeapTracer( isolate->SetEmbedderHeapTracer(
V8PerIsolateData::From(isolate)->GetScriptWrappableMarkingVisitor()); V8PerIsolateData::From(isolate)->GetV8HeapController());
isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped); isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
......
...@@ -67,6 +67,7 @@ void ScriptWrappableMarkingVisitor::TraceEpilogue() { ...@@ -67,6 +67,7 @@ void ScriptWrappableMarkingVisitor::TraceEpilogue() {
} }
void ScriptWrappableMarkingVisitor::AbortTracing() { void ScriptWrappableMarkingVisitor::AbortTracing() {
CHECK(tracing_in_progress_);
CHECK(ThreadState::Current()); CHECK(ThreadState::Current());
should_cleanup_ = true; should_cleanup_ = true;
tracing_in_progress_ = false; tracing_in_progress_ = false;
...@@ -218,10 +219,12 @@ void ScriptWrappableMarkingVisitor::MarkWrapperHeader( ...@@ -218,10 +219,12 @@ void ScriptWrappableMarkingVisitor::MarkWrapperHeader(
void ScriptWrappableMarkingVisitor::WriteBarrier( void ScriptWrappableMarkingVisitor::WriteBarrier(
v8::Isolate* isolate, v8::Isolate* isolate,
const TraceWrapperV8Reference<v8::Value>& dst_object) { const TraceWrapperV8Reference<v8::Value>& dst_object) {
ScriptWrappableMarkingVisitor* visitor = CurrentVisitor(isolate); if (!ThreadState::IsAnyWrapperTracing() || dst_object.IsEmpty())
if (dst_object.IsEmpty() || !visitor->WrapperTracingInProgress())
return; return;
ScriptWrappableMarkingVisitor* visitor = CurrentVisitor(isolate);
if (!visitor->WrapperTracingInProgress())
return;
// Conservatively assume that the source object containing |dst_object| is // Conservatively assume that the source object containing |dst_object| is
// marked. // marked.
visitor->Trace(dst_object); visitor->Trace(dst_object);
...@@ -231,6 +234,9 @@ void ScriptWrappableMarkingVisitor::WriteBarrier( ...@@ -231,6 +234,9 @@ void ScriptWrappableMarkingVisitor::WriteBarrier(
v8::Isolate* isolate, v8::Isolate* isolate,
DOMWrapperMap<ScriptWrappable>* wrapper_map, DOMWrapperMap<ScriptWrappable>* wrapper_map,
ScriptWrappable* key) { ScriptWrappable* key) {
if (!ThreadState::IsAnyWrapperTracing())
return;
ScriptWrappableMarkingVisitor* visitor = CurrentVisitor(isolate); ScriptWrappableMarkingVisitor* visitor = CurrentVisitor(isolate);
if (!visitor->WrapperTracingInProgress()) if (!visitor->WrapperTracingInProgress())
return; return;
...@@ -301,24 +307,32 @@ void ScriptWrappableMarkingVisitor::InvalidateDeadObjectsInMarkingDeque() { ...@@ -301,24 +307,32 @@ void ScriptWrappableMarkingVisitor::InvalidateDeadObjectsInMarkingDeque() {
} }
} }
void ScriptWrappableMarkingVisitor::FinalizeAndCleanup() {
FinalizeTracing();
PerformCleanup();
}
void ScriptWrappableMarkingVisitor::InvalidateDeadObjectsInMarkingDeque( void ScriptWrappableMarkingVisitor::InvalidateDeadObjectsInMarkingDeque(
v8::Isolate* isolate) { v8::Isolate* isolate) {
ScriptWrappableMarkingVisitor* script_wrappable_visitor = ScriptWrappableMarkingVisitor* script_wrappable_visitor =
V8PerIsolateData::From(isolate)->GetScriptWrappableMarkingVisitor(); static_cast<ScriptWrappableMarkingVisitor*>(
V8PerIsolateData::From(isolate)->GetV8HeapController());
if (script_wrappable_visitor) if (script_wrappable_visitor)
script_wrappable_visitor->InvalidateDeadObjectsInMarkingDeque(); script_wrappable_visitor->InvalidateDeadObjectsInMarkingDeque();
} }
void ScriptWrappableMarkingVisitor::PerformCleanup(v8::Isolate* isolate) { void ScriptWrappableMarkingVisitor::PerformCleanup(v8::Isolate* isolate) {
ScriptWrappableMarkingVisitor* script_wrappable_visitor = ScriptWrappableMarkingVisitor* script_wrappable_visitor =
V8PerIsolateData::From(isolate)->GetScriptWrappableMarkingVisitor(); static_cast<ScriptWrappableMarkingVisitor*>(
V8PerIsolateData::From(isolate)->GetV8HeapController());
if (script_wrappable_visitor) if (script_wrappable_visitor)
script_wrappable_visitor->PerformCleanup(); script_wrappable_visitor->PerformCleanup();
} }
ScriptWrappableMarkingVisitor* ScriptWrappableMarkingVisitor::CurrentVisitor( ScriptWrappableMarkingVisitor* ScriptWrappableMarkingVisitor::CurrentVisitor(
v8::Isolate* isolate) { v8::Isolate* isolate) {
return V8PerIsolateData::From(isolate)->GetScriptWrappableMarkingVisitor(); return static_cast<ScriptWrappableMarkingVisitor*>(
V8PerIsolateData::From(isolate)->GetV8HeapController());
} }
bool ScriptWrappableMarkingVisitor::MarkingDequeContains(void* needle) { bool ScriptWrappableMarkingVisitor::MarkingDequeContains(void* needle) {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/platform/bindings/script_wrappable_visitor.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable_visitor.h"
#include "third_party/blink/renderer/platform/heap/heap_page.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/threading_traits.h"
#include "third_party/blink/renderer/platform/heap/v8_heap_controller.h"
#include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/deque.h" #include "third_party/blink/renderer/platform/wtf/deque.h"
#include "third_party/blink/renderer/platform/wtf/time.h" #include "third_party/blink/renderer/platform/wtf/time.h"
...@@ -29,8 +30,8 @@ class TraceWrapperV8Reference; ...@@ -29,8 +30,8 @@ class TraceWrapperV8Reference;
// reachable wrappers. V8 calls this visitor during its garbage collection, // reachable wrappers. V8 calls this visitor during its garbage collection,
// see v8::EmbedderHeapTracer. // see v8::EmbedderHeapTracer.
class PLATFORM_EXPORT ScriptWrappableMarkingVisitor class PLATFORM_EXPORT ScriptWrappableMarkingVisitor
: public v8::EmbedderHeapTracer, : public ScriptWrappableVisitor,
public ScriptWrappableVisitor { public V8HeapController {
DISALLOW_IMPLICIT_CONSTRUCTORS(ScriptWrappableMarkingVisitor); DISALLOW_IMPLICIT_CONSTRUCTORS(ScriptWrappableMarkingVisitor);
public: public:
...@@ -69,7 +70,6 @@ class PLATFORM_EXPORT ScriptWrappableMarkingVisitor ...@@ -69,7 +70,6 @@ class PLATFORM_EXPORT ScriptWrappableMarkingVisitor
bool WrapperTracingInProgress() const { return tracing_in_progress_; } bool WrapperTracingInProgress() const { return tracing_in_progress_; }
// v8::EmbedderHeapTracer interface. // v8::EmbedderHeapTracer interface.
void TracePrologue() override; void TracePrologue() override;
void RegisterV8References(const std::vector<std::pair<void*, void*>>& void RegisterV8References(const std::vector<std::pair<void*, void*>>&
internal_fields_of_potential_wrappers) override; internal_fields_of_potential_wrappers) override;
...@@ -81,8 +81,10 @@ class PLATFORM_EXPORT ScriptWrappableMarkingVisitor ...@@ -81,8 +81,10 @@ class PLATFORM_EXPORT ScriptWrappableMarkingVisitor
void EnterFinalPause() override; void EnterFinalPause() override;
size_t NumberOfWrappersToTrace() override; size_t NumberOfWrappersToTrace() override;
// ScriptWrappableVisitor interface. // V8HeapController interface.
void FinalizeAndCleanup() override;
// ScriptWrappableVisitor interface.
void Visit(const TraceWrapperV8Reference<v8::Value>&) override; void Visit(const TraceWrapperV8Reference<v8::Value>&) override;
void VisitWithWrappers(void*, TraceDescriptor) override; void VisitWithWrappers(void*, TraceDescriptor) override;
void Visit(DOMWrapperMap<ScriptWrappable>*, void Visit(DOMWrapperMap<ScriptWrappable>*,
......
...@@ -114,13 +114,12 @@ inline void V8DOMWrapper::SetNativeInfoInternal( ...@@ -114,13 +114,12 @@ inline void V8DOMWrapper::SetNativeInfoInternal(
wrapper->SetAlignedPointerInInternalFields(base::size(indices), indices, wrapper->SetAlignedPointerInInternalFields(base::size(indices), indices,
values); values);
auto* per_isolate_data = V8PerIsolateData::From(isolate); auto* per_isolate_data = V8PerIsolateData::From(isolate);
// We notify ScriptWrappableVisitor about the new wrapper association, // We notify V8HeapController about the new wrapper association,
// so the visitor can make sure to trace the association (in case it is // so the controller can make sure to trace the association (in case it is
// currently tracing). Because of some optimizations, V8 will not // currently tracing). Because of some optimizations, V8 will not
// necessarily detect wrappers created during its incremental marking. // necessarily detect wrappers created during its incremental marking.
per_isolate_data->GetScriptWrappableMarkingVisitor()->RegisterV8Reference( per_isolate_data->GetV8HeapController()->RegisterV8References({std::make_pair(
std::make_pair(const_cast<WrapperTypeInfo*>(wrapper_type_info), const_cast<WrapperTypeInfo*>(wrapper_type_info), wrappable)});
wrappable));
} }
inline void V8DOMWrapper::ClearNativeInfo(v8::Isolate* isolate, inline void V8DOMWrapper::ClearNativeInfo(v8::Isolate* isolate,
......
...@@ -153,9 +153,8 @@ void V8PerIsolateData::WillBeDestroyed(v8::Isolate* isolate) { ...@@ -153,9 +153,8 @@ void V8PerIsolateData::WillBeDestroyed(v8::Isolate* isolate) {
// Detach V8's garbage collector. // Detach V8's garbage collector.
isolate->SetEmbedderHeapTracer(nullptr); isolate->SetEmbedderHeapTracer(nullptr);
if (data->script_wrappable_visitor_->WrapperTracingInProgress()) data->v8_heap_controller_->FinalizeAndCleanup();
data->script_wrappable_visitor_->AbortTracing(); data->v8_heap_controller_.reset();
data->script_wrappable_visitor_.reset();
} }
// destroy() clear things that should be cleared after ThreadState::detach() // destroy() clear things that should be cleared after ThreadState::detach()
...@@ -368,16 +367,4 @@ void V8PerIsolateData::AddActiveScriptWrappable( ...@@ -368,16 +367,4 @@ void V8PerIsolateData::AddActiveScriptWrappable(
active_script_wrappables_->insert(wrappable); active_script_wrappables_->insert(wrappable);
} }
void V8PerIsolateData::TemporaryScriptWrappableVisitorScope::
SwapWithV8PerIsolateDataVisitor(
std::unique_ptr<ScriptWrappableMarkingVisitor>& visitor) {
ScriptWrappableMarkingVisitor* current = CurrentVisitor();
if (current)
ScriptWrappableMarkingVisitor::PerformCleanup(isolate_);
V8PerIsolateData::From(isolate_)->script_wrappable_visitor_.swap(
saved_visitor_);
isolate_->SetEmbedderHeapTracer(CurrentVisitor());
}
} // namespace blink } // namespace blink
...@@ -33,9 +33,9 @@ ...@@ -33,9 +33,9 @@
#include "gin/public/isolate_holder.h" #include "gin/public/isolate_holder.h"
#include "third_party/blink/renderer/platform/bindings/runtime_call_stats.h" #include "third_party/blink/renderer/platform/bindings/runtime_call_stats.h"
#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h" #include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h"
#include "third_party/blink/renderer/platform/bindings/v8_global_value_map.h" #include "third_party/blink/renderer/platform/bindings/v8_global_value_map.h"
#include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/v8_heap_controller.h"
#include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/forward.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_map.h"
...@@ -200,41 +200,19 @@ class PLATFORM_EXPORT V8PerIsolateData { ...@@ -200,41 +200,19 @@ class PLATFORM_EXPORT V8PerIsolateData {
return active_script_wrappables_.Get(); return active_script_wrappables_.Get();
} }
class PLATFORM_EXPORT TemporaryScriptWrappableVisitorScope { void SetV8HeapController(std::unique_ptr<V8HeapController> controller) {
WTF_MAKE_NONCOPYABLE(TemporaryScriptWrappableVisitorScope); DCHECK(!v8_heap_controller_);
STACK_ALLOCATED(); v8_heap_controller_ = std::move(controller);
}
public:
TemporaryScriptWrappableVisitorScope(
v8::Isolate* isolate,
std::unique_ptr<ScriptWrappableMarkingVisitor> visitor)
: isolate_(isolate), saved_visitor_(std::move(visitor)) {
SwapWithV8PerIsolateDataVisitor(saved_visitor_);
}
~TemporaryScriptWrappableVisitorScope() {
SwapWithV8PerIsolateDataVisitor(saved_visitor_);
}
inline ScriptWrappableMarkingVisitor* CurrentVisitor() {
return V8PerIsolateData::From(isolate_)
->GetScriptWrappableMarkingVisitor();
}
private:
void SwapWithV8PerIsolateDataVisitor(
std::unique_ptr<ScriptWrappableMarkingVisitor>&);
v8::Isolate* isolate_;
std::unique_ptr<ScriptWrappableMarkingVisitor> saved_visitor_;
};
void SetScriptWrappableMarkingVisitor( V8HeapController* GetV8HeapController() const {
std::unique_ptr<ScriptWrappableMarkingVisitor> visitor) { return v8_heap_controller_.get();
script_wrappable_visitor_ = std::move(visitor);
} }
ScriptWrappableMarkingVisitor* GetScriptWrappableMarkingVisitor() {
return script_wrappable_visitor_.get(); void SwapV8HeapController(std::unique_ptr<V8HeapController>& other) {
v8_heap_controller_.swap(other);
} }
int IsNearV8HeapLimitHandled() { return handled_near_v8_heap_limit_; } int IsNearV8HeapLimitHandled() { return handled_near_v8_heap_limit_; }
void HandledNearV8HeapLimit() { handled_near_v8_heap_limit_ = true; } void HandledNearV8HeapLimit() { handled_near_v8_heap_limit_ = true; }
...@@ -306,7 +284,8 @@ class PLATFORM_EXPORT V8PerIsolateData { ...@@ -306,7 +284,8 @@ class PLATFORM_EXPORT V8PerIsolateData {
std::unique_ptr<Data> thread_debugger_; std::unique_ptr<Data> thread_debugger_;
Persistent<ActiveScriptWrappableSet> active_script_wrappables_; Persistent<ActiveScriptWrappableSet> active_script_wrappables_;
std::unique_ptr<ScriptWrappableMarkingVisitor> script_wrappable_visitor_;
std::unique_ptr<V8HeapController> v8_heap_controller_;
RuntimeCallStats runtime_call_stats_; RuntimeCallStats runtime_call_stats_;
bool handled_near_v8_heap_limit_; bool handled_near_v8_heap_limit_;
......
...@@ -79,6 +79,7 @@ blink_platform_sources("heap") { ...@@ -79,6 +79,7 @@ blink_platform_sources("heap") {
"thread_state.h", "thread_state.h",
"threading_traits.h", "threading_traits.h",
"trace_traits.h", "trace_traits.h",
"v8_heap_controller.h",
"visitor.h", "visitor.h",
"worklist.h", "worklist.h",
] ]
......
// 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_V8_HEAP_CONTROLLER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_HEAP_CONTROLLER_H_
#include "v8/include/v8.h"
namespace blink {
// Common interface for all V8 heap tracers used in Blink.
class V8HeapController : public v8::EmbedderHeapTracer {
public:
~V8HeapController() override = default;
virtual void FinalizeAndCleanup() = 0;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_V8_HEAP_CONTROLLER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment