blob: 2c1da757e4014984c83d7d7bb2b2b03531c8daa9 [file] [log] [blame]
// Copyright 2016 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 V8PrivateProperty_h
#define V8PrivateProperty_h
#include "bindings/core/v8/ScopedPersistent.h"
#include "bindings/core/v8/ScriptPromiseProperties.h"
#include "bindings/core/v8/V8BindingMacros.h"
#include "bindings/core/v8/V8PerIsolateData.h"
#include "core/CoreExport.h"
#include "wtf/Allocator.h"
#include "wtf/PtrUtil.h"
#include <memory>
#include <v8.h>
namespace blink {
class ScriptState;
class ScriptWrappable;
// Apply |X| for each pair of (InterfaceName, PrivateKeyName).
#define V8_PRIVATE_PROPERTY_FOR_EACH(X) \
X(CustomEvent, Detail) \
X(DOMException, Error) \
X(ErrorEvent, Error) \
X(IDBObserver, Callback) \
X(IntersectionObserver, Callback) \
X(MessageEvent, CachedData) \
X(MutationObserver, Callback) \
X(PerformanceObserver, Callback) \
X(PrivateScriptRunner, IsInitialized) \
X(SameObject, NotificationActions) \
X(SameObject, NotificationData) \
X(SameObject, NotificationVibrate) \
X(V8NodeFilterCondition, Filter)
// The getter's name for a private property.
#define V8_PRIVATE_PROPERTY_GETTER_NAME(InterfaceName, PrivateKeyName) \
get##InterfaceName##PrivateKeyName
// The member variable's name for a private property.
#define V8_PRIVATE_PROPERTY_MEMBER_NAME(InterfaceName, PrivateKeyName) \
m_symbol##InterfaceName##PrivateKeyName
// The string used to create a private symbol. Must be unique per V8 instance.
#define V8_PRIVATE_PROPERTY_SYMBOL_STRING(InterfaceName, PrivateKeyName) \
#InterfaceName "#" #PrivateKeyName // NOLINT(whitespace/indent)
// Provides access to V8's private properties.
//
// Usage 1) Fast path to use a pre-registered symbol.
// auto private = V8PrivateProperty::getMessageEventCachedData(isolate);
// v8::Local<v8::Context> context = ...;
// v8::Local<v8::Object> object = ...;
// v8::Local<v8::Value> value = private.get(context, object);
// value = ...;
// private.set(context, object, value);
//
// Usage 2) Slow path to create a global private symbol.
// const char symbolName[] = "Interface#PrivateKeyName";
// auto private = V8PrivateProperty::createSymbol(isolate, symbolName,
// sizeof symbolName);
// ...
class CORE_EXPORT V8PrivateProperty {
USING_FAST_MALLOC(V8PrivateProperty);
WTF_MAKE_NONCOPYABLE(V8PrivateProperty);
public:
// Provides fast access to V8's private properties.
//
// Retrieving/creating a global private symbol from a string is very
// expensive compared to get or set a private property. This class
// provides a way to cache a private symbol and re-use it.
class CORE_EXPORT Symbol {
STACK_ALLOCATED();
public:
bool hasValue(v8::Local<v8::Context> context,
v8::Local<v8::Object> object) const {
return v8CallBoolean(object->HasPrivate(context, m_privateSymbol));
}
// Returns the value of the private property if set, or undefined.
v8::Local<v8::Value> getOrUndefined(v8::Local<v8::Context> context,
v8::Local<v8::Object> object) const {
return object->GetPrivate(context, m_privateSymbol).ToLocalChecked();
}
// Returns the value of the private property if set, or an empty handle.
v8::Local<v8::Value> get(v8::Local<v8::Context> context,
v8::Local<v8::Object> object) const {
if (!v8CallBoolean(object->HasPrivate(context, m_privateSymbol)))
return v8::Local<v8::Value>();
v8::Local<v8::Value> value;
if (v8Call(object->GetPrivate(context, m_privateSymbol), value))
return value;
return v8::Local<v8::Value>();
}
bool set(v8::Local<v8::Context> context,
v8::Local<v8::Object> object,
v8::Local<v8::Value> value) const {
return v8CallBoolean(object->SetPrivate(context, m_privateSymbol, value));
}
private:
friend class V8PrivateProperty;
// The following classes are exceptionally allowed to call to
// getFromMainWorld.
friend class V8CustomEvent;
friend class V8ServiceWorkerMessageEventInternal;
explicit Symbol(v8::Local<v8::Private> privateSymbol)
: m_privateSymbol(privateSymbol) {}
// Only friend classes are allowed to use this API.
v8::Local<v8::Value> getFromMainWorld(ScriptState*, ScriptWrappable*);
v8::Local<v8::Private> m_privateSymbol;
};
static std::unique_ptr<V8PrivateProperty> create() {
return wrapUnique(new V8PrivateProperty());
}
#define V8_PRIVATE_PROPERTY_DEFINE_GETTER(InterfaceName, KeyName) \
static Symbol V8_PRIVATE_PROPERTY_GETTER_NAME(InterfaceName, KeyName)( \
v8::Isolate * isolate) /* NOLINT(readability/naming/underscores) */ \
{ \
V8PrivateProperty* privateProp = \
V8PerIsolateData::from(isolate)->privateProperty(); \
if (UNLIKELY(privateProp \
->V8_PRIVATE_PROPERTY_MEMBER_NAME(InterfaceName, KeyName) \
.isEmpty())) { \
privateProp->V8_PRIVATE_PROPERTY_MEMBER_NAME(InterfaceName, KeyName) \
.set( \
isolate, \
createV8Private( \
isolate, \
V8_PRIVATE_PROPERTY_SYMBOL_STRING(InterfaceName, KeyName), \
sizeof V8_PRIVATE_PROPERTY_SYMBOL_STRING( \
InterfaceName, \
KeyName))); /* NOLINT(readability/naming/underscores) */ \
} \
return Symbol( \
privateProp->V8_PRIVATE_PROPERTY_MEMBER_NAME(InterfaceName, KeyName) \
.newLocal(isolate)); \
}
V8_PRIVATE_PROPERTY_FOR_EACH(V8_PRIVATE_PROPERTY_DEFINE_GETTER)
#undef V8_PRIVATE_PROPERTY_DEFINE_GETTER
static Symbol createSymbol(v8::Isolate* isolate,
const char* symbol,
size_t length) {
return Symbol(createV8Private(isolate, symbol, length));
}
private:
V8PrivateProperty() {}
static v8::Local<v8::Private> createV8Private(v8::Isolate*,
const char* symbol,
size_t length);
#define V8_PRIVATE_PROPERTY_DECLARE_MEMBER(InterfaceName, KeyName) \
ScopedPersistent<v8::Private> V8_PRIVATE_PROPERTY_MEMBER_NAME( \
InterfaceName, KeyName); // NOLINT(readability/naming/underscores)
V8_PRIVATE_PROPERTY_FOR_EACH(V8_PRIVATE_PROPERTY_DECLARE_MEMBER)
#undef V8_PRIVATE_PROPERTY_DECLARE_MEMBER
};
} // namespace blink
#endif // V8PrivateProperty_h