mirror of https://github.com/electron/electron
1232 lines
56 KiB
Diff
1232 lines
56 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Michael Lippautz <mlippautz@chromium.org>
|
|
Date: Tue, 30 Jan 2024 16:05:33 +0000
|
|
Subject: bindings: Refactor DOMDataStore
|
|
|
|
Make DOMDataStore the entity that can set wrapper references in all
|
|
worlds, using inline storage where supported and otherwise fall back
|
|
to the wrapper map.
|
|
|
|
This is a refactoring that does not change any semantics but should
|
|
make fast paths more obvious.
|
|
|
|
Bug: chromium:1520621
|
|
Change-Id: Id8fd21d7598d818d3e820cc728f7f9357c1ec2d6
|
|
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5245546
|
|
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
|
|
Reviewed-by: Kentaro Hara <haraken@chromium.org>
|
|
Cr-Commit-Position: refs/heads/main@{#1253935}
|
|
|
|
diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
|
|
index c15355bf971294b99e9bb484faad84ff760398eb..770fd0a15c4a3521315b70e46a3646e361432508 100644
|
|
--- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
|
|
+++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
|
|
@@ -122,9 +122,17 @@ void LocalWindowProxy::DisposeContext(Lifecycle next_status,
|
|
ToScriptWrappable(global->GetPrototype().As<v8::Object>()));
|
|
}
|
|
V8DOMWrapper::ClearNativeInfo(GetIsolate(), global);
|
|
- DOMWrapperWorld::ClearWrapperIfEqualTo(GetFrame()->DomWindow(), global);
|
|
+ script_state_->World().DomDataStore().ClearIfEqualTo(
|
|
+ GetFrame()->DomWindow(), global);
|
|
+#if DCHECK_IS_ON()
|
|
+ Vector<scoped_refptr<DOMWrapperWorld>> all_worlds;
|
|
+ DOMWrapperWorld::AllWorldsInIsolate(script_state_->GetIsolate(),
|
|
+ all_worlds);
|
|
+ for (auto& world : all_worlds) {
|
|
+ DCHECK(!world->DomDataStore().EqualTo(GetFrame()->DomWindow(), global));
|
|
+ }
|
|
+#endif // DCHECK_IS_ON()
|
|
script_state_->DetachGlobalObject();
|
|
-
|
|
#if DCHECK_IS_ON()
|
|
DidDetachGlobalObject();
|
|
#endif
|
|
@@ -534,7 +542,7 @@ void LocalWindowProxy::NamedItemAdded(HTMLDocument* document,
|
|
|
|
ScriptState::Scope scope(script_state_);
|
|
v8::Local<v8::Object> document_wrapper =
|
|
- world_->DomDataStore().Get(document, GetIsolate());
|
|
+ world_->DomDataStore().Get(GetIsolate(), document).ToLocalChecked();
|
|
// When a non-configurable own property (e.g. unforgeable attribute) already
|
|
// exists, `SetAccessor` fails and throws. Ignore the exception because own
|
|
// properties have priority over named properties.
|
|
@@ -561,7 +569,7 @@ void LocalWindowProxy::NamedItemRemoved(HTMLDocument* document,
|
|
return;
|
|
ScriptState::Scope scope(script_state_);
|
|
v8::Local<v8::Object> document_wrapper =
|
|
- world_->DomDataStore().Get(document, GetIsolate());
|
|
+ world_->DomDataStore().Get(GetIsolate(), document).ToLocalChecked();
|
|
document_wrapper
|
|
->Delete(GetIsolate()->GetCurrentContext(), V8String(GetIsolate(), name))
|
|
.ToChecked();
|
|
diff --git a/third_party/blink/renderer/bindings/core/v8/observable_array_exotic_object_impl.cc b/third_party/blink/renderer/bindings/core/v8/observable_array_exotic_object_impl.cc
|
|
index d53c06ed5d436bd22898470c3de297d80e6ebae3..f1bbf27750c6d269a3d02f08348d78a2bd4ee375 100644
|
|
--- a/third_party/blink/renderer/bindings/core/v8/observable_array_exotic_object_impl.cc
|
|
+++ b/third_party/blink/renderer/bindings/core/v8/observable_array_exotic_object_impl.cc
|
|
@@ -64,7 +64,7 @@ ObservableArrayExoticObjectImpl::ObservableArrayExoticObjectImpl(
|
|
v8::Local<v8::Value> ObservableArrayExoticObjectImpl::Wrap(
|
|
ScriptState* script_state) {
|
|
v8::Isolate* isolate = script_state->GetIsolate();
|
|
- DCHECK(!DOMDataStore::ContainsWrapper(this, isolate));
|
|
+ DCHECK(!DOMDataStore::ContainsWrapper(isolate, this));
|
|
|
|
// The proxy target object must be a JS Array (v8::Array) by definition.
|
|
// Especially it's important that IsArray(proxy) evaluates to true.
|
|
diff --git a/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
|
|
index 3caa238f10adc7294cac000aedf326d097758362..89211fcb8cb37549446ea9bbb14e1ae3a21afe1c 100644
|
|
--- a/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
|
|
+++ b/third_party/blink/renderer/bindings/core/v8/remote_window_proxy.cc
|
|
@@ -75,10 +75,16 @@ void RemoteWindowProxy::DisposeContext(Lifecycle next_status,
|
|
v8::HandleScope handle_scope(GetIsolate());
|
|
v8::Local<v8::Object> global = global_proxy_.Get(GetIsolate());
|
|
V8DOMWrapper::ClearNativeInfo(GetIsolate(), global);
|
|
- DOMWrapperWorld::ClearWrapperIfEqualTo(GetFrame()->DomWindow(), global);
|
|
+ world_->DomDataStore().ClearIfEqualTo(GetFrame()->DomWindow(), global);
|
|
#if DCHECK_IS_ON()
|
|
+ Vector<scoped_refptr<DOMWrapperWorld>> all_worlds;
|
|
+ DOMWrapperWorld::AllWorldsInIsolate(GetIsolate(), all_worlds);
|
|
+ for (auto& world : all_worlds) {
|
|
+ DCHECK(!world->DomDataStore().EqualTo(GetFrame()->DomWindow(), global));
|
|
+ }
|
|
+
|
|
DidDetachGlobalObject();
|
|
-#endif
|
|
+#endif // DCHECK_IS_ON()
|
|
}
|
|
|
|
DCHECK_EQ(lifecycle_, Lifecycle::kContextIsInitialized);
|
|
diff --git a/third_party/blink/renderer/bindings/core/v8/to_v8_traits.h b/third_party/blink/renderer/bindings/core/v8/to_v8_traits.h
|
|
index 30ddc5b219c7d6d7630557e90d209a90bd0e00cd..45f4c36c20cc2db00ff6769c08271e629de99634 100644
|
|
--- a/third_party/blink/renderer/bindings/core/v8/to_v8_traits.h
|
|
+++ b/third_party/blink/renderer/bindings/core/v8/to_v8_traits.h
|
|
@@ -240,9 +240,10 @@ namespace bindings {
|
|
ScriptState* script_state,
|
|
ScriptWrappable* script_wrappable) {
|
|
CHECK(script_wrappable);
|
|
- v8::Local<v8::Value> wrapper =
|
|
- DOMDataStore::GetWrapper(script_wrappable, script_state->GetIsolate());
|
|
- if (LIKELY(!wrapper.IsEmpty())) {
|
|
+ v8::Local<v8::Object> wrapper;
|
|
+ if (LIKELY(
|
|
+ DOMDataStore::GetWrapper(script_state->GetIsolate(), script_wrappable)
|
|
+ .ToLocal(&wrapper))) {
|
|
return wrapper;
|
|
}
|
|
|
|
@@ -255,9 +256,9 @@ namespace bindings {
|
|
ScriptWrappable* script_wrappable,
|
|
v8::Local<v8::Object> creation_context_object) {
|
|
CHECK(script_wrappable);
|
|
- v8::Local<v8::Value> wrapper =
|
|
- DOMDataStore::GetWrapper(script_wrappable, isolate);
|
|
- if (LIKELY(!wrapper.IsEmpty())) {
|
|
+ v8::Local<v8::Object> wrapper;
|
|
+ if (LIKELY(DOMDataStore::GetWrapper(isolate, script_wrappable)
|
|
+ .ToLocal(&wrapper))) {
|
|
return wrapper;
|
|
}
|
|
|
|
diff --git a/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc b/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc
|
|
index a8d881630c81218d231e955eb1dabb266b81b309..e6ed0f24ea30453ae35a7d5e140085f6c5fdb432 100644
|
|
--- a/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc
|
|
+++ b/third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_impl.cc
|
|
@@ -15,6 +15,7 @@
|
|
#include "third_party/blink/renderer/bindings/modules/v8/v8_window.h"
|
|
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
|
|
#include "third_party/blink/renderer/core/html/html_document.h"
|
|
+#include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
|
|
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
|
|
#include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
|
|
#include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
|
|
@@ -245,9 +246,10 @@ void DeserializeInternalFieldCallback(v8::Local<v8::Object> object,
|
|
V8DOMWrapper::SetNativeInfo(deserializer_data->isolate, object,
|
|
V8HTMLDocument::GetWrapperTypeInfo(),
|
|
deserializer_data->html_document);
|
|
- bool result = deserializer_data->html_document->SetWrapper(
|
|
- deserializer_data->isolate, V8HTMLDocument::GetWrapperTypeInfo(),
|
|
- object);
|
|
+ const bool result =
|
|
+ DOMDataStore::SetWrapperInInlineStorage</*entered_context=*/false>(
|
|
+ deserializer_data->isolate, deserializer_data->html_document,
|
|
+ V8HTMLDocument::GetWrapperTypeInfo(), object);
|
|
CHECK(result);
|
|
break;
|
|
}
|
|
diff --git a/third_party/blink/renderer/core/dom/text.cc b/third_party/blink/renderer/core/dom/text.cc
|
|
index fbbfa23941811c4dd6e56cd6a13244b77cc39783..f79f59a91bf66ce07b4401accab88f1f3dbc3e53 100644
|
|
--- a/third_party/blink/renderer/core/dom/text.cc
|
|
+++ b/third_party/blink/renderer/core/dom/text.cc
|
|
@@ -144,7 +144,7 @@ Text* Text::splitText(unsigned offset, ExceptionState& exception_state) {
|
|
|
|
// [NewObject] must always create a new wrapper. Check that a wrapper
|
|
// does not exist yet.
|
|
- DCHECK(DOMDataStore::GetWrapper(new_text, GetDocument().GetAgent().isolate())
|
|
+ DCHECK(DOMDataStore::GetWrapper(GetDocument().GetAgent().isolate(), new_text)
|
|
.IsEmpty());
|
|
|
|
return new_text;
|
|
diff --git a/third_party/blink/renderer/core/frame/dom_window.cc b/third_party/blink/renderer/core/frame/dom_window.cc
|
|
index 41dfa6067538064d4b7f21c143baaee21dae5528..db557dc5f118cb0190085f61a799709791f7a606 100644
|
|
--- a/third_party/blink/renderer/core/frame/dom_window.cc
|
|
+++ b/third_party/blink/renderer/core/frame/dom_window.cc
|
|
@@ -106,7 +106,8 @@ v8::Local<v8::Object> DOMWindow::AssociateWithWrapper(
|
|
v8::Local<v8::Object> wrapper) {
|
|
// Using the world directly avoids fetching it from a potentially
|
|
// half-initialized context.
|
|
- if (world->DomDataStore().Set(isolate, this, wrapper_type_info, wrapper)) {
|
|
+ if (world->DomDataStore().Set</*entered_context=*/false>(
|
|
+ isolate, this, wrapper_type_info, wrapper)) {
|
|
V8DOMWrapper::SetNativeInfo(isolate, wrapper, wrapper_type_info, this);
|
|
DCHECK(V8DOMWrapper::HasInternalFieldsSet(wrapper));
|
|
}
|
|
diff --git a/third_party/blink/renderer/core/frame/location.cc b/third_party/blink/renderer/core/frame/location.cc
|
|
index f9dbd16a03d80224b0d3e28a46917fbbe337d8a2..31676b163494573f77e65f1362678385bb1bb68e 100644
|
|
--- a/third_party/blink/renderer/core/frame/location.cc
|
|
+++ b/third_party/blink/renderer/core/frame/location.cc
|
|
@@ -56,7 +56,7 @@ v8::Local<v8::Value> Location::Wrap(ScriptState* script_state) {
|
|
// the cross-origin status changes by changing properties like
|
|
// |document.domain|.
|
|
if (IsA<RemoteDOMWindow>(dom_window_.Get())) {
|
|
- DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
|
|
+ DCHECK(!DOMDataStore::ContainsWrapper(script_state->GetIsolate(), this));
|
|
|
|
DOMWrapperWorld& world = script_state->World();
|
|
v8::Isolate* isolate = script_state->GetIsolate();
|
|
diff --git a/third_party/blink/renderer/core/script/detect_javascript_frameworks.cc b/third_party/blink/renderer/core/script/detect_javascript_frameworks.cc
|
|
index 15efc675f87b855e1b868be80cf5b98338ee2bbe..4fcace96ccfa5ec5897590480099fe60ccdfd921 100644
|
|
--- a/third_party/blink/renderer/core/script/detect_javascript_frameworks.cc
|
|
+++ b/third_party/blink/renderer/core/script/detect_javascript_frameworks.cc
|
|
@@ -95,12 +95,14 @@ inline void CheckPropertyMatches(Element& element,
|
|
v8::Local<v8::Context> context,
|
|
v8::Isolate* isolate,
|
|
JavaScriptFrameworkDetectionResult& result) {
|
|
- v8::Local<v8::Object> v8_element = dom_data_store.Get(&element, isolate);
|
|
- if (v8_element.IsEmpty())
|
|
+ v8::Local<v8::Object> v8_element;
|
|
+ if (!dom_data_store.Get(isolate, &element).ToLocal(&v8_element)) {
|
|
return;
|
|
+ }
|
|
v8::Local<v8::Array> property_names;
|
|
- if (!v8_element->GetOwnPropertyNames(context).ToLocal(&property_names))
|
|
+ if (!v8_element->GetOwnPropertyNames(context).ToLocal(&property_names)) {
|
|
return;
|
|
+ }
|
|
|
|
DEFINE_STATIC_LOCAL(AtomicString, vue_string, ("__vue__"));
|
|
DEFINE_STATIC_LOCAL(AtomicString, vue_app_string, ("__vue_app__"));
|
|
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
|
|
index 69060a1e5f6937896d385b5ceb70f2d49ef8669c..44e2849c8e4dfc38834c88937dc561858c13e726 100644
|
|
--- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
|
|
+++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
|
|
@@ -51,9 +51,12 @@ static void AccumulateArrayBuffersForAllWorlds(
|
|
Vector<scoped_refptr<DOMWrapperWorld>> worlds;
|
|
DOMWrapperWorld::AllWorldsInIsolate(isolate, worlds);
|
|
for (const auto& world : worlds) {
|
|
- v8::Local<v8::Object> wrapper = world->DomDataStore().Get(object, isolate);
|
|
- if (!wrapper.IsEmpty())
|
|
+ v8::Local<v8::Object> wrapper;
|
|
+ if (world->DomDataStore()
|
|
+ .Get</*entered_context=*/false>(isolate, object)
|
|
+ .ToLocal(&wrapper)) {
|
|
buffers.push_back(v8::Local<v8::ArrayBuffer>::Cast(wrapper));
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -237,7 +240,7 @@ DOMArrayBuffer* DOMArrayBuffer::CreateUninitializedOrNull(
|
|
}
|
|
|
|
v8::Local<v8::Value> DOMArrayBuffer::Wrap(ScriptState* script_state) {
|
|
- DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
|
|
+ DCHECK(!DOMDataStore::ContainsWrapper(script_state->GetIsolate(), this));
|
|
|
|
const WrapperTypeInfo* wrapper_type_info = GetWrapperTypeInfo();
|
|
|
|
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc b/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc
|
|
index 59d8e8553b3c43ea68f43019974703d6fc0e83b8..fe5f1104ea156361f397cfa69944e6c19eb4ceb3 100644
|
|
--- a/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc
|
|
+++ b/third_party/blink/renderer/core/typed_arrays/dom_data_view.cc
|
|
@@ -50,7 +50,7 @@ DOMDataView* DOMDataView::Create(DOMArrayBufferBase* buffer,
|
|
}
|
|
|
|
v8::Local<v8::Value> DOMDataView::Wrap(ScriptState* script_state) {
|
|
- DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
|
|
+ DCHECK(!DOMDataStore::ContainsWrapper(script_state->GetIsolate(), this));
|
|
|
|
const WrapperTypeInfo* wrapper_type_info = GetWrapperTypeInfo();
|
|
v8::Local<v8::Value> v8_buffer =
|
|
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc b/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc
|
|
index 62278876ae55934c878dc22b97c8c6df1731e350..4ad4a143e1b08cea59a79171a0f7521f4e5aaa72 100644
|
|
--- a/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc
|
|
+++ b/third_party/blink/renderer/core/typed_arrays/dom_shared_array_buffer.cc
|
|
@@ -38,7 +38,7 @@ const WrapperTypeInfo& DOMSharedArrayBuffer::wrapper_type_info_ =
|
|
#endif
|
|
|
|
v8::Local<v8::Value> DOMSharedArrayBuffer::Wrap(ScriptState* script_state) {
|
|
- DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
|
|
+ DCHECK(!DOMDataStore::ContainsWrapper(script_state->GetIsolate(), this));
|
|
|
|
const WrapperTypeInfo* wrapper_type_info = GetWrapperTypeInfo();
|
|
v8::Local<v8::SharedArrayBuffer> wrapper;
|
|
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc b/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc
|
|
index 2d874ba75ab27369f34ee9e51d6989fbf2e6da46..ba88280f7a7931dd7c23949ab2e9dd9ec424c31a 100644
|
|
--- a/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc
|
|
+++ b/third_party/blink/renderer/core/typed_arrays/dom_typed_array.cc
|
|
@@ -12,7 +12,7 @@ namespace blink {
|
|
template <typename T, typename V8TypedArray, bool clamped>
|
|
v8::Local<v8::Value> DOMTypedArray<T, V8TypedArray, clamped>::Wrap(
|
|
ScriptState* script_state) {
|
|
- DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
|
|
+ DCHECK(!DOMDataStore::ContainsWrapper(script_state->GetIsolate(), this));
|
|
|
|
const WrapperTypeInfo* wrapper_type_info = GetWrapperTypeInfo();
|
|
DOMArrayBufferBase* buffer = BufferBase();
|
|
diff --git a/third_party/blink/renderer/platform/bindings/dom_data_store.cc b/third_party/blink/renderer/platform/bindings/dom_data_store.cc
|
|
index f6b574ba2460b149f45379117e52a9d82b3bcad4..5bc84b868dbf072e9e2cb8c4aeee22a5ed4a9c57 100644
|
|
--- a/third_party/blink/renderer/platform/bindings/dom_data_store.cc
|
|
+++ b/third_party/blink/renderer/platform/bindings/dom_data_store.cc
|
|
@@ -6,8 +6,8 @@
|
|
|
|
namespace blink {
|
|
|
|
-DOMDataStore::DOMDataStore(v8::Isolate* isolate, bool is_main_world)
|
|
- : is_main_world_(is_main_world) {}
|
|
+DOMDataStore::DOMDataStore(v8::Isolate* isolate, bool can_use_inline_storage)
|
|
+ : can_use_inline_storage_(can_use_inline_storage) {}
|
|
|
|
void DOMDataStore::Dispose() {
|
|
for (auto& it : wrapper_map_) {
|
|
diff --git a/third_party/blink/renderer/platform/bindings/dom_data_store.h b/third_party/blink/renderer/platform/bindings/dom_data_store.h
|
|
index db1c7e1592b01ed6b29a607a598b810b81aadde4..7153e8db04789ef2961b8de5e2a3d47fe747237a 100644
|
|
--- a/third_party/blink/renderer/platform/bindings/dom_data_store.h
|
|
+++ b/third_party/blink/renderer/platform/bindings/dom_data_store.h
|
|
@@ -44,175 +44,389 @@
|
|
|
|
namespace blink {
|
|
|
|
-// Holds a map specialized to map between ScriptWrappable objects and their
|
|
-// wrappers and provides an API to perform common operations with this map and
|
|
-// manage wrappers in a single world. Each world (DOMWrapperWorld) holds a
|
|
-// single map instance to hold wrappers only for that world.
|
|
+// DOMDataStore is the entity responsible for managing wrapper references (C++
|
|
+// to JS) in different worlds and settings (get/set wrapper, set return value).
|
|
+// Such references are stored in two ways:
|
|
+// - Inline in ScriptWrappable (or CustomWrappable); or
|
|
+// - In an ephemeron map in the DOMDataStore instance that is tied to a context
|
|
+// in a V8 Isolate.
|
|
+//
|
|
+// The methods on DOMDataStore generally come in two forms:
|
|
+// - static methods: Have fast paths for inline storage (e.g. main world on the
|
|
+// main rendering thread) and otherwise consider the current world, i.e., the
|
|
+// world that corresponds to the current context
|
|
+// (`v8::Isolate::GetCurrentContext()`).
|
|
+// - instance methods: Have fast paths for inline storage and consider the
|
|
+// world the methods are invoked on. The calls are faster than the static
|
|
+// calls if the DOMDataStore is already around.
|
|
+//
|
|
+// Exceptions are methods that operate on all worlds instead of the current
|
|
+// world. The methods mention this fact explicitly.
|
|
class DOMDataStore final : public GarbageCollected<DOMDataStore> {
|
|
public:
|
|
static DOMDataStore& Current(v8::Isolate* isolate) {
|
|
return DOMWrapperWorld::Current(isolate).DomDataStore();
|
|
}
|
|
|
|
- static bool SetReturnValue(v8::ReturnValue<v8::Value> return_value,
|
|
- ScriptWrappable* object) {
|
|
- if (CanUseMainWorldWrapper())
|
|
- return object->SetReturnValue(return_value);
|
|
- return Current(return_value.GetIsolate())
|
|
- .SetReturnValueFrom(return_value, object);
|
|
- }
|
|
+ // Sets the `return_value` from `value`. Can be used from any world. Will only
|
|
+ // consider the current world.
|
|
+ static inline bool SetReturnValue(v8::ReturnValue<v8::Value> return_value,
|
|
+ ScriptWrappable* value);
|
|
|
|
- static bool SetReturnValueForMainWorld(
|
|
+ // Sets the `return_value` from `value` in a world that can use inline
|
|
+ // storage.
|
|
+ static inline bool SetReturnValueFromInlineStorage(
|
|
v8::ReturnValue<v8::Value> return_value,
|
|
- ScriptWrappable* object) {
|
|
- return object->SetReturnValue(return_value);
|
|
- }
|
|
-
|
|
- static bool SetReturnValueFast(v8::ReturnValue<v8::Value> return_value,
|
|
- ScriptWrappable* object,
|
|
- v8::Local<v8::Object> holder,
|
|
- const ScriptWrappable* wrappable) {
|
|
- if (HolderContainsWrapperForMainWorld(holder, wrappable)) {
|
|
- // Verify our assumptions about the main world.
|
|
- DCHECK(Current(return_value.GetIsolate()).is_main_world_);
|
|
- return object->SetReturnValue(return_value);
|
|
- }
|
|
- return Current(return_value.GetIsolate())
|
|
- .SetReturnValueFrom(return_value, object);
|
|
- }
|
|
+ const ScriptWrappable* value);
|
|
|
|
- static v8::Local<v8::Object> GetWrapper(ScriptWrappable* object,
|
|
- v8::Isolate* isolate) {
|
|
- if (CanUseMainWorldWrapper())
|
|
- return object->MainWorldWrapper(isolate);
|
|
- return Current(isolate).Get(object, isolate);
|
|
- }
|
|
+ // Sets the `return_value` from `value` if already wrapped and returns false
|
|
+ // otherwise. Will use the `v8_receiver` and `blink_receiver` to check whether
|
|
+ // inline storage can be used. Can be used from any world. Will only consider
|
|
+ // the current world.
|
|
+ static inline bool SetReturnValueFast(v8::ReturnValue<v8::Value> return_value,
|
|
+ ScriptWrappable* value,
|
|
+ v8::Local<v8::Object> v8_receiver,
|
|
+ const ScriptWrappable* blink_receiver);
|
|
|
|
- // Associates the given |object| with the given |wrapper| if the object is
|
|
- // not yet associated with any wrapper. Returns true if the given wrapper
|
|
- // is associated with the object, or false if the object is already
|
|
- // associated with a wrapper. In the latter case, |wrapper| will be updated
|
|
- // to the existing wrapper.
|
|
- [[nodiscard]] static bool SetWrapper(v8::Isolate* isolate,
|
|
- ScriptWrappable* object,
|
|
- const WrapperTypeInfo* wrapper_type_info,
|
|
- v8::Local<v8::Object>& wrapper) {
|
|
- if (CanUseMainWorldWrapper())
|
|
- return object->SetWrapper(isolate, wrapper_type_info, wrapper);
|
|
- return Current(isolate).Set(isolate, object, wrapper_type_info, wrapper);
|
|
- }
|
|
+ // Returns the wrapper for `object` in the world corresponding to `isolate`.
|
|
+ // Can be used from any world. Will only consider the current world.
|
|
+ static inline v8::MaybeLocal<v8::Object> GetWrapper(
|
|
+ v8::Isolate* isolate,
|
|
+ const ScriptWrappable* object);
|
|
|
|
- static bool ContainsWrapper(const ScriptWrappable* object,
|
|
- v8::Isolate* isolate) {
|
|
- return Current(isolate).ContainsWrapper(object);
|
|
- }
|
|
+ // Associates the given `object` with the given `wrapper` if the object is not
|
|
+ // yet associated with any wrapper. Returns true if the given wrapper is
|
|
+ // associated with the object, or false if the object is already associated
|
|
+ // with a wrapper. In the latter case, `wrapper` will be updated to the
|
|
+ // existing wrapper. Can be used from any world. Will only consider the
|
|
+ // current world.
|
|
+ [[nodiscard]] static inline bool SetWrapper(
|
|
+ v8::Isolate* isolate,
|
|
+ ScriptWrappable* object,
|
|
+ const WrapperTypeInfo* wrapper_type_info,
|
|
+ v8::Local<v8::Object>& wrapper);
|
|
+
|
|
+ // Same as `SetWrapper()` with the difference that it only considers inline
|
|
+ // storage. Can be used from any world.
|
|
+ template <bool entered_context = true>
|
|
+ [[nodiscard]] static inline bool SetWrapperInInlineStorage(
|
|
+ v8::Isolate* isolate,
|
|
+ ScriptWrappable* object,
|
|
+ const WrapperTypeInfo* wrapper_type_info,
|
|
+ v8::Local<v8::Object>& wrapper);
|
|
+
|
|
+ // Checks for the wrapper pair in all worlds and clears the first found pair.
|
|
+ // This should only be needed for garbage collection. All other callsites
|
|
+ // should know their worlds.
|
|
+ template <typename HandleType>
|
|
+ static inline bool ClearWrapperInAnyWorldIfEqualTo(ScriptWrappable* object,
|
|
+ const HandleType& handle);
|
|
|
|
- DOMDataStore(v8::Isolate* isolate, bool is_main_world);
|
|
+ // Clears the inline storage wrapper if it is equal to `handle`. Can be used
|
|
+ // from any world.
|
|
+ template <typename HandleType>
|
|
+ static inline bool ClearInlineStorageWrapperIfEqualTo(
|
|
+ ScriptWrappable* object,
|
|
+ const HandleType& handle);
|
|
+
|
|
+ // Checks whether a wrapper for `object` exists. Can be used from any world.
|
|
+ // Will only consider the current world.
|
|
+ static inline bool ContainsWrapper(v8::Isolate* isolate,
|
|
+ const ScriptWrappable* object);
|
|
+
|
|
+ DOMDataStore(v8::Isolate* isolate, bool);
|
|
DOMDataStore(const DOMDataStore&) = delete;
|
|
DOMDataStore& operator=(const DOMDataStore&) = delete;
|
|
|
|
// Clears all references.
|
|
void Dispose();
|
|
|
|
- v8::Local<v8::Object> Get(ScriptWrappable* object, v8::Isolate* isolate) {
|
|
- if (is_main_world_)
|
|
- return object->MainWorldWrapper(isolate);
|
|
- auto it = wrapper_map_.find(object);
|
|
- if (it != wrapper_map_.end())
|
|
- return it->value.Get(isolate);
|
|
- return v8::Local<v8::Object>();
|
|
- }
|
|
-
|
|
- [[nodiscard]] bool Set(v8::Isolate* isolate,
|
|
- ScriptWrappable* object,
|
|
- const WrapperTypeInfo* wrapper_type_info,
|
|
- v8::Local<v8::Object>& wrapper) {
|
|
- DCHECK(object);
|
|
- DCHECK(!wrapper.IsEmpty());
|
|
- if (is_main_world_)
|
|
- return object->SetWrapper(isolate, wrapper_type_info, wrapper);
|
|
-
|
|
- auto result = wrapper_map_.insert(
|
|
- object, wrapper_type_info->SupportsDroppingWrapper()
|
|
- ? TraceWrapperV8Reference<v8::Object>(
|
|
- isolate, wrapper,
|
|
- TraceWrapperV8Reference<v8::Object>::IsDroppable{})
|
|
- : TraceWrapperV8Reference<v8::Object>(isolate, wrapper));
|
|
- // TODO(mlippautz): Check whether there's still recursive cases of
|
|
- // Wrap()/AssociateWithWrapper() that can run into the case of an existing
|
|
- // entry.
|
|
- if (UNLIKELY(!result.is_new_entry)) {
|
|
- DCHECK(!result.stored_value->value.IsEmpty());
|
|
- wrapper = result.stored_value->value.Get(isolate);
|
|
- }
|
|
- return result.is_new_entry;
|
|
- }
|
|
+ // Same as `GetWrapper()` but for a single world.
|
|
+ template <bool entered_context = true>
|
|
+ inline v8::MaybeLocal<v8::Object> Get(v8::Isolate* isolate,
|
|
+ const ScriptWrappable* object);
|
|
+
|
|
+ // Same as `SetWrapper()` but for a single world.
|
|
+ template <bool entered_context = true>
|
|
+ [[nodiscard]] inline bool Set(v8::Isolate* isolate,
|
|
+ ScriptWrappable* object,
|
|
+ const WrapperTypeInfo* wrapper_type_info,
|
|
+ v8::Local<v8::Object>& wrapper);
|
|
+
|
|
+ // Same as `ContainsWrapper()` but for a single world.
|
|
+ inline bool Contains(const ScriptWrappable* object) const;
|
|
+
|
|
+ // Returns true if the pair {object, handle} exists in the current world.
|
|
+ template <typename HandleType>
|
|
+ inline bool EqualTo(const ScriptWrappable* object, const HandleType& handle);
|
|
|
|
+ // Clears the connection between object and handle in the current world.
|
|
template <typename HandleType>
|
|
- bool ClearWrapperIfEqualTo(ScriptWrappable* object,
|
|
+ inline bool ClearIfEqualTo(ScriptWrappable* object,
|
|
const HandleType& handle) {
|
|
- DCHECK(!is_main_world_);
|
|
- const auto& it = wrapper_map_.find(object);
|
|
- if (it != wrapper_map_.end() && it->value == handle) {
|
|
- it->value.Reset();
|
|
- wrapper_map_.erase(it);
|
|
- return true;
|
|
+ if (can_use_inline_storage_) {
|
|
+ return ClearInlineStorageWrapperIfEqualTo(object, handle);
|
|
}
|
|
- return false;
|
|
+ return ClearInMapIfEqualTo(object, handle);
|
|
}
|
|
|
|
- bool SetReturnValueFrom(v8::ReturnValue<v8::Value> return_value,
|
|
- ScriptWrappable* object) {
|
|
- if (is_main_world_)
|
|
- return object->SetReturnValue(return_value);
|
|
- auto it = wrapper_map_.find(object);
|
|
- if (it != wrapper_map_.end()) {
|
|
- return_value.SetNonEmpty(it->value);
|
|
+ // Clears the connection between object and handle in the current world
|
|
+ // assuming no inline storage is available for this world.
|
|
+ template <typename HandleType>
|
|
+ inline bool ClearInMapIfEqualTo(const ScriptWrappable* object,
|
|
+ const HandleType& handle) {
|
|
+ DCHECK(!can_use_inline_storage_);
|
|
+ if (const auto& it = wrapper_map_.find(object);
|
|
+ it != wrapper_map_.end() && it->value == handle) {
|
|
+ it->value.Reset();
|
|
+ wrapper_map_.erase(it);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
- bool ContainsWrapper(const ScriptWrappable* object) {
|
|
- if (is_main_world_)
|
|
- return object->ContainsWrapper();
|
|
- return base::Contains(wrapper_map_, object);
|
|
- }
|
|
-
|
|
virtual void Trace(Visitor*) const;
|
|
|
|
private:
|
|
- // We can use a wrapper stored in a ScriptWrappable when we're in the main
|
|
- // world. This method does the fast check if we're in the main world. If this
|
|
+ // We can use the inline storage in a ScriptWrappable when we're in the main
|
|
+ // world. This method does the fast check if we're in the main world. If this
|
|
// method returns true, it is guaranteed that we're in the main world. On the
|
|
// other hand, if this method returns false, nothing is guaranteed (we might
|
|
// be in the main world).
|
|
- static bool CanUseMainWorldWrapper() {
|
|
+ static bool CanUseInlineStorageForWrapper() {
|
|
return !WTF::MayNotBeMainThread() &&
|
|
!DOMWrapperWorld::NonMainWorldsExistInMainThread();
|
|
}
|
|
|
|
- static bool HolderContainsWrapperForMainWorld(
|
|
- v8::Local<v8::Object> holder,
|
|
+ inline bool SetReturnValueFrom(v8::ReturnValue<v8::Value> return_value,
|
|
+ const ScriptWrappable* value);
|
|
+
|
|
+ using WrapperRefType = decltype(ScriptWrappable::wrapper_);
|
|
+
|
|
+ // Convenience methods for accessing the inlined storage.
|
|
+ static inline WrapperRefType& GetUncheckedInlineStorage(
|
|
+ ScriptWrappable* wrappable) {
|
|
+ return wrappable->wrapper_;
|
|
+ }
|
|
+ static inline const WrapperRefType& GetUncheckedInlineStorage(
|
|
const ScriptWrappable* wrappable) {
|
|
- // The first fastest way is to check that there is only the main world
|
|
- // on the main thread.
|
|
- if (CanUseMainWorldWrapper()) {
|
|
- return true;
|
|
- }
|
|
- // The second fastest way to check if we're in the main world is to
|
|
- // check if the wrappable's wrapper is the same as the holder.
|
|
- DCHECK(wrappable);
|
|
- return wrappable->IsEqualTo(holder);
|
|
+ return GetUncheckedInlineStorage(const_cast<ScriptWrappable*>(wrappable));
|
|
+ }
|
|
+ static inline WrapperRefType& GetInlineStorage(v8::Isolate* isolate,
|
|
+ ScriptWrappable* wrappable) {
|
|
+ // The following will crash if no context is entered. This is by design. The
|
|
+ // validation can be skipped with `SetWrapperInInlineStorage<false>()`.
|
|
+ DCHECK(Current(isolate).can_use_inline_storage_);
|
|
+ return GetUncheckedInlineStorage(wrappable);
|
|
+ }
|
|
+ static inline const WrapperRefType& GetInlineStorage(
|
|
+ v8::Isolate* isolate,
|
|
+ const ScriptWrappable* wrappable) {
|
|
+ return GetInlineStorage(isolate, const_cast<ScriptWrappable*>(wrappable));
|
|
}
|
|
|
|
- bool is_main_world_;
|
|
+ // Specifies whether this data store is allowed to use inline storage of a
|
|
+ // ScriptWrappable and can avoid using the ephemeron map below.
|
|
+ const bool can_use_inline_storage_;
|
|
// Ephemeron map: V8 wrapper will be kept alive as long as ScriptWrappable is.
|
|
HeapHashMap<WeakMember<const ScriptWrappable>,
|
|
TraceWrapperV8Reference<v8::Object>>
|
|
wrapper_map_;
|
|
};
|
|
|
|
+// static
|
|
+bool DOMDataStore::SetReturnValue(v8::ReturnValue<v8::Value> return_value,
|
|
+ ScriptWrappable* value) {
|
|
+ if (CanUseInlineStorageForWrapper()) {
|
|
+ return SetReturnValueFromInlineStorage(return_value, value);
|
|
+ }
|
|
+ return Current(return_value.GetIsolate())
|
|
+ .SetReturnValueFrom(return_value, value);
|
|
+}
|
|
+
|
|
+// static
|
|
+bool DOMDataStore::SetReturnValueFromInlineStorage(
|
|
+ v8::ReturnValue<v8::Value> return_value,
|
|
+ const ScriptWrappable* value) {
|
|
+ const auto& ref = GetInlineStorage(return_value.GetIsolate(), value);
|
|
+ if (!ref.IsEmpty()) {
|
|
+ return_value.SetNonEmpty(ref);
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+// static
|
|
+bool DOMDataStore::SetReturnValueFast(v8::ReturnValue<v8::Value> return_value,
|
|
+ ScriptWrappable* object,
|
|
+ v8::Local<v8::Object> v8_receiver,
|
|
+ const ScriptWrappable* blink_receiver) {
|
|
+ // Fast checks for using inline storage:
|
|
+ // 1. Fast check for inline storage.
|
|
+ // 2. If the receiver receiver's inline wrapper is the V8 receiver. In this
|
|
+ // case we know we are in the world that can use inline storage.
|
|
+ DCHECK(blink_receiver);
|
|
+ DCHECK(!v8_receiver.IsEmpty());
|
|
+ if (CanUseInlineStorageForWrapper() ||
|
|
+ v8_receiver == GetUncheckedInlineStorage(blink_receiver)) {
|
|
+ return SetReturnValueFromInlineStorage(return_value, object);
|
|
+ }
|
|
+ return Current(return_value.GetIsolate())
|
|
+ .SetReturnValueFrom(return_value, object);
|
|
+}
|
|
+
|
|
+bool DOMDataStore::SetReturnValueFrom(v8::ReturnValue<v8::Value> return_value,
|
|
+ const ScriptWrappable* value) {
|
|
+ if (can_use_inline_storage_) {
|
|
+ return SetReturnValueFromInlineStorage(return_value, value);
|
|
+ }
|
|
+ if (const auto it = wrapper_map_.find(value); it != wrapper_map_.end()) {
|
|
+ return_value.SetNonEmpty(it->value);
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+// static
|
|
+v8::MaybeLocal<v8::Object> DOMDataStore::GetWrapper(
|
|
+ v8::Isolate* isolate,
|
|
+ const ScriptWrappable* object) {
|
|
+ if (CanUseInlineStorageForWrapper()) {
|
|
+ return GetInlineStorage(isolate, object).Get(isolate);
|
|
+ }
|
|
+ return Current(isolate).Get(isolate, object);
|
|
+}
|
|
+
|
|
+template <bool entered_context>
|
|
+v8::MaybeLocal<v8::Object> DOMDataStore::Get(v8::Isolate* isolate,
|
|
+ const ScriptWrappable* object) {
|
|
+ if (can_use_inline_storage_) {
|
|
+ return entered_context ? GetInlineStorage(isolate, object).Get(isolate)
|
|
+ : GetUncheckedInlineStorage(object).Get(isolate);
|
|
+ }
|
|
+ if (const auto it = wrapper_map_.find(object); it != wrapper_map_.end()) {
|
|
+ return it->value.Get(isolate);
|
|
+ }
|
|
+ return {};
|
|
+}
|
|
+
|
|
+// static
|
|
+bool DOMDataStore::SetWrapper(v8::Isolate* isolate,
|
|
+ ScriptWrappable* object,
|
|
+ const WrapperTypeInfo* wrapper_type_info,
|
|
+ v8::Local<v8::Object>& wrapper) {
|
|
+ if (CanUseInlineStorageForWrapper()) {
|
|
+ return SetWrapperInInlineStorage(isolate, object, wrapper_type_info,
|
|
+ wrapper);
|
|
+ }
|
|
+ return Current(isolate).Set(isolate, object, wrapper_type_info, wrapper);
|
|
+}
|
|
+
|
|
+// static
|
|
+template <bool entered_context>
|
|
+bool DOMDataStore::SetWrapperInInlineStorage(
|
|
+ v8::Isolate* isolate,
|
|
+ ScriptWrappable* object,
|
|
+ const WrapperTypeInfo* wrapper_type_info,
|
|
+ v8::Local<v8::Object>& wrapper) {
|
|
+ DCHECK(!wrapper.IsEmpty());
|
|
+ auto& ref = entered_context ? GetInlineStorage(isolate, object)
|
|
+ : GetUncheckedInlineStorage(object);
|
|
+ if (UNLIKELY(!ref.IsEmpty())) {
|
|
+ wrapper = ref.Get(isolate);
|
|
+ return false;
|
|
+ }
|
|
+ if (wrapper_type_info->SupportsDroppingWrapper()) {
|
|
+ ref.Reset(isolate, wrapper,
|
|
+ TraceWrapperV8Reference<v8::Object>::IsDroppable{});
|
|
+ } else {
|
|
+ ref.Reset(isolate, wrapper);
|
|
+ }
|
|
+ DCHECK(!ref.IsEmpty());
|
|
+ return true;
|
|
+}
|
|
+
|
|
+template <bool entered_context>
|
|
+bool DOMDataStore::Set(v8::Isolate* isolate,
|
|
+ ScriptWrappable* object,
|
|
+ const WrapperTypeInfo* wrapper_type_info,
|
|
+ v8::Local<v8::Object>& wrapper) {
|
|
+ DCHECK(object);
|
|
+ DCHECK(!wrapper.IsEmpty());
|
|
+ if (can_use_inline_storage_) {
|
|
+ return SetWrapperInInlineStorage<entered_context>(
|
|
+ isolate, object, wrapper_type_info, wrapper);
|
|
+ }
|
|
+ auto result = wrapper_map_.insert(
|
|
+ object, wrapper_type_info->SupportsDroppingWrapper()
|
|
+ ? TraceWrapperV8Reference<v8::Object>(
|
|
+ isolate, wrapper,
|
|
+ TraceWrapperV8Reference<v8::Object>::IsDroppable{})
|
|
+ : TraceWrapperV8Reference<v8::Object>(isolate, wrapper));
|
|
+ // TODO(mlippautz): Check whether there's still recursive cases of
|
|
+ // Wrap()/AssociateWithWrapper() that can run into the case of an existing
|
|
+ // entry.
|
|
+ if (UNLIKELY(!result.is_new_entry)) {
|
|
+ DCHECK(!result.stored_value->value.IsEmpty());
|
|
+ wrapper = result.stored_value->value.Get(isolate);
|
|
+ }
|
|
+ return result.is_new_entry;
|
|
+}
|
|
+
|
|
+// static
|
|
+bool DOMDataStore::ContainsWrapper(v8::Isolate* isolate,
|
|
+ const ScriptWrappable* object) {
|
|
+ if (CanUseInlineStorageForWrapper()) {
|
|
+ return !GetInlineStorage(isolate, object).IsEmpty();
|
|
+ }
|
|
+ return Current(isolate).Contains(object);
|
|
+}
|
|
+
|
|
+// Same as `ContainsWrapper()` but for a single world.
|
|
+bool DOMDataStore::Contains(const ScriptWrappable* object) const {
|
|
+ if (can_use_inline_storage_) {
|
|
+ return !GetUncheckedInlineStorage(object).IsEmpty();
|
|
+ }
|
|
+ return base::Contains(wrapper_map_, object);
|
|
+}
|
|
+
|
|
+// static
|
|
+template <typename HandleType>
|
|
+bool DOMDataStore::ClearWrapperInAnyWorldIfEqualTo(ScriptWrappable* object,
|
|
+ const HandleType& handle) {
|
|
+ if (LIKELY(ClearInlineStorageWrapperIfEqualTo(object, handle))) {
|
|
+ return true;
|
|
+ }
|
|
+ return DOMWrapperWorld::ClearWrapperInAnyNonInlineStorageWorldIfEqualTo(
|
|
+ object, handle);
|
|
+}
|
|
+
|
|
+// static
|
|
+template <typename HandleType>
|
|
+bool DOMDataStore::ClearInlineStorageWrapperIfEqualTo(
|
|
+ ScriptWrappable* object,
|
|
+ const HandleType& handle) {
|
|
+ auto& ref = GetUncheckedInlineStorage(object);
|
|
+ if (ref == handle) {
|
|
+ ref.Reset();
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+template <typename HandleType>
|
|
+bool DOMDataStore::EqualTo(const ScriptWrappable* object,
|
|
+ const HandleType& handle) {
|
|
+ if (can_use_inline_storage_) {
|
|
+ return GetUncheckedInlineStorage(object) == handle;
|
|
+ }
|
|
+ if (const auto& it = wrapper_map_.find(object);
|
|
+ it != wrapper_map_.end() && it->value == handle) {
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
} // namespace blink
|
|
|
|
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_DOM_DATA_STORE_H_
|
|
diff --git a/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc b/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc
|
|
index e330dd46f1ed0bee4f209ab0ce2c058ca52f4029..663d5ecbfe3e2b7440e34e6c90d9738f666a8905 100644
|
|
--- a/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc
|
|
+++ b/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc
|
|
@@ -291,12 +291,12 @@ int DOMWrapperWorld::GenerateWorldIdForType(WorldType world_type) {
|
|
}
|
|
|
|
// static
|
|
-bool DOMWrapperWorld::ClearNonMainWorldWrapperIfEqualTo(
|
|
+bool DOMWrapperWorld::ClearWrapperInAnyNonInlineStorageWorldIfEqualTo(
|
|
ScriptWrappable* object,
|
|
const v8::Local<v8::Object>& handle) {
|
|
for (DOMWrapperWorld* world : GetWorldMap().Values()) {
|
|
DOMDataStore& data_store = world->DomDataStore();
|
|
- if (data_store.ClearWrapperIfEqualTo(object, handle)) {
|
|
+ if (data_store.ClearInMapIfEqualTo(object, handle)) {
|
|
return true;
|
|
}
|
|
}
|
|
@@ -304,12 +304,12 @@ bool DOMWrapperWorld::ClearNonMainWorldWrapperIfEqualTo(
|
|
}
|
|
|
|
// static
|
|
-bool DOMWrapperWorld::ClearNonMainWorldWrapperIfEqualTo(
|
|
+bool DOMWrapperWorld::ClearWrapperInAnyNonInlineStorageWorldIfEqualTo(
|
|
ScriptWrappable* object,
|
|
const v8::TracedReference<v8::Object>& handle) {
|
|
for (DOMWrapperWorld* world : GetWorldMap().Values()) {
|
|
DOMDataStore& data_store = world->DomDataStore();
|
|
- if (data_store.ClearWrapperIfEqualTo(object, handle)) {
|
|
+ if (data_store.ClearInMapIfEqualTo(object, handle)) {
|
|
return true;
|
|
}
|
|
}
|
|
diff --git a/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h b/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
|
|
index b8fccf776cb01c120ac589072f5183d0f4318bdf..ec51d8bbed1af2a192211d19a89ced7da643dda8 100644
|
|
--- a/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
|
|
+++ b/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
|
|
@@ -171,24 +171,17 @@ class PLATFORM_EXPORT DOMWrapperWorld : public RefCounted<DOMWrapperWorld> {
|
|
return *v8_object_data_store_;
|
|
}
|
|
|
|
- // Clear the reference pointing from |object| to |handle| in any world.
|
|
- template <typename HandleType>
|
|
- inline static bool ClearWrapperIfEqualTo(ScriptWrappable* object,
|
|
- const HandleType& handle);
|
|
-
|
|
- // Clear the reference pointing from |object| to |handle| in the main world.
|
|
- template <typename HandleType>
|
|
- inline static bool ClearMainWorldWrapperIfEqualTo(ScriptWrappable* object,
|
|
- const HandleType& handle);
|
|
-
|
|
- private:
|
|
- static bool ClearNonMainWorldWrapperIfEqualTo(
|
|
+ // Methods iterate all worlds and invokes the clearing methods on
|
|
+ // DOMDataStore. The WorldMap is only known to the DOMWrapperWorld and as such
|
|
+ // the iteration cannot be folded into DOMDataStore.
|
|
+ static bool ClearWrapperInAnyNonInlineStorageWorldIfEqualTo(
|
|
ScriptWrappable* object,
|
|
const v8::Local<v8::Object>& handle);
|
|
- static bool ClearNonMainWorldWrapperIfEqualTo(
|
|
+ static bool ClearWrapperInAnyNonInlineStorageWorldIfEqualTo(
|
|
ScriptWrappable* object,
|
|
const v8::TracedReference<v8::Object>& handle);
|
|
|
|
+private:
|
|
DOMWrapperWorld(v8::Isolate*, WorldType, int32_t world_id);
|
|
|
|
static unsigned number_of_non_main_worlds_in_main_thread_;
|
|
@@ -204,24 +197,6 @@ class PLATFORM_EXPORT DOMWrapperWorld : public RefCounted<DOMWrapperWorld> {
|
|
Persistent<V8ObjectDataStore> v8_object_data_store_;
|
|
};
|
|
|
|
-// static
|
|
-template <typename HandleType>
|
|
-bool DOMWrapperWorld::ClearMainWorldWrapperIfEqualTo(ScriptWrappable* object,
|
|
- const HandleType& handle) {
|
|
- return object->ClearMainWorldWrapperIfEqualTo(handle);
|
|
-}
|
|
-
|
|
-// static
|
|
-template <typename HandleType>
|
|
-bool DOMWrapperWorld::ClearWrapperIfEqualTo(ScriptWrappable* object,
|
|
- const HandleType& handle) {
|
|
- if (ClearMainWorldWrapperIfEqualTo(object, handle)) {
|
|
- return true;
|
|
- }
|
|
- // Slow path: |object| may point to |handle| in any non-main DOM world.
|
|
- return DOMWrapperWorld::ClearNonMainWorldWrapperIfEqualTo(object, handle);
|
|
-}
|
|
-
|
|
} // namespace blink
|
|
|
|
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_DOM_WRAPPER_WORLD_H_
|
|
diff --git a/third_party/blink/renderer/platform/bindings/frozen_array_base.cc b/third_party/blink/renderer/platform/bindings/frozen_array_base.cc
|
|
index 4af0f5ef920e981e6cf0b7ff1e53d69d1bd41a29..5d01d17390f4de24190956f56e2784929266c21d 100644
|
|
--- a/third_party/blink/renderer/platform/bindings/frozen_array_base.cc
|
|
+++ b/third_party/blink/renderer/platform/bindings/frozen_array_base.cc
|
|
@@ -39,9 +39,9 @@ v8::Local<v8::Value> FrozenArrayBase::ToV8(ScriptState* script_state) const {
|
|
}
|
|
|
|
v8::Local<v8::Value> FrozenArrayBase::ToV8(ScriptState* script_state) {
|
|
- v8::Local<v8::Object> wrapper = script_state->World().DomDataStore().Get(
|
|
- this, script_state->GetIsolate());
|
|
- if (LIKELY(!wrapper.IsEmpty())) {
|
|
+ v8::Local<v8::Object> wrapper;
|
|
+ if (LIKELY(DOMDataStore::GetWrapper(script_state->GetIsolate(), this)
|
|
+ .ToLocal(&wrapper))) {
|
|
return wrapper;
|
|
}
|
|
|
|
@@ -49,7 +49,7 @@ v8::Local<v8::Value> FrozenArrayBase::ToV8(ScriptState* script_state) {
|
|
}
|
|
|
|
v8::Local<v8::Value> FrozenArrayBase::Wrap(ScriptState* script_state) {
|
|
- DCHECK(!script_state->World().DomDataStore().ContainsWrapper(this));
|
|
+ DCHECK(!DOMDataStore::ContainsWrapper(script_state->GetIsolate(), this));
|
|
|
|
v8::Local<v8::Value> wrapper = MakeV8ArrayToBeFrozen(script_state);
|
|
|
|
diff --git a/third_party/blink/renderer/platform/bindings/script_wrappable.cc b/third_party/blink/renderer/platform/bindings/script_wrappable.cc
|
|
index 92fa7df37915a3f456562f9cc0ef20436bfcad5f..9733be3a28b1eb315e7774dcb5a197143457cf8c 100644
|
|
--- a/third_party/blink/renderer/platform/bindings/script_wrappable.cc
|
|
+++ b/third_party/blink/renderer/platform/bindings/script_wrappable.cc
|
|
@@ -20,9 +20,9 @@ struct SameSizeAsScriptWrappable {
|
|
ASSERT_SIZE(ScriptWrappable, SameSizeAsScriptWrappable);
|
|
|
|
v8::Local<v8::Value> ScriptWrappable::ToV8(ScriptState* script_state) {
|
|
- v8::Local<v8::Value> wrapper =
|
|
- DOMDataStore::GetWrapper(this, script_state->GetIsolate());
|
|
- if (LIKELY(!wrapper.IsEmpty())) {
|
|
+ v8::Local<v8::Object> wrapper;
|
|
+ if (LIKELY(DOMDataStore::GetWrapper(script_state->GetIsolate(), this)
|
|
+ .ToLocal(&wrapper))) {
|
|
return wrapper;
|
|
}
|
|
return Wrap(script_state);
|
|
@@ -31,8 +31,8 @@ v8::Local<v8::Value> ScriptWrappable::ToV8(ScriptState* script_state) {
|
|
v8::Local<v8::Value> ScriptWrappable::ToV8(
|
|
v8::Isolate* isolate,
|
|
v8::Local<v8::Object> creation_context_object) {
|
|
- v8::Local<v8::Value> wrapper = DOMDataStore::GetWrapper(this, isolate);
|
|
- if (LIKELY(!wrapper.IsEmpty())) {
|
|
+ v8::Local<v8::Object> wrapper;
|
|
+ if (LIKELY(DOMDataStore::GetWrapper(isolate, this).ToLocal(&wrapper))) {
|
|
return wrapper;
|
|
}
|
|
CHECK(!creation_context_object.IsEmpty());
|
|
@@ -44,7 +44,7 @@ v8::Local<v8::Value> ScriptWrappable::ToV8(
|
|
v8::Local<v8::Value> ScriptWrappable::Wrap(ScriptState* script_state) {
|
|
const WrapperTypeInfo* wrapper_type_info = GetWrapperTypeInfo();
|
|
|
|
- DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
|
|
+ DCHECK(!DOMDataStore::ContainsWrapper(script_state->GetIsolate(), this));
|
|
|
|
v8::Local<v8::Object> wrapper =
|
|
V8DOMWrapper::CreateWrapper(script_state, wrapper_type_info);
|
|
@@ -61,7 +61,7 @@ v8::Local<v8::Object> ScriptWrappable::AssociateWithWrapper(
|
|
}
|
|
|
|
void ScriptWrappable::Trace(Visitor* visitor) const {
|
|
- visitor->Trace(main_world_wrapper_);
|
|
+ visitor->Trace(wrapper_);
|
|
}
|
|
|
|
const char* ScriptWrappable::NameInHeapSnapshot() const {
|
|
diff --git a/third_party/blink/renderer/platform/bindings/script_wrappable.h b/third_party/blink/renderer/platform/bindings/script_wrappable.h
|
|
index ba1b49d06bd26f4f04767a953ffa2d918a5d93e9..858ae35448ba23ddc200cc8a44d3b77f47e69e35 100644
|
|
--- a/third_party/blink/renderer/platform/bindings/script_wrappable.h
|
|
+++ b/third_party/blink/renderer/platform/bindings/script_wrappable.h
|
|
@@ -42,6 +42,7 @@
|
|
|
|
namespace blink {
|
|
|
|
+class DOMDataStore;
|
|
class ScriptState;
|
|
|
|
// ScriptWrappable provides a way to map from/to C++ DOM implementation to/from
|
|
@@ -174,78 +175,22 @@ class PLATFORM_EXPORT ScriptWrappable
|
|
const WrapperTypeInfo*,
|
|
v8::Local<v8::Object> wrapper);
|
|
|
|
- // Associates this instance with the given |wrapper| if this instance is not
|
|
- // yet associated with any wrapper. Returns true if the given wrapper is
|
|
- // associated with this instance, or false if this instance is already
|
|
- // associated with a wrapper. In the latter case, |wrapper| will be updated
|
|
- // to the existing wrapper.
|
|
- [[nodiscard]] bool SetWrapper(v8::Isolate* isolate,
|
|
- const WrapperTypeInfo* wrapper_type_info,
|
|
- v8::Local<v8::Object>& wrapper) {
|
|
- DCHECK(!wrapper.IsEmpty());
|
|
- if (UNLIKELY(ContainsWrapper())) {
|
|
- wrapper = MainWorldWrapper(isolate);
|
|
- return false;
|
|
- }
|
|
- if (wrapper_type_info->SupportsDroppingWrapper()) {
|
|
- main_world_wrapper_.Reset(
|
|
- isolate, wrapper, TraceWrapperV8Reference<v8::Object>::IsDroppable{});
|
|
- } else {
|
|
- main_world_wrapper_.Reset(isolate, wrapper);
|
|
- }
|
|
- DCHECK(ContainsWrapper());
|
|
- return true;
|
|
- }
|
|
-
|
|
- bool IsEqualTo(const v8::Local<v8::Object>& other) const {
|
|
- return main_world_wrapper_ == other;
|
|
- }
|
|
-
|
|
- bool SetReturnValue(v8::ReturnValue<v8::Value> return_value) {
|
|
- const bool contains_wrapper = ContainsWrapper();
|
|
- if (contains_wrapper) {
|
|
- return_value.SetNonEmpty(main_world_wrapper_);
|
|
- }
|
|
- return contains_wrapper;
|
|
- }
|
|
-
|
|
-
|
|
protected:
|
|
ScriptWrappable() = default;
|
|
|
|
private:
|
|
- bool ContainsWrapper() const { return !main_world_wrapper_.IsEmpty(); }
|
|
-
|
|
- v8::Local<v8::Object> MainWorldWrapper(v8::Isolate* isolate) const {
|
|
- return main_world_wrapper_.Get(isolate);
|
|
- }
|
|
-
|
|
- // Clear the main world wrapper if it is set to |handle|.
|
|
- template <typename HandleType>
|
|
- inline bool ClearMainWorldWrapperIfEqualTo(const HandleType& handle);
|
|
-
|
|
static_assert(
|
|
std::is_trivially_destructible<
|
|
TraceWrapperV8Reference<v8::Object>>::value,
|
|
"TraceWrapperV8Reference<v8::Object> should be trivially destructible.");
|
|
|
|
- TraceWrapperV8Reference<v8::Object> main_world_wrapper_;
|
|
-
|
|
- // These classes are exceptionally allowed to directly interact with the main
|
|
- // world wrapper.
|
|
+ // Inline storage for the a single wrapper reference. Only
|
|
+ // `DOMDataStore::UncheckedInlineStorageForWrappable()` should access this
|
|
+ // field.
|
|
+ TraceWrapperV8Reference<v8::Object> wrapper_;
|
|
friend class DOMDataStore;
|
|
- friend class DOMWrapperWorld;
|
|
};
|
|
|
|
-template <typename HandleType>
|
|
-bool ScriptWrappable::ClearMainWorldWrapperIfEqualTo(const HandleType& handle) {
|
|
- if (main_world_wrapper_ == handle) {
|
|
- main_world_wrapper_.Reset();
|
|
- return true;
|
|
- }
|
|
- return false;
|
|
-}
|
|
-
|
|
// Defines |GetWrapperTypeInfo| virtual method which returns the WrapperTypeInfo
|
|
// of the instance. Also declares a static member of type WrapperTypeInfo, of
|
|
// which the definition is given by the IDL code generator.
|
|
diff --git a/third_party/blink/renderer/platform/bindings/v8_set_return_value.h b/third_party/blink/renderer/platform/bindings/v8_set_return_value.h
|
|
index 6cf3278d7a186ad97b49841fb9bddd584582b9f7..2987c64bdbed2a7b797cd04a9b35a95c3f3f7aa9 100644
|
|
--- a/third_party/blink/renderer/platform/bindings/v8_set_return_value.h
|
|
+++ b/third_party/blink/renderer/platform/bindings/v8_set_return_value.h
|
|
@@ -50,16 +50,16 @@ struct V8ReturnValue {
|
|
enum InterfaceObject { kInterfaceObject };
|
|
enum NamespaceObject { kNamespaceObject };
|
|
|
|
- // Selects the appropriate creation context.
|
|
- static v8::Local<v8::Object> CreationContext(
|
|
+ // Selects the appropriate receiver from which e.g. the creation context can
|
|
+ // be retrieved.
|
|
+ static v8::Local<v8::Object> GetReceiver(
|
|
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
|
return info.This();
|
|
}
|
|
- static v8::Local<v8::Object> CreationContext(
|
|
+ static v8::Local<v8::Object> GetReceiver(
|
|
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
|
return info.Holder();
|
|
}
|
|
-
|
|
// Helper function for ScriptWrappable
|
|
template <typename CallbackInfo>
|
|
static void SetWrapper(const CallbackInfo& info,
|
|
@@ -290,12 +290,13 @@ void V8SetReturnValue(const CallbackInfo& info,
|
|
if (UNLIKELY(!value))
|
|
return info.GetReturnValue().SetNull();
|
|
ScriptWrappable* wrappable = const_cast<ScriptWrappable*>(value);
|
|
- if (DOMDataStore::SetReturnValueForMainWorld(info.GetReturnValue(),
|
|
- wrappable))
|
|
+ if (DOMDataStore::SetReturnValueFromInlineStorage(info.GetReturnValue(),
|
|
+ wrappable)) {
|
|
return;
|
|
+ }
|
|
V8ReturnValue::SetWrapper(
|
|
info, wrappable,
|
|
- V8ReturnValue::CreationContext(info)->GetCreationContextChecked());
|
|
+ V8ReturnValue::GetReceiver(info)->GetCreationContextChecked());
|
|
}
|
|
|
|
template <typename CallbackInfo>
|
|
@@ -304,12 +305,13 @@ void V8SetReturnValue(const CallbackInfo& info,
|
|
V8ReturnValue::MainWorld) {
|
|
DCHECK(DOMWrapperWorld::Current(info.GetIsolate()).IsMainWorld());
|
|
ScriptWrappable* wrappable = const_cast<ScriptWrappable*>(&value);
|
|
- if (DOMDataStore::SetReturnValueForMainWorld(info.GetReturnValue(),
|
|
- wrappable))
|
|
+ if (DOMDataStore::SetReturnValueFromInlineStorage(info.GetReturnValue(),
|
|
+ wrappable)) {
|
|
return;
|
|
+ }
|
|
V8ReturnValue::SetWrapper(
|
|
info, wrappable,
|
|
- V8ReturnValue::CreationContext(info)->GetCreationContextChecked());
|
|
+ V8ReturnValue::GetReceiver(info)->GetCreationContextChecked());
|
|
}
|
|
|
|
template <typename CallbackInfo>
|
|
@@ -320,13 +322,13 @@ void V8SetReturnValue(const CallbackInfo& info,
|
|
return info.GetReturnValue().SetNull();
|
|
ScriptWrappable* wrappable = const_cast<ScriptWrappable*>(value);
|
|
if (DOMDataStore::SetReturnValueFast(info.GetReturnValue(), wrappable,
|
|
- V8ReturnValue::CreationContext(info),
|
|
+ V8ReturnValue::GetReceiver(info),
|
|
receiver)) {
|
|
return;
|
|
}
|
|
V8ReturnValue::SetWrapper(
|
|
info, wrappable,
|
|
- V8ReturnValue::CreationContext(info)->GetCreationContextChecked());
|
|
+ V8ReturnValue::GetReceiver(info)->GetCreationContextChecked());
|
|
}
|
|
|
|
template <typename CallbackInfo>
|
|
@@ -335,13 +337,13 @@ void V8SetReturnValue(const CallbackInfo& info,
|
|
const ScriptWrappable* receiver) {
|
|
ScriptWrappable* wrappable = const_cast<ScriptWrappable*>(&value);
|
|
if (DOMDataStore::SetReturnValueFast(info.GetReturnValue(), wrappable,
|
|
- V8ReturnValue::CreationContext(info),
|
|
+ V8ReturnValue::GetReceiver(info),
|
|
receiver)) {
|
|
return;
|
|
}
|
|
V8ReturnValue::SetWrapper(
|
|
info, wrappable,
|
|
- V8ReturnValue::CreationContext(info)->GetCreationContextChecked());
|
|
+ V8ReturnValue::GetReceiver(info)->GetCreationContextChecked());
|
|
}
|
|
|
|
template <typename CallbackInfo>
|
|
@@ -353,7 +355,7 @@ void V8SetReturnValue(const CallbackInfo& info,
|
|
return info.GetReturnValue().SetNull();
|
|
ScriptWrappable* wrappable = const_cast<ScriptWrappable*>(value);
|
|
if (DOMDataStore::SetReturnValueFast(info.GetReturnValue(), wrappable,
|
|
- V8ReturnValue::CreationContext(info),
|
|
+ V8ReturnValue::GetReceiver(info),
|
|
receiver)) {
|
|
return;
|
|
}
|
|
@@ -369,7 +371,7 @@ void V8SetReturnValue(const CallbackInfo& info,
|
|
// with the current context will still have the correct v8::Isolate and
|
|
// DOMWrapperWorld.
|
|
v8::Local<v8::Context> context;
|
|
- if (!V8ReturnValue::CreationContext(info)->GetCreationContext().ToLocal(
|
|
+ if (!V8ReturnValue::GetReceiver(info)->GetCreationContext().ToLocal(
|
|
&context)) {
|
|
context = info.GetIsolate()->GetCurrentContext();
|
|
}
|
|
@@ -383,7 +385,7 @@ void V8SetReturnValue(const CallbackInfo& info,
|
|
V8ReturnValue::MaybeCrossOrigin) {
|
|
ScriptWrappable* wrappable = const_cast<ScriptWrappable*>(&value);
|
|
if (DOMDataStore::SetReturnValueFast(info.GetReturnValue(), wrappable,
|
|
- V8ReturnValue::CreationContext(info),
|
|
+ V8ReturnValue::GetReceiver(info),
|
|
receiver)) {
|
|
return;
|
|
}
|
|
@@ -399,7 +401,7 @@ void V8SetReturnValue(const CallbackInfo& info,
|
|
// with the current context will still have the correct v8::Isolate and
|
|
// DOMWrapperWorld.
|
|
v8::Local<v8::Context> context;
|
|
- if (!V8ReturnValue::CreationContext(info)->GetCreationContext().ToLocal(
|
|
+ if (!V8ReturnValue::GetReceiver(info)->GetCreationContext().ToLocal(
|
|
&context)) {
|
|
context = info.GetIsolate()->GetCurrentContext();
|
|
}
|
|
diff --git a/third_party/blink/renderer/platform/heap/thread_state.cc b/third_party/blink/renderer/platform/heap/thread_state.cc
|
|
index 55434e8c3a6d57ff8088821e7c4777334d9119b8..f68b52c7fd23f2b296abf8493fa52b216d68fe98 100644
|
|
--- a/third_party/blink/renderer/platform/heap/thread_state.cc
|
|
+++ b/third_party/blink/renderer/platform/heap/thread_state.cc
|
|
@@ -10,6 +10,7 @@
|
|
#include "base/functional/callback.h"
|
|
#include "base/notreached.h"
|
|
#include "gin/public/v8_platform.h"
|
|
+#include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
|
|
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
|
|
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
|
|
#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
|
|
@@ -46,7 +47,7 @@ class BlinkRootsHandler final : public v8::EmbedderRootsHandler {
|
|
// generation garbage collections.
|
|
void ResetRoot(const v8::TracedReference<v8::Value>& handle) final {
|
|
const v8::TracedReference<v8::Object>& traced = handle.As<v8::Object>();
|
|
- bool success = DOMWrapperWorld::ClearWrapperIfEqualTo(
|
|
+ bool success = DOMDataStore::ClearWrapperInAnyWorldIfEqualTo(
|
|
ToScriptWrappable(traced), traced);
|
|
// Since V8 found a handle, Blink needs to find it as well when trying to
|
|
// remove it.
|
|
@@ -55,7 +56,7 @@ class BlinkRootsHandler final : public v8::EmbedderRootsHandler {
|
|
|
|
bool TryResetRoot(const v8::TracedReference<v8::Value>& handle) final {
|
|
const v8::TracedReference<v8::Object>& traced = handle.As<v8::Object>();
|
|
- return DOMWrapperWorld::ClearMainWorldWrapperIfEqualTo(
|
|
+ return DOMDataStore::ClearInlineStorageWrapperIfEqualTo(
|
|
ToScriptWrappable(traced), traced);
|
|
}
|
|
};
|