ShadowRoot needs guardRef() and guardDeref()
authormorrita@google.com <morrita@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Mar 2013 08:08:15 +0000 (08:08 +0000)
committermorrita@google.com <morrita@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Mar 2013 08:08:15 +0000 (08:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=109777

Reviewed by Dimitri Glazkov.

This change moves m_guardRefCount from Document to TreeScope,
which allows ShadowRoot to be guarded by guardRef() mechanism as
Document. After r137524, Node referes TreeScope instead of
Document. This is natural consequence of the change: It no longer
makes sense to guardRef() Document pointer from Node.

Detail:

- Document::m_guardRefCount and related funcdtions are moved to TreeScope
- Document::removedLastRef is factored out into TreeScope::removedLastRefToScope(),
  TreeScope::dispose() and Docuent::dispose(). ShadowRoot also got its own dispose() implementation.
- Moved guardRef() and guardDeref() calls to TreeScope and Node.
  Note that there are two "guarded" TreeScope references. One is
  Node::m_treeScope and another is TreeScope::m_parentTreeScope.
  The guarded-ref management is now encapsulated in these two classes.

No new tests. Covered by existing tests.

* WebCore.exp.in:
* dom/Document.cpp:
(WebCore::Document::Document):
(WebCore::Document::~Document):
(WebCore::Document::dispose): Extracted from removedLastRef()
* dom/Document.h:
(WebCore::Node::isTreeScope):
(WebCore::Node::Node):
* dom/DocumentFragment.cpp:
(WebCore::DocumentFragment::DocumentFragment): Remove ASSERT() and move it to ...
(WebCore::DocumentFragment::create): ... here, to allow NULL document from ShadowRoot.
* dom/Node.cpp:
(WebCore::Node::~Node):
(WebCore::Node::removedLastRef):
* dom/Node.h:
(WebCore::Node::setTreeScope):
* dom/Element.cpp:
(WebCore::Element::ensureAttr): This has been wrong and is fixed in this revision since the incorrectness is unveiled by this change.
* dom/ShadowRoot.cpp:
(WebCore::ShadowRoot::ShadowRoot): Passed NULL document to superclass. This aligns what Document is doing.
(WebCore::ShadowRoot::dispose): Added.
* dom/ShadowRoot.h:
(ShadowRoot):
* dom/TreeScope.cpp:
(SameSizeAsTreeScope):
(WebCore::TreeScope::TreeScope):
(WebCore::TreeScope::~TreeScope):
(WebCore::TreeScope::dispose): Added.
(WebCore::TreeScope::setParentTreeScope):
(WebCore::TreeScope::deletionHasBegun):
(WebCore::TreeScope::beginDeletion):
(WebCore::TreeScope::refCount): Added.
* dom/TreeScope.h: Turned m_rootNode to Node* from ContainerNode* for Node::isTreeScope to be inlined.
(WebCore::TreeScope::guardRef): Pulled up from Document.
(WebCore::TreeScope::guardDeref): Ditto.
(WebCore::TreeScope::hasGuardRefCount): Added to hide m_guardRefCount.
(WebCore::TreeScope::deletionHasBegun): Added.
(WebCore::TreeScope::beginDeletion): Added.
(WebCore::TreeScope::removedLastRefToScope): Pulled up from Document.
* dom/TreeScopeAdopter.cpp:
(WebCore::TreeScopeAdopter::moveTreeToNewScope):
(WebCore::TreeScopeAdopter::moveNodeToNewDocument):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@144735 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/DocumentFragment.cpp
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Node.cpp
Source/WebCore/dom/Node.h
Source/WebCore/dom/ShadowRoot.cpp
Source/WebCore/dom/ShadowRoot.h
Source/WebCore/dom/TreeScope.cpp
Source/WebCore/dom/TreeScope.h
Source/WebCore/dom/TreeScopeAdopter.cpp
Source/WebCore/dom/TreeScopeAdopter.h

index 1233350..9f4ca67 100644 (file)
@@ -1,3 +1,71 @@
+2013-03-05  Hajime Morrita  <morrita@google.com>
+
+        ShadowRoot needs guardRef() and guardDeref()
+        https://bugs.webkit.org/show_bug.cgi?id=109777
+
+        Reviewed by Dimitri Glazkov.
+
+        This change moves m_guardRefCount from Document to TreeScope,
+        which allows ShadowRoot to be guarded by guardRef() mechanism as
+        Document. After r137524, Node referes TreeScope instead of
+        Document. This is natural consequence of the change: It no longer
+        makes sense to guardRef() Document pointer from Node.
+
+        Detail:
+
+        - Document::m_guardRefCount and related funcdtions are moved to TreeScope
+        - Document::removedLastRef is factored out into TreeScope::removedLastRefToScope(),
+          TreeScope::dispose() and Docuent::dispose(). ShadowRoot also got its own dispose() implementation.
+        - Moved guardRef() and guardDeref() calls to TreeScope and Node.
+          Note that there are two "guarded" TreeScope references. One is
+          Node::m_treeScope and another is TreeScope::m_parentTreeScope.
+          The guarded-ref management is now encapsulated in these two classes.
+
+        No new tests. Covered by existing tests.
+
+        * WebCore.exp.in:
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        (WebCore::Document::~Document):
+        (WebCore::Document::dispose): Extracted from removedLastRef()
+        * dom/Document.h:
+        (WebCore::Node::isTreeScope):
+        (WebCore::Node::Node):
+        * dom/DocumentFragment.cpp:
+        (WebCore::DocumentFragment::DocumentFragment): Remove ASSERT() and move it to ...
+        (WebCore::DocumentFragment::create): ... here, to allow NULL document from ShadowRoot.
+        * dom/Node.cpp:
+        (WebCore::Node::~Node):
+        (WebCore::Node::removedLastRef):
+        * dom/Node.h:
+        (WebCore::Node::setTreeScope):
+        * dom/Element.cpp:
+        (WebCore::Element::ensureAttr): This has been wrong and is fixed in this revision since the incorrectness is unveiled by this change.
+        * dom/ShadowRoot.cpp:
+        (WebCore::ShadowRoot::ShadowRoot): Passed NULL document to superclass. This aligns what Document is doing.
+        (WebCore::ShadowRoot::dispose): Added.
+        * dom/ShadowRoot.h:
+        (ShadowRoot):
+        * dom/TreeScope.cpp:
+        (SameSizeAsTreeScope):
+        (WebCore::TreeScope::TreeScope):
+        (WebCore::TreeScope::~TreeScope):
+        (WebCore::TreeScope::dispose): Added.
+        (WebCore::TreeScope::setParentTreeScope):
+        (WebCore::TreeScope::deletionHasBegun):
+        (WebCore::TreeScope::beginDeletion):
+        (WebCore::TreeScope::refCount): Added.
+        * dom/TreeScope.h: Turned m_rootNode to Node* from ContainerNode* for Node::isTreeScope to be inlined.
+        (WebCore::TreeScope::guardRef): Pulled up from Document.
+        (WebCore::TreeScope::guardDeref): Ditto.
+        (WebCore::TreeScope::hasGuardRefCount): Added to hide m_guardRefCount.
+        (WebCore::TreeScope::deletionHasBegun): Added.
+        (WebCore::TreeScope::beginDeletion): Added.
+        (WebCore::TreeScope::removedLastRefToScope): Pulled up from Document.
+        * dom/TreeScopeAdopter.cpp:
+        (WebCore::TreeScopeAdopter::moveTreeToNewScope):
+        (WebCore::TreeScopeAdopter::moveNodeToNewDocument):
+
 2013-03-04  Uday Kiran  <udaykiran@motorola.com>
 
         getPropertyValue for -webkit-text-stroke returns null, should compute the shorthand value
index 33799ca..86ed721 100644 (file)
@@ -1423,7 +1423,6 @@ __ZNK7WebCore4Node11textContentEb
 __ZN7WebCore4Node12insertBeforeEN3WTF10PassRefPtrIS0_EEPS0_Rib
 __ZNK7WebCore4Node13ownerDocumentEv
 __ZNK7WebCore4Node14isDescendantOfEPKS0_
-__ZNK7WebCore4Node11isTreeScopeEv
 __ZNK7WebCore4Node18getSubresourceURLsERN3WTF11ListHashSetINS_4KURLELm256ENS_8KURLHashEEE
 __ZNK7WebCore4Node31numberOfScopedHTMLStyleChildrenEv
 __ZNK7WebCore4Node9nodeIndexEv
index 5b8c646..eff27b3 100644 (file)
@@ -417,7 +417,6 @@ uint64_t Document::s_globalTreeVersion = 0;
 Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
     : ContainerNode(0, CreateDocument)
     , TreeScope(this)
-    , m_guardRefCount(0)
     , m_styleResolverThrowawayTimer(this, &Document::styleResolverThrowawayTimerFired)
     , m_lastStyleResolverAccessTime(0)
     , m_activeParserCount(0)
@@ -489,8 +488,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
     , m_templateDocumentHost(0)
 #endif
 {
-    setTreeScope(this);
-
     m_printing = false;
     m_paginatedForScreen = false;
 
@@ -590,7 +587,7 @@ Document::~Document()
     ASSERT(m_ranges.isEmpty());
     ASSERT(!m_styleRecalcTimer.isActive());
     ASSERT(!m_parentTreeScope);
-    ASSERT(!m_guardRefCount);
+    ASSERT(!hasGuardRefCount());
 
 #if ENABLE(TEMPLATE_ELEMENT)
     if (m_templateDocument)
@@ -657,64 +654,45 @@ Document::~Document()
     InspectorCounters::decrementCounter(InspectorCounters::DocumentCounter);
 }
 
-void Document::removedLastRef()
+void Document::dispose()
 {
     ASSERT(!m_deletionHasBegun);
-    if (m_guardRefCount) {
-        // If removing a child removes the last self-only ref, we don't
-        // want the scope to be destructed until after
-        // removeDetachedChildren returns, so we guard ourselves with an
-        // extra self-only ref.
-        guardRef();
-
-        // We must make sure not to be retaining any of our children through
-        // these extra pointers or we will create a reference cycle.
-        m_docType = 0;
-        m_focusedNode = 0;
-        m_hoverNode = 0;
-        m_activeElement = 0;
-        m_titleElement = 0;
-        m_documentElement = 0;
-        m_contextFeatures = ContextFeatures::defaultSwitch();
-        m_userActionElements.documentDidRemoveLastRef();
+    // We must make sure not to be retaining any of our children through
+    // these extra pointers or we will create a reference cycle.
+    m_docType = 0;
+    m_focusedNode = 0;
+    m_hoverNode = 0;
+    m_activeElement = 0;
+    m_titleElement = 0;
+    m_documentElement = 0;
+    m_contextFeatures = ContextFeatures::defaultSwitch();
+    m_userActionElements.documentDidRemoveLastRef();
 #if ENABLE(FULLSCREEN_API)
-        m_fullScreenElement = 0;
-        m_fullScreenElementStack.clear();
+    m_fullScreenElement = 0;
+    m_fullScreenElementStack.clear();
 #endif
 
-        detachParser();
+    detachParser();
 
 #if ENABLE(CUSTOM_ELEMENTS)
-        m_registry.clear();
+    m_registry.clear();
 #endif
 
-        // removeDetachedChildren() doesn't always unregister IDs,
-        // so tear down scope information upfront to avoid having stale references in the map.
-        destroyTreeScopeData();
-        removeDetachedChildren();
+    // removeDetachedChildren() doesn't always unregister IDs,
+    // so tear down scope information upfront to avoid having stale references in the map.
+    destroyTreeScopeData();
+    removeDetachedChildren();
 
-        m_markers->detach();
+    m_markers->detach();
 
-        m_cssCanvasElements.clear();
+    m_cssCanvasElements.clear();
 
 #if ENABLE(REQUEST_ANIMATION_FRAME)
-        // FIXME: consider using ActiveDOMObject.
-        if (m_scriptedAnimationController)
-            m_scriptedAnimationController->clearDocumentPointer();
-        m_scriptedAnimationController.clear();
-#endif
-
-#ifndef NDEBUG
-        m_inRemovedLastRefFunction = false;
+    // FIXME: consider using ActiveDOMObject.
+    if (m_scriptedAnimationController)
+        m_scriptedAnimationController->clearDocumentPointer();
+    m_scriptedAnimationController.clear();
 #endif
-
-        guardDeref();
-    } else {
-#ifndef NDEBUG 
-        m_deletionHasBegun = true; 
-#endif 
-        delete this;
-    }
 }
 
 Element* Document::getElementById(const AtomicString& id) const
index 06363d3..1ad6151 100644 (file)
@@ -231,29 +231,6 @@ public:
     using ContainerNode::ref;
     using ContainerNode::deref;
 
-    // Nodes belonging to this document hold guard references -
-    // these are enough to keep the document from being destroyed, but
-    // not enough to keep it from removing its children. This allows a
-    // node that outlives its document to still have a valid document
-    // pointer without introducing reference cycles.
-    void guardRef()
-    {
-        ASSERT(!m_deletionHasBegun);
-        ++m_guardRefCount;
-    }
-
-    void guardDeref()
-    {
-        ASSERT(!m_deletionHasBegun);
-        --m_guardRefCount;
-        if (!m_guardRefCount && !refCount()) {
-#ifndef NDEBUG
-            m_deletionHasBegun = true;
-#endif
-            delete this;
-        }
-    }
-
     Element* getElementById(const AtomicString& id) const;
 
     virtual bool canContainRangeEndPoint() const { return true; }
@@ -1226,8 +1203,8 @@ private:
     friend class Node;
     friend class IgnoreDestructiveWriteCountIncrementer;
 
-    void removedLastRef();
-    
+    virtual void dispose() OVERRIDE;
+
     void detachParser();
 
     typedef void (*ArgumentsCallback)(const String& keyString, const String& valueString, Document*, void* data);
@@ -1295,8 +1272,6 @@ private:
     void addListenerType(ListenerType listenerType) { m_listenerTypes |= listenerType; }
     void addMutationEventListenerTypeIfEnabled(ListenerType);
 
-    int m_guardRefCount;
-
     void styleResolverThrowawayTimerFired(Timer<Document>*);
     Timer<Document> m_styleResolverThrowawayTimer;
     double m_lastStyleResolverAccessTime;
@@ -1616,10 +1591,9 @@ inline Node::Node(Document* document, ConstructionType type)
     , m_previous(0)
     , m_next(0)
 {
-    if (document)
-        document->guardRef();
-    else
+    if (!m_treeScope)
         m_treeScope = TreeScope::noDocumentInstance();
+    m_treeScope->guardRef();
 
 #if !defined(NDEBUG) || (defined(DUMP_NODE_STATISTICS) && DUMP_NODE_STATISTICS)
     trackForDebugging();
index 85015b2..e660248 100644 (file)
@@ -34,11 +34,11 @@ namespace WebCore {
 DocumentFragment::DocumentFragment(Document* document, ConstructionType constructionType)
     : ContainerNode(document, constructionType)
 {
-    ASSERT(document);
 }
 
 PassRefPtr<DocumentFragment> DocumentFragment::create(Document* document)
 {
+    ASSERT(document);
     return adoptRef(new DocumentFragment(document, Node::CreateDocumentFragment));
 }
 
index b02ad35..9531855 100644 (file)
@@ -2753,6 +2753,7 @@ PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
     RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
     if (!attrNode) {
         attrNode = Attr::create(this, name);
+        treeScope()->adoptIfNeeded(attrNode.get());
         attrNodeList->append(attrNode);
     }
     return attrNode.release();
index 1445a00..dc11c97 100644 (file)
@@ -442,8 +442,7 @@ Node::~Node()
     if (m_next)
         m_next->setPreviousSibling(0);
 
-    if (doc)
-        doc->guardDeref();
+    m_treeScope->guardDeref();
 
     InspectorCounters::decrementCounter(InspectorCounters::NodeCounter);
 }
@@ -892,11 +891,6 @@ bool Node::isFocusable() const
     return true;
 }
 
-bool Node::isTreeScope() const
-{
-    return treeScope()->rootNode() == this;
-}
-
 bool Node::isKeyboardFocusable(KeyboardEvent*) const
 {
     return isFocusable() && tabIndex() >= 0;
@@ -2567,6 +2561,31 @@ PassRefPtr<PropertyNodeList> Node::propertyNodeList(const String& name)
 }
 #endif
 
+// This is here for inlining
+inline void TreeScope::removedLastRefToScope()
+{
+    ASSERT(!deletionHasBegun());
+    if (m_guardRefCount) {
+        // If removing a child removes the last self-only ref, we don't
+        // want the scope to be destructed until after
+        // removeDetachedChildren returns, so we guard ourselves with an
+        // extra self-only ref.
+        guardRef();
+        dispose();
+#ifndef NDEBUG
+        // We need to do this right now since guardDeref() can delete this.
+        rootNode()->m_inRemovedLastRefFunction = false;
+#endif
+        guardDeref();
+    } else {
+#ifndef NDEBUG
+        rootNode()->m_inRemovedLastRefFunction = false;
+        beginDeletion();
+#endif
+        delete this;
+    }
+}
+
 // It's important not to inline removedLastRef, because we don't want to inline the code to
 // delete a Node at each deref call site.
 void Node::removedLastRef()
@@ -2574,10 +2593,11 @@ void Node::removedLastRef()
     // An explicit check for Document here is better than a virtual function since it is
     // faster for non-Document nodes, and because the call to removedLastRef that is inlined
     // at all deref call sites is smaller if it's a non-virtual function.
-    if (isDocumentNode()) {
-        static_cast<Document*>(this)->removedLastRef();
+    if (isTreeScope()) {
+        treeScope()->removedLastRefToScope();
         return;
     }
+
 #ifndef NDEBUG
     m_deletionHasBegun = true;
 #endif
index a836bf0..710c1c6 100644 (file)
@@ -248,7 +248,7 @@ public:
     virtual bool isInsertionPointNode() const { return false; }
 
     bool isDocumentNode() const;
-    bool isTreeScope() const;
+    bool isTreeScope() const { return treeScope()->rootNode() == this; }
     bool isDocumentFragment() const { return getFlag(IsDocumentFragmentFlag); }
     bool isShadowRoot() const { return isDocumentFragment() && isTreeScope(); }
     bool isInsertionPoint() const { return getFlag(NeedsShadowTreeWalkerFlag) && isInsertionPointNode(); }
index b4f2419..1143ba3 100644 (file)
@@ -52,7 +52,7 @@ enum ShadowRootUsageOriginType {
 };
 
 ShadowRoot::ShadowRoot(Document* document, ShadowRootType type)
-    : DocumentFragment(document, CreateShadowRoot)
+    : DocumentFragment(0, CreateShadowRoot)
     , TreeScope(this, document)
     , m_prev(0)
     , m_next(0)
@@ -63,7 +63,6 @@ ShadowRoot::ShadowRoot(Document* document, ShadowRootType type)
     , m_registeredWithParentShadowRoot(false)
 {
     ASSERT(document);
-    setTreeScope(this);
 
 #if PLATFORM(CHROMIUM)
     if (type == ShadowRoot::AuthorShadowRoot) {
@@ -89,6 +88,11 @@ ShadowRoot::~ShadowRoot()
         clearRareData();
 }
 
+void ShadowRoot::dispose()
+{
+    removeDetachedChildren();
+}
+
 PassRefPtr<Node> ShadowRoot::cloneNode(bool, ExceptionCode& ec)
 {
     ec = DATA_CLONE_ERR;
index 2d1cf23..dbc71dc 100644 (file)
@@ -100,6 +100,7 @@ private:
     ShadowRoot(Document*, ShadowRootType);
     virtual ~ShadowRoot();
 
+    virtual void dispose() OVERRIDE;
     virtual bool childTypeAllowed(NodeType) const OVERRIDE;
     virtual void childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) OVERRIDE;
 
index 454af5d..3809d5d 100644 (file)
@@ -59,6 +59,7 @@ namespace WebCore {
 struct SameSizeAsTreeScope {
     virtual ~SameSizeAsTreeScope();
     void* pointers[8];
+    int ints[1];
 };
 
 COMPILE_ASSERT(sizeof(TreeScope) == sizeof(SameSizeAsTreeScope), treescope_should_stay_small);
@@ -69,35 +70,47 @@ TreeScope::TreeScope(ContainerNode* rootNode, Document* document)
     : m_rootNode(rootNode)
     , m_documentScope(document)
     , m_parentTreeScope(document)
+    , m_guardRefCount(0)
     , m_idTargetObserverRegistry(IdTargetObserverRegistry::create())
 {
     ASSERT(rootNode);
     ASSERT(document);
     ASSERT(rootNode != document);
+    m_parentTreeScope->guardRef();
+    m_rootNode->setTreeScope(this);
 }
 
 TreeScope::TreeScope(Document* document)
     : m_rootNode(document)
     , m_documentScope(document)
     , m_parentTreeScope(0)
+    , m_guardRefCount(0)
     , m_idTargetObserverRegistry(IdTargetObserverRegistry::create())
 {
     ASSERT(document);
+    m_rootNode->setTreeScope(this);
 }
 
 TreeScope::TreeScope()
     : m_rootNode(0)
     , m_documentScope(0)
     , m_parentTreeScope(0)
+    , m_guardRefCount(0)
 {
 }
 
 TreeScope::~TreeScope()
 {
+    ASSERT(!m_guardRefCount);
+    m_rootNode->setTreeScope(noDocumentInstance());
+
     if (m_selection) {
         m_selection->clearTreeScope();
         m_selection = 0;
     }
+
+    if (m_parentTreeScope)
+        m_parentTreeScope->guardDeref();
 }
 
 void TreeScope::destroyTreeScopeData()
@@ -120,6 +133,9 @@ void TreeScope::setParentTreeScope(TreeScope* newParentScope)
     // Every scope other than document needs a parent scope.
     ASSERT(newParentScope);
 
+    newParentScope->guardRef();
+    if (m_parentTreeScope)
+        m_parentTreeScope->guardDeref();
     m_parentTreeScope = newParentScope;
     setDocumentScope(newParentScope->documentScope());
 }
@@ -415,4 +431,24 @@ TreeScope* commonTreeScope(Node* nodeA, Node* nodeB)
     return treeScopesA[indexA] == treeScopesB[indexB] ? treeScopesA[indexA] : 0;
 }
 
+#ifndef NDEBUG
+bool TreeScope::deletionHasBegun()
+{
+    return rootNode() && rootNode()->m_deletionHasBegun;
+}
+
+void TreeScope::beginDeletion()
+{
+    ASSERT(this != noDocumentInstance());
+    rootNode()->m_deletionHasBegun = true;
+}
+#endif
+
+int TreeScope::refCount() const
+{
+    if (Node* root = rootNode())
+        return root->refCount();
+    return 0;
+}
+
 } // namespace WebCore
index be500f1..e540152 100644 (file)
@@ -92,7 +92,7 @@ public:
     // Used by the basic DOM mutation methods (e.g., appendChild()).
     void adoptIfNeeded(Node*);
 
-    ContainerNode* rootNode() const { return m_rootNode; }
+    Node* rootNode() const { return m_rootNode; }
 
     IdTargetObserverRegistry& idTargetObserverRegistry() const { return *m_idTargetObserverRegistry.get(); }
 
@@ -104,6 +104,29 @@ public:
         return &instance;
     }
 
