| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORLD_SAFE_V8_REFERENCE_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORLD_SAFE_V8_REFERENCE_H_ |
| |
| #include "third_party/blink/renderer/core/core_export.h" |
| #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h" |
| #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h" |
| #include "third_party/blink/renderer/platform/heap/handle.h" |
| #include "v8/include/v8.h" |
| |
| namespace blink { |
| |
| class ScriptState; |
| |
| // This is a namespace to provide utility functions to WorldSafeV8Reference. |
| class CORE_EXPORT WorldSafeV8ReferenceInternal final { |
| STATIC_ONLY(WorldSafeV8ReferenceInternal); |
| |
| private: |
| // Returns a V8 reference that is safe to access in |target_script_state|. |
| // The return value may be a cloned object. |
| // |
| // TODO(crbug.com/803478): ScriptValue::V8ValueFor should be replaced with |
| // this function, or these two functions should be merged at least. |
| static v8::Local<v8::Value> ToWorldSafeValue( |
| ScriptState* target_script_state, |
| const TraceWrapperV8Reference<v8::Value>& v8_reference, |
| const DOMWrapperWorld& v8_reference_world); |
| |
| // Checks the world of |value|'s creation context if |value| is a v8::Object. |
| // The given |world| and |value|'s world must match. Otherwise, crashes. |
| // |
| // TODO(yukishiino): Find the best place to put this function. We might want |
| // to share this function among other clients, e.g. access to wrapper objects |
| // across worlds. |
| static void MaybeCheckCreationContextWorld(const DOMWrapperWorld& world, |
| v8::Local<v8::Value> value); |
| |
| template <typename V8Type> |
| friend class WorldSafeV8Reference; |
| }; |
| |
| // This class provides safe access to v8::Value across worlds. This class |
| // provides accessors that check whether the value is accessed in the same world |
| // or not, also provides an accessor that clones the value when accessed across |
| // worlds. |
| template <typename V8Type> |
| class WorldSafeV8Reference final { |
| DISALLOW_NEW(); |
| |
| public: |
| WorldSafeV8Reference() = default; |
| explicit WorldSafeV8Reference(v8::Isolate* isolate, v8::Local<V8Type> value) |
| : v8_reference_(isolate, value), |
| world_(&DOMWrapperWorld::Current(isolate)) { |
| WorldSafeV8ReferenceInternal::MaybeCheckCreationContextWorld(*world_.get(), |
| value); |
| } |
| ~WorldSafeV8Reference() = default; |
| |
| // Returns the V8 reference. Crashes if |target_script_state|'s world is |
| // different from this V8 reference's world. |
| v8::Local<V8Type> Get(ScriptState* target_script_state) const { |
| DCHECK(!v8_reference_.IsEmpty()); |
| CHECK_EQ(world_.get(), &target_script_state->World()); |
| return v8_reference_.NewLocal(target_script_state->GetIsolate()); |
| } |
| |
| // Returns a V8 reference that is safe to access in |target_script_state|. |
| // The return value may be a cloned object. |
| v8::Local<V8Type> GetAcrossWorld(ScriptState* target_script_state) const { |
| return WorldSafeV8ReferenceInternal::ToWorldSafeValue( |
| target_script_state, v8_reference_, *world_.get()) |
| .template As<V8Type>(); |
| } |
| |
| // Sets a new V8 reference. Crashes if |new_value|'s world is different from |
| // this V8 reference's world. |
| void Set(v8::Isolate* isolate, v8::Local<V8Type> new_value) { |
| DCHECK(!new_value.IsEmpty()); |
| const DOMWrapperWorld& new_world = DOMWrapperWorld::Current(isolate); |
| WorldSafeV8ReferenceInternal::MaybeCheckCreationContextWorld(new_world, |
| new_value); |
| CHECK(v8_reference_.IsEmpty() || world_.get() == &new_world); |
| v8_reference_.Set(isolate, new_value); |
| world_ = WrapRefCounted(&new_world); |
| } |
| |
| // Forcibly sets a new V8 reference even when the worlds are different. The |
| // world of this V8 reference will be |new_value|'s world. |
| void SetAcrossWorld(v8::Isolate* isolate, v8::Local<V8Type> new_value) { |
| DCHECK(!new_value.IsEmpty()); |
| const DOMWrapperWorld& new_world = DOMWrapperWorld::Current(isolate); |
| v8_reference_.Set(isolate, new_value); |
| world_ = WrapRefCounted(&new_world); |
| } |
| |
| void Reset() { |
| v8_reference_.Clear(); |
| world_.reset(); |
| } |
| |
| bool IsEmpty() const { return v8_reference_.IsEmpty(); } |
| |
| void Trace(blink::Visitor* visitor) { visitor->Trace(v8_reference_); } |
| |
| private: |
| TraceWrapperV8Reference<V8Type> v8_reference_; |
| // The world of the current context at the time when |v8_reference_| was set. |
| // It's guaranteed that, if |v8_reference_| is a v8::Object, the world of the |
| // creation context of |v8_reference_| is the same as |world_|. |
| scoped_refptr<const DOMWrapperWorld> world_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WorldSafeV8Reference); |
| }; |
| |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORLD_SAFE_V8_REFERENCE_H_ |