Changeset 83990 in webkit
- Timestamp:
- Apr 15, 2011 10:44:34 AM (13 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r83987 r83990 1 2011-04-14 Geoffrey Garen <ggaren@apple.com> 2 3 Reviewed by Oliver Hunt. 4 5 Complicated hash table is complicated 6 https://bugs.webkit.org/show_bug.cgi?id=58631 7 8 Now that we use the opaque roots system to track node wrapper lifetime, 9 we can remove a lot of complicated hash-tablery that used to do the same. 10 11 Now normal world node wrappers are just set as direct properties of 12 ScriptWrappable, while isolated world node wrappers and other DOM object 13 wrappers are stored in a shared, per-world hash table. 14 15 In addition to reducing complexity, this makes DOM wrapper allocation 16 1.6X faster (tested with scratch-gc-dom3.html), and it reduces the memory 17 footprint of normal world wrappers by ~2/3, and isolated world wrappers 18 by ~1/3. 19 20 * WebCore.exp.in: Paying the patch tithe. 21 22 * bindings/js/DOMWrapperWorld.cpp: 23 (WebCore::DOMWrapperWorld::~DOMWrapperWorld): 24 (WebCore::DOMWrapperWorld::clearWrappers): No more per-document hash tables. 25 26 (WebCore::JSNodeHandleOwner::finalize): Changed to call a helper function, 27 so the code to destroy a wrapper can live next to the code to create one. 28 29 * bindings/js/DOMWrapperWorld.h: No more per-document hash tables. 30 31 * bindings/js/JSDOMBinding.cpp: 32 (WebCore::uncacheDOMObjectWrapper): 33 * bindings/js/JSDOMBinding.h: 34 (WebCore::createDOMNodeWrapper): 35 (WebCore::getDOMNodeWrapper): No more per-document hash tables. 36 Added uncacheDOMObjectWrapper to be symmetrical with cacheDOMObjectWrapper. 37 38 * bindings/js/JSDocumentCustom.cpp: 39 (WebCore::toJS): 40 * bindings/js/JSElementCustom.cpp: 41 (WebCore::toJSNewlyCreated): 42 * bindings/js/JSNodeCustom.cpp: 43 (WebCore::createWrapperInline): Ditto. 44 45 * bindings/js/JSNodeCustom.h: 46 (WebCore::getCachedDOMNodeWrapper): 47 (WebCore::cacheDOMNodeWrapper): 48 (WebCore::uncacheDOMNodeWrapper): 49 (WebCore::toJS): Implemented the scheme described above. 50 51 * bindings/js/ScriptWrappable.h: 52 (WebCore::ScriptWrappable::wrapper): 53 (WebCore::ScriptWrappable::setWrapper): 54 (WebCore::ScriptWrappable::clearWrapper): ScriptWrappable needs a handle 55 owner now, since we don't have an extra handle living in a hash table 56 to maintain ownership for us. 57 58 * dom/Document.cpp: 59 (WebCore::Document::Document): 60 (WebCore::Document::~Document): 61 * dom/Document.h: 62 * dom/Node.cpp: 63 (WebCore::Node::setDocument): No more per-document hash tables. 64 65 * html/HTMLCanvasElement.cpp: 66 (WebCore::HTMLCanvasElement::createImageBuffer): Removed call to 67 hasCachedDOMNodeWrapperUnchecked because that was the old way of doing 68 things, and I was in the mood for getting rid of the old way. It's 69 debatable whether the check was ever a good idea. Even when a <canvas> 70 doesn't have a direct JS wrapper, other JS references can still keep 71 the <canvas> alive. So, it's probably best always to report extra cost. 72 1 73 2011-04-15 Vsevolod Vlasov <vsevik@chromium.org> 2 74 -
trunk/Source/WebCore/WebCore.exp.in
r83955 r83990 298 298 __ZN7WebCore12TextEncodingC1ERKN3WTF6StringE 299 299 __ZN7WebCore12TextIterator11rangeLengthEPKNS_5RangeEb 300 __ZN7WebCore12TextIterator26locationAndLengthFromRangeEPKNS_5RangeERmS4_ 300 301 __ZN7WebCore12TextIterator26rangeFromLocationAndLengthEPNS_7ElementEiib 301 __ZN7WebCore12TextIterator26locationAndLengthFromRangeEPKNS_5RangeERmS4_302 302 __ZN7WebCore12TextIterator7advanceEv 303 303 __ZN7WebCore12TextIterator8subrangeEPNS_5RangeEii … … 351 351 __ZN7WebCore14DocumentWriter11setEncodingERKN3WTF6StringEb 352 352 __ZN7WebCore14ResourceHandle12releaseProxyEv 353 __ZN7WebCore25getCachedDOMObjectWrapperEPN3JSC9ExecStateEPv 353 354 __ZN7WebCore14ResourceHandle20forceContentSniffingEv 354 355 __ZN7WebCore14ResourceLoader14cancelledErrorEv … … 813 814 __ZN7WebCore8Document16isPageBoxVisibleEi 814 815 __ZN7WebCore8Document17getFocusableNodesERN3WTF6VectorINS1_6RefPtrINS_4NodeEEELm0EEE 815 __ZN7WebCore8Document18createWrapperCacheEPNS_15DOMWrapperWorldE816 816 __ZN7WebCore8Document19accessSVGExtensionsEv 817 817 __ZN7WebCore8Document20styleSelectorChangedENS_23StyleSelectorUpdateFlagE -
trunk/Source/WebCore/bindings/js/DOMWrapperWorld.cpp
r83938 r83990 162 162 ASSERT(clientData); 163 163 static_cast<WebCoreJSClientData*>(clientData)->forgetWorld(this); 164 165 // These items are created lazily.166 while (!m_documentsWithWrapperCaches.isEmpty())167 (*m_documentsWithWrapperCaches.begin())->destroyWrapperCache(this);168 169 while (!m_scriptControllersWithWindowShells.isEmpty())170 (*m_scriptControllersWithWindowShells.begin())->destroyWindowShell(this);171 164 } 172 165 … … 175 168 m_wrappers.clear(); 176 169 m_stringCache.clear(); 177 178 // These items are created lazily.179 while (!m_documentsWithWrapperCaches.isEmpty())180 (*m_documentsWithWrapperCaches.begin())->destroyWrapperCache(this);181 182 while (!m_scriptControllersWithWindowShells.isEmpty())183 (*m_scriptControllersWithWindowShells.begin())->destroyWindowShell(this);184 170 } 185 171 … … 207 193 { 208 194 JSNode* jsNode = static_cast<JSNode*>(handle.get().asCell()); 209 Node* node = jsNode->impl(); 210 ASSERT(node->document()); 211 ASSERT(node->document()->getWrapperCache(m_world)->find(node)->second == jsNode); 212 node->document()->getWrapperCache(m_world)->remove(node); 195 uncacheDOMNodeWrapper(m_world, jsNode->impl(), jsNode); 213 196 } 214 197 -
trunk/Source/WebCore/bindings/js/DOMWrapperWorld.h
r83773 r83990 23 23 #define DOMWrapperWorld_h 24 24 25 #include "Document.h"26 25 #include "JSDOMGlobalObject.h" 27 #include "JSDOMWrapper.h"28 26 #include <runtime/WeakGCMap.h> 29 27 #include <wtf/Forward.h> … … 31 29 namespace WebCore { 32 30 31 class DOMObject; 33 32 class ScriptController; 34 33 … … 77 76 void clearWrappers(); 78 77 79 void didCreateWrapperCache(Document* document) { m_documentsWithWrapperCaches.add(document); }80 void didDestroyWrapperCache(Document* document) { m_documentsWithWrapperCaches.remove(document); }81 82 78 void didCreateWindowShell(ScriptController* scriptController) { m_scriptControllersWithWindowShells.add(scriptController); } 83 79 void didDestroyWindowShell(ScriptController* scriptController) { m_scriptControllersWithWindowShells.remove(scriptController); } … … 98 94 private: 99 95 JSC::JSGlobalData* m_globalData; 100 HashSet<Document*> m_documentsWithWrapperCaches;101 96 HashSet<ScriptController*> m_scriptControllersWithWindowShells; 102 97 bool m_isNormal; … … 115 110 } 116 111 117 // From Document.h118 119 inline Document::JSWrapperCache* Document::getWrapperCache(DOMWrapperWorld* world)120 {121 if (world->isNormal()) {122 if (Document::JSWrapperCache* wrapperCache = m_normalWorldWrapperCache)123 return wrapperCache;124 ASSERT(!m_wrapperCacheMap.contains(world));125 } else if (Document::JSWrapperCache* wrapperCache = m_wrapperCacheMap.get(world))126 return wrapperCache;127 return createWrapperCache(world);128 }129 130 112 } // namespace WebCore 131 113 -
trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp
r83955 r83990 95 95 using namespace HTMLNames; 96 96 97 typedef Document::JSWrapperCache JSWrapperCache;98 typedef Document::JSWrapperCacheMap JSWrapperCacheMap;99 100 97 class JSGlobalDataWorldIterator { 101 98 public: … … 168 165 } 169 166 170 bool hasCachedDOMNodeWrapperUnchecked(Document* document, Node* node) 171 { 172 if (!document) 173 return hasCachedDOMObjectWrapperUnchecked(JSDOMWindow::commonJSGlobalData(), node); 174 175 JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap(); 176 for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) { 177 if (iter->second->get(node)) 178 return true; 179 } 180 return false; 181 } 182 183 void cacheDOMNodeWrapper(JSC::ExecState* exec, Document* document, Node* node, JSNode* wrapper) 184 { 185 ASSERT(wrapper); 186 if (!document) 187 cacheDOMObjectWrapper(exec, node, wrapper); 188 else 189 document->getWrapperCache(currentWorld(exec))->set(node, Weak<JSNode>(exec->globalData(), wrapper, currentWorld(exec)->jsNodeHandleOwner())); 190 191 if (currentWorld(exec)->isNormal()) { 192 node->setWrapper(exec->globalData(), wrapper); 193 ASSERT(node->wrapper() == (document ? document->getWrapperCache(currentWorld(exec))->get(node).get() : domObjectWrapperMapFor(exec).get(node).get())); 194 } 167 void uncacheDOMObjectWrapper(DOMWrapperWorld* world, void* objectHandle, DOMObject* wrapper) 168 { 169 ASSERT_UNUSED(wrapper, world->m_wrappers.get(objectHandle) == wrapper); 170 world->m_wrappers.remove(objectHandle); 195 171 } 196 172 … … 219 195 } 220 196 221 typedef std::pair<JSNode*, DOMWrapperWorld*> WrapperAndWorld;222 typedef WTF::Vector<WrapperAndWorld, 8> WrapperSet;223 224 static inline void takeWrappers(Node* node, Document* document, WrapperSet& wrapperSet)225 {226 if (document) {227 JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();228 for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {229 JSNode* wrapper = iter->second->take(node).get();230 if (!wrapper)231 continue;232 wrapperSet.append(WrapperAndWorld(wrapper, iter->first));233 }234 } else {235 for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) {236 DOMWrapperWorld* world = *worldIter;237 if (JSNode* wrapper = static_cast<JSNode*>(world->m_wrappers.take(node).get()))238 wrapperSet.append(WrapperAndWorld(wrapper, world));239 }240 }241 }242 243 void updateDOMNodeDocument(Node* node, Document* oldDocument, Document* newDocument)244 {245 ASSERT(oldDocument != newDocument);246 247 WrapperSet wrapperSet;248 takeWrappers(node, oldDocument, wrapperSet);249 250 for (unsigned i = 0; i < wrapperSet.size(); ++i) {251 JSNode* wrapper = wrapperSet[i].first;252 if (newDocument)253 newDocument->getWrapperCache(wrapperSet[i].second)->set(node, Weak<JSNode>(*wrapperSet[i].second->globalData(), wrapper, wrapperSet[i].second->jsNodeHandleOwner()));254 else255 wrapperSet[i].second->m_wrappers.set(node, Weak<DOMObject>(*wrapperSet[i].second->globalData(), wrapper, wrapperSet[i].second->domObjectHandleOwner()));256 }257 }258 259 197 void markDOMObjectWrapper(MarkStack& markStack, JSGlobalData& globalData, void* object) 260 198 { -
trunk/Source/WebCore/bindings/js/JSDOMBinding.h
r83955 r83990 117 117 bool hasCachedDOMObjectWrapper(JSC::JSGlobalData*, void* objectHandle); 118 118 void cacheDOMObjectWrapper(JSC::ExecState*, void* objectHandle, DOMObject* wrapper); 119 120 JSNode* getCachedDOMNodeWrapper(JSC::ExecState*, Document*, Node*); 121 void cacheDOMNodeWrapper(JSC::ExecState*, Document*, Node*, JSNode* wrapper); 122 void updateDOMNodeDocument(Node*, Document* oldDocument, Document* newDocument); 123 119 void uncacheDOMObjectWrapper(DOMWrapperWorld*, void* objectHandle, DOMObject* wrapper); 120 121 JSNode* getCachedDOMNodeWrapper(JSC::ExecState*, Node*); 122 void cacheDOMNodeWrapper(JSC::ExecState*, Node*, JSNode* wrapper); 123 void uncacheDOMNodeWrapper(DOMWrapperWorld*, Node*, JSNode* wrapper); 124 124 125 void markActiveObjectsForContext(JSC::MarkStack&, JSC::JSGlobalData&, ScriptExecutionContext*); 125 126 void markDOMObjectWrapper(JSC::MarkStack&, JSC::JSGlobalData& globalData, void* object); 126 127 bool hasCachedDOMObjectWrapperUnchecked(JSC::JSGlobalData*, void* objectHandle); 127 bool hasCachedDOMNodeWrapperUnchecked(Document*, Node*);128 128 129 129 JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*); … … 176 176 { 177 177 ASSERT(node); 178 ASSERT(!getCachedDOMNodeWrapper(exec, node ->document(), node));178 ASSERT(!getCachedDOMNodeWrapper(exec, node)); 179 179 WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, node); 180 180 // FIXME: The entire function can be removed, once we fix caching. 181 181 // This function is a one-off hack to make Nodes cache in the right global object. 182 cacheDOMNodeWrapper(exec, node ->document(), node, wrapper);182 cacheDOMNodeWrapper(exec, node, wrapper); 183 183 return wrapper; 184 184 } … … 187 187 if (!node) 188 188 return JSC::jsNull(); 189 if (JSC::JSCell* wrapper = getCachedDOMNodeWrapper(exec, node ->document(), node))189 if (JSC::JSCell* wrapper = getCachedDOMNodeWrapper(exec, node)) 190 190 return wrapper; 191 191 return createDOMNodeWrapper<WrapperClass>(exec, globalObject, node); -
trunk/Source/WebCore/bindings/js/JSDocumentCustom.cpp
r83938 r83990 101 101 return jsNull(); 102 102 103 DOMObject* wrapper = getCachedDOMNodeWrapper(exec, document , document);103 DOMObject* wrapper = getCachedDOMNodeWrapper(exec, document); 104 104 if (wrapper) 105 105 return wrapper; -
trunk/Source/WebCore/bindings/js/JSElementCustom.cpp
r78150 r83990 72 72 return jsNull(); 73 73 74 ASSERT(!getCachedDOMNodeWrapper(exec, element ->document(), element));74 ASSERT(!getCachedDOMNodeWrapper(exec, element)); 75 75 76 76 JSNode* wrapper; -
trunk/Source/WebCore/bindings/js/JSNodeCustom.cpp
r83938 r83990 131 131 { 132 132 ASSERT(node); 133 ASSERT(!getCachedDOMNodeWrapper(exec, node ->document(), node));133 ASSERT(!getCachedDOMNodeWrapper(exec, node)); 134 134 135 135 JSNode* wrapper; -
trunk/Source/WebCore/bindings/js/JSNodeCustom.h
r83938 r83990 32 32 namespace WebCore { 33 33 34 inline JSNode* getCachedDOMNodeWrapper(JSC::ExecState* exec, Document* document,Node* node)34 inline JSNode* getCachedDOMNodeWrapper(JSC::ExecState* exec, Node* node) 35 35 { 36 if (currentWorld(exec)->isNormal()) { 37 ASSERT(node->wrapper() == (document ? document->getWrapperCache(currentWorld(exec))->get(node).get() : domObjectWrapperMapFor(exec).get(node).get())); 36 if (currentWorld(exec)->isNormal()) 38 37 return static_cast<JSNode*>(node->wrapper()); 38 return static_cast<JSNode*>(getCachedDOMObjectWrapper(exec, node)); 39 } 40 41 inline void cacheDOMNodeWrapper(JSC::ExecState* exec, Node* node, JSNode* wrapper) 42 { 43 ASSERT(wrapper); 44 45 DOMWrapperWorld* world = currentWorld(exec); 46 if (world->isNormal()) { 47 node->setWrapper(*world->globalData(), wrapper, world->jsNodeHandleOwner()); 48 return; 39 49 } 50 cacheDOMObjectWrapper(exec, node, wrapper); 51 } 40 52 41 if (document) 42 return document->getWrapperCache(currentWorld(exec))->get(node).get(); 43 return static_cast<JSNode*>(domObjectWrapperMapFor(exec).get(node).get()); 53 inline void uncacheDOMNodeWrapper(DOMWrapperWorld* world, Node* node, JSNode* jsNode) 54 { 55 if (world->isNormal()) { 56 node->clearWrapper(); 57 return; 58 } 59 uncacheDOMObjectWrapper(world, node, jsNode); 44 60 } 45 61 … … 51 67 return JSC::jsNull(); 52 68 53 JSNode* wrapper = getCachedDOMNodeWrapper(exec, node ->document(), node);69 JSNode* wrapper = getCachedDOMNodeWrapper(exec, node); 54 70 if (wrapper) 55 71 return wrapper; -
trunk/Source/WebCore/bindings/js/ScriptWrappable.h
r83385 r83990 39 39 class ScriptWrappable { 40 40 public: 41 ScriptWrappable()42 {43 }44 45 41 DOMObject* wrapper() const 46 42 { … … 48 44 } 49 45 50 void setWrapper(JSC::JSGlobalData& globalData, DOMObject* wrapper )46 void setWrapper(JSC::JSGlobalData& globalData, DOMObject* wrapper, JSC::WeakHandleOwner* wrapperOwner) 51 47 { 52 m_wrapper.set(globalData, wrapper, 0); 48 m_wrapper.set(globalData, wrapper, wrapperOwner); 49 } 50 51 void clearWrapper() 52 { 53 m_wrapper.clear(); 53 54 } 54 55 -
trunk/Source/WebCore/dom/Document.cpp
r83883 r83990 415 415 , m_usesViewSourceStyles(false) 416 416 , m_sawElementsInKnownNamespaces(false) 417 #if USE(JSC)418 , m_normalWorldWrapperCache(0)419 #endif420 417 , m_usingGeolocation(false) 421 418 , m_eventQueue(EventQueue::create(this)) … … 522 519 523 520 removeAllEventListeners(); 524 525 #if USE(JSC)526 destroyAllWrapperCaches();527 #endif528 521 529 522 // Currently we believe that Document can never outlive the parser. … … 632 625 return m_mediaQueryMatcher.get(); 633 626 } 634 635 #if USE(JSC)636 Document::JSWrapperCache* Document::createWrapperCache(DOMWrapperWorld* world)637 {638 JSWrapperCache* wrapperCache = new JSWrapperCache;639 m_wrapperCacheMap.set(world, wrapperCache);640 if (world->isNormal()) {641 ASSERT(!m_normalWorldWrapperCache);642 m_normalWorldWrapperCache = wrapperCache;643 }644 world->didCreateWrapperCache(this);645 return wrapperCache;646 }647 648 void Document::destroyWrapperCache(DOMWrapperWorld* world)649 {650 Document::JSWrapperCache* wrappers = wrapperCacheMap().take(world);651 ASSERT(wrappers);652 delete wrappers;653 world->didDestroyWrapperCache(this);654 }655 656 void Document::destroyAllWrapperCaches()657 {658 JSWrapperCacheMap& wrapperCacheMap = this->wrapperCacheMap();659 while (!wrapperCacheMap.isEmpty())660 destroyWrapperCache(wrapperCacheMap.begin()->first);661 }662 #endif663 627 664 628 void Document::setCompatibilityMode(CompatibilityMode mode) -
trunk/Source/WebCore/dom/Document.h
r83900 r83990 44 44 #include <wtf/PassOwnPtr.h> 45 45 #include <wtf/PassRefPtr.h> 46 47 #if USE(JSC)48 #include <heap/Weak.h>49 #endif50 46 51 47 namespace WebCore { … … 948 944 virtual void resumeScriptedAnimationControllerCallbacks(); 949 945 950 #if USE(JSC)951 typedef HashMap<WebCore::Node*, JSC::Weak<JSNode> > JSWrapperCache;952 typedef HashMap<DOMWrapperWorld*, JSWrapperCache*> JSWrapperCacheMap;953 JSWrapperCacheMap& wrapperCacheMap() { return m_wrapperCacheMap; }954 JSWrapperCache* getWrapperCache(DOMWrapperWorld* world);955 JSWrapperCache* createWrapperCache(DOMWrapperWorld*);956 void destroyWrapperCache(DOMWrapperWorld*);957 void destroyAllWrapperCaches();958 #endif959 960 946 virtual void finishedParsing(); 961 947 … … 1364 1350 bool m_sawElementsInKnownNamespaces; 1365 1351 1366 #if USE(JSC)1367 JSWrapperCacheMap m_wrapperCacheMap;1368 JSWrapperCache* m_normalWorldWrapperCache;1369 #endif1370 1371 1352 bool m_usingGeolocation; 1372 1353 -
trunk/Source/WebCore/dom/Node.cpp
r83922 r83990 449 449 ASSERT(willMoveToNewOwnerDocumentWasCalled); 450 450 451 #if USE(JSC)452 updateDOMNodeDocument(this, m_document, document);453 #endif454 455 451 if (hasRareData() && rareData()->nodeLists()) { 456 452 if (m_document) -
trunk/Source/WebCore/html/HTMLCanvasElement.cpp
r83396 r83990 439 439 440 440 #if USE(JSC) 441 if (hasCachedDOMNodeWrapperUnchecked(document(), const_cast<HTMLCanvasElement*>(this))) { 442 JSC::JSLock lock(JSC::SilenceAssertionsOnly); 443 scriptExecutionContext()->globalData()->heap.reportExtraMemoryCost(m_imageBuffer->dataSize()); 444 } 441 JSC::JSLock lock(JSC::SilenceAssertionsOnly); 442 scriptExecutionContext()->globalData()->heap.reportExtraMemoryCost(m_imageBuffer->dataSize()); 445 443 #endif 446 444 }
Note: See TracChangeset
for help on using the changeset viewer.