+    // Nodes belonging to this scope hold guard references -
+    // these are enough to keep the scope from being destroyed, but
+    // not enough to keep it from removing its children. This allows a
+    // node that outlives its scope to still have a valid document
+    // pointer without introducing reference cycles.
+    void guardRef()
+    {
+        ASSERT(!deletionHasBegun());
+        ++m_guardRefCount;
+    }
+
+    void guardDeref()
+    {
+        ASSERT(!deletionHasBegun());
+        --m_guardRefCount;
+        if (!m_guardRefCount && !refCount() && this != noDocumentInstance()) {
+            beginDeletion();
+            delete this;
+        }
+    }
+
+    void removedLastRefToScope();
+
 protected:
     TreeScope(ContainerNode*, Document*);
     TreeScope(Document*);
@@ -118,12 +141,26 @@ protected:
         m_documentScope = document;
     }
 
+    bool hasGuardRefCount() const { return m_guardRefCount; }
+
 private:
     TreeScope();
 
-    ContainerNode* m_rootNode;
+    virtual void dispose() { }
+
+    int refCount() const;
+#ifndef NDEBUG
+    bool deletionHasBegun();
+    void beginDeletion();
+#else
+    bool deletionHasBegun() { return false; }
+    void beginDeletion() { }
+#endif
+
+    Node* m_rootNode;
     Document* m_documentScope;
     TreeScope* m_parentTreeScope;
