blob: 85b3e322567122d3d13b3e65569d348180037aec [file] [log] [blame]
// 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_