diff --git a/layout/html/base/src/nsDST.cpp b/layout/html/base/src/nsDST.cpp index f400c7b2027..165df3f6218 100644 --- a/layout/html/base/src/nsDST.cpp +++ b/layout/html/base/src/nsDST.cpp @@ -15,7 +15,7 @@ * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ -#define PL_ARENA_CONST_ALIGN_MASK 7 +#define PL_ARENA_CONST_ALIGN_MASK 3 #include "nslayout.h" #include "nsDST.h" #include "nsISupports.h" @@ -24,38 +24,110 @@ #endif ///////////////////////////////////////////////////////////////////////////// -// Structure that represents a node in the DST +// Classes that represents nodes in the DST + +// To reduce the amount of memory we use there are two types of nodes: +// - leaf nodes +// - two nodes (left and right child) +// +// We distinguish the two types of nodes by looking at the low-order +// bit of the key. If it is 0, then the node is a leaf node. If it is +// 1, then the node is a two node. Use function Key() when retrieving +// the key, and function IsLeaf() to tell what type of node it is +// +// It's an invariant of the tree that a two node can not have both child links +// NULL. In that case it must be converted back to a leaf node + +// Leaf node class +class nsDST::LeafNode { +public: + void* mKey; + void* mValue; + + // Constructors + LeafNode(void* aKey, void* aValue); + LeafNode(const LeafNode& aLeafNode); + + // Accessor for getting the key. Clears the bit used to tell if the + // node is a leaf. This function can be safely used on any node without + // knowing whether it's a leaf or a two node + void* Key() const {return (void*)(PtrBits(mKey) & ~0x1);} + + // Helper function that returns TRUE if the node is a leaf + int IsLeaf() const {return 0 == (PtrBits(mKey) & 0x1);} + + // Overloaded placement operator for allocating from an arena + void* operator new(size_t aSize, NodeArena& aArena) {return aArena.AllocLeafNode();} + +private: + void operator delete(void*); // no implementation +}; + +// Constructors +inline nsDST::LeafNode::LeafNode(void* aKey, void* aValue) + : mKey(aKey), mValue(aValue) +{ +} + +inline nsDST::LeafNode::LeafNode(const LeafNode& aNode) + : mKey(aNode.Key()), // don't assume it's a leaf node + mValue(aNode.mValue) +{ +} + +// Two node class +class nsDST::TwoNode : public nsDST::LeafNode { +public: + LeafNode* mLeft; // left subtree + LeafNode* mRight; // right subtree + + TwoNode(const LeafNode& aLeafNode); + + void SetKeyAndValue(void* aKey, void* aValue) { + mKey = (void*)(PtrBits(aKey) | 0x01); + mValue = aValue; + } + + // Overloaded placement operator for allocating from an arena + void* operator new(size_t aSize, NodeArena& aArena) {return aArena.AllocTwoNode();} + +private: + TwoNode(const TwoNode&); // no implementation + void operator=(const TwoNode&); // no implementation + void operator delete(void*); // no implementation +}; // Constructor -inline nsDST::Node::Node(void* aKey, void* aValue) - : mKey(aKey), mValue(aValue), mLeft(0), mRight(0) +inline nsDST::TwoNode::TwoNode(const LeafNode& aLeafNode) + : LeafNode((void*)(PtrBits(aLeafNode.mKey) | 0x1), aLeafNode.mValue), + mLeft(0), mRight(0) { } -// Helper function that returns TRUE if the node is a leaf (i.e., no left or -// right child), and FALSE otherwise -inline int nsDST::Node::IsLeaf() const -{ - return !mLeft && !mRight; -} +// If you know that the node is a leaf node, then you can quickly access +// the key without clearing the bit that indicates whether it's a leaf or +// a two node +#define DST_GET_LEAF_KEY(leaf) ((leaf)->mKey) -// Overloaded placement operator for allocating from an arena -inline void* nsDST::Node::operator new(size_t aSize, NodeArena& aArena) -{ - return aArena.AllocNode(aSize); -} +// Macros to check whether we branch left or branch right for a given +// key and bit mask +#define DST_BRANCHES_LEFT(key, mask) \ + (0 == (PtrBits(key) & (mask))) + +#define DST_BRANCHES_RIGHT(key, mask) \ + ((mask) == (PtrBits(key) & (mask))) ///////////////////////////////////////////////////////////////////////////// // Arena used for fast allocation and deallocation of Node structures. -// Maintains a free-list of freed objects +// Maintains free-list of freed objects -#define NS_DST_ARENA_BLOCK_SIZE 1024 +#define NS_DST_ARENA_BLOCK_SIZE 512 MOZ_DECL_CTOR_COUNTER(NodeArena); // Constructor nsDST::NodeArena::NodeArena() - : mFreeList(0) + : mLeafNodeFreeList(0), mTwoNodeFreeList(0) { MOZ_COUNT_CTOR(NodeArena); PL_INIT_ARENA_POOL(&mPool, "DSTNodeArena", NS_DST_ARENA_BLOCK_SIZE); @@ -70,35 +142,70 @@ nsDST::NodeArena::~NodeArena() PL_FinishArenaPool(&mPool); } -// Called by the nsDST::Node's overloaded placement operator when allocating -// a new node. First checks the free list. If the free list is empty, then -// it allocates memory from the arena +// Called by the nsDST::LeafNode's overloaded placement operator when +// allocating a new node. First checks the free list. If the free list is +// empty, then it allocates memory from the arena void* -nsDST::NodeArena::AllocNode(size_t aSize) +nsDST::NodeArena::AllocLeafNode() { void* p; - if (mFreeList) { + if (mLeafNodeFreeList) { // Remove the node at the head of the free-list - p = mFreeList; - mFreeList = mFreeList->mLeft; + p = mLeafNodeFreeList; + mLeafNodeFreeList = (LeafNode*)mLeafNodeFreeList->mKey; + } else { - PL_ARENA_ALLOCATE(p, &mPool, aSize); + PL_ARENA_ALLOCATE(p, &mPool, sizeof(nsDST::LeafNode)); } + + return p; +} + +// Called by the nsDST::TwoNode's overloaded placement operator when +// allocating a new node. First checks the free list. If the free list is +// empty, then it allocates memory from the arena +void* +nsDST::NodeArena::AllocTwoNode() +{ + void* p; + + if (mTwoNodeFreeList) { + // Remove the node at the head of the free-list + p = mTwoNodeFreeList; + mTwoNodeFreeList = (TwoNode*)mTwoNodeFreeList->mKey; + + } else { + PL_ARENA_ALLOCATE(p, &mPool, sizeof(nsDST::TwoNode)); + } + return p; } // Called by the DST's DestroyNode() function. Adds the node to the head // of the free list where it can be reused by AllocateNode() void -nsDST::NodeArena::FreeNode(void* p) +nsDST::NodeArena::FreeNode(LeafNode* aLeafNode) { #ifdef NS_DEBUG - memset(p, 0xde, sizeof(Node)); + memset(aLeafNode, 0xde, sizeof(*aLeafNode)); #endif // Add this node to the head of the free-list - ((Node*)p)->mLeft = mFreeList; - mFreeList = (Node*)p; + aLeafNode->mKey = mLeafNodeFreeList; + mLeafNodeFreeList = aLeafNode; +} + +// Called by the DST's DestroyNode() function. Adds the node to the head +// of the free list where it can be reused by AllocateNode() +void +nsDST::NodeArena::FreeNode(TwoNode* aTwoNode) +{ +#ifdef NS_DEBUG + memset(aTwoNode, 0xde, sizeof(*aTwoNode)); +#endif + // Add this node to the head of the free-list + aTwoNode->mKey = mTwoNodeFreeList; + mTwoNodeFreeList = aTwoNode; } // Called by the DST's Clear() function when we want to free the memory @@ -109,8 +216,9 @@ nsDST::NodeArena::FreeArenaPool() // Free the arena in the pool, but continue using it PL_FreeArenaPool(&mPool); - // Clear the free list - mFreeList = 0; + // Clear the free lists + mLeafNodeFreeList = 0; + mTwoNodeFreeList = 0; } ///////////////////////////////////////////////////////////////////////////// @@ -139,26 +247,196 @@ nsDST::Clear() mRoot = 0; } +// Called by Remove() to destroy a node. Explicitly calls the destructor +// and then asks the memory arena to free the memory +inline void +nsDST::DestroyNode(LeafNode* aLeafNode) +{ + aLeafNode->~LeafNode(); // call destructor + mArena.FreeNode(aLeafNode); // free memory +} + +// Called by Remove() to destroy a node. Explicitly calls the destructor +// and then asks the memory arena to free the memory +inline void +nsDST::DestroyNode(TwoNode* aTwoNode) +{ + aTwoNode->~TwoNode(); // call destructor + mArena.FreeNode(aTwoNode); // free memory +} + +nsDST::LeafNode* +nsDST::ConvertToLeafNode(TwoNode** aTwoNode) +{ + LeafNode* leaf = new (mArena)LeafNode((*aTwoNode)->Key(), (*aTwoNode)->mValue); + + DestroyNode(*aTwoNode); + *aTwoNode = (TwoNode*)leaf; + return leaf; +} + +nsDST::TwoNode* +nsDST::ConvertToTwoNode(LeafNode** aLeafNode) +{ + TwoNode* twoNode = new (mArena)TwoNode(**aLeafNode); + + DestroyNode(*aLeafNode); + *aLeafNode = (LeafNode*)twoNode; + return twoNode; +} + +// Searches the tree for a node with the specified key. Return the value +// or NULL if the key is not in the tree +void* +nsDST::Search(void* aKey) const +{ + NS_PRECONDITION(0 == (PtrBits(aKey) & (mLevelZeroBit - 1)), + "ignored low-order bits are not zero"); + + if (mRoot) { + LeafNode* node = mRoot; + PtrBits bitMask = mLevelZeroBit; + + while (1) { + // Check if the key matches + if (node->Key() == aKey) { + return node->mValue; + } + + // See if this is a leaf node + if (node->IsLeaf()) { + // We didn't find a matching key + break; + } + + // Check whether we search the left branch or the right branch + if (DST_BRANCHES_LEFT(aKey, bitMask)) { + node = ((TwoNode*)node)->mLeft; + } else { + node = ((TwoNode*)node)->mRight; + } + + if (!node) { + break; // we reached a null link + } + + // Move to the next bit in the key + bitMask <<= 1; + } + +#ifdef DEBUG_troy + // We didn't find a matching node. Use an alternative algorithm to verify + // that the key is not in the tree + NS_POSTCONDITION(!DepthFirstSearch(mRoot, aKey), "DST search failed"); +#endif + } + + return 0; +} + // Adds a new key to the tree. If the specified key is already in the // tree, then the existing value is replaced by the new value. Returns // the old value, or NULL if this is a new key void* nsDST::Insert(void* aKey, void* aValue) { - // See if there's a matching key - Node** node = SearchTree(aKey); - void* previousValue; + NS_PRECONDITION(0 == (PtrBits(aKey) & (mLevelZeroBit - 1)), + "ignored low-order bits are not zero"); + LeafNode** node = (LeafNode**)&mRoot; + void* previousValue = 0; + TwoNode* branchReduction = 0; + + // See if there's an existing node with a matching key if (*node) { + PtrBits bitMask = mLevelZeroBit; + + while (1) { + // See if the key matches + if ((*node)->Key() == aKey) { + break; + } + + // Is this a leaf node? + if ((*node)->IsLeaf()) { + if (!branchReduction) { + // Replace the leaf node with a two node and destroy the + // leaf node + TwoNode* twoNode = ConvertToTwoNode(node); + + // Exit the loop and allocate a new leaf node and set its + // key and value + node = DST_BRANCHES_LEFT(aKey, bitMask) ? &twoNode->mLeft : + &twoNode->mRight; + } + break; + + } else { + TwoNode*& twoNode = *(TwoNode**)node; + + // Check whether we search the left branch or the right branch + if (DST_BRANCHES_LEFT(aKey, bitMask)) { + // If there's a left node and no right node, then see if we + // can reduce the one way braching in the tree + if (twoNode->mLeft && !twoNode->mRight) { + if (DST_BRANCHES_RIGHT(twoNode->mKey, bitMask)) { + // Yes, this node can become the right node of the tree. Remember + // this for later in case we don't find a matching node + branchReduction = twoNode; + } + } + + node = &twoNode->mLeft; + + } else { + // If there's a right node and no left node, then see if we + // can reduce the one way braching in the tree + if (twoNode->mRight && !twoNode->mLeft) { + if (DST_BRANCHES_LEFT(twoNode->mKey, bitMask)) { + // Yes, this node can become the left node of the tree. Remember + // this for later in case we don't find a matching node + branchReduction = twoNode; + } + } + + node = &twoNode->mRight; + } + + // Did we reach a null link? + if (!*node) { + break; + } + } + + // Move to the next bit in the key + bitMask <<= 1; + } + } + + if (branchReduction) { + // Reduce the one way branching by moving the existing key and + // value to either the right or left node + if (!branchReduction->mLeft) { + NS_ASSERTION(branchReduction->mRight, "bad state"); + branchReduction->mLeft = new (mArena)LeafNode(*branchReduction); + + } else { + NS_ASSERTION(!branchReduction->mRight, "bad state"); + branchReduction->mRight = new (mArena)LeafNode(*branchReduction); + } + + // Replace the existing key and value with the new key and value + branchReduction->SetKeyAndValue(aKey, aValue); + + } else if (*node) { + // We found an existing node with a matching key. Replace the current + // value with the new value previousValue = (*node)->mValue; - - // Replace the current value with the new value (*node)->mValue = aValue; } else { - // Allocate a new node and insert it into the tree - *node = new (mArena)Node(aKey, aValue); - previousValue = 0; + // Allocate a new leaf node and insert it into the tree + *node = new (mArena)LeafNode(aKey, aValue); } #ifdef DEBUG_troy @@ -167,36 +445,65 @@ nsDST::Insert(void* aKey, void* aValue) return previousValue; } -// Helper function that returns the left most leaf node of the specified -// subtree -nsDST::Node** -nsDST::GetLeftMostLeafNode(Node** aNode) const +// Helper function that removes and returns the left most leaf node +// of the specified subtree. +// Note: if the parent of the node that is removed is now a leaf, +// it will be converted to a leaf node... +nsDST::LeafNode* +nsDST::RemoveLeftMostLeafNode(TwoNode** aTwoNode) { -keepLooking: - // See if the node has none, one, or two child nodes - if ((*aNode)->mLeft) { - // Walk down the left branch - aNode = &(*aNode)->mLeft; - goto keepLooking; + NS_PRECONDITION(!(*aTwoNode)->IsLeaf(), "bad parameter"); - } else if ((*aNode)->mRight) { +keepLooking: + LeafNode** child; + + if ((*aTwoNode)->mLeft) { + // Walk down the left branch + child = &(*aTwoNode)->mLeft; + + // See if it's a leaf + if ((*child)->IsLeaf()) { + // Remove the child from its parent + LeafNode* result = *child; + *child = 0; + + // If there's no right node then the parent is now a leaf so + // convert it to a leaf node + if (!(*aTwoNode)->mRight) { + ConvertToLeafNode(aTwoNode); + } + + // Return the leaf node + return result; + } + + + } else if ((*aTwoNode)->mRight) { // No left branch, so walk down the right branch - aNode = &(*aNode)->mRight; - goto keepLooking; + child = &(*aTwoNode)->mRight; + + if ((*child)->IsLeaf()) { + // Remove the child from its parent + LeafNode* result = *child; + *child = 0; + + // That was the parent's only child node so convert the parent + // node to a leaf node + ConvertToLeafNode(aTwoNode); + + // Return the leaf node + return result; + } } else { - // We found a leaf node - return aNode; + // We should never encounter a two node with both links NULL. It should + // have been coverted to a leaf instead... + NS_ASSERTION(0, "bad node type"); + return 0; } -} -// Called by Remove() to destroy a node. Explicitly calls the destructor -// and then asks the memory arena to free the memory -inline void -nsDST::DestroyNode(Node* aNode) -{ - aNode->~Node(); // call destructor - mArena.FreeNode(aNode); // free memory + aTwoNode = (TwoNode**)child; + goto keepLooking; } // Removes a key from the tree. Returns the current value, or NULL if @@ -204,36 +511,88 @@ nsDST::DestroyNode(Node* aNode) void* nsDST::Remove(void* aKey) { - Node** node = SearchTree(aKey); + NS_PRECONDITION(0 == (PtrBits(aKey) & (mLevelZeroBit - 1)), + "ignored low-order bits are not zero"); + if (mRoot) { + LeafNode** node; + TwoNode** parentNode = 0; + PtrBits bitMask = mLevelZeroBit; + + if (mRoot->Key() == aKey) { + node = (LeafNode**)&mRoot; - if (*node) { - Node* tmp = *node; + } else if (!mRoot->IsLeaf()) { + // Look for a node with a matching key + node = (LeafNode**)&mRoot; + while (1) { + NS_ASSERTION(!(*node)->IsLeaf(), "unexpected leaf mode"); + parentNode = (TwoNode**)node; + + // Check whether we search the left branch or the right branch + if (DST_BRANCHES_LEFT(aKey, bitMask)) { + node = &(*(TwoNode**)node)->mLeft; + } else { + node = &(*(TwoNode**)node)->mRight; + } + + if (!*node) { + // We found a NULL link which means no node with a matching key + return 0; + } + + // Check if the key matches + if ((*node)->Key() == aKey) { + break; + } + + // The key doesn't match. If this is a leaf node that means no + // node with a matching key + if ((*node)->IsLeaf()) { + return 0; + } + + // Move to the next bit in the key + bitMask <<= 1; + } + } + + // We found a matching node void* value = (*node)->mValue; if ((*node)->IsLeaf()) { - // Just disconnect the node from its parent node + // Delete the leaf node + DestroyNode(*node); + + // Disconnect the node from its parent node *node = 0; + + // If the parent now has no child nodes, then convert it to a + // leaf frame + if (parentNode && !(*parentNode)->mLeft && !(*parentNode)->mRight) { + ConvertToLeafNode(parentNode); + } + } else { // We can't just move the left or right subtree up one level, because - // then we would have to re-sort the tree. Instead replace the node - // with the left most leaf node - Node** leaf = GetLeftMostLeafNode(node); + // then we would have to re-sort the tree. Instead replace the node's + // key and value with that of its left most leaf node (any leaf frame + // would do) + LeafNode* leaf = RemoveLeftMostLeafNode((TwoNode**)node); - // Copy over both the left and right subtree pointers - if ((*node)->mLeft != (*leaf)) { - (*leaf)->mLeft = (*node)->mLeft; - } - if ((*node)->mRight != (*leaf)) { - (*leaf)->mRight = (*node)->mRight; + // Copy over the leaf's key and value + // Note: RemoveLeftMostLeafNode() may have converted "node" to a + // leaf node so don't make any assumptions here + if ((*node)->IsLeaf()) { + (*node)->mKey = DST_GET_LEAF_KEY(leaf); + } else { + (*node)->mKey = (void*)(PtrBits(DST_GET_LEAF_KEY(leaf)) | 0x01); } + (*node)->mValue = leaf->mValue; - // Insert the leaf node in its new level, and disconnect it from its old - // parent node - *node = *leaf; - *leaf = 0; + // Delete the leaf node + DestroyNode(leaf); } - - DestroyNode(tmp); + #ifdef DEBUG_troy VerifyTree(mRoot); #endif @@ -243,71 +602,24 @@ nsDST::Remove(void* aKey) return 0; } -// Searches the tree for a node with the specified key. Return the value -// or NULL if the key is not in the tree -void* -nsDST::Search(void* aKey) const -{ - Node** result = SearchTree(aKey); - -#ifdef DEBUG_troy - if (!*result) { - // Use an alternative algorithm to verify that the key is not in - // the tree - NS_POSTCONDITION(!DepthFirstSearch(mRoot, aKey), "DST search failed"); - } -#endif - - return (*result) ? (*result)->mValue : 0; -} - -// Non-recursive search function. Returns a pointer to the pointer to the -// node. Called by Search(), Insert(), and Remove() -nsDST::Node** -nsDST::SearchTree(void* aKey) const -{ - NS_PRECONDITION(0 == (PtrBits(aKey) & (mLevelZeroBit - 1)), - "ignored low-order bits are not zero"); - - Node** result = (Node**)&mRoot; - PtrBits bitMask = mLevelZeroBit; - - while (*result) { - // Check if the node matches - if ((*result)->mKey == aKey) { - return result; - } - - // Check whether we search the left branch or the right branch - if (0 == (PtrBits(aKey) & bitMask)) { - result = &(*result)->mLeft; - } else { - result = &(*result)->mRight; - } - // Move to the next bit in the key - bitMask <<= 1; - } - - // We failed to find the key: return where the node would be inserted - return result; -} - #ifdef NS_DEBUG // Helper function used to verify the integrity of the tree. Does a // depth-first search of the tree looking for a node with the specified // key. Called by Search() if we don't find the key using the radix-search -nsDST::Node* -nsDST::DepthFirstSearch(Node* aNode, void* aKey) const +nsDST::LeafNode* +nsDST::DepthFirstSearch(LeafNode* aNode, void* aKey) const { if (!aNode) { return 0; - } else if (aNode->mKey == aKey) { + } else if (aNode->Key() == aKey) { return aNode; + } else if (aNode->IsLeaf()) { + return 0; } else { - Node* result = DepthFirstSearch(aNode->mLeft, aKey); + LeafNode* result = DepthFirstSearch(((TwoNode*)aNode)->mLeft, aKey); if (!result) { - result = DepthFirstSearch(aNode->mRight, aKey); + result = DepthFirstSearch(((TwoNode*)aNode)->mRight, aKey); } return result; @@ -317,7 +629,7 @@ nsDST::DepthFirstSearch(Node* aNode, void* aKey) const // Helper function that verifies the integrity of the tree. Called // by Insert() and Remove() void -nsDST::VerifyTree(Node* aNode, int aLevel, PtrBits aLevelKeyBits) const +nsDST::VerifyTree(LeafNode* aNode, int aLevel, PtrBits aLevelKeyBits) const { if (aNode) { // Verify that the first "aLevel" bits of this node's key agree with the @@ -327,31 +639,42 @@ nsDST::VerifyTree(Node* aNode, int aLevel, PtrBits aLevelKeyBits) const // When calculating the bit mask, take into consideration the low-order // bits we ignore PtrBits bitMask = (mLevelZeroBit << aLevel) - 1; - NS_ASSERTION(aLevelKeyBits == (PtrBits(aNode->mKey) & bitMask), + NS_ASSERTION(aLevelKeyBits == (PtrBits(aNode->Key()) & bitMask), "key's bits don't match"); } - // All node keys in the left subtree should have the next bit set to 0 - VerifyTree(aNode->mLeft, aLevel + 1, aLevelKeyBits); + if (!aNode->IsLeaf()) { + const TwoNode* twoNode = (TwoNode*)aNode; + NS_ASSERTION(twoNode->mLeft || twoNode->mRight, + "two node with no child nodes"); - // All node keys in the left subtree should have the next bit set to 1 - VerifyTree(aNode->mRight, aLevel + 1, aLevelKeyBits | (mLevelZeroBit << aLevel)); + // All node keys in the left subtree should have the next bit set to 0 + VerifyTree(twoNode->mLeft, aLevel + 1, aLevelKeyBits); + + // All node keys in the left subtree should have the next bit set to 1 + VerifyTree(twoNode->mRight, aLevel + 1, aLevelKeyBits | (mLevelZeroBit << aLevel)); + } } } void -nsDST::GatherStatistics(Node* aNode, - int aLevel, - int& aNumNodes, - int aNodesPerLevel[]) const +nsDST::GatherStatistics(LeafNode* aNode, + int aLevel, + int& aNumLeafNodes, + int& aNumTwoNodes, + int aNodesPerLevel[]) const { - aNumNodes++; - aNodesPerLevel[aLevel]++; - if (aNode->mLeft) { - GatherStatistics(aNode->mLeft, aLevel + 1, aNumNodes, aNodesPerLevel); - } - if (aNode->mRight) { - GatherStatistics(aNode->mRight, aLevel + 1, aNumNodes, aNodesPerLevel); + if (aNode) { + aNodesPerLevel[aLevel]++; + if (aNode->IsLeaf()) { + aNumLeafNodes++; + } else { + aNumTwoNodes++; + GatherStatistics(((TwoNode*)aNode)->mLeft, aLevel + 1, aNumLeafNodes, + aNumTwoNodes, aNodesPerLevel); + GatherStatistics(((TwoNode*)aNode)->mRight, aLevel + 1, aNumLeafNodes, + aNumTwoNodes, aNodesPerLevel); + } } } @@ -363,12 +686,13 @@ nsDST::Dump(FILE* out) const // node level static const int maxLevels = sizeof(void*) * 8; - int numNodes = 0; + int numLeafNodes = 0; + int numTwoNodes = 0; int nodesPerLevel[maxLevels]; // count of the number of nodes at a given level memset(&nodesPerLevel, 0, sizeof(int) * maxLevels); // Walk each node in the tree recording its node level - GatherStatistics(mRoot, 0, numNodes, nodesPerLevel); + GatherStatistics(mRoot, 0, numLeafNodes, numTwoNodes, nodesPerLevel); // Calculate the height, average node level, and median node level int height, medianLevel = 0, pathLength = 0; @@ -387,11 +711,28 @@ nsDST::Dump(FILE* out) const pathLength += height * count; } + // Calculate the number of arenas in use + int numArenas = 0; + for (PLArena* arena = mArena.mPool.first.next; arena; arena = arena->next) { + numArenas++; + } + // Output the statistics + int numTotalNodes = numLeafNodes + numTwoNodes; + fputs("DST statistics\n", out); - fprintf(out, " Number of nodes: %d\n", numNodes); + fprintf(out, " Number of leaf nodes: %d\n", numLeafNodes); + fprintf(out, " Number of tree nodes: %d\n", numTwoNodes); + if (numTotalNodes > 0) { + fprintf(out, " Average node size: %.1f\n", + float(numLeafNodes * sizeof(LeafNode) + numTwoNodes * sizeof(TwoNode)) / + float(numTotalNodes)); + } + fprintf(out, " Number of arenas: %d(%d)\n", numArenas, mArena.mPool.arenasize); fprintf(out, " Height (maximum node level) of the tree: %d\n", height - 1); - fprintf(out, " Average node level: %.1f\n", float(pathLength) / float(numNodes)); + if (numTotalNodes > 0) { + fprintf(out, " Average node level: %.1f\n", float(pathLength) / float(numTotalNodes)); + } fprintf(out, " Median node level: %d\n", medianLevel); fprintf(out, " Path length: %d\n", pathLength); diff --git a/layout/html/base/src/nsDST.h b/layout/html/base/src/nsDST.h index 5a0a97af9b8..b2f0486707a 100644 --- a/layout/html/base/src/nsDST.h +++ b/layout/html/base/src/nsDST.h @@ -50,54 +50,49 @@ public: #endif private: - struct Node; + class LeafNode; + class TwoNode; struct NodeArena; - friend struct Node; // needs access to struct NodeArena - friend struct NodeArena; // needs access to struct Node - - struct Node { - void* mKey; - void* mValue; - Node* mLeft; // left subtree - Node* mRight; // right subtree - - Node(void* aKey, void* aValue); - int IsLeaf() const; - - // Overloaded placement operator for allocating from an arena - void* operator new(size_t aSize, NodeArena& aArena); - }; + friend class LeafNode; + friend class TwoNode; + friend struct NodeArena; // needs access to structs LeafNode and TwoNode struct NodeArena { PLArenaPool mPool; - Node* mFreeList; + LeafNode* mLeafNodeFreeList; + TwoNode* mTwoNodeFreeList; NodeArena(); ~NodeArena(); - void* AllocNode(size_t); - void FreeNode(void*); - void FreeArenaPool(); + void* AllocLeafNode(); + void* AllocTwoNode(); + void FreeNode(LeafNode*); + void FreeNode(TwoNode*); + void FreeArenaPool(); }; - Node* mRoot; // root node of the tree + LeafNode* mRoot; // root node of the tree NodeArena mArena; PtrBits mLevelZeroBit; private: // Helper functions - Node** SearchTree(void* aKey) const; - Node** GetLeftMostLeafNode(Node** aNode) const; - void DestroyNode(Node* aNode); + LeafNode* RemoveLeftMostLeafNode(TwoNode** aTwoNode); + void DestroyNode(LeafNode* aLeafNode); + void DestroyNode(TwoNode* aTwoNode); + LeafNode* ConvertToLeafNode(TwoNode** aTwoNode); + TwoNode* ConvertToTwoNode(LeafNode** aLeafNode); #ifdef NS_DEBUG // Diagnostic functions - Node* DepthFirstSearch(Node* aNode, void* aKey) const; - void VerifyTree(Node* aNode, int aLevel = 0, PtrBits aLevelKeyBits = 0) const; - void GatherStatistics(Node* aNode, - int aLevel, - int& aNumNodes, - int aNodesPerLevel[]) const; + void VerifyTree(LeafNode* aNode, int aLevel = 0, PtrBits aLevelKeyBits = 0) const; + LeafNode* DepthFirstSearch(LeafNode* aNode, void* aKey) const; + void GatherStatistics(LeafNode* aNode, + int aLevel, + int& aNumLeafNodes, + int& aNumTwoNodes, + int aNodesPerLevel[]) const; #endif nsDST(const nsDST&); // no implementation