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 V8DOMWrapper_h
     32 #define V8DOMWrapper_h
     33 
     34 #include "bindings/core/v8/DOMDataStore.h"
     35 #include "bindings/core/v8/ScriptWrappable.h"
     36 #include "wtf/PassRefPtr.h"
     37 #include "wtf/RawPtr.h"
     38 #include "wtf/text/AtomicString.h"
     39 #include <v8.h>
     40 
     41 namespace blink {
     42 
     43 class Node;
     44 struct WrapperTypeInfo;
     45 
     46 class V8DOMWrapper {
     47 public:
     48     static v8::Local<v8::Object> createWrapper(v8::Handle<v8::Object> creationContext, const WrapperTypeInfo*, ScriptWrappableBase* internalPointer, v8::Isolate*);
     49 
     50     template<typename V8T, typename T>
     51     static v8::Handle<v8::Object> associateObjectWithWrapper(PassRefPtr<T>, const WrapperTypeInfo*, v8::Handle<v8::Object>, v8::Isolate*);
     52     template<typename V8T, typename T>
     53     static v8::Handle<v8::Object> associateObjectWithWrapper(RawPtr<T> object, const WrapperTypeInfo* wrapperTypeInfo, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate)
     54     {
     55         return associateObjectWithWrapper<V8T, T>(object.get(), wrapperTypeInfo, wrapper, isolate);
     56     }
     57     template<typename V8T, typename T>
     58     static v8::Handle<v8::Object> associateObjectWithWrapper(T*, const WrapperTypeInfo*, v8::Handle<v8::Object>, v8::Isolate*);
     59     static v8::Handle<v8::Object> associateObjectWithWrapperNonTemplate(ScriptWrappable*, const WrapperTypeInfo*, v8::Handle<v8::Object>, v8::Isolate*);
     60     static v8::Handle<v8::Object> associateObjectWithWrapperNonTemplate(Node*, const WrapperTypeInfo*, v8::Handle<v8::Object>, v8::Isolate*);
     61     static void setNativeInfo(v8::Handle<v8::Object>, const WrapperTypeInfo*, ScriptWrappableBase* internalPointer);
     62     static void setNativeInfoForHiddenWrapper(v8::Handle<v8::Object>, const WrapperTypeInfo*, ScriptWrappableBase* internalPointer);
     63     static void setNativeInfoWithPersistentHandle(v8::Handle<v8::Object>, const WrapperTypeInfo*, ScriptWrappableBase* internalPointer, WrapperPersistentNode*);
     64     static void clearNativeInfo(v8::Handle<v8::Object>, const WrapperTypeInfo*);
     65 
     66     static bool isDOMWrapper(v8::Handle<v8::Value>);
     67 };
     68 
     69 inline void V8DOMWrapper::setNativeInfo(v8::Handle<v8::Object> wrapper, const WrapperTypeInfo* wrapperTypeInfo, ScriptWrappableBase* internalPointer)
     70 {
     71     ASSERT(wrapper->InternalFieldCount() >= 2);
     72     ASSERT(internalPointer);
     73     ASSERT(wrapperTypeInfo);
     74 #if ENABLE(OILPAN)
     75     ASSERT(wrapperTypeInfo->gcType == WrapperTypeInfo::RefCountedObject);
     76 #else
     77     ASSERT(wrapperTypeInfo->gcType == WrapperTypeInfo::RefCountedObject || wrapperTypeInfo->gcType == WrapperTypeInfo::WillBeGarbageCollectedObject);
     78 #endif
     79     wrapper->SetAlignedPointerInInternalField(v8DOMWrapperObjectIndex, internalPointer);
     80     wrapper->SetAlignedPointerInInternalField(v8DOMWrapperTypeIndex, const_cast<WrapperTypeInfo*>(wrapperTypeInfo));
     81 }
     82 
     83 inline void V8DOMWrapper::setNativeInfoForHiddenWrapper(v8::Handle<v8::Object> wrapper, const WrapperTypeInfo* wrapperTypeInfo, ScriptWrappableBase* internalPointer)
     84 {
     85     // see WindowProxy::installDOMWindow() comment for why this version is needed and safe.
     86     ASSERT(wrapper->InternalFieldCount() >= 2);
     87     ASSERT(internalPointer);
     88     ASSERT(wrapperTypeInfo);
     89 #if ENABLE(OILPAN)
     90     ASSERT(wrapperTypeInfo->gcType != WrapperTypeInfo::RefCountedObject);
     91 #else
     92     ASSERT(wrapperTypeInfo->gcType == WrapperTypeInfo::RefCountedObject || wrapperTypeInfo->gcType == WrapperTypeInfo::WillBeGarbageCollectedObject);
     93 #endif
     94 
     95     // Clear out the last internal field, which is assumed to contain a valid persistent pointer value.
     96     if (wrapperTypeInfo->gcType == WrapperTypeInfo::GarbageCollectedObject) {
     97         wrapper->SetAlignedPointerInInternalField(wrapper->InternalFieldCount() - 1, 0);
     98     } else if (wrapperTypeInfo->gcType == WrapperTypeInfo::WillBeGarbageCollectedObject) {
     99 #if ENABLE(OILPAN)
    100         wrapper->SetAlignedPointerInInternalField(wrapper->InternalFieldCount() - 1, 0);
    101 #endif
    102     }
    103     wrapper->SetAlignedPointerInInternalField(v8DOMWrapperObjectIndex, internalPointer);
    104     wrapper->SetAlignedPointerInInternalField(v8DOMWrapperTypeIndex, const_cast<WrapperTypeInfo*>(wrapperTypeInfo));
    105 }
    106 
    107 inline void V8DOMWrapper::setNativeInfoWithPersistentHandle(v8::Handle<v8::Object> wrapper, const WrapperTypeInfo* wrapperTypeInfo, ScriptWrappableBase* internalPointer, WrapperPersistentNode* handle)
    108 {
    109     ASSERT(wrapper->InternalFieldCount() >= 3);
    110     ASSERT(internalPointer);
    111     ASSERT(wrapperTypeInfo);
    112 #if ENABLE(OILPAN)
    113     ASSERT(wrapperTypeInfo->gcType == WrapperTypeInfo::WillBeGarbageCollectedObject || wrapperTypeInfo->gcType == WrapperTypeInfo::GarbageCollectedObject);
    114 #else
    115     ASSERT(wrapperTypeInfo->gcType == WrapperTypeInfo::GarbageCollectedObject);
    116 #endif
    117     wrapper->SetAlignedPointerInInternalField(v8DOMWrapperObjectIndex, internalPointer);
    118     wrapper->SetAlignedPointerInInternalField(v8DOMWrapperTypeIndex, const_cast<WrapperTypeInfo*>(wrapperTypeInfo));
    119     // Persistent handle is stored in the last internal field.
    120     wrapper->SetAlignedPointerInInternalField(wrapper->InternalFieldCount() - 1, handle);
    121 }
    122 
    123 inline void V8DOMWrapper::clearNativeInfo(v8::Handle<v8::Object> wrapper, const WrapperTypeInfo* wrapperTypeInfo)
    124 {
    125     ASSERT(wrapper->InternalFieldCount() >= 2);
    126     ASSERT(wrapperTypeInfo);
    127     // clearNativeInfo() is used only by NP objects, which are not garbage collected.
    128     ASSERT(wrapperTypeInfo->gcType == WrapperTypeInfo::RefCountedObject);
    129     wrapper->SetAlignedPointerInInternalField(v8DOMWrapperTypeIndex, const_cast<WrapperTypeInfo*>(wrapperTypeInfo));
    130     wrapper->SetAlignedPointerInInternalField(v8DOMWrapperObjectIndex, 0);
    131 }
    132 
    133 template<typename V8T, typename T>
    134 inline v8::Handle<v8::Object> V8DOMWrapper::associateObjectWithWrapper(PassRefPtr<T> object, const WrapperTypeInfo* wrapperTypeInfo, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate)
    135 {
    136     setNativeInfo(wrapper, wrapperTypeInfo, V8T::toScriptWrappableBase(object.get()));
    137     ASSERT(isDOMWrapper(wrapper));
    138     DOMDataStore::setWrapper<V8T>(object.leakRef(), wrapper, isolate, wrapperTypeInfo);
    139     return wrapper;
    140 }
    141 
    142 template<typename V8T, typename T>
    143 inline v8::Handle<v8::Object> V8DOMWrapper::associateObjectWithWrapper(T* object, const WrapperTypeInfo* wrapperTypeInfo, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate)
    144 {
    145     setNativeInfoWithPersistentHandle(wrapper, wrapperTypeInfo, V8T::toScriptWrappableBase(object), WrapperPersistent<T>::create(object));
    146     ASSERT(isDOMWrapper(wrapper));
    147     DOMDataStore::setWrapper<V8T>(object, wrapper, isolate, wrapperTypeInfo);
    148     return wrapper;
    149 }
    150 
    151 inline v8::Handle<v8::Object> V8DOMWrapper::associateObjectWithWrapperNonTemplate(ScriptWrappable* impl, const WrapperTypeInfo* wrapperTypeInfo, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate)
    152 {
    153     wrapperTypeInfo->refObject(impl->toScriptWrappableBase());
    154 #if ENABLE(OILPAN)
    155     if (wrapperTypeInfo->gcType == WrapperTypeInfo::RefCountedObject)
    156         setNativeInfo(wrapper, wrapperTypeInfo, impl->toScriptWrappableBase());
    157     else
    158         setNativeInfoWithPersistentHandle(wrapper, wrapperTypeInfo, impl->toScriptWrappableBase(), wrapperTypeInfo->createPersistentHandle(impl));
    159 #else
    160     if (wrapperTypeInfo->gcType != WrapperTypeInfo::GarbageCollectedObject)
    161         setNativeInfo(wrapper, wrapperTypeInfo, impl->toScriptWrappableBase());
    162     else
    163         setNativeInfoWithPersistentHandle(wrapper, wrapperTypeInfo, impl->toScriptWrappableBase(), wrapperTypeInfo->createPersistentHandle(impl));
    164 #endif
    165     ASSERT(isDOMWrapper(wrapper));
    166     DOMDataStore::setWrapperNonTemplate(impl, wrapper, isolate, wrapperTypeInfo);
    167     return wrapper;
    168 }
    169 
    170 inline v8::Handle<v8::Object> V8DOMWrapper::associateObjectWithWrapperNonTemplate(Node* node, const WrapperTypeInfo* wrapperTypeInfo, v8::Handle<v8::Object> wrapper, v8::Isolate* isolate)
    171 {
    172     wrapperTypeInfo->refObject(ScriptWrappable::fromObject(node)->toScriptWrappableBase());
    173 #if ENABLE(OILPAN)
    174     if (wrapperTypeInfo->gcType == WrapperTypeInfo::RefCountedObject)
    175         setNativeInfo(wrapper, wrapperTypeInfo, ScriptWrappable::fromObject(node)->toScriptWrappableBase());
    176     else
    177         setNativeInfoWithPersistentHandle(wrapper, wrapperTypeInfo, ScriptWrappable::fromObject(node)->toScriptWrappableBase(), wrapperTypeInfo->createPersistentHandle(ScriptWrappable::fromObject(node)));
    178 #else
    179     if (wrapperTypeInfo->gcType != WrapperTypeInfo::GarbageCollectedObject)
    180         setNativeInfo(wrapper, wrapperTypeInfo, ScriptWrappable::fromObject(node)->toScriptWrappableBase());
    181     else
    182         setNativeInfoWithPersistentHandle(wrapper, wrapperTypeInfo, ScriptWrappable::fromObject(node)->toScriptWrappableBase(), wrapperTypeInfo->createPersistentHandle(ScriptWrappable::fromObject(node)));
    183 #endif
    184     ASSERT(isDOMWrapper(wrapper));
    185     DOMDataStore::setWrapperNonTemplate(node, wrapper, isolate, wrapperTypeInfo);
    186     return wrapper;
    187 }
    188 
    189 class V8WrapperInstantiationScope {
    190 public:
    191     V8WrapperInstantiationScope(v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
    192         : m_didEnterContext(false)
    193         , m_context(isolate->GetCurrentContext())
    194     {
    195         // creationContext should not be empty. Because if we have an
    196         // empty creationContext, we will end up creating
    197         // a new object in the context currently entered. This is wrong.
    198         RELEASE_ASSERT(!creationContext.IsEmpty());
    199         v8::Handle<v8::Context> contextForWrapper = creationContext->CreationContext();
    200         // For performance, we enter the context only if the currently running context
    201         // is different from the context that we are about to enter.
    202         if (contextForWrapper == m_context)
    203             return;
    204         m_context = v8::Local<v8::Context>::New(isolate, contextForWrapper);
    205         m_didEnterContext = true;
    206         m_context->Enter();
    207     }
    208 
    209     ~V8WrapperInstantiationScope()
    210     {
    211         if (!m_didEnterContext)
    212             return;
    213         m_context->Exit();
    214     }
    215 
    216     v8::Handle<v8::Context> context() const { return m_context; }
    217 
    218 private:
    219     bool m_didEnterContext;
    220     v8::Handle<v8::Context> m_context;
    221 };
    222 
    223 } // namespace blink
    224 
    225 #endif // V8DOMWrapper_h
    226