/platform/external/webkit/WebCore/bindings/v8/DOMDataStore.cpp

https://github.com/aharish/totoro-gb-opensource-update2 · C++ · 209 lines · 110 code · 23 blank · 76 comment · 7 complexity · 0dd5080bfc0b839dee29c04f24dce0e5 MD5 · raw file

  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. #include "config.h"
  31. #include "DOMDataStore.h"
  32. #include "DOMData.h"
  33. namespace WebCore {
  34. // DOM binding algorithm:
  35. //
  36. // There are two kinds of DOM objects:
  37. // 1. DOM tree nodes, such as Document, HTMLElement, ...
  38. // there classes implement TreeShared<T> interface;
  39. // 2. Non-node DOM objects, such as CSSRule, Location, etc.
  40. // these classes implement a ref-counted scheme.
  41. //
  42. // A DOM object may have a JS wrapper object. If a tree node
  43. // is alive, its JS wrapper must be kept alive even it is not
  44. // reachable from JS roots.
  45. // However, JS wrappers of non-node objects can go away if
  46. // not reachable from other JS objects. It works like a cache.
  47. //
  48. // DOM objects are ref-counted, and JS objects are traced from
  49. // a set of root objects. They can create a cycle. To break
  50. // cycles, we do following:
  51. // Handles from DOM objects to JS wrappers are always weak,
  52. // so JS wrappers of non-node object cannot create a cycle.
  53. // Before starting a global GC, we create a virtual connection
  54. // between nodes in the same tree in the JS heap. If the wrapper
  55. // of one node in a tree is alive, wrappers of all nodes in
  56. // the same tree are considered alive. This is done by creating
  57. // object groups in GC prologue callbacks. The mark-compact
  58. // collector will remove these groups after each GC.
  59. //
  60. // DOM objects should be deref-ed from the owning thread, not the GC thread
  61. // that does not own them. In V8, GC can kick in from any thread. To ensure
  62. // that DOM objects are always deref-ed from the owning thread when running
  63. // V8 in multi-threading environment, we do following:
  64. // 1. Maintain a thread specific DOM wrapper map for each object map.
  65. // (We're using TLS support from WTF instead of base since V8Bindings
  66. // does not depend on base. We further assume that all child threads
  67. // running V8 instances are created by WTF and thus a destructor will
  68. // be called to clean up all thread specific data.)
  69. // 2. When GC happens:
  70. // 2.1. If the dead object is in GC thread's map, remove the JS reference
  71. // and deref the DOM object.
  72. // 2.2. Otherwise, go through all thread maps to find the owning thread.
  73. // Remove the JS reference from the owning thread's map and move the
  74. // DOM object to a delayed queue. Post a task to the owning thread
  75. // to have it deref-ed from the owning thread at later time.
  76. // 3. When a thread is tearing down, invoke a cleanup routine to go through
  77. // all objects in the delayed queue and the thread map and deref all of
  78. // them.
  79. DOMDataStore::DOMDataStore(DOMData* domData)
  80. : m_domNodeMap(0)
  81. , m_domObjectMap(0)
  82. , m_activeDomObjectMap(0)
  83. #if ENABLE(SVG)
  84. , m_domSvgElementInstanceMap(0)
  85. , m_domSvgObjectWithContextMap(0)
  86. #endif
  87. , m_domData(domData)
  88. {
  89. WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
  90. DOMDataStore::allStores().append(this);
  91. }
  92. DOMDataStore::~DOMDataStore()
  93. {
  94. WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
  95. DOMDataStore::allStores().remove(DOMDataStore::allStores().find(this));
  96. }
  97. DOMDataList& DOMDataStore::allStores()
  98. {
  99. DEFINE_STATIC_LOCAL(DOMDataList, staticDOMDataList, ());
  100. return staticDOMDataList;
  101. }
  102. WTF::Mutex& DOMDataStore::allStoresMutex()
  103. {
  104. DEFINE_STATIC_LOCAL(WTF::Mutex, staticDOMDataListMutex, ());
  105. return staticDOMDataListMutex;
  106. }
  107. void DOMDataStore::forgetDelayedObject(DOMData* domData, void* object)
  108. {
  109. domData->forgetDelayedObject(object);
  110. }
  111. void* DOMDataStore::getDOMWrapperMap(DOMWrapperMapType type)
  112. {
  113. switch (type) {
  114. case DOMNodeMap:
  115. return m_domNodeMap;
  116. case DOMObjectMap:
  117. return m_domObjectMap;
  118. case ActiveDOMObjectMap:
  119. return m_activeDomObjectMap;
  120. #if ENABLE(SVG)
  121. case DOMSVGElementInstanceMap:
  122. return m_domSvgElementInstanceMap;
  123. case DOMSVGObjectWithContextMap:
  124. return m_domSvgObjectWithContextMap;
  125. #endif
  126. }
  127. ASSERT_NOT_REACHED();
  128. return 0;
  129. }
  130. // Called when the object is near death (not reachable from JS roots).
  131. // It is time to remove the entry from the table and dispose the handle.
  132. void DOMDataStore::weakDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
  133. {
  134. v8::HandleScope scope;
  135. ASSERT(v8Object->IsObject());
  136. DOMData::handleWeakObject(DOMDataStore::DOMObjectMap, v8::Persistent<v8::Object>::Cast(v8Object), domObject);
  137. }
  138. void DOMDataStore::weakActiveDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
  139. {
  140. v8::HandleScope scope;
  141. ASSERT(v8Object->IsObject());
  142. DOMData::handleWeakObject(DOMDataStore::ActiveDOMObjectMap, v8::Persistent<v8::Object>::Cast(v8Object), domObject);
  143. }
  144. void DOMDataStore::weakNodeCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
  145. {
  146. ASSERT(WTF::isMainThread());
  147. Node* node = static_cast<Node*>(domObject);
  148. WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
  149. DOMDataList& list = DOMDataStore::allStores();
  150. for (size_t i = 0; i < list.size(); ++i) {
  151. DOMDataStore* store = list[i];
  152. if (store->domNodeMap().removeIfPresent(node, v8Object)) {
  153. ASSERT(store->domData()->owningThread() == WTF::currentThread());
  154. node->deref(); // Nobody overrides Node::deref so it's safe
  155. break; // There might be at most one wrapper for the node in world's maps
  156. }
  157. }
  158. }
  159. bool DOMDataStore::IntrusiveDOMWrapperMap::removeIfPresent(Node* obj, v8::Persistent<v8::Data> value)
  160. {
  161. ASSERT(obj);
  162. v8::Persistent<v8::Object>* entry = obj->wrapper();
  163. if (!entry)
  164. return false;
  165. if (*entry != value)
  166. return false;
  167. obj->clearWrapper();
  168. m_table.remove(entry);
  169. value.Dispose();
  170. return true;
  171. }
  172. #if ENABLE(SVG)
  173. void DOMDataStore::weakSVGElementInstanceCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
  174. {
  175. v8::HandleScope scope;
  176. ASSERT(v8Object->IsObject());
  177. DOMData::handleWeakObject(DOMDataStore::DOMSVGElementInstanceMap, v8::Persistent<v8::Object>::Cast(v8Object), static_cast<SVGElementInstance*>(domObject));
  178. }
  179. void DOMDataStore::weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
  180. {
  181. v8::HandleScope scope;
  182. ASSERT(v8Object->IsObject());
  183. DOMData::handleWeakObject(DOMDataStore::DOMSVGObjectWithContextMap, v8::Persistent<v8::Object>::Cast(v8Object), domObject);
  184. }
  185. #endif // ENABLE(SVG)
  186. } // namespace WebCore