+    int m_guardRefCount;
 
     OwnPtr<DocumentOrderedMap> m_elementsById;
     OwnPtr<DocumentOrderedMap> m_imageMapsByName;
index 41bfd25..2550c2d 100644 (file)
@@ -40,6 +40,8 @@ void TreeScopeAdopter::moveTreeToNewScope(Node* root) const
 {
     ASSERT(needsScopeChange());
 
+    m_oldScope->guardRef();
+
     // If an element is moved from a document and then eventually back again the collection cache for
     // that element may contain stale data as changes made to it will have updated the DOMTreeVersion
     // of the document it was moved to. By increasing the DOMTreeVersion of the donating document here
@@ -51,7 +53,7 @@ void TreeScopeAdopter::moveTreeToNewScope(Node* root) const
         oldDocument->incDOMTreeVersion();
 
     for (Node* node = root; node; node = NodeTraversal::next(node, root)) {
-        node->setTreeScope(m_newScope);
+        updateTreeScope(node);
 
         if (willMoveToNewDocument)
             moveNodeToNewDocument(node, oldDocument, newDocument);
@@ -76,6 +78,8 @@ void TreeScopeAdopter::moveTreeToNewScope(Node* root) const
                 moveTreeToNewDocument(shadow, oldDocument, newDocument);
         }
     }
+
+    m_oldScope->guardDeref();
 }
 
 void TreeScopeAdopter::moveTreeToNewDocument(Node* root, Document* oldDocument, Document* newDocument) const
@@ -99,6 +103,15 @@ void TreeScopeAdopter::ensureDidMoveToNewDocumentWasCalled(Document* oldDocument
 }
 #endif
 
+inline void TreeScopeAdopter::updateTreeScope(Node* node) const
+{
+    ASSERT(!node->isTreeScope());
+    ASSERT(node->treeScope() == m_oldScope);
+    m_newScope->guardRef();
+    m_oldScope->guardDeref();
+    node->setTreeScope(m_newScope);
+}
+
 inline void TreeScopeAdopter::moveNodeToNewDocument(Node* node, Document* oldDocument, Document* newDocument) const
 {
     ASSERT(!node->inDocument() || oldDocument != newDocument);
@@ -109,7 +122,6 @@ inline void TreeScopeAdopter::moveNodeToNewDocument(Node* node, Document* oldDoc
             rareData->nodeLists()->adoptDocument(oldDocument, newDocument);
     }
 
-    newDocument->guardRef();
     if (oldDocument)
         oldDocument->moveNodeIteratorsToNewDocument(node, newDocument);
 
@@ -123,9 +135,6 @@ inline void TreeScopeAdopter::moveNodeToNewDocument(Node* node, Document* oldDoc
 
     node->didMoveToNewDocument(oldDocument);
     ASSERT(didMoveToNewDocumentWasCalled);
-    
-    if (oldDocument)
-        oldDocument->guardDeref();
 }
 
 }
index 4ca4182..cea4dca 100644 (file)
@@ -45,6 +45,7 @@ public:
 #endif
 
 private:
+    void updateTreeScope(Node*) const;
     void moveTreeToNewScope(Node*) const;
     void moveTreeToNewDocument(Node*, Document* oldDocument, Document* newDocument) const;
     void moveNodeToNewDocument(Node*, Document* oldDocument, Document* newDocument) const;