From 46ea975af99c6f90f5dde0823be332ed33fd3508 Mon Sep 17 00:00:00 2001 From: "peterv%propagandism.org" Date: Tue, 14 Nov 2006 23:23:20 +0000 Subject: [PATCH] Part of the fix for bug 193678 (support exslt:common - allow txXPathNode to hold a strong ref to its root). r/sr=sicking. --- .../src/xpath/txMozillaXPathTreeWalker.cpp | 52 +++++------- content/xslt/src/xpath/txNodeSet.cpp | 51 ++++++++--- content/xslt/src/xpath/txNodeSet.h | 13 ++- content/xslt/src/xpath/txXPathNode.h | 84 +++++++++++++++++-- content/xslt/src/xpath/txXPathTreeWalker.h | 17 +++- 5 files changed, 167 insertions(+), 50 deletions(-) diff --git a/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp b/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp index 515b1be9b27..52e1121c68d 100644 --- a/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp +++ b/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp @@ -86,16 +86,13 @@ txXPathTreeWalker::moveToRoot() mPosition.mNode = root; } else { - nsINode *parent, *current = mPosition.mNode; - while ((parent = current->GetNodeParent())) { - current = parent; - } + nsINode *rootNode = mPosition.Root(); - NS_ASSERTION(current->IsNodeOfType(nsINode::eCONTENT), + NS_ASSERTION(rootNode->IsNodeOfType(nsINode::eCONTENT), "root of subtree wasn't an nsIContent"); mPosition.mIndex = txXPathNode::eContent; - mPosition.mNode = current; + mPosition.mNode = rootNode; } mCurrentIndex = kUnknownIndex; @@ -123,16 +120,13 @@ txXPathTreeWalker::moveToElementById(const nsAString& aID) } else { // We're in a disconnected subtree, search only that subtree. - nsINode *parent, *current = mPosition.mNode; - while ((parent = current->GetNodeParent())) { - current = parent; - } + nsINode *rootNode = mPosition.Root(); - NS_ASSERTION(current->IsNodeOfType(nsINode::eCONTENT), + NS_ASSERTION(rootNode->IsNodeOfType(nsINode::eCONTENT), "root of subtree wasn't an nsIContent"); content = nsContentUtils::MatchElementId( - NS_STATIC_CAST(nsIContent*, current), aID); + NS_STATIC_CAST(nsIContent*, rootNode), aID); } if (!content) { @@ -350,17 +344,6 @@ txXPathTreeWalker::moveToSibling(PRInt32 aDir) return PR_TRUE; } -txXPathNode::txXPathNode(const txXPathNode& aNode) : mIndex(aNode.mIndex), - mNode(aNode.mNode) -{ -} - -PRBool -txXPathNode::operator==(const txXPathNode& aNode) const -{ - return mIndex == aNode.mIndex && mNode == aNode.mNode; -} - /* static */ PRBool txXPathNodeUtils::getAttr(const txXPathNode& aNode, nsIAtom* aLocalName, @@ -695,7 +678,6 @@ txXPathNodeUtils::comparePosition(const txXPathNode& aNode, nsINode* node = aNode.mNode; nsINode* otherNode = aOtherNode.mNode; nsINode* parent, *otherParent; - PRInt32 index, otherIndex; while (node && otherNode) { parent = node->GetNodeParent(); otherParent = otherNode->GetNodeParent(); @@ -764,7 +746,7 @@ txXPathNodeUtils::comparePosition(const txXPathNode& aNode, /* static */ txXPathNode* -txXPathNativeNode::createXPathNode(nsIDOMNode* aNode) +txXPathNativeNode::createXPathNode(nsIDOMNode* aNode, PRBool aKeepRootAlive) { PRUint16 nodeType; aNode->GetNodeType(&nodeType); @@ -779,11 +761,13 @@ txXPathNativeNode::createXPathNode(nsIDOMNode* aNode) return nsnull; } + nsINode* root = aKeepRootAlive ? txXPathNode::RootOf(parent) : nsnull; + PRUint32 i, total = parent->GetAttrCount(); for (i = 0; i < total; ++i) { const nsAttrName* name = parent->GetAttrNameAt(i); if (nodeInfo->Equals(name->LocalName(), name->NamespaceID())) { - return new txXPathNode(parent, i); + return new txXPathNode(parent, i, root); } } @@ -792,13 +776,21 @@ txXPathNativeNode::createXPathNode(nsIDOMNode* aNode) return nsnull; } + nsCOMPtr node = do_QueryInterface(aNode); + PRUint32 index; + nsINode* root = aKeepRootAlive ? node : nsnull; + if (nodeType == nsIDOMNode::DOCUMENT_NODE) { - nsCOMPtr document = do_QueryInterface(aNode); - return new txXPathNode(document); + index = txXPathNode::eDocument; + } + else { + index = txXPathNode::eContent; + if (root) { + root = txXPathNode::RootOf(root); + } } - nsCOMPtr content = do_QueryInterface(aNode); - return new txXPathNode(content); + return new txXPathNode(node, index, root); } /* static */ diff --git a/content/xslt/src/xpath/txNodeSet.cpp b/content/xslt/src/xpath/txNodeSet.cpp index 67028f8c21b..b60a968ebd8 100644 --- a/content/xslt/src/xpath/txNodeSet.cpp +++ b/content/xslt/src/xpath/txNodeSet.cpp @@ -45,6 +45,24 @@ * Implementation of an XPath nodeset */ +#ifdef NS_BUILD_REFCNT_LOGGING +#define LOG_CHUNK_MOVE(_start, _new_start, _count) \ +{ \ + txXPathNode *start = NS_CONST_CAST(txXPathNode*, _start); \ + while (start < _start + _count) { \ + NS_LogDtor(start, "txXPathNode", sizeof(*start)); \ + ++start; \ + } \ + start = NS_CONST_CAST(txXPathNode*, _new_start); \ + while (start < _new_start + _count) { \ + NS_LogCtor(start, "txXPathNode", sizeof(*start)); \ + ++start; \ + } \ +} +#else +#define LOG_CHUNK_MOVE(_start, _new_start, _count) +#endif + static const PRInt32 kTxNodeSetMinSize = 4; static const PRInt32 kTxNodeSetGrowFactor = 2; @@ -96,10 +114,7 @@ txNodeSet::~txNodeSet() delete [] mMarks; if (mStartBuffer) { - while (mStart < mEnd) { - mStart->~txXPathNode(); - ++mStart; - } + destroyElements(mStart, mEnd); nsMemory::Free(mStartBuffer); } @@ -131,6 +146,7 @@ nsresult txNodeSet::add(const txXPathNode& aNode) pos = mStart + offset; if (moveSize > 0) { + LOG_CHUNK_MOVE(pos, pos + 1, moveSize); memmove(pos + 1, pos, moveSize * sizeof(txXPathNode)); } @@ -142,13 +158,13 @@ nsresult txNodeSet::add(const txXPathNode& aNode) nsresult txNodeSet::add(const txNodeSet& aNodes) { - return add(aNodes, copyElements); + return add(aNodes, copyElements, nsnull); } nsresult txNodeSet::addAndTransfer(txNodeSet* aNodes) { // failure is out-of-memory, transfer didn't happen - nsresult rv = add(*aNodes, transferElements); + nsresult rv = add(*aNodes, transferElements, destroyElements); NS_ENSURE_SUCCESS(rv, rv); #ifdef TX_DONT_RECYCLE_BUFFER @@ -203,7 +219,8 @@ nsresult txNodeSet::addAndTransfer(txNodeSet* aNodes) * check for sequences of duplicate nodes, which can be optimized. * */ -nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer) +nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer, + destroyOp aDestroy) { NS_ASSERTION(mDirection == kForward, "only append(aNode) is supported on reversed nodesets"); @@ -244,6 +261,7 @@ nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer) pos = findPosition(thisPos[-1], aNodes.mStart, otherPos, dupe); if (dupe) { + const txXPathNode *deletePos = thisPos; --thisPos; // this is already added // check dupe sequence while (thisPos > mStart && pos > aNodes.mStart && @@ -251,6 +269,10 @@ nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer) --thisPos; --pos; } + + if (aDestroy) { + aDestroy(thisPos, deletePos); + } } } else { @@ -271,6 +293,7 @@ nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer) pos = findPosition(otherPos[-1], mStart, thisPos, dupe); if (dupe) { + const txXPathNode *deletePos = otherPos; --otherPos; // this is already added // check dupe sequence while (otherPos > aNodes.mStart && pos > mStart && @@ -278,6 +301,10 @@ nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer) --otherPos; --pos; } + + if (aDestroy) { + aDestroy(otherPos, deletePos); + } } } else { @@ -289,6 +316,7 @@ nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer) count = thisPos - pos; if (count > 0) { insertPos -= count; + LOG_CHUNK_MOVE(pos, insertPos, count); memmove(insertPos, pos, count * sizeof(txXPathNode)); thisPos -= count; } @@ -396,6 +424,7 @@ txNodeSet::sweep() } // move chunk if (chunk > 0) { + LOG_CHUNK_MOVE(mStart + pos - chunk, insertion, chunk); memmove(insertion, mStart + pos - chunk, chunk * sizeof(txXPathNode)); insertion += chunk; @@ -412,10 +441,7 @@ txNodeSet::sweep() void txNodeSet::clear() { - while (mStart < mEnd) { - mStart->~txXPathNode(); - ++mStart; - } + destroyElements(mStart, mEnd); #ifdef TX_DONT_RECYCLE_BUFFER if (mStartBuffer) { nsMemory::Free(mStartBuffer); @@ -517,6 +543,7 @@ PRBool txNodeSet::ensureGrowSize(PRInt32 aSize) if (mDirection == kReversed) { dest = mEndBuffer - oldSize; } + LOG_CHUNK_MOVE(mStart, dest, oldSize); memmove(dest, mStart, oldSize * sizeof(txXPathNode)); mStart = dest; mEnd = dest + oldSize; @@ -545,6 +572,7 @@ PRBool txNodeSet::ensureGrowSize(PRInt32 aSize) } if (oldSize > 0) { + LOG_CHUNK_MOVE(mStart, dest, oldSize); memcpy(dest, mStart, oldSize * sizeof(txXPathNode)); } @@ -623,5 +651,6 @@ void txNodeSet::transferElements(txXPathNode* aDest, const txXPathNode* aStart, const txXPathNode* aEnd) { + LOG_CHUNK_MOVE(aStart, aDest, (aEnd - aStart)); memcpy(aDest, aStart, (aEnd - aStart) * sizeof(txXPathNode)); } diff --git a/content/xslt/src/xpath/txNodeSet.h b/content/xslt/src/xpath/txNodeSet.h index 87bc286401c..538f1174d75 100644 --- a/content/xslt/src/xpath/txNodeSet.h +++ b/content/xslt/src/xpath/txNodeSet.h @@ -227,10 +227,21 @@ private: const txXPathNode* aEnd); static void transferElements(txXPathNode* aDest, const txXPathNode* aStart, const txXPathNode* aEnd); + static void destroyElements(const txXPathNode* aStart, + const txXPathNode* aEnd) + { + while (aStart < aEnd) { + aStart->~txXPathNode(); + ++aStart; + } + } typedef void (*transferOp) (txXPathNode* aDest, const txXPathNode* aStart, const txXPathNode* aEnd); - nsresult add(const txNodeSet& aNodes, transferOp aTransfer); + typedef void (*destroyOp) (const txXPathNode* aStart, + const txXPathNode* aEnd); + nsresult add(const txNodeSet& aNodes, transferOp aTransfer, + destroyOp aDestroy); txXPathNode *mStart, *mEnd, *mStartBuffer, *mEndBuffer; PRInt32 mDirection; diff --git a/content/xslt/src/xpath/txXPathNode.h b/content/xslt/src/xpath/txXPathNode.h index 6af7887ff42..84c7ea31de9 100644 --- a/content/xslt/src/xpath/txXPathNode.h +++ b/content/xslt/src/xpath/txXPathNode.h @@ -64,6 +64,7 @@ public: { return !(*this == aNode); } + ~txXPathNode(); private: friend class txNodeSet; @@ -71,24 +72,48 @@ private: friend class txXPathNodeUtils; friend class txXPathTreeWalker; + txXPathNode(const txXPathNode& aNode); + #ifdef TX_EXE txXPathNode(NodeDefinition* aNode) : mInner(aNode) { } - txXPathNode(const txXPathNode& aNode); NodeDefinition* mInner; #else txXPathNode(nsIDocument* aDocument) : mNode(aDocument), + mRefCountRoot(0), mIndex(eDocument) { + MOZ_COUNT_CTOR(txXPathNode); } - txXPathNode(nsIContent* aContent, PRUint32 aIndex = eContent) - : mNode(aContent), + txXPathNode(nsINode *aNode, PRUint32 aIndex, nsINode *aRoot) + : mNode(aNode), + mRefCountRoot(aRoot ? 1 : 0), mIndex(aIndex) { + MOZ_COUNT_CTOR(txXPathNode); + if (aRoot) { + NS_ADDREF(aRoot); + } + } + + static nsINode *RootOf(nsINode *aNode) + { + nsINode *ancestor, *root = aNode; + while ((ancestor = root->GetNodeParent())) { + root = ancestor; + } + return root; + } + nsINode *Root() const + { + return RootOf(mNode); + } + nsINode *GetRootToAddRef() const + { + return mRefCountRoot ? Root() : nsnull; } - txXPathNode(const txXPathNode& aNode); PRBool isDocument() const { @@ -116,11 +141,13 @@ private: enum PositionType { - eDocument = (PRUint32)-2, - eContent = (PRUint32)-1 + eDocument = (1 << 30), + eContent = eDocument - 1 }; + nsINode* mNode; - PRUint32 mIndex; + PRUint32 mRefCountRoot : 1; + PRUint32 mIndex : 31; #endif }; @@ -157,4 +184,47 @@ txNamespaceManager::getNamespaceURI(const PRInt32 aID, nsAString& aResult) #endif } +#ifdef TX_EXE +inline +txXPathNode::txXPathNode(const txXPathNode& aNode) + : mInner(aNode.mInner) +{ +} +#else +inline +txXPathNode::txXPathNode(const txXPathNode& aNode) + : mNode(aNode.mNode), + mRefCountRoot(aNode.mRefCountRoot), + mIndex(aNode.mIndex) +{ + MOZ_COUNT_CTOR(txXPathNode); + if (mRefCountRoot) { + NS_ADDREF(Root()); + } +} +#endif + +inline +txXPathNode::~txXPathNode() +{ +#ifdef TX_EXE +#else + MOZ_COUNT_DTOR(txXPathNode); + if (mRefCountRoot) { + nsINode *root = Root(); + NS_RELEASE(root); + } +#endif +} + +inline PRBool +txXPathNode::operator==(const txXPathNode& aNode) const +{ +#ifdef TX_EXE + return (mInner == aNode.mInner); +#else + return mIndex == aNode.mIndex && mNode == aNode.mNode; +#endif +} + #endif /* txXPathNode_h__ */ diff --git a/content/xslt/src/xpath/txXPathTreeWalker.h b/content/xslt/src/xpath/txXPathTreeWalker.h index 27106b29a79..743d892655e 100644 --- a/content/xslt/src/xpath/txXPathTreeWalker.h +++ b/content/xslt/src/xpath/txXPathTreeWalker.h @@ -160,7 +160,8 @@ public: class txXPathNativeNode { public: - static txXPathNode* createXPathNode(nsIDOMNode* aNode); + static txXPathNode* createXPathNode(nsIDOMNode* aNode, + PRBool aKeepRootAlive = PR_FALSE); static txXPathNode* createXPathNode(nsIDOMDocument* aDocument); static nsresult getNode(const txXPathNode& aNode, nsIDOMNode** aResult); static nsIContent* getContent(const txXPathNode& aNode); @@ -215,8 +216,22 @@ txXPathTreeWalker::moveTo(const txXPathTreeWalker& aWalker) #ifdef TX_EXE mPosition.mInner = aWalker.mPosition.mInner; #else + nsINode *root = nsnull; + if (mPosition.mRefCountRoot) { + root = mPosition.Root(); + } mPosition.mIndex = aWalker.mPosition.mIndex; + mPosition.mRefCountRoot = aWalker.mPosition.mRefCountRoot; mPosition.mNode = aWalker.mPosition.mNode; + nsINode *newRoot = nsnull; + if (mPosition.mRefCountRoot) { + newRoot = mPosition.Root(); + } + if (root != newRoot) { + NS_IF_ADDREF(newRoot); + NS_IF_RELEASE(root); + } + mCurrentIndex = aWalker.mCurrentIndex; mDescendants.Clear(); #endif