blob: ead9b5febbddcb2d467b46c9d04ff67f77c02a0d [file] [log] [blame]
/*
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DOMDataStore_h
#define DOMDataStore_h
#include "bindings/core/v8/DOMWrapperMap.h"
#include "bindings/core/v8/DOMWrapperWorld.h"
#include "bindings/core/v8/ScriptWrappable.h"
#include "bindings/core/v8/WrapperTypeInfo.h"
#include "wtf/Noncopyable.h"
#include "wtf/StdLibExtras.h"
#include <v8.h>
namespace blink {
class Node;
class DOMDataStore {
WTF_MAKE_NONCOPYABLE(DOMDataStore);
public:
explicit DOMDataStore(bool isMainWorld);
~DOMDataStore();
static DOMDataStore& current(v8::Isolate*);
// 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 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).
template<typename T>
static bool canUseScriptWrappable(T* object)
{
return !DOMWrapperWorld::isolatedWorldsExist()
&& !canExistInWorker(object)
&& ScriptWrappable::wrapperCanBeStoredInObject(object);
}
template<typename V8T, typename T, typename Wrappable>
static bool setReturnValueFromWrapperFast(v8::ReturnValue<v8::Value> returnValue, T* object, v8::Local<v8::Object> holder, Wrappable* wrappable)
{
if (canUseScriptWrappable(object)) {
ScriptWrappable::assertWrapperSanity<V8T, T>(object, object);
return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
}
// 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.
// FIXME: Investigate if it's worth having this check for performance.
if (holderContainsWrapper(holder, wrappable)) {
if (ScriptWrappable::wrapperCanBeStoredInObject(object)) {
ScriptWrappable::assertWrapperSanity<V8T, T>(object, object);
return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
}
return DOMWrapperWorld::mainWorld().domDataStore().m_wrapperMap.setReturnValueFrom(returnValue, V8T::toScriptWrappableBase(object));
}
return current(returnValue.GetIsolate()).template setReturnValueFrom<V8T>(returnValue, object);
}
static bool setReturnValueFastNonTemplate(v8::ReturnValue<v8::Value> returnValue, ScriptWrappable* object, v8::Local<v8::Object> holder, const ScriptWrappable* wrappable)
{
// 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.
// FIXME: Investigate if it's worth having this check for performance.
if (holderContainsWrapper(holder, wrappable))
return object->setReturnValue(returnValue);
return current(returnValue.GetIsolate()).setReturnValueFromNonTemplate(returnValue, object);
}
static bool setReturnValueFastNonTemplate(v8::ReturnValue<v8::Value> returnValue, Node* node, v8::Local<v8::Object> holder, const ScriptWrappable* wrappable)
{
if (canUseScriptWrappable(node)
// 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.
// FIXME: Investigate if it's worth having this check for performance.
|| holderContainsWrapper(holder, wrappable))
return ScriptWrappable::fromNode(node)->setReturnValue(returnValue);
return current(returnValue.GetIsolate()).setReturnValueFromNonTemplate(returnValue, ScriptWrappable::fromNode(node));
}
template<typename V8T, typename T>
static bool setReturnValueFromWrapper(v8::ReturnValue<v8::Value> returnValue, T* object)
{
if (canUseScriptWrappable(object)) {
ScriptWrappable::assertWrapperSanity<V8T, T>(object, object);
return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
}
return current(returnValue.GetIsolate()).template setReturnValueFrom<V8T>(returnValue, object);
}
static bool setReturnValueNonTemplate(v8::ReturnValue<v8::Value> returnValue, ScriptWrappableBase* object)
{
return current(returnValue.GetIsolate()).setReturnValueFromNonTemplate(returnValue, object);
}
static bool setReturnValueNonTemplate(v8::ReturnValue<v8::Value> returnValue, ScriptWrappable* object)
{
return current(returnValue.GetIsolate()).setReturnValueFromNonTemplate(returnValue, object);
}
static bool setReturnValueNonTemplate(v8::ReturnValue<v8::Value> returnValue, Node* object)
{
if (canUseScriptWrappable(object))
return ScriptWrappable::fromNode(object)->setReturnValue(returnValue);
return current(returnValue.GetIsolate()).setReturnValueFromNonTemplate(returnValue, ScriptWrappable::fromNode(object));
}
template<typename V8T, typename T>
static bool setReturnValueFromWrapperForMainWorld(v8::ReturnValue<v8::Value> returnValue, T* object)
{
if (ScriptWrappable::wrapperCanBeStoredInObject(object))
return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
return DOMWrapperWorld::mainWorld().domDataStore().m_wrapperMap.setReturnValueFrom(returnValue, V8T::toScriptWrappableBase(object));
}
static bool setReturnValueForMainWorldNonTemplate(v8::ReturnValue<v8::Value> returnValue, ScriptWrappable* object)
{
return object->setReturnValue(returnValue);
}
template<typename V8T, typename T>
static v8::Handle<v8::Object> getWrapper(T* object, v8::Isolate* isolate)
{
if (canUseScriptWrappable(object)) {
v8::Handle<v8::Object> result = ScriptWrappable::fromObject(object)->newLocalWrapper(isolate);
// Security: always guard against malicious tampering.
ScriptWrappable::assertWrapperSanity<V8T, T>(result, object);
return result;
}
return current(isolate).template get<V8T>(object, isolate);
}
static v8::Handle<v8::Object> getWrapperNonTemplate(ScriptWrappableBase* object, v8::Isolate* isolate)
{
return current(isolate).getNonTemplate(object, isolate);
}
static v8::Handle<v8::Object> getWrapperNonTemplate(ScriptWrappable* object, v8::Isolate* isolate)
{
return current(isolate).getNonTemplate(object, isolate);
}
static v8::Handle<v8::Object> getWrapperNonTemplate(Node* node, v8::Isolate* isolate)
{
if (canUseScriptWrappable(node)) {
v8::Handle<v8::Object> result = ScriptWrappable::fromNode(node)->newLocalWrapper(isolate);
// Security: always guard against malicious tampering.
ScriptWrappable::fromNode(node)->assertWrapperSanity(result);
return result;
}
return current(isolate).getNonTemplate(ScriptWrappable::fromNode(node), isolate);
}
template<typename V8T, typename T>
static void setWrapperReference(const v8::Persistent<v8::Object>& parent, T* child, v8::Isolate* isolate)
{
if (canUseScriptWrappable(child)) {
ScriptWrappable::assertWrapperSanity<V8T, T>(child, child);
ScriptWrappable::fromObject(child)->setReference(parent, isolate);
return;
}
current(isolate).template setReference<V8T>(parent, child, isolate);
}
template<typename V8T, typename T>
static void setWrapper(T* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
{
if (canUseScriptWrappable(object)) {
ScriptWrappable::fromObject(object)->setWrapper(wrapper, isolate, wrapperTypeInfo);
return;
}
return current(isolate).template set<V8T>(object, wrapper, isolate, wrapperTypeInfo);
}
static void setWrapperNonTemplate(ScriptWrappableBase* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
{
return current(isolate).setNonTemplate(object, wrapper, isolate, wrapperTypeInfo);
}
static void setWrapperNonTemplate(ScriptWrappable* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
{
return current(isolate).setNonTemplate(object, wrapper, isolate, wrapperTypeInfo);
}
static void setWrapperNonTemplate(Node* node, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
{
if (canUseScriptWrappable(node)) {
ScriptWrappable::fromNode(node)->setWrapper(wrapper, isolate, wrapperTypeInfo);
return;
}
return current(isolate).setNonTemplate(ScriptWrappable::fromNode(node), wrapper, isolate, wrapperTypeInfo);
}
template<typename V8T, typename T>
static bool containsWrapper(T* object, v8::Isolate* isolate)
{
return current(isolate).template containsWrapper<V8T>(object);
}
static bool containsWrapperNonTemplate(ScriptWrappableBase* object, v8::Isolate* isolate)
{
return current(isolate).containsWrapperNonTemplate(object);
}
static bool containsWrapperNonTemplate(ScriptWrappable* object, v8::Isolate* isolate)
{
return current(isolate).containsWrapperNonTemplate(object);
}
template<typename V8T, typename T>
v8::Handle<v8::Object> get(T* object, v8::Isolate* isolate)
{
if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld)
return ScriptWrappable::fromObject(object)->newLocalWrapper(isolate);
return m_wrapperMap.newLocal(V8T::toScriptWrappableBase(object), isolate);
}
v8::Handle<v8::Object> getNonTemplate(ScriptWrappableBase* object, v8::Isolate* isolate)
{
return m_wrapperMap.newLocal(object->toScriptWrappableBase(), isolate);
}
v8::Handle<v8::Object> getNonTemplate(ScriptWrappable* object, v8::Isolate* isolate)
{
if (m_isMainWorld)
return object->newLocalWrapper(isolate);
return m_wrapperMap.newLocal(object->toScriptWrappableBase(), isolate);
}
template<typename V8T, typename T>
void setReference(const v8::Persistent<v8::Object>& parent, T* child, v8::Isolate* isolate)
{
if (ScriptWrappable::wrapperCanBeStoredInObject(child) && m_isMainWorld) {
ScriptWrappable::fromObject(child)->setReference(parent, isolate);
return;
}
m_wrapperMap.setReference(parent, V8T::toScriptWrappableBase(child), isolate);
}
template<typename V8T, typename T>
bool setReturnValueFrom(v8::ReturnValue<v8::Value> returnValue, T* object)
{
if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld)
return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
return m_wrapperMap.setReturnValueFrom(returnValue, V8T::toScriptWrappableBase(object));
}
bool setReturnValueFromNonTemplate(v8::ReturnValue<v8::Value> returnValue, ScriptWrappableBase* object)
{
return m_wrapperMap.setReturnValueFrom(returnValue, object);
}
bool setReturnValueFromNonTemplate(v8::ReturnValue<v8::Value> returnValue, ScriptWrappable* object)
{
if (m_isMainWorld)
return object->setReturnValue(returnValue);
return m_wrapperMap.setReturnValueFrom(returnValue, object->toScriptWrappableBase());
}
template<typename V8T, typename T>
bool containsWrapper(T* object)
{
if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld)
return ScriptWrappable::fromObject(object)->containsWrapper();
return m_wrapperMap.containsKey(V8T::toScriptWrappableBase(object));
}
bool containsWrapperNonTemplate(ScriptWrappableBase* object)
{
return m_wrapperMap.containsKey(object->toScriptWrappableBase());
}
bool containsWrapperNonTemplate(ScriptWrappable* object)
{
if (m_isMainWorld)
return object->containsWrapper();
return m_wrapperMap.containsKey(object->toScriptWrappableBase());
}
private:
template<typename V8T, typename T>
void set(T* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
{
ASSERT(object);
ASSERT(!wrapper.IsEmpty());
if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld) {
ScriptWrappable::fromObject(object)->setWrapper(wrapper, isolate, wrapperTypeInfo);
return;
}
m_wrapperMap.set(V8T::toScriptWrappableBase(object), wrapper, wrapperTypeInfo);
}
void setNonTemplate(ScriptWrappableBase* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
{
ASSERT(object);
ASSERT(!wrapper.IsEmpty());
m_wrapperMap.set(object->toScriptWrappableBase(), wrapper, wrapperTypeInfo);
}
void setNonTemplate(ScriptWrappable* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
{
ASSERT(object);
ASSERT(!wrapper.IsEmpty());
if (m_isMainWorld) {
object->setWrapper(wrapper, isolate, wrapperTypeInfo);
return;
}
m_wrapperMap.set(object->toScriptWrappableBase(), wrapper, wrapperTypeInfo);
}
static bool canExistInWorker(void*) { return true; }
static bool canExistInWorker(Node*) { return false; }
static bool holderContainsWrapper(v8::Local<v8::Object>, void*)
{
return false;
}
static bool holderContainsWrapper(v8::Local<v8::Object> holder, const ScriptWrappable* wrappable)
{
// Verify our assumptions about the main world.
ASSERT(wrappable);
ASSERT(!wrappable->containsWrapper() || !wrappable->isEqualTo(holder) || current(v8::Isolate::GetCurrent()).m_isMainWorld);
return wrappable->isEqualTo(holder);
}
bool m_isMainWorld;
DOMWrapperMap<ScriptWrappableBase> m_wrapperMap;
};
template<>
inline void DOMWrapperMap<ScriptWrappableBase>::PersistentValueMapTraits::Dispose(
v8::Isolate* isolate,
v8::UniquePersistent<v8::Object> value,
ScriptWrappableBase* key)
{
RELEASE_ASSERT(!value.IsEmpty()); // See crbug.com/368095.
releaseObject(v8::Local<v8::Object>::New(isolate, value));
}
} // namespace blink
#endif // DOMDataStore_h