diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 16:23:34 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:37:21 +0000 |
commit | 38a9a29f4f9436cace7f0e7abf9c586057df8a4e (patch) | |
tree | c4e8c458dc595bc0ddb435708fa2229edfd00bd4 /chromium/third_party/blink/renderer/platform/bindings | |
parent | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (diff) | |
download | qtwebengine-chromium-38a9a29f4f9436cace7f0e7abf9c586057df8a4e.tar.gz |
BASELINE: Update Chromium to 73.0.3683.37
Change-Id: I08c9af2948b645f671e5d933aca1f7a90ea372f2
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/bindings')
25 files changed, 557 insertions, 201 deletions
diff --git a/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.cc b/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.cc index 6d2eb3757b3..77350a1f66e 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.cc +++ b/chromium/third_party/blink/renderer/platform/bindings/active_script_wrappable_base.cc @@ -20,7 +20,7 @@ void ActiveScriptWrappableBase::TraceActiveScriptWrappables( if (!active_script_wrappables) return; - for (auto active_wrappable : *active_script_wrappables) { + for (const auto& active_wrappable : *active_script_wrappables) { if (!active_wrappable->DispatchHasPendingActivity()) continue; diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.cc b/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.cc index 07c8a4c7e8c..90fb952442e 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.cc +++ b/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.cc @@ -4,18 +4,30 @@ #include "third_party/blink/renderer/platform/bindings/callback_function_base.h" +#include "third_party/blink/renderer/platform/bindings/binding_security_for_platform.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" + namespace blink { CallbackFunctionBase::CallbackFunctionBase( v8::Local<v8::Object> callback_function) { DCHECK(!callback_function.IsEmpty()); - callback_relevant_script_state_ = - ScriptState::From(callback_function->CreationContext()); - v8::Isolate* isolate = callback_relevant_script_state_->GetIsolate(); - + v8::Isolate* isolate = callback_function->GetIsolate(); callback_function_.Set(isolate, callback_function); + incumbent_script_state_ = ScriptState::From(isolate->GetIncumbentContext()); + + // Set |callback_relevant_script_state_| iff the creation context and the + // incumbent context are the same origin-domain. Otherwise, leave it as + // nullptr. + v8::Local<v8::Context> creation_context = + callback_function->CreationContext(); + if (BindingSecurityForPlatform::ShouldAllowAccessToV8Context( + incumbent_script_state_->GetContext(), creation_context, + BindingSecurityForPlatform::ErrorReportOption::kDoNotReport)) { + callback_relevant_script_state_ = ScriptState::From(creation_context); + } } void CallbackFunctionBase::Trace(Visitor* visitor) { @@ -24,9 +36,44 @@ void CallbackFunctionBase::Trace(Visitor* visitor) { visitor->Trace(incumbent_script_state_); } +ScriptState* CallbackFunctionBase::CallbackRelevantScriptStateOrReportError( + const char* interface, + const char* operation) { + if (callback_relevant_script_state_) + return callback_relevant_script_state_; + + // Report a SecurityError due to a cross origin callback object. + ScriptState::Scope incumbent_scope(incumbent_script_state_); + v8::TryCatch try_catch(GetIsolate()); + try_catch.SetVerbose(true); + ExceptionState exception_state( + GetIsolate(), ExceptionState::kExecutionContext, interface, operation); + exception_state.ThrowSecurityError( + "An invocation of the provided callback failed due to cross origin " + "access."); + return nullptr; +} + +ScriptState* CallbackFunctionBase::CallbackRelevantScriptStateOrThrowException( + const char* interface, + const char* operation) { + if (callback_relevant_script_state_) + return callback_relevant_script_state_; + + // Throw a SecurityError due to a cross origin callback object. + ScriptState::Scope incumbent_scope(incumbent_script_state_); + ExceptionState exception_state( + GetIsolate(), ExceptionState::kExecutionContext, interface, operation); + exception_state.ThrowSecurityError( + "An invocation of the provided callback failed due to cross origin " + "access."); + return nullptr; +} + V8PersistentCallbackFunctionBase::V8PersistentCallbackFunctionBase( CallbackFunctionBase* callback_function) : callback_function_(callback_function) { + v8::HandleScope scope(callback_function_->GetIsolate()); v8_function_.Reset(callback_function_->GetIsolate(), callback_function_->callback_function_.Get()); } diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.h b/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.h index cc38447a2ad..e13ff148990 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.h +++ b/chromium/third_party/blink/renderer/platform/bindings/callback_function_base.h @@ -36,22 +36,55 @@ class PLATFORM_EXPORT CallbackFunctionBase } v8::Isolate* GetIsolate() const { - return callback_relevant_script_state_->GetIsolate(); + return incumbent_script_state_->GetIsolate(); } + // Returns the ScriptState of the relevant realm of the callback object. + // + // NOTE: This function must be used only when it's pretty sure that the + // callcack object is the same origin-domain. Otherwise, + // |CallbackRelevantScriptStateOrReportError| or + // |CallbackRelevantScriptStateOrThrowException| must be used instead. ScriptState* CallbackRelevantScriptState() { + DCHECK(callback_relevant_script_state_); return callback_relevant_script_state_; } + // Returns the ScriptState of the relevant realm of the callback object iff + // the callback is the same origin-domain. Otherwise, reports an error and + // returns nullptr. + ScriptState* CallbackRelevantScriptStateOrReportError(const char* interface, + const char* operation); + + // Returns the ScriptState of the relevant realm of the callback object iff + // the callback is the same origin-domain. Otherwise, throws an exception and + // returns nullptr. + ScriptState* CallbackRelevantScriptStateOrThrowException( + const char* interface, + const char* operation); + + DOMWrapperWorld& GetWorld() const { return incumbent_script_state_->World(); } + // Returns true if the ES function has a [[Construct]] internal method. bool IsConstructor() const { return CallbackFunction()->IsConstructor(); } + // Makes the underlying V8 function collectable by V8 Scavenger GC. Do not + // use this function unless you really need a hacky performance optimization. + // The V8 function is collectable by V8 Full GC whenever this instance is no + // longer referenced, so there is no need to call this function unless you + // really need V8 *Scavenger* GC to collect the V8 function before V8 Full GC + // runs. + void DisposeV8FunctionImmediatelyToReduceMemoryFootprint() { + callback_function_.Clear(); + } + protected: explicit CallbackFunctionBase(v8::Local<v8::Object>); v8::Local<v8::Function> CallbackFunction() const { return callback_function_.NewLocal(GetIsolate()).As<v8::Function>(); } + ScriptState* IncumbentScriptState() { return incumbent_script_state_; } private: @@ -59,7 +92,8 @@ class PLATFORM_EXPORT CallbackFunctionBase // Use v8::Object instead of v8::Function in order to handle // [TreatNonObjectAsNull]. TraceWrapperV8Reference<v8::Object> callback_function_; - // The associated Realm of the callback function type value. + // The associated Realm of the callback function type value iff it's the same + // origin-domain. Otherwise, nullptr. Member<ScriptState> callback_relevant_script_state_; // The callback context, i.e. the incumbent Realm when an ECMAScript value is // converted to an IDL value. @@ -67,9 +101,6 @@ class PLATFORM_EXPORT CallbackFunctionBase Member<ScriptState> incumbent_script_state_; friend class V8PersistentCallbackFunctionBase; - friend v8::Local<v8::Value> ToV8(CallbackFunctionBase* callback, - v8::Local<v8::Object> creation_context, - v8::Isolate*); }; // V8PersistentCallbackFunctionBase retains the underlying v8::Function of a @@ -124,7 +155,8 @@ ToV8PersistentCallbackFunction(V8CallbackFunction* callback_function) { std::is_base_of<CallbackFunctionBase, V8CallbackFunction>::value, "V8CallbackFunction must be a subclass of CallbackFunctionBase."); return callback_function - ? new V8PersistentCallbackFunction<V8CallbackFunction>( + ? MakeGarbageCollected< + V8PersistentCallbackFunction<V8CallbackFunction>>( callback_function) : nullptr; } diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.cc b/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.cc index 6523b794190..f5d336ffc0a 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.cc +++ b/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.cc @@ -4,25 +4,32 @@ #include "third_party/blink/renderer/platform/bindings/callback_interface_base.h" +#include "third_party/blink/renderer/platform/bindings/binding_security_for_platform.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" + namespace blink { CallbackInterfaceBase::CallbackInterfaceBase( v8::Local<v8::Object> callback_object, - v8::Local<v8::Context> callback_object_creation_context, SingleOperationOrNot single_op_or_not) { DCHECK(!callback_object.IsEmpty()); - DCHECK(!callback_object_creation_context.IsEmpty()); - DCHECK(callback_object->CreationContext() == - callback_object_creation_context); - - callback_relevant_script_state_ = - ScriptState::From(callback_object_creation_context); - v8::Isolate* isolate = callback_relevant_script_state_->GetIsolate(); + v8::Isolate* isolate = callback_object->GetIsolate(); callback_object_.Set(isolate, callback_object); + + incumbent_script_state_ = ScriptState::From(isolate->GetIncumbentContext()); is_callback_object_callable_ = (single_op_or_not == kSingleOperation) && callback_object->IsCallable(); - incumbent_script_state_ = ScriptState::From(isolate->GetIncumbentContext()); + + // Set |callback_relevant_script_state_| iff the creation context and the + // incumbent context are the same origin-domain. Otherwise, leave it as + // nullptr. + v8::Local<v8::Context> creation_context = callback_object->CreationContext(); + if (BindingSecurityForPlatform::ShouldAllowAccessToV8Context( + incumbent_script_state_->GetContext(), creation_context, + BindingSecurityForPlatform::ErrorReportOption::kDoNotReport)) { + callback_relevant_script_state_ = ScriptState::From(creation_context); + } } void CallbackInterfaceBase::Trace(Visitor* visitor) { @@ -31,6 +38,40 @@ void CallbackInterfaceBase::Trace(Visitor* visitor) { visitor->Trace(incumbent_script_state_); } +ScriptState* CallbackInterfaceBase::CallbackRelevantScriptStateOrReportError( + const char* interface, + const char* operation) { + if (callback_relevant_script_state_) + return callback_relevant_script_state_; + + // Report a SecurityError due to a cross origin callback object. + ScriptState::Scope incumbent_scope(incumbent_script_state_); + v8::TryCatch try_catch(GetIsolate()); + try_catch.SetVerbose(true); + ExceptionState exception_state( + GetIsolate(), ExceptionState::kExecutionContext, interface, operation); + exception_state.ThrowSecurityError( + "An invocation of the provided callback failed due to cross origin " + "access."); + return nullptr; +} + +ScriptState* CallbackInterfaceBase::CallbackRelevantScriptStateOrThrowException( + const char* interface, + const char* operation) { + if (callback_relevant_script_state_) + return callback_relevant_script_state_; + + // Throw a SecurityError due to a cross origin callback object. + ScriptState::Scope incumbent_scope(incumbent_script_state_); + ExceptionState exception_state( + GetIsolate(), ExceptionState::kExecutionContext, interface, operation); + exception_state.ThrowSecurityError( + "An invocation of the provided callback failed due to cross origin " + "access."); + return nullptr; +} + V8PersistentCallbackInterfaceBase::V8PersistentCallbackInterfaceBase( CallbackInterfaceBase* callback_interface) : callback_interface_(callback_interface) { diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.h b/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.h index cdd141a3f2b..902d3badf87 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.h +++ b/chromium/third_party/blink/renderer/platform/bindings/callback_interface_base.h @@ -49,14 +49,34 @@ class PLATFORM_EXPORT CallbackInterfaceBase return callback_object_.NewLocal(GetIsolate()); } - v8::Isolate* GetIsolate() { - return callback_relevant_script_state_->GetIsolate(); - } - + v8::Isolate* GetIsolate() { return incumbent_script_state_->GetIsolate(); } + + // Returns the ScriptState of the relevant realm of the callback object. + // + // NOTE: This function must be used only when it's pretty sure that the + // callcack object is the same origin-domain. Otherwise, + // |CallbackRelevantScriptStateOrReportError| or + // |CallbackRelevantScriptStateOrThrowException| must be used instead. ScriptState* CallbackRelevantScriptState() { + DCHECK(callback_relevant_script_state_); return callback_relevant_script_state_; } + // Returns the ScriptState of the relevant realm of the callback object iff + // the callback is the same origin-domain. Otherwise, reports an error and + // returns nullptr. + ScriptState* CallbackRelevantScriptStateOrReportError(const char* interface, + const char* operation); + + // Returns the ScriptState of the relevant realm of the callback object iff + // the callback is the same origin-domain. Otherwise, throws an exception and + // returns nullptr. + ScriptState* CallbackRelevantScriptStateOrThrowException( + const char* interface, + const char* operation); + + DOMWrapperWorld& GetWorld() const { return incumbent_script_state_->World(); } + // NodeIteratorBase counts the invocation of those which are callable and // those which are not. bool IsCallbackObjectCallableForNodeIteratorBase() const { @@ -64,13 +84,13 @@ class PLATFORM_EXPORT CallbackInterfaceBase } protected: - CallbackInterfaceBase(v8::Local<v8::Object> callback_object, - v8::Local<v8::Context> callback_object_creation_context, - SingleOperationOrNot); + explicit CallbackInterfaceBase(v8::Local<v8::Object> callback_object, + SingleOperationOrNot); // Returns true iff the callback interface is a single operation callback // interface and the callback interface type value is callable. bool IsCallbackObjectCallable() const { return is_callback_object_callable_; } + ScriptState* IncumbentScriptState() { return incumbent_script_state_; } private: @@ -87,10 +107,6 @@ class PLATFORM_EXPORT CallbackInterfaceBase Member<ScriptState> incumbent_script_state_; friend class V8PersistentCallbackInterfaceBase; - // ToV8 needs to call |CallbackObject| member function. - friend v8::Local<v8::Value> ToV8(CallbackInterfaceBase* callback, - v8::Local<v8::Object> creation_context, - v8::Isolate*); }; // V8PersistentCallbackInterfaceBase retains the underlying v8::Object of a @@ -145,7 +161,8 @@ ToV8PersistentCallbackInterface(V8CallbackInterface* callback_interface) { std::is_base_of<CallbackInterfaceBase, V8CallbackInterface>::value, "V8CallbackInterface must be a subclass of CallbackInterfaceBase."); return callback_interface - ? new V8PersistentCallbackInterface<V8CallbackInterface>( + ? MakeGarbageCollected< + V8PersistentCallbackInterface<V8CallbackInterface>>( callback_interface) : nullptr; } diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.cc b/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.cc index 2394eec2ba1..ba8e013d0c7 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.cc +++ b/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.cc @@ -18,8 +18,9 @@ CallbackMethodRetriever::CallbackMethodRetriever( DCHECK(constructor_->IsConstructor()); } -void CallbackMethodRetriever::GetPrototypeObject( +v8::Local<v8::Object> CallbackMethodRetriever::GetPrototypeObject( ExceptionState& exception_state) { + DCHECK(prototype_object_.IsEmpty()) << "Do not call GetPrototypeObject twice"; // https://html.spec.whatwg.org/C/custom-elements.html#element-definition // step 10.1. Let prototype be Get(constructor, "prototype"). Rethrow any // exceptions. @@ -29,15 +30,16 @@ void CallbackMethodRetriever::GetPrototypeObject( ->Get(current_context_, V8AtomicString(isolate_, "prototype")) .ToLocal(&prototype)) { exception_state.RethrowV8Exception(try_catch.Exception()); - return; + return v8::Local<v8::Object>(); } // step 10.2. If Type(prototype) is not Object, then throw a TypeError // exception. if (!prototype->IsObject()) { exception_state.ThrowTypeError("constructor prototype is not an object"); - return; + return v8::Local<v8::Object>(); } prototype_object_ = prototype.As<v8::Object>(); + return prototype_object_; } v8::Local<v8::Value> CallbackMethodRetriever::GetFunctionOrUndefined( diff --git a/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.h b/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.h index 1207dbe811b..ee8f10acb2d 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.h +++ b/chromium/third_party/blink/renderer/platform/bindings/callback_method_retriever.h @@ -28,7 +28,7 @@ class PLATFORM_EXPORT CallbackMethodRetriever { // Get the prototype object from the callback function. Must be invoked prior // to GetMethod or GetStaticMethod. - void GetPrototypeObject(ExceptionState&); + v8::Local<v8::Object> GetPrototypeObject(ExceptionState&); // Returns a function extracted from the prototype chain, or undefined. // Throws if the property is neither of function nor undefined. diff --git a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc index 0777e2cf2b6..7b69bb134e8 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc +++ b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.cc @@ -133,7 +133,6 @@ DOMWrapperWorld::~DOMWrapperWorld() { } void DOMWrapperWorld::Dispose() { - dom_object_holders_.clear(); dom_data_store_.reset(); DCHECK(GetWorldMap().Contains(world_id_)); GetWorldMap().erase(world_id_); @@ -207,26 +206,6 @@ void DOMWrapperWorld::SetNonMainWorldHumanReadableName( IsolatedWorldHumanReadableNames().Set(world_id, human_readable_name); } -void DOMWrapperWorld::RegisterDOMObjectHolderInternal( - std::unique_ptr<DOMObjectHolderBase> holder_base) { - DCHECK(!dom_object_holders_.Contains(holder_base.get())); - holder_base->SetWorld(this); - holder_base->SetWeak(&DOMWrapperWorld::WeakCallbackForDOMObjectHolder); - dom_object_holders_.insert(std::move(holder_base)); -} - -void DOMWrapperWorld::UnregisterDOMObjectHolder( - DOMObjectHolderBase* holder_base) { - DCHECK(dom_object_holders_.Contains(holder_base)); - dom_object_holders_.erase(holder_base); -} - -void DOMWrapperWorld::WeakCallbackForDOMObjectHolder( - const v8::WeakCallbackInfo<DOMObjectHolderBase>& data) { - DOMObjectHolderBase* holder_base = data.GetParameter(); - holder_base->World()->UnregisterDOMObjectHolder(holder_base); -} - // static int DOMWrapperWorld::GenerateWorldIdForType(WorldType world_type) { DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<int>, next_world_id, ()); diff --git a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h index fca64772026..251116e7bc9 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h +++ b/chromium/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h @@ -45,7 +45,6 @@ namespace blink { class DOMDataStore; -class DOMObjectHolderBase; class ScriptWrappable; class SecurityOrigin; @@ -122,8 +121,11 @@ class PLATFORM_EXPORT DOMWrapperWorld : public RefCounted<DOMWrapperWorld> { // Associates an isolated world (see above for description) with a security // origin. XMLHttpRequest instances used in that world will be considered // to come from that origin, not the frame's. - static void SetIsolatedWorldSecurityOrigin(int world_id, - scoped_refptr<SecurityOrigin>); + // Note: if |security_origin| is null, the security origin stored for the + // isolated world is cleared. + static void SetIsolatedWorldSecurityOrigin( + int world_id, + scoped_refptr<SecurityOrigin> security_origin); SecurityOrigin* IsolatedWorldSecurityOrigin(); static bool HasWrapperInAnyWorldInMainThread(ScriptWrappable*); @@ -138,58 +140,9 @@ class PLATFORM_EXPORT DOMWrapperWorld : public RefCounted<DOMWrapperWorld> { int GetWorldId() const { return world_id_; } DOMDataStore& DomDataStore() const { return *dom_data_store_; } - template <typename T> - void RegisterDOMObjectHolder(v8::Isolate* isolate, - T* object, - v8::Local<v8::Value> wrapper) { - RegisterDOMObjectHolderInternal( - DOMObjectHolder<T>::Create(isolate, object, wrapper)); - } - private: - class DOMObjectHolderBase { - USING_FAST_MALLOC(DOMObjectHolderBase); - - public: - DOMObjectHolderBase(v8::Isolate* isolate, v8::Local<v8::Value> wrapper) - : wrapper_(isolate, wrapper), world_(nullptr) {} - virtual ~DOMObjectHolderBase() = default; - - DOMWrapperWorld* World() const { return world_; } - void SetWorld(DOMWrapperWorld* world) { world_ = world; } - void SetWeak(v8::WeakCallbackInfo<DOMObjectHolderBase>::Callback callback) { - wrapper_.SetWeak(this, callback); - } - - private: - ScopedPersistent<v8::Value> wrapper_; - DOMWrapperWorld* world_; - }; - - template <typename T> - class DOMObjectHolder : public DOMObjectHolderBase { - public: - static std::unique_ptr<DOMObjectHolder<T>> - Create(v8::Isolate* isolate, T* object, v8::Local<v8::Value> wrapper) { - return base::WrapUnique(new DOMObjectHolder(isolate, object, wrapper)); - } - - private: - DOMObjectHolder(v8::Isolate* isolate, - T* object, - v8::Local<v8::Value> wrapper) - : DOMObjectHolderBase(isolate, wrapper), object_(object) {} - - Persistent<T> object_; - }; - DOMWrapperWorld(v8::Isolate*, WorldType, int world_id); - static void WeakCallbackForDOMObjectHolder( - const v8::WeakCallbackInfo<DOMObjectHolderBase>&); - void RegisterDOMObjectHolderInternal(std::unique_ptr<DOMObjectHolderBase>); - void UnregisterDOMObjectHolder(DOMObjectHolderBase*); - static unsigned number_of_non_main_worlds_in_main_thread_; // Returns an identifier for a given world type. This must not be called for @@ -224,7 +177,6 @@ class PLATFORM_EXPORT DOMWrapperWorld : public RefCounted<DOMWrapperWorld> { const WorldType world_type_; const int world_id_; std::unique_ptr<DOMDataStore> dom_data_store_; - HashSet<std::unique_ptr<DOMObjectHolderBase>> dom_object_holders_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string.cc b/chromium/third_party/blink/renderer/platform/bindings/parkable_string.cc index f2189c0b52c..df13aa4ab0e 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string.cc +++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string.cc @@ -15,10 +15,12 @@ #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/bindings/parkable_string_manager.h" #include "third_party/blink/renderer/platform/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/instrumentation/tracing/web_process_memory_dump.h" #include "third_party/blink/renderer/platform/scheduler/public/background_scheduler.h" #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" #include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/wtf/address_sanitizer.h" +#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h" #include "third_party/blink/renderer/platform/wtf/thread_specific.h" #include "third_party/blink/renderer/platform/wtf/vector.h" #include "third_party/zlib/google/compression_utils.h" @@ -86,6 +88,32 @@ void AsanUnpoisonString(const String& string) { #endif // defined(ADDRESS_SANITIZER) } +// Char buffer allocated using PartitionAlloc, may be nullptr. +class NullableCharBuffer final { + public: + explicit NullableCharBuffer(size_t size) { + data_ = + reinterpret_cast<char*>(WTF::Partitions::BufferPartition()->AllocFlags( + base::PartitionAllocReturnNull, size, "NullableCharBuffer")); + size_ = size; + } + + ~NullableCharBuffer() { + if (data_) + WTF::Partitions::BufferPartition()->Free(data_); + } + + // May return nullptr. + char* data() const { return data_; } + size_t size() const { return size_; } + + private: + char* data_; + size_t size_; + + DISALLOW_COPY_AND_ASSIGN(NullableCharBuffer); +}; + } // namespace // Created and destroyed on the same thread, accessed on a background thread as @@ -185,6 +213,12 @@ void ParkableStringImpl::Unlock() { #endif // defined(ADDRESS_SANITIZER) && DCHECK_IS_ON() } +void ParkableStringImpl::PurgeMemory() { + AssertOnValidThread(); + if (state_ == State::kUnparked) + compressed_ = nullptr; +} + const String& ParkableStringImpl::ToString() { AssertOnValidThread(); MutexLocker locker(mutex_); @@ -338,22 +372,43 @@ void ParkableStringImpl::CompressInBackground( #endif // defined(ADDRESS_SANITIZER) // Compression touches the string. AsanUnpoisonString(params->string->string_); + bool ok; base::StringPiece data(reinterpret_cast<const char*>(params->data), params->size); - std::string compressed_string; - bool ok = compression::GzipCompress(data, &compressed_string); - std::unique_ptr<Vector<uint8_t>> compressed = nullptr; - if (ok && compressed_string.size() < params->size) { - compressed = std::make_unique<Vector<uint8_t>>(); - compressed->Append( - reinterpret_cast<const uint8_t*>(compressed_string.c_str()), - compressed_string.size()); - } + + { + // Temporary vector. As we don't want to waste memory, the temporary buffer + // has the same size as the initial data. Compression will fail if this is + // not large enough. + // + // This is not using: + // - malloc() or any STL container: this is discouraged in blink, and there + // is a suspected memory regression caused by using it (crbug.com/920194). + // - WTF::Vector<> as allocation failures result in an OOM crash, whereas + // we can fail gracefully. See crbug.com/905777 for an example of OOM + // triggered from there. + NullableCharBuffer buffer(params->size); + ok = buffer.data(); + size_t compressed_size; + if (ok) { + ok = compression::GzipCompress(data, buffer.data(), buffer.size(), + &compressed_size); + } + #if defined(ADDRESS_SANITIZER) - params->string->Unlock(); + params->string->Unlock(); #endif // defined(ADDRESS_SANITIZER) + if (ok) { + compressed = std::make_unique<Vector<uint8_t>>(); + // Not using realloc() as we want the compressed data to be a regular + // WTF::Vector. + compressed->Append(reinterpret_cast<const uint8_t*>(buffer.data()), + compressed_size); + } + } + auto* task_runner = params->callback_task_runner.get(); size_t size = params->size; PostCrossThreadTask( @@ -396,6 +451,18 @@ void ParkableString::Unlock() const { impl_->Unlock(); } +void ParkableString::OnMemoryDump(WebProcessMemoryDump* pmd, + const String& name) const { + // Parkable strings are reported by ParkableStringManager. + if (!impl_ || may_be_parked()) + return; + + auto* dump = pmd->CreateMemoryAllocatorDump(name); + dump->AddScalar("size", "bytes", CharactersSizeInBytes()); + pmd->AddSuballocation(dump->Guid(), + String(WTF::Partitions::kAllocatedObjectPoolName)); +} + bool ParkableString::Is8Bit() const { return impl_->is_8bit(); } diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string.h b/chromium/third_party/blink/renderer/platform/bindings/parkable_string.h index d828bcc9c35..30cdf7bd3fb 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string.h +++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string.h @@ -30,6 +30,7 @@ namespace blink { +class WebProcessMemoryDump; struct CompressionTaskParams; // A parked string is parked by calling |Park()|, and unparked by calling @@ -60,6 +61,8 @@ class PLATFORM_EXPORT ParkableStringImpl final void Lock(); void Unlock(); + void PurgeMemory(); + // The returned string may be used as a normal one, as long as the // returned value (or a copy of it) is alive. const String& ToString(); @@ -153,6 +156,8 @@ class PLATFORM_EXPORT ParkableString final { // Can be called from any thread. void Unlock() const; + void OnMemoryDump(WebProcessMemoryDump* pmd, const String& name) const; + // See the matching String methods. bool Is8Bit() const; bool IsNull() const { return !impl_; } diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc index 11b9aa40e8b..b38c876b53c 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc +++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc @@ -10,6 +10,8 @@ #include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/single_thread_task_runner.h" +#include "base/trace_event/memory_allocator_dump.h" +#include "base/trace_event/process_memory_dump.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/bindings/parkable_string.h" #include "third_party/blink/renderer/platform/memory_coordinator.h" @@ -21,6 +23,8 @@ namespace blink { +namespace { + class OnPurgeMemoryListener : public GarbageCollected<OnPurgeMemoryListener>, public MemoryCoordinatorClient { USING_GARBAGE_COLLECTED_MIXIN(OnPurgeMemoryListener); @@ -28,12 +32,30 @@ class OnPurgeMemoryListener : public GarbageCollected<OnPurgeMemoryListener>, void OnPurgeMemory() override { if (!base::FeatureList::IsEnabled(kCompressParkableStringsInBackground)) return; - - ParkableStringManager::Instance().ParkAllIfRendererBackgrounded( - ParkableStringImpl::ParkingMode::kAlways); + ParkableStringManager::Instance().PurgeMemory(); } }; +} // namespace + +// static +ParkableStringManagerDumpProvider* +ParkableStringManagerDumpProvider::Instance() { + static ParkableStringManagerDumpProvider instance; + return &instance; +} + +bool ParkableStringManagerDumpProvider::OnMemoryDump( + const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) { + return ParkableStringManager::Instance().OnMemoryDump(pmd); +} + +ParkableStringManagerDumpProvider::~ParkableStringManagerDumpProvider() = + default; +ParkableStringManagerDumpProvider::ParkableStringManagerDumpProvider() = + default; + ParkableStringManager& ParkableStringManager::Instance() { DCHECK(IsMainThread()); DEFINE_STATIC_LOCAL(ParkableStringManager, instance, ()); @@ -94,6 +116,43 @@ bool ParkableStringManager::IsRendererBackgrounded() const { return backgrounded_; } +bool ParkableStringManager::OnMemoryDump( + base::trace_event::ProcessMemoryDump* pmd) { + DCHECK(IsMainThread()); + base::trace_event::MemoryAllocatorDump* dump = + pmd->CreateAllocatorDump("parkable_strings"); + + size_t uncompressed_size = 0; + size_t compressed_size = 0; + size_t metadata_size = 0; + size_t overhead_size = 0; + + for (ParkableStringImpl* str : unparked_strings_.Values()) { + uncompressed_size += str->CharactersSizeInBytes(); + metadata_size += sizeof(ParkableStringImpl); + + if (str->has_compressed_data()) + overhead_size += str->compressed_size(); + } + + for (ParkableStringImpl* str : parked_strings_) { + compressed_size += str->compressed_size(); + metadata_size += sizeof(ParkableStringImpl); + } + + size_t total_size = + uncompressed_size + compressed_size + metadata_size + overhead_size; + dump->AddScalar("size", "bytes", total_size); + dump->AddScalar("uncompressed_size", "bytes", uncompressed_size); + dump->AddScalar("compressed_size", "bytes", compressed_size); + dump->AddScalar("metadata_size", "bytes", metadata_size); + dump->AddScalar("overhead_size", "bytes", overhead_size); + + pmd->AddSuballocation(dump->guid(), + WTF::Partitions::kAllocatedObjectPoolName); + return true; +} + // static bool ParkableStringManager::ShouldPark(const StringImpl& string) { // Don't attempt to park strings smaller than this size. @@ -151,14 +210,10 @@ void ParkableStringManager::OnUnparked(ParkableStringImpl* was_parked_string, unparked_strings_.insert(new_unparked_string, was_parked_string); } -void ParkableStringManager::ParkAllIfRendererBackgrounded( - ParkableStringImpl::ParkingMode mode) { +void ParkableStringManager::ParkAll(ParkableStringImpl::ParkingMode mode) { DCHECK(IsMainThread()); DCHECK(base::FeatureList::IsEnabled(kCompressParkableStringsInBackground)); - if (!IsRendererBackgrounded()) - return; - size_t total_size = 0; for (ParkableStringImpl* str : parked_strings_) total_size += str->CharactersSizeInBytes(); @@ -182,8 +237,9 @@ void ParkableStringManager::ParkAllIfRendererBackgrounded( total_size += str->CharactersSizeInBytes(); } - // Only collect stats for "full" parking calls. - if (mode == ParkableStringImpl::ParkingMode::kAlways) { + // Only collect stats for "full" parking calls in background. + if (mode == ParkableStringImpl::ParkingMode::kAlways && + IsRendererBackgrounded()) { size_t total_size_kb = total_size / 1000; UMA_HISTOGRAM_COUNTS_100000("Memory.MovableStringsTotalSizeKb", total_size_kb); @@ -191,6 +247,14 @@ void ParkableStringManager::ParkAllIfRendererBackgrounded( } } +void ParkableStringManager::ParkAllIfRendererBackgrounded( + ParkableStringImpl::ParkingMode mode) { + DCHECK(IsMainThread()); + + if (IsRendererBackgrounded()) + ParkAll(mode); +} + size_t ParkableStringManager::Size() const { return parked_strings_.size() + unparked_strings_.size(); } @@ -238,6 +302,23 @@ void ParkableStringManager::DropStringsWithCompressedDataAndRecordStatistics() { } } +void ParkableStringManager::PurgeMemory() { + DCHECK(IsMainThread()); + DCHECK(base::FeatureList::IsEnabled(kCompressParkableStringsInBackground)); + + ParkAll(ParkableStringImpl::ParkingMode::kAlways); + // Critical memory pressure: drop compressed data for strings that we cannot + // park now. + // + // After |ParkAll()| has been called, parkable strings have either been parked + // synchronously (and no longer in |unparked_strings_|), or being parked and + // purging is a no-op. + if (!IsRendererBackgrounded()) { + for (ParkableStringImpl* str : unparked_strings_.Values()) + str->PurgeMemory(); + } +} + void ParkableStringManager::ResetForTesting() { backgrounded_ = false; waiting_to_record_stats_ = false; @@ -254,7 +335,8 @@ ParkableStringManager::ParkableStringManager() parked_strings_() { // No need to ever unregister, as the only ParkableStringManager instance // lives forever. - MemoryCoordinator::Instance().RegisterClient(new OnPurgeMemoryListener()); + MemoryCoordinator::Instance().RegisterClient( + MakeGarbageCollected<OnPurgeMemoryListener>()); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h index 262b9ddea2f..54e763184f3 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h +++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_manager.h @@ -8,6 +8,7 @@ #include "base/feature_list.h" #include "base/macros.h" #include "base/memory/scoped_refptr.h" +#include "base/trace_event/memory_dump_provider.h" #include "third_party/blink/renderer/platform/bindings/parkable_string.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" @@ -23,6 +24,23 @@ class ParkableString; const base::Feature kCompressParkableStringsInBackground{ "CompressParkableStringsInBackground", base::FEATURE_DISABLED_BY_DEFAULT}; +class PLATFORM_EXPORT ParkableStringManagerDumpProvider + : public base::trace_event::MemoryDumpProvider { + USING_FAST_MALLOC(ParkableStringManagerDumpProvider); + + public: + static ParkableStringManagerDumpProvider* Instance(); + ~ParkableStringManagerDumpProvider() override; + + bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&, + base::trace_event::ProcessMemoryDump*) override; + + private: + ParkableStringManagerDumpProvider(); + + DISALLOW_COPY_AND_ASSIGN(ParkableStringManagerDumpProvider); +}; + // Manages all the ParkableStrings, and parks eligible strings after the // renderer has been backgrounded. // Main Thread only. @@ -35,9 +53,12 @@ class PLATFORM_EXPORT ParkableStringManager { void SetRendererBackgrounded(bool backgrounded); bool IsRendererBackgrounded() const; + void PurgeMemory(); // Number of parked and unparked strings. Public for testing. size_t Size() const; + bool OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd); + // Whether a string is parkable or not. Can be called from any thread. static bool ShouldPark(const StringImpl& string); @@ -48,7 +69,6 @@ class PLATFORM_EXPORT ParkableStringManager { private: friend class ParkableString; friend class ParkableStringImpl; - friend class OnPurgeMemoryListener; scoped_refptr<ParkableStringImpl> Add(scoped_refptr<StringImpl>&&); void Remove(ParkableStringImpl*, StringImpl*); @@ -56,6 +76,7 @@ class PLATFORM_EXPORT ParkableStringManager { void OnParked(ParkableStringImpl*, StringImpl*); void OnUnparked(ParkableStringImpl*, StringImpl*); + void ParkAll(ParkableStringImpl::ParkingMode mode); void ParkAllIfRendererBackgrounded(ParkableStringImpl::ParkingMode mode); void DropStringsWithCompressedDataAndRecordStatistics(); void ResetForTesting(); diff --git a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc index b186942e1e8..a42626e9944 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc +++ b/chromium/third_party/blink/renderer/platform/bindings/parkable_string_test.cc @@ -2,12 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <limits> +#include <random> #include <thread> #include <vector> #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" +#include "base/trace_event/memory_allocator_dump.h" +#include "base/trace_event/memory_dump_provider.h" +#include "base/trace_event/process_memory_dump.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" #include "third_party/blink/renderer/platform/bindings/parkable_string.h" @@ -25,7 +31,7 @@ constexpr size_t kCompressedSize = 55; String MakeLargeString() { std::vector<char> data(kSizeKb * 1000, 'a'); - return String(String(data.data(), data.size()).ReleaseImpl()); + return String(data.data(), data.size()).ReleaseImpl(); } } // namespace @@ -101,6 +107,37 @@ TEST_F(ParkableStringTest, CheckCompressedSize) { EXPECT_EQ(kCompressedSize, parkable.Impl()->compressed_size()); } +TEST_F(ParkableStringTest, DontCompressRandomString) { + // Make a large random string. Large to make sure it's parkable, and random to + // ensure its compressed size is larger than the initial size (at least from + // gzip's header). Mersenne-Twister implementation is specified, making the + // test deterministic. + std::vector<unsigned char> data(kSizeKb * 1000); + std::mt19937 engine(42); + // uniform_int_distribution<T> is undefined behavior for T = unsigned char. + std::uniform_int_distribution<int> dist( + 0, std::numeric_limits<unsigned char>::max()); + + for (size_t i = 0; i < data.size(); ++i) { + data[i] = static_cast<unsigned char>(dist(engine)); + } + ParkableString parkable(String(data.data(), data.size()).ReleaseImpl()); + + EXPECT_TRUE(parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways)); + RunPostedTasks(); + // Not parked because the temporary buffer wasn't large enough. + EXPECT_FALSE(parkable.Impl()->is_parked()); +} + +TEST_F(ParkableStringTest, ParkUnparkIdenticalContent) { + ParkableString parkable(MakeLargeString().ReleaseImpl()); + EXPECT_TRUE(parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways)); + RunPostedTasks(); + EXPECT_TRUE(parkable.Impl()->is_parked()); + + EXPECT_EQ(MakeLargeString(), parkable.ToString()); +} + TEST_F(ParkableStringTest, Simple) { ParkableString parkable_abc(String("abc").ReleaseImpl()); @@ -543,14 +580,14 @@ TEST_F(ParkableStringTest, SynchronousCompression) { parkable.ToString(); EXPECT_TRUE(parkable.Impl()->has_compressed_data()); // No waiting, synchronous compression. - manager.ParkAllIfRendererBackgrounded( - ParkableStringImpl::ParkingMode::kIfCompressedDataExists); + manager.ParkAll(ParkableStringImpl::ParkingMode::kIfCompressedDataExists); EXPECT_TRUE(parkable.Impl()->is_parked()); scoped_task_environment_.FastForwardUntilNoTasksRemain(); } -TEST_F(ParkableStringTest, OnPurgeMemory) { +TEST_F(ParkableStringTest, OnPurgeMemoryInBackground) { ParkableString parkable = CreateAndParkAll(); + EXPECT_TRUE(ParkableStringManager::Instance().IsRendererBackgrounded()); parkable.ToString(); EXPECT_FALSE(parkable.Impl()->is_parked()); @@ -558,6 +595,80 @@ TEST_F(ParkableStringTest, OnPurgeMemory) { MemoryCoordinator::Instance().OnPurgeMemory(); EXPECT_TRUE(parkable.Impl()->is_parked()); + + parkable.ToString(); + EXPECT_TRUE(parkable.Impl()->has_compressed_data()); +} + +TEST_F(ParkableStringTest, OnPurgeMemoryInForeground) { + ParkableString parkable1 = CreateAndParkAll(); + ParkableString parkable2(MakeLargeString().ReleaseImpl()); + + // Park everything. + ParkableStringManager::Instance().SetRendererBackgrounded(true); + WaitForDelayedParking(); + EXPECT_TRUE(parkable1.Impl()->is_parked()); + EXPECT_TRUE(parkable2.Impl()->is_parked()); + + ParkableStringManager::Instance().SetRendererBackgrounded(false); + + // Different usage patterns: + // 1. Parkable, will be parked synchronouly. + // 2. Cannot be parked, compressed representation is purged. + parkable1.ToString(); + String retained = parkable2.ToString(); + EXPECT_TRUE(parkable2.Impl()->has_compressed_data()); + + MemoryCoordinator::Instance().OnPurgeMemory(); + EXPECT_TRUE(parkable1.Impl()->is_parked()); // Parked synchronously. + EXPECT_FALSE(parkable2.Impl()->is_parked()); + EXPECT_FALSE(parkable2.Impl()->has_compressed_data()); // Purged. + + parkable1.ToString(); + EXPECT_TRUE(parkable1.Impl()->has_compressed_data()); +} + +TEST_F(ParkableStringTest, ReportMemoryDump) { + using base::trace_event::MemoryAllocatorDump; + using testing::ByRef; + using testing::Contains; + using testing::Eq; + + auto& manager = ParkableStringManager::Instance(); + ParkableString parkable1(MakeLargeString().ReleaseImpl()); + ParkableString parkable2(MakeLargeString().ReleaseImpl()); + // Not reported in stats below. + ParkableString parkable3(String("short string, not parkable").ReleaseImpl()); + + manager.SetRendererBackgrounded(true); + WaitForDelayedParking(); + parkable1.ToString(); + + base::trace_event::MemoryDumpArgs args = { + base::trace_event::MemoryDumpLevelOfDetail::DETAILED}; + base::trace_event::ProcessMemoryDump pmd(args); + manager.OnMemoryDump(&pmd); + base::trace_event::MemoryAllocatorDump* dump = + pmd.GetAllocatorDump("parkable_strings"); + ASSERT_NE(nullptr, dump); + + // |parkable1| is unparked. + MemoryAllocatorDump::Entry uncompressed("uncompressed_size", "bytes", + kSizeKb * 1000); + EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(uncompressed)))); + + MemoryAllocatorDump::Entry compressed("compressed_size", "bytes", + kCompressedSize); + EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(compressed)))); + + // |parkable1| compressed data is overhead. + MemoryAllocatorDump::Entry overhead("overhead_size", "bytes", + kCompressedSize); + EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(overhead)))); + + MemoryAllocatorDump::Entry metadata("metadata_size", "bytes", + 2 * sizeof(ParkableStringImpl)); + EXPECT_THAT(dump->entries(), Contains(Eq(ByRef(metadata)))); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h b/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h index 24643901979..749837ee49c 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h +++ b/chromium/third_party/blink/renderer/platform/bindings/runtime_call_stats.h @@ -199,7 +199,6 @@ class PLATFORM_EXPORT RuntimeCallStats { #define BINDINGS_COUNTERS(V) \ V(AssociateObjectWithWrapper) \ V(CreateWrapper) \ - V(GetEventListener) \ V(HasInstance) \ V(ToExecutionContext) \ V(ToV8DOMWindow) \ diff --git a/chromium/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h b/chromium/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h index 20778d6a0de..8433c4b8c5b 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h +++ b/chromium/third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h @@ -57,6 +57,9 @@ class PLATFORM_EXPORT ScriptWrappableMarkingVisitor template <typename T> inline static void WriteBarrier(const T* dst_object); + template <typename T> + static void WriteBarrier(TraceWrapperMember<T>* array, size_t length); + static void WriteBarrier(v8::Isolate*, const WrapperTypeInfo*, void*); static void WriteBarrier(v8::Isolate*, @@ -229,6 +232,25 @@ inline void ScriptWrappableMarkingVisitor::WriteBarrier(const T* dst_object) { TraceDescriptorFor(dst_object)); } +template <typename T> +inline void ScriptWrappableMarkingVisitor::WriteBarrier( + TraceWrapperMember<T>* array, + size_t length) { + if (!ThreadState::IsAnyWrapperTracing() || !array) + return; + + const ThreadState* thread_state = + ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState(); + DCHECK(thread_state); + // Bail out if tracing is not in progress. + if (!thread_state->IsWrapperTracing()) + return; + + for (size_t i = 0; i < length; ++i) { + CurrentVisitor(thread_state->GetIsolate())->Trace(array[i]); + } +} + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_SCRIPT_WRAPPABLE_MARKING_VISITOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/bindings/to_v8.h b/chromium/third_party/blink/renderer/platform/bindings/to_v8.h index 75478328831..00370018f60 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/to_v8.h +++ b/chromium/third_party/blink/renderer/platform/bindings/to_v8.h @@ -47,10 +47,11 @@ inline v8::Local<v8::Value> ToV8(CallbackFunctionBase* callback, v8::Isolate* isolate) { // |creation_context| is intentionally ignored. Callback functions are not // wrappers nor clonable. ToV8 on a callback function must be used only when - // it's the same origin-domain in the same world. - DCHECK(!callback || (callback->CallbackRelevantScriptState()->GetContext() == - creation_context->CreationContext())); - return callback ? callback->CallbackFunction().As<v8::Value>() + // it's in the same world. + DCHECK(!callback || + (&callback->GetWorld() == + &ScriptState::From(creation_context->CreationContext())->World())); + return callback ? callback->CallbackObject().As<v8::Value>() : v8::Null(isolate).As<v8::Value>(); } @@ -59,11 +60,12 @@ inline v8::Local<v8::Value> ToV8(CallbackFunctionBase* callback, inline v8::Local<v8::Value> ToV8(CallbackInterfaceBase* callback, v8::Local<v8::Object> creation_context, v8::Isolate* isolate) { - // |creation_context| is intentionally ignored. Callback interface objects - // are not wrappers nor clonable. ToV8 on a callback interface object must - // be used only when it's the same origin-domain in the same world. - DCHECK(!callback || (callback->CallbackRelevantScriptState()->GetContext() == - creation_context->CreationContext())); + // |creation_context| is intentionally ignored. Callback interfaces are not + // wrappers nor clonable. ToV8 on a callback interface must be used only when + // it's in the same world. + DCHECK(!callback || + (&callback->GetWorld() == + &ScriptState::From(creation_context->CreationContext())->World())); return callback ? callback->CallbackObject().As<v8::Value>() : v8::Null(isolate).As<v8::Value>(); } diff --git a/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_member.h b/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_member.h index d021dcc8977..79304ef441e 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_member.h +++ b/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_member.h @@ -61,30 +61,6 @@ class TraceWrapperMember : public Member<T> { } }; -// Swaps two HeapVectors specialized for TraceWrapperMember. The custom swap -// function is required as TraceWrapperMember potentially requires emitting a -// write barrier. -template <typename T> -void swap(HeapVector<TraceWrapperMember<T>>& a, - HeapVector<TraceWrapperMember<T>>& b) { - // HeapVector<Member<T>> and HeapVector<TraceWrapperMember<T>> have the - // same size and semantics. - HeapVector<Member<T>>& a_ = reinterpret_cast<HeapVector<Member<T>>&>(a); - HeapVector<Member<T>>& b_ = reinterpret_cast<HeapVector<Member<T>>&>(b); - a_.swap(b_); - if (ThreadState::IsAnyWrapperTracing() && - ThreadState::Current()->IsWrapperTracing()) { - // If incremental marking is enabled we need to emit the write barrier since - // the swap was performed on HeapVector<Member<T>>. - for (auto item : a) { - ScriptWrappableMarkingVisitor::WriteBarrier(item.Get()); - } - for (auto item : b) { - ScriptWrappableMarkingVisitor::WriteBarrier(item.Get()); - } - } -} - // HeapVectorBacking<TraceWrapperMember<T>> need to map to // HeapVectorBacking<Member<T>> for performing the swap method below. template <typename T, typename Traits> diff --git a/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h b/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h index 21bb8db0d92..41c038346a5 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h +++ b/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h @@ -11,8 +11,9 @@ namespace blink { /** - * TraceWrapperV8Reference is used to trace from Blink to V8. The reference is - * (strongly) traced by wrapper tracing. + * TraceWrapperV8Reference is used to hold references from Blink to V8 that are + * known to both garbage collectors. The reference is a regular traced reference + * for wrapper tracing as well as unified heap garbage collections. * * TODO(mlippautz): Use a better handle type than v8::Persistent. */ @@ -37,16 +38,6 @@ class TraceWrapperV8Reference { handle_.SetWeak(); } - template <typename P> - void Set(v8::Isolate* isolate, - v8::Local<T> handle, - P* parameters, - void (*callback)(const v8::WeakCallbackInfo<P>&), - v8::WeakCallbackType type = v8::WeakCallbackType::kParameter) { - InternalSet(isolate, handle); - handle_.SetWeak(parameters, callback, type); - } - ALWAYS_INLINE v8::Local<T> NewLocal(v8::Isolate* isolate) const { return v8::Local<T>::New(isolate, handle_); } diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_binding.h b/chromium/third_party/blink/renderer/platform/bindings/v8_binding.h index 378f5434309..ba7445d3342 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/v8_binding.h +++ b/chromium/third_party/blink/renderer/platform/bindings/v8_binding.h @@ -276,9 +276,9 @@ inline v8::Local<v8::String> V8String(v8::Isolate* isolate, DCHECK(isolate); if (!string || string[0] == '\0') return v8::String::Empty(isolate); - return v8::String::NewFromOneByte(isolate, - reinterpret_cast<const uint8_t*>(string), - v8::NewStringType::kNormal, strlen(string)) + return v8::String::NewFromOneByte( + isolate, reinterpret_cast<const uint8_t*>(string), + v8::NewStringType::kNormal, static_cast<int>(strlen(string))) .ToLocalChecked(); } @@ -324,7 +324,7 @@ inline v8::Local<v8::String> V8AtomicString(v8::Isolate* isolate, return v8::String::Empty(isolate); return v8::String::NewFromOneByte( isolate, reinterpret_cast<const uint8_t*>(string), - v8::NewStringType::kInternalized, strlen(string)) + v8::NewStringType::kInternalized, static_cast<int>(strlen(string))) .ToLocalChecked(); } diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_global_value_map.h b/chromium/third_party/blink/renderer/platform/bindings/v8_global_value_map.h index df0f8eb117c..6ca82aea230 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/v8_global_value_map.h +++ b/chromium/third_party/blink/renderer/platform/bindings/v8_global_value_map.h @@ -111,6 +111,8 @@ class V8GlobalValueMap : public v8::GlobalValueMap< typedef V8GlobalValueMapTraits<KeyType, ValueType, type> Traits; explicit V8GlobalValueMap(v8::Isolate* isolate) : v8::GlobalValueMap<KeyType, ValueType, Traits>(isolate) {} + V8GlobalValueMap(v8::Isolate* isolate, const char* label) + : v8::GlobalValueMap<KeyType, ValueType, Traits>(isolate, label) {} }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc b/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc index 20c5c4df946..ee25586573c 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc +++ b/chromium/third_party/blink/renderer/platform/bindings/v8_per_context_data.cc @@ -45,16 +45,25 @@ namespace blink { +namespace { + +constexpr char kWrapperBoilerplatesLabel[] = + "V8PerContextData::wrapper_boilerplates_"; +constexpr char kConstructorMapLabel[] = "V8PerContextData::constructor_map_"; +constexpr char kContextLabel[] = "V8PerContextData::context_"; + +} // namespace + V8PerContextData::V8PerContextData(v8::Local<v8::Context> context) : isolate_(context->GetIsolate()), - wrapper_boilerplates_(isolate_), - constructor_map_(isolate_), + wrapper_boilerplates_(isolate_, kWrapperBoilerplatesLabel), + constructor_map_(isolate_, kConstructorMapLabel), context_holder_(std::make_unique<gin::ContextHolder>(isolate_)), context_(isolate_, context), activity_logger_(nullptr), data_map_(MakeGarbageCollected<DataMap>()) { context_holder_->SetContext(context); - context_.Get().AnnotateStrongRetainer("blink::V8PerContextData::context_"); + context_.Get().AnnotateStrongRetainer(kContextLabel); if (IsMainThread()) { InstanceCounters::IncrementCounter( diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc index eed599acde1..5766cb414fe 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc +++ b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc @@ -49,6 +49,13 @@ namespace blink { +namespace { + +constexpr char kInterfaceMapLabel[] = + "V8PerIsolateData::interface_template_map_for_v8_context_snapshot_"; + +} // namespace + // Wrapper function defined in WebKit.h v8::Isolate* MainThreadIsolate() { return V8PerIsolateData::MainThreadIsolate(); @@ -75,7 +82,8 @@ V8PerIsolateData::V8PerIsolateData( : gin::IsolateHolder::kAllowAtomicsWait, IsMainThread() ? gin::IsolateHolder::IsolateType::kBlinkMainThread : gin::IsolateHolder::IsolateType::kBlinkWorkerThread), - interface_template_map_for_v8_context_snapshot_(GetIsolate()), + interface_template_map_for_v8_context_snapshot_(GetIsolate(), + kInterfaceMapLabel), string_cache_(std::make_unique<StringCache>(GetIsolate())), private_property_(V8PrivateProperty::Create()), constructor_mode_(ConstructorMode::kCreateNewObject), @@ -86,8 +94,7 @@ V8PerIsolateData::V8PerIsolateData( new ScriptWrappableMarkingVisitor(ThreadState::Current())), unified_heap_controller_( new UnifiedHeapController(ThreadState::Current())), - runtime_call_stats_(base::DefaultTickClock::GetInstance()), - handled_near_v8_heap_limit_(false) { + runtime_call_stats_(base::DefaultTickClock::GetInstance()) { // FIXME: Remove once all v8::Isolate::GetCurrent() calls are gone. GetIsolate()->Enter(); GetIsolate()->AddBeforeCallEnteredCallback(&BeforeCallEnteredCallback); @@ -112,8 +119,7 @@ V8PerIsolateData::V8PerIsolateData() use_counter_disabled_(false), is_handling_recursion_level_error_(false), is_reporting_exception_(false), - runtime_call_stats_(base::DefaultTickClock::GetInstance()), - handled_near_v8_heap_limit_(false) { + runtime_call_stats_(base::DefaultTickClock::GetInstance()) { CHECK(IsMainThread()); // SnapshotCreator enters the isolate, so we don't call Isolate::Enter() here. diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h index d126266a5c4..6599b4fed71 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h +++ b/chromium/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h @@ -219,10 +219,6 @@ class PLATFORM_EXPORT V8PerIsolateData { return unified_heap_controller_.get(); } - int IsNearV8HeapLimitHandled() { return handled_near_v8_heap_limit_; } - - void HandledNearV8HeapLimit() { handled_near_v8_heap_limit_ = true; } - private: V8PerIsolateData(scoped_refptr<base::SingleThreadTaskRunner>, V8ContextSnapshotMode); @@ -294,7 +290,6 @@ class PLATFORM_EXPORT V8PerIsolateData { std::unique_ptr<UnifiedHeapController> unified_heap_controller_; RuntimeCallStats runtime_call_stats_; - bool handled_near_v8_heap_limit_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/bindings/v8_private_property.h b/chromium/third_party/blink/renderer/platform/bindings/v8_private_property.h index 6eff732d5b3..8dfd6ec588c 100644 --- a/chromium/third_party/blink/renderer/platform/bindings/v8_private_property.h +++ b/chromium/third_party/blink/renderer/platform/bindings/v8_private_property.h @@ -49,8 +49,6 @@ class ScriptWrappable; X(SameObject, NotificationVibrate) \ X(SameObject, PerformanceLongTaskTimingAttribution) \ X(SameObject, PushManagerSupportedContentEncodings) \ - X(CustomWrappable, EventHandler) \ - X(CustomWrappable, EventListener) \ SCRIPT_PROMISE_PROPERTIES(X, Promise) \ SCRIPT_PROMISE_PROPERTIES(X, Resolver) |