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