Commit bde44e52 authored by Daniel Cheng's avatar Daniel Cheng Committed by Chromium LUCI CQ

Migrate V8PerContextData to the Oilpan heap.

Bug: 1013149
Change-Id: I776f91f8fec4623af9735b63060545ab473956e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2617354
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#842225}
parent c719b4ab
...@@ -17,7 +17,7 @@ ScriptState::ScriptState(v8::Local<v8::Context> context, ...@@ -17,7 +17,7 @@ ScriptState::ScriptState(v8::Local<v8::Context> context,
: isolate_(context->GetIsolate()), : isolate_(context->GetIsolate()),
context_(isolate_, context), context_(isolate_, context),
world_(std::move(world)), world_(std::move(world)),
per_context_data_(std::make_unique<V8PerContextData>(context)), per_context_data_(MakeGarbageCollected<V8PerContextData>(context)),
reference_from_v8_context_(PERSISTENT_FROM_HERE, this) { reference_from_v8_context_(PERSISTENT_FROM_HERE, this) {
DCHECK(world_); DCHECK(world_);
context_.SetWeak(this, &OnV8ContextCollectedCallback); context_.SetWeak(this, &OnV8ContextCollectedCallback);
...@@ -34,12 +34,17 @@ ScriptState::~ScriptState() { ...@@ -34,12 +34,17 @@ ScriptState::~ScriptState() {
RendererResourceCoordinator::Get()->OnScriptStateDestroyed(this); RendererResourceCoordinator::Get()->OnScriptStateDestroyed(this);
} }
void ScriptState::Trace(Visitor* visitor) const {
visitor->Trace(per_context_data_);
}
void ScriptState::DetachGlobalObject() { void ScriptState::DetachGlobalObject() {
DCHECK(!context_.IsEmpty()); DCHECK(!context_.IsEmpty());
GetContext()->DetachGlobal(); GetContext()->DetachGlobal();
} }
void ScriptState::DisposePerContextData() { void ScriptState::DisposePerContextData() {
per_context_data_->Dispose();
per_context_data_ = nullptr; per_context_data_ = nullptr;
InstanceCounters::IncrementCounter( InstanceCounters::IncrementCounter(
InstanceCounters::kDetachedScriptStateCounter); InstanceCounters::kDetachedScriptStateCounter);
......
...@@ -130,7 +130,7 @@ class PLATFORM_EXPORT ScriptState final : public GarbageCollected<ScriptState> { ...@@ -130,7 +130,7 @@ class PLATFORM_EXPORT ScriptState final : public GarbageCollected<ScriptState> {
ExecutionContext* execution_context); ExecutionContext* execution_context);
~ScriptState(); ~ScriptState();
void Trace(Visitor*) const {} void Trace(Visitor*) const;
static ScriptState* Current(v8::Isolate* isolate) { // DEPRECATED static ScriptState* Current(v8::Isolate* isolate) { // DEPRECATED
return From(isolate->GetCurrentContext()); return From(isolate->GetCurrentContext());
...@@ -190,7 +190,7 @@ class PLATFORM_EXPORT ScriptState final : public GarbageCollected<ScriptState> { ...@@ -190,7 +190,7 @@ class PLATFORM_EXPORT ScriptState final : public GarbageCollected<ScriptState> {
} }
void DetachGlobalObject(); void DetachGlobalObject();
V8PerContextData* PerContextData() const { return per_context_data_.get(); } V8PerContextData* PerContextData() const { return per_context_data_.Get(); }
void DisposePerContextData(); void DisposePerContextData();
// This method is expected to be called only from // This method is expected to be called only from
...@@ -217,7 +217,7 @@ class PLATFORM_EXPORT ScriptState final : public GarbageCollected<ScriptState> { ...@@ -217,7 +217,7 @@ class PLATFORM_EXPORT ScriptState final : public GarbageCollected<ScriptState> {
// So you must explicitly clear the std::unique_ptr by calling // So you must explicitly clear the std::unique_ptr by calling
// disposePerContextData() once you no longer need V8PerContextData. // disposePerContextData() once you no longer need V8PerContextData.
// Otherwise, the v8::Context will leak. // Otherwise, the v8::Context will leak.
std::unique_ptr<V8PerContextData> per_context_data_; Member<V8PerContextData> per_context_data_;
// v8::Context has an internal field to this ScriptState* as a raw pointer, // v8::Context has an internal field to this ScriptState* as a raw pointer,
// which is out of scope of Blink GC, but it must be a strong reference. We // which is out of scope of Blink GC, but it must be a strong reference. We
......
...@@ -46,21 +46,15 @@ namespace blink { ...@@ -46,21 +46,15 @@ namespace blink {
namespace { namespace {
constexpr char kWrapperBoilerplatesLabel[] =
"V8PerContextData::wrapper_boilerplates_";
constexpr char kConstructorMapLabel[] = "V8PerContextData::constructor_map_";
constexpr char kContextLabel[] = "V8PerContextData::context_"; constexpr char kContextLabel[] = "V8PerContextData::context_";
} // namespace } // namespace
V8PerContextData::V8PerContextData(v8::Local<v8::Context> context) V8PerContextData::V8PerContextData(v8::Local<v8::Context> context)
: isolate_(context->GetIsolate()), : isolate_(context->GetIsolate()),
wrapper_boilerplates_(isolate_, kWrapperBoilerplatesLabel),
constructor_map_(isolate_, kConstructorMapLabel),
context_holder_(std::make_unique<gin::ContextHolder>(isolate_)), context_holder_(std::make_unique<gin::ContextHolder>(isolate_)),
context_(isolate_, context), context_(isolate_, context),
activity_logger_(nullptr), activity_logger_(nullptr) {
data_map_(MakeGarbageCollected<DataMap>()) {
context_holder_->SetContext(context); context_holder_->SetContext(context);
context_.Get().AnnotateStrongRetainer(kContextLabel); context_.Get().AnnotateStrongRetainer(kContextLabel);
...@@ -77,24 +71,47 @@ V8PerContextData::~V8PerContextData() { ...@@ -77,24 +71,47 @@ V8PerContextData::~V8PerContextData() {
} }
} }
void V8PerContextData::Dispose() {
// These fields are not traced by the garbage collector and could contain
// strong GC roots that prevent `this` from otherwise being collected, so
// explicitly break any potential cycles in the ownership graph now.
context_holder_ = nullptr;
if (!context_.IsEmpty())
context_.SetPhantom();
if (!private_custom_element_definition_id_.IsEmpty())
private_custom_element_definition_id_.SetPhantom();
}
void V8PerContextData::Trace(Visitor* visitor) const {
visitor->Trace(wrapper_boilerplates_);
visitor->Trace(constructor_map_);
visitor->Trace(data_map_);
}
V8PerContextData* V8PerContextData::From(v8::Local<v8::Context> context) { V8PerContextData* V8PerContextData::From(v8::Local<v8::Context> context) {
return ScriptState::From(context)->PerContextData(); return ScriptState::From(context)->PerContextData();
} }
v8::Local<v8::Object> V8PerContextData::CreateWrapperFromCacheSlowCase( v8::Local<v8::Object> V8PerContextData::CreateWrapperFromCacheSlowCase(
const WrapperTypeInfo* type) { const WrapperTypeInfo* type) {
DCHECK(!wrapper_boilerplates_.Contains(type));
v8::Context::Scope scope(GetContext()); v8::Context::Scope scope(GetContext());
v8::Local<v8::Function> interface_object = ConstructorForType(type); v8::Local<v8::Function> interface_object = ConstructorForType(type);
CHECK(!interface_object.IsEmpty()); CHECK(!interface_object.IsEmpty());
v8::Local<v8::Object> instance_template = v8::Local<v8::Object> instance_template =
V8ObjectConstructor::NewInstance(isolate_, interface_object) V8ObjectConstructor::NewInstance(isolate_, interface_object)
.ToLocalChecked(); .ToLocalChecked();
wrapper_boilerplates_.Set(type, instance_template);
TraceWrapperV8Reference<v8::Object> traced_wrapper;
traced_wrapper.Set(isolate_, instance_template);
wrapper_boilerplates_.insert(type, traced_wrapper);
return instance_template->Clone(); return instance_template->Clone();
} }
v8::Local<v8::Function> V8PerContextData::ConstructorForTypeSlowCase( v8::Local<v8::Function> V8PerContextData::ConstructorForTypeSlowCase(
const WrapperTypeInfo* type) { const WrapperTypeInfo* type) {
DCHECK(!constructor_map_.Contains(type));
v8::Local<v8::Context> context = GetContext(); v8::Local<v8::Context> context = GetContext();
v8::Context::Scope scope(context); v8::Context::Scope scope(context);
...@@ -109,7 +126,10 @@ v8::Local<v8::Function> V8PerContextData::ConstructorForTypeSlowCase( ...@@ -109,7 +126,10 @@ v8::Local<v8::Function> V8PerContextData::ConstructorForTypeSlowCase(
type, context, world, isolate_, parent_interface_object, type, context, world, isolate_, parent_interface_object,
V8ObjectConstructor::CreationMode::kInstallConditionalFeatures); V8ObjectConstructor::CreationMode::kInstallConditionalFeatures);
constructor_map_.Set(type, interface_object); TraceWrapperV8Reference<v8::Function> traced_wrapper;
traced_wrapper.Set(isolate_, interface_object);
constructor_map_.insert(type, traced_wrapper);
return interface_object; return interface_object;
} }
...@@ -130,26 +150,28 @@ bool V8PerContextData::GetExistingConstructorAndPrototypeForType( ...@@ -130,26 +150,28 @@ bool V8PerContextData::GetExistingConstructorAndPrototypeForType(
const WrapperTypeInfo* type, const WrapperTypeInfo* type,
v8::Local<v8::Object>* prototype_object, v8::Local<v8::Object>* prototype_object,
v8::Local<v8::Function>* interface_object) { v8::Local<v8::Function>* interface_object) {
*interface_object = constructor_map_.Get(type); auto it = constructor_map_.find(type);
if (interface_object->IsEmpty()) { if (it == constructor_map_.end()) {
*prototype_object = v8::Local<v8::Object>(); interface_object->Clear();
prototype_object->Clear();
return false; return false;
} }
*interface_object = it->value.NewLocal(isolate_);
*prototype_object = PrototypeForType(type); *prototype_object = PrototypeForType(type);
DCHECK(!prototype_object->IsEmpty()); DCHECK(!prototype_object->IsEmpty());
return true; return true;
} }
void V8PerContextData::AddData(const char* key, Data* data) { void V8PerContextData::AddData(const char* key, Data* data) {
data_map_->Set(key, data); data_map_.Set(key, data);
} }
void V8PerContextData::ClearData(const char* key) { void V8PerContextData::ClearData(const char* key) {
data_map_->erase(key); data_map_.erase(key);
} }
V8PerContextData::Data* V8PerContextData::GetData(const char* key) { V8PerContextData::Data* V8PerContextData::GetData(const char* key) {
return data_map_->at(key); return data_map_.at(key);
} }
} // namespace blink } // namespace blink
...@@ -36,11 +36,11 @@ ...@@ -36,11 +36,11 @@
#include "gin/public/context_holder.h" #include "gin/public/context_holder.h"
#include "gin/public/gin_embedders.h" #include "gin/public/gin_embedders.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/v8_global_value_map.h" #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.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/heap.h"
#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/heap/persistent.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/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
...@@ -55,9 +55,8 @@ struct WrapperTypeInfo; ...@@ -55,9 +55,8 @@ struct WrapperTypeInfo;
// Used to hold data that is associated with a single v8::Context object, and // Used to hold data that is associated with a single v8::Context object, and
// has a 1:1 relationship with v8::Context. // has a 1:1 relationship with v8::Context.
class PLATFORM_EXPORT V8PerContextData final { class PLATFORM_EXPORT V8PerContextData final
USING_FAST_MALLOC(V8PerContextData); : public GarbageCollected<V8PerContextData> {
public: public:
explicit V8PerContextData(v8::Local<v8::Context>); explicit V8PerContextData(v8::Local<v8::Context>);
...@@ -65,23 +64,27 @@ class PLATFORM_EXPORT V8PerContextData final { ...@@ -65,23 +64,27 @@ class PLATFORM_EXPORT V8PerContextData final {
~V8PerContextData(); ~V8PerContextData();
void Trace(Visitor* visitor) const;
void Dispose();
v8::Local<v8::Context> GetContext() { return context_.NewLocal(isolate_); } v8::Local<v8::Context> GetContext() { return context_.NewLocal(isolate_); }
// To create JS Wrapper objects, we create a cache of a 'boiler plate' // To create JS Wrapper objects, we create a cache of a 'boiler plate'
// object, and then simply Clone that object each time we need a new one. // object, and then simply Clone that object each time we need a new one.
// This is faster than going through the full object creation process. // This is faster than going through the full object creation process.
v8::Local<v8::Object> CreateWrapperFromCache(const WrapperTypeInfo* type) { v8::Local<v8::Object> CreateWrapperFromCache(const WrapperTypeInfo* type) {
v8::Local<v8::Object> boilerplate = wrapper_boilerplates_.Get(type); auto it = wrapper_boilerplates_.find(type);
return !boilerplate.IsEmpty() ? boilerplate->Clone() return it != wrapper_boilerplates_.end()
: CreateWrapperFromCacheSlowCase(type); ? it->value.Get()->Clone()
: CreateWrapperFromCacheSlowCase(type);
} }
// Returns the interface object that is appropriately initialized (e.g. // Returns the interface object that is appropriately initialized (e.g.
// context-dependent properties are installed). // context-dependent properties are installed).
v8::Local<v8::Function> ConstructorForType(const WrapperTypeInfo* type) { v8::Local<v8::Function> ConstructorForType(const WrapperTypeInfo* type) {
v8::Local<v8::Function> interface_object = constructor_map_.Get(type); auto it = constructor_map_.find(type);
return (!interface_object.IsEmpty()) ? interface_object return it != constructor_map_.end() ? it->value.NewLocal(isolate_)
: ConstructorForTypeSlowCase(type); : ConstructorForTypeSlowCase(type);
} }
v8::Local<v8::Object> PrototypeForType(const WrapperTypeInfo*); v8::Local<v8::Object> PrototypeForType(const WrapperTypeInfo*);
...@@ -127,13 +130,15 @@ class PLATFORM_EXPORT V8PerContextData final { ...@@ -127,13 +130,15 @@ class PLATFORM_EXPORT V8PerContextData final {
v8::Local<v8::Object> CreateWrapperFromCacheSlowCase(const WrapperTypeInfo*); v8::Local<v8::Object> CreateWrapperFromCacheSlowCase(const WrapperTypeInfo*);
v8::Local<v8::Function> ConstructorForTypeSlowCase(const WrapperTypeInfo*); v8::Local<v8::Function> ConstructorForTypeSlowCase(const WrapperTypeInfo*);
v8::Isolate* isolate_; v8::Isolate* const isolate_;
// For each possible type of wrapper, we keep a boilerplate object. // For each possible type of wrapper, we keep a boilerplate object.
// The boilerplate is used to create additional wrappers of the same type. // The boilerplate is used to create additional wrappers of the same type.
V8GlobalValueMap<const WrapperTypeInfo*, v8::Object> wrapper_boilerplates_; HeapHashMap<const WrapperTypeInfo*, TraceWrapperV8Reference<v8::Object>>
wrapper_boilerplates_;
V8GlobalValueMap<const WrapperTypeInfo*, v8::Function> constructor_map_; HeapHashMap<const WrapperTypeInfo*, TraceWrapperV8Reference<v8::Function>>
constructor_map_;
std::unique_ptr<gin::ContextHolder> context_holder_; std::unique_ptr<gin::ContextHolder> context_holder_;
...@@ -145,7 +150,7 @@ class PLATFORM_EXPORT V8PerContextData final { ...@@ -145,7 +150,7 @@ class PLATFORM_EXPORT V8PerContextData final {
V8DOMActivityLogger* activity_logger_; V8DOMActivityLogger* activity_logger_;
using DataMap = HeapHashMap<const char*, Member<Data>>; using DataMap = HeapHashMap<const char*, Member<Data>>;
Persistent<DataMap> data_map_; DataMap data_map_;
DISALLOW_COPY_AND_ASSIGN(V8PerContextData); DISALLOW_COPY_AND_ASSIGN(V8PerContextData);
}; };
......
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