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