Home | History | Annotate | Download | only in v8
      1 /*
      2  * Copyright (C) 2009 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #ifndef DOMDataStore_h
     32 #define DOMDataStore_h
     33 
     34 #include "bindings/core/v8/DOMWrapperMap.h"
     35 #include "bindings/core/v8/DOMWrapperWorld.h"
     36 #include "bindings/core/v8/ScriptWrappable.h"
     37 #include "bindings/core/v8/WrapperTypeInfo.h"
     38 #include "wtf/Noncopyable.h"
     39 #include "wtf/StdLibExtras.h"
     40 #include <v8.h>
     41 
     42 namespace blink {
     43 
     44 class Node;
     45 
     46 class DOMDataStore {
     47     WTF_MAKE_NONCOPYABLE(DOMDataStore);
     48 public:
     49     explicit DOMDataStore(bool isMainWorld);
     50     ~DOMDataStore();
     51 
     52     static DOMDataStore& current(v8::Isolate*);
     53 
     54     // We can use a wrapper stored in a ScriptWrappable when we're in the main world.
     55     // This method does the fast check if we're in the main world. If this method returns true,
     56     // it is guaranteed that we're in the main world. On the other hand, if this method returns
     57     // false, nothing is guaranteed (we might be in the main world).
     58     template<typename T>
     59     static bool canUseScriptWrappable(T* object)
     60     {
     61         return !DOMWrapperWorld::isolatedWorldsExist()
     62             && !canExistInWorker(object)
     63             && ScriptWrappable::wrapperCanBeStoredInObject(object);
     64     }
     65 
     66     static bool canUseScriptWrappableNonTemplate(Node* object)
     67     {
     68         // Node cannot exist in workers and a wrapper can be stored in Node
     69         // which (indirectly) derives ScriptWrappable.
     70         return !DOMWrapperWorld::isolatedWorldsExist();
     71     }
     72 
     73     template<typename V8T, typename T, typename Wrappable>
     74     static bool setReturnValueFromWrapperFast(v8::ReturnValue<v8::Value> returnValue, T* object, v8::Local<v8::Object> holder, Wrappable* wrappable)
     75     {
     76         if (canUseScriptWrappable(object)) {
     77             ScriptWrappable::assertWrapperSanity<V8T, T>(object, object);
     78             return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
     79         }
     80         // The second fastest way to check if we're in the main world is to check if
     81         // the wrappable's wrapper is the same as the holder.
     82         // FIXME: Investigate if it's worth having this check for performance.
     83         if (holderContainsWrapper(holder, wrappable)) {
     84             if (ScriptWrappable::wrapperCanBeStoredInObject(object)) {
     85                 ScriptWrappable::assertWrapperSanity<V8T, T>(object, object);
     86                 return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
     87             }
     88             return DOMWrapperWorld::mainWorld().domDataStore().m_wrapperMap.setReturnValueFrom(returnValue, V8T::toScriptWrappableBase(object));
     89         }
     90         return current(returnValue.GetIsolate()).template setReturnValueFrom<V8T>(returnValue, object);
     91     }
     92 
     93     template<typename V8T, typename T>
     94     static bool setReturnValueFromWrapper(v8::ReturnValue<v8::Value> returnValue, T* object)
     95     {
     96         if (canUseScriptWrappable(object)) {
     97             ScriptWrappable::assertWrapperSanity<V8T, T>(object, object);
     98             return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
     99         }
    100         return current(returnValue.GetIsolate()).template setReturnValueFrom<V8T>(returnValue, object);
    101     }
    102 
    103     template<typename V8T, typename T>
    104     static bool setReturnValueFromWrapperForMainWorld(v8::ReturnValue<v8::Value> returnValue, T* object)
    105     {
    106         if (ScriptWrappable::wrapperCanBeStoredInObject(object))
    107             return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
    108         return DOMWrapperWorld::mainWorld().domDataStore().m_wrapperMap.setReturnValueFrom(returnValue, V8T::toScriptWrappableBase(object));
    109     }
    110 
    111     template<typename V8T, typename T>
    112     static v8::Handle<v8::Object> getWrapper(T* object, v8::Isolate* isolate)
    113     {
    114         if (canUseScriptWrappable(object)) {
    115             v8::Handle<v8::Object> result = ScriptWrappable::fromObject(object)->newLocalWrapper(isolate);
    116             // Security: always guard against malicious tampering.
    117             ScriptWrappable::assertWrapperSanity<V8T, T>(result, object);
    118             return result;
    119         }
    120         return current(isolate).template get<V8T>(object, isolate);
    121     }
    122 
    123     static v8::Handle<v8::Object> getWrapperNonTemplate(ScriptWrappableBase* object, v8::Isolate* isolate)
    124     {
    125         return current(isolate).getNonTemplate(object, isolate);
    126     }
    127 
    128     static v8::Handle<v8::Object> getWrapperNonTemplate(ScriptWrappable* object, v8::Isolate* isolate)
    129     {
    130         return current(isolate).getNonTemplate(object, isolate);
    131     }
    132 
    133     static v8::Handle<v8::Object> getWrapperNonTemplate(Node* node, v8::Isolate* isolate)
    134     {
    135         if (canUseScriptWrappableNonTemplate(node)) {
    136             v8::Handle<v8::Object> result = ScriptWrappable::fromObject(node)->newLocalWrapper(isolate);
    137             // Security: always guard against malicious tampering.
    138             ScriptWrappable::fromObject(node)->assertWrapperSanity(result);
    139             return result;
    140         }
    141         return current(isolate).getNonTemplate(ScriptWrappable::fromObject(node), isolate);
    142     }
    143 
    144     template<typename V8T, typename T>
    145     static void setWrapperReference(const v8::Persistent<v8::Object>& parent, T* child, v8::Isolate* isolate)
    146     {
    147         if (canUseScriptWrappable(child)) {
    148             ScriptWrappable::assertWrapperSanity<V8T, T>(child, child);
    149             ScriptWrappable::fromObject(child)->setReference(parent, isolate);
    150             return;
    151         }
    152         current(isolate).template setReference<V8T>(parent, child, isolate);
    153     }
    154 
    155     template<typename V8T, typename T>
    156     static void setWrapper(T* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
    157     {
    158         if (canUseScriptWrappable(object)) {
    159             ScriptWrappable::fromObject(object)->setWrapper(wrapper, isolate, wrapperTypeInfo);
    160             return;
    161         }
    162         return current(isolate).template set<V8T>(object, wrapper, isolate, wrapperTypeInfo);
    163     }
    164 
    165     static void setWrapperNonTemplate(ScriptWrappableBase* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
    166     {
    167         return current(isolate).setNonTemplate(object, wrapper, isolate, wrapperTypeInfo);
    168     }
    169 
    170     static void setWrapperNonTemplate(ScriptWrappable* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
    171     {
    172         return current(isolate).setNonTemplate(object, wrapper, isolate, wrapperTypeInfo);
    173     }
    174 
    175     static void setWrapperNonTemplate(Node* node, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
    176     {
    177         if (canUseScriptWrappableNonTemplate(node)) {
    178             ScriptWrappable::fromObject(node)->setWrapper(wrapper, isolate, wrapperTypeInfo);
    179             return;
    180         }
    181         return current(isolate).setNonTemplate(ScriptWrappable::fromObject(node), wrapper, isolate, wrapperTypeInfo);
    182     }
    183 
    184     template<typename V8T, typename T>
    185     static bool containsWrapper(T* object, v8::Isolate* isolate)
    186     {
    187         return current(isolate).template containsWrapper<V8T>(object);
    188     }
    189 
    190     static bool containsWrapperNonTemplate(ScriptWrappableBase* object, v8::Isolate* isolate)
    191     {
    192         return current(isolate).containsWrapperNonTemplate(object);
    193     }
    194 
    195     static bool containsWrapperNonTemplate(ScriptWrappable* object, v8::Isolate* isolate)
    196     {
    197         return current(isolate).containsWrapperNonTemplate(object);
    198     }
    199 
    200     template<typename V8T, typename T>
    201     v8::Handle<v8::Object> get(T* object, v8::Isolate* isolate)
    202     {
    203         if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld)
    204             return ScriptWrappable::fromObject(object)->newLocalWrapper(isolate);
    205         return m_wrapperMap.newLocal(V8T::toScriptWrappableBase(object), isolate);
    206     }
    207 
    208     v8::Handle<v8::Object> getNonTemplate(ScriptWrappableBase* object, v8::Isolate* isolate)
    209     {
    210         return m_wrapperMap.newLocal(object->toScriptWrappableBase(), isolate);
    211     }
    212 
    213     v8::Handle<v8::Object> getNonTemplate(ScriptWrappable* object, v8::Isolate* isolate)
    214     {
    215         if (m_isMainWorld)
    216             return object->newLocalWrapper(isolate);
    217         return m_wrapperMap.newLocal(object->toScriptWrappableBase(), isolate);
    218     }
    219 
    220     template<typename V8T, typename T>
    221     void setReference(const v8::Persistent<v8::Object>& parent, T* child, v8::Isolate* isolate)
    222     {
    223         if (ScriptWrappable::wrapperCanBeStoredInObject(child) && m_isMainWorld) {
    224             ScriptWrappable::fromObject(child)->setReference(parent, isolate);
    225             return;
    226         }
    227         m_wrapperMap.setReference(parent, V8T::toScriptWrappableBase(child), isolate);
    228     }
    229 
    230     template<typename V8T, typename T>
    231     bool setReturnValueFrom(v8::ReturnValue<v8::Value> returnValue, T* object)
    232     {
    233         if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld)
    234             return ScriptWrappable::fromObject(object)->setReturnValue(returnValue);
    235         return m_wrapperMap.setReturnValueFrom(returnValue, V8T::toScriptWrappableBase(object));
    236     }
    237 
    238     template<typename V8T, typename T>
    239     bool containsWrapper(T* object)
    240     {
    241         if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld)
    242             return ScriptWrappable::fromObject(object)->containsWrapper();
    243         return m_wrapperMap.containsKey(V8T::toScriptWrappableBase(object));
    244     }
    245 
    246     bool containsWrapperNonTemplate(ScriptWrappableBase* object)
    247     {
    248         return m_wrapperMap.containsKey(object->toScriptWrappableBase());
    249     }
    250 
    251     bool containsWrapperNonTemplate(ScriptWrappable* object)
    252     {
    253         if (m_isMainWorld)
    254             return object->containsWrapper();
    255         return m_wrapperMap.containsKey(object->toScriptWrappableBase());
    256     }
    257 
    258 private:
    259     template<typename V8T, typename T>
    260     void set(T* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
    261     {
    262         ASSERT(object);
    263         ASSERT(!wrapper.IsEmpty());
    264         if (ScriptWrappable::wrapperCanBeStoredInObject(object) && m_isMainWorld) {
    265             ScriptWrappable::fromObject(object)->setWrapper(wrapper, isolate, wrapperTypeInfo);
    266             return;
    267         }
    268         m_wrapperMap.set(V8T::toScriptWrappableBase(object), wrapper, wrapperTypeInfo);
    269     }
    270 
    271     void setNonTemplate(ScriptWrappableBase* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
    272     {
    273         ASSERT(object);
    274         ASSERT(!wrapper.IsEmpty());
    275         m_wrapperMap.set(object->toScriptWrappableBase(), wrapper, wrapperTypeInfo);
    276     }
    277 
    278     void setNonTemplate(ScriptWrappable* object, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate, const WrapperTypeInfo* wrapperTypeInfo)
    279     {
    280         ASSERT(object);
    281         ASSERT(!wrapper.IsEmpty());
    282         if (m_isMainWorld) {
    283             ScriptWrappable::fromObject(object)->setWrapper(wrapper, isolate, wrapperTypeInfo);
    284             return;
    285         }
    286         m_wrapperMap.set(object->toScriptWrappableBase(), wrapper, wrapperTypeInfo);
    287     }
    288 
    289     static bool canExistInWorker(void*) { return true; }
    290     static bool canExistInWorker(Node*) { return false; }
    291 
    292     static bool holderContainsWrapper(v8::Local<v8::Object>, void*)
    293     {
    294         return false;
    295     }
    296 
    297     static bool holderContainsWrapper(v8::Local<v8::Object> holder, ScriptWrappable* wrappable)
    298     {
    299         // Verify our assumptions about the main world.
    300         ASSERT(wrappable);
    301         ASSERT(!wrappable->containsWrapper() || !wrappable->isEqualTo(holder) || current(v8::Isolate::GetCurrent()).m_isMainWorld);
    302         return wrappable->isEqualTo(holder);
    303     }
    304 
    305     bool m_isMainWorld;
    306     DOMWrapperMap<ScriptWrappableBase> m_wrapperMap;
    307 };
    308 
    309 template <>
    310 inline void DOMWrapperMap<ScriptWrappableBase>::PersistentValueMapTraits::Dispose(
    311     v8::Isolate* isolate,
    312     v8::UniquePersistent<v8::Object> value,
    313     ScriptWrappableBase* key)
    314 {
    315     RELEASE_ASSERT(!value.IsEmpty()); // See crbug.com/368095.
    316     releaseObject(v8::Local<v8::Object>::New(isolate, value));
    317 }
    318 
    319 } // namespace blink
    320 
    321 #endif // DOMDataStore_h
    322