--- a/memory/build/mozjemalloc.cpp
+++ b/memory/build/mozjemalloc.cpp
@@ -639,34 +639,50 @@ struct ExtentTreeBoundsTrait : public Ex
return (key_addr > node_addr) - (key_addr < node_addr);
}
};
/******************************************************************************/
/*
* Radix tree data structures.
+ *
+ * The number of bits passed to the template is the number of significant bits
+ * in an address to do a radix lookup with.
+ *
+ * An address is looked up by splitting it in kBitsPerLevel bit chunks, except
+ * the most significant bits, where the bit chunk is kBitsAtLevel1 which can be
+ * different if Bits is not a multiple of kBitsPerLevel.
+ *
+ * With e.g. sizeof(void*)=4, Bits=16 and kBitsPerLevel=8, an address is split
+ * like the following:
+ * 0x12345678 -> mRoot[0x12][0x34]
*/
+template <size_t Bits>
class AddressRadixTree {
// Size of each radix tree node (as a power of 2).
// This impacts tree depth.
#if (SIZEOF_PTR == 4)
static const size_t kNodeSize2Pow = 14;
#else
static const size_t kNodeSize2Pow = CACHELINE_2POW;
#endif
+ static const size_t kBitsPerLevel = kNodeSize2Pow - SIZEOF_PTR_2POW;
+ static const size_t kBitsAtLevel1 =
+ (Bits % kBitsPerLevel) ? Bits % kBitsPerLevel : kBitsPerLevel;
+ static const size_t kHeight = (Bits + kBitsPerLevel - 1) / kBitsPerLevel;
+ static_assert(kBitsAtLevel1 + (kHeight - 1) * kBitsPerLevel == Bits,
+ "AddressRadixTree parameters don't work out");
malloc_spinlock_t mLock;
void** mRoot;
- unsigned mHeight;
- unsigned mLevel2Bits[2];
public:
- static AddressRadixTree* Create(unsigned aBits);
+ static AddressRadixTree<Bits>* Create();
inline void* Get(void* aAddr);
// Returns whether the value was properly set
inline bool Set(void* aAddr, void* aValue);
inline bool Unset(void* aAddr)
{
@@ -1048,17 +1064,17 @@ struct ArenaTreeTrait
}
};
/********/
/*
* Chunks.
*/
-static AddressRadixTree* gChunkRTree;
+static AddressRadixTree<(SIZEOF_PTR << 3) - CHUNK_2POW_DEFAULT>* gChunkRTree;
/* Protects chunk-related data structures. */
static malloc_mutex_t chunks_mtx;
/*
* Trees of chunks that were previously allocated (trees differ only in node
* ordering). These are used when allocating chunks, in an attempt to re-use
* address space. Depending on function, different tree orderings are needed,
@@ -1728,85 +1744,77 @@ pages_copy(void *dest, const void *src,
MOZ_ASSERT(n >= VM_COPY_MIN);
MOZ_ASSERT((void *)((uintptr_t)src & ~pagesize_mask) == src);
vm_copy(mach_task_self(), (vm_address_t)src, (vm_size_t)n,
(vm_address_t)dest);
}
#endif
-AddressRadixTree*
-AddressRadixTree::Create(unsigned aBits)
+template <size_t Bits>
+AddressRadixTree<Bits>*
+AddressRadixTree<Bits>::Create()
{
- AddressRadixTree* ret;
- unsigned bits_per_level, height;
-
- bits_per_level = AddressRadixTree::kNodeSize2Pow - SIZEOF_PTR_2POW;
- height = (aBits + bits_per_level - 1) / bits_per_level;
-
- ret = (AddressRadixTree*)base_calloc(1, sizeof(AddressRadixTree));
+ AddressRadixTree<Bits>* ret;
+
+ ret = (AddressRadixTree<Bits>*)base_calloc(1, sizeof(AddressRadixTree<Bits>));
if (!ret) {
return nullptr;
}
malloc_spin_init(&ret->mLock);
- ret->mHeight = height;
- if (bits_per_level * height > aBits) {
- ret->mLevel2Bits[0] = aBits % bits_per_level;
- } else {
- ret->mLevel2Bits[0] = bits_per_level;
- }
- ret->mLevel2Bits[1] = bits_per_level;
-
- ret->mRoot = (void**)base_calloc(1 << ret->mLevel2Bits[0], sizeof(void*));
+
+ ret->mRoot = (void**)base_calloc(1 << kBitsAtLevel1, sizeof(void*));
if (!ret->mRoot) {
// We leak the rtree here, since there's no generic base deallocation.
return nullptr;
}
return ret;
}
+template <size_t Bits>
void**
-AddressRadixTree::GetSlot(void* aKey, bool aCreate)
+AddressRadixTree<Bits>::GetSlot(void* aKey, bool aCreate)
{
uintptr_t key = reinterpret_cast<uintptr_t>(aKey);
uintptr_t subkey;
unsigned i, lshift, height, bits;
void** node;
void** child;
- for (i = lshift = 0, height = mHeight, node = mRoot;
+ for (i = lshift = 0, height = kHeight, node = mRoot;
i < height - 1;
i++, lshift += bits, node = child) {
- bits = mLevel2Bits[i ? 1 : 0];
+ bits = i ? kBitsPerLevel : kBitsAtLevel1;
subkey = (key << lshift) >> ((SIZEOF_PTR << 3) - bits);
child = (void**) node[subkey];
if (!child && aCreate) {
- child = (void**) base_calloc(1 << mLevel2Bits[1], sizeof(void*));
+ child = (void**) base_calloc(1 << kBitsPerLevel, sizeof(void*));
if (child) {
node[subkey] = child;
}
}
if (!child) {
return nullptr;
}
}
/*
* node is a leaf, so it contains values rather than node
* pointers.
*/
- bits = mLevel2Bits[i ? 1 : 0];
+ bits = i ? kBitsPerLevel : kBitsAtLevel1;
subkey = (key << lshift) >> ((SIZEOF_PTR << 3) - bits);
return &node[subkey];
}
+template <size_t Bits>
void*
-AddressRadixTree::Get(void* aKey)
+AddressRadixTree<Bits>::Get(void* aKey)
{
void* ret = nullptr;
void** slot = GetSlot(aKey);
if (slot) {
ret = *slot;
}
@@ -1832,18 +1840,19 @@ AddressRadixTree::Get(void* aKey)
} else {
MOZ_ASSERT(ret == nullptr);
}
malloc_spin_unlock(&mlock);
#endif
return ret;
}
+template <size_t Bits>
bool
-AddressRadixTree::Set(void* aKey, void* aValue)
+AddressRadixTree<Bits>::Set(void* aKey, void* aValue)
{
malloc_spin_lock(&mLock);
void** slot = GetSlot(aKey, /* create */ true);
if (slot) {
*slot = aValue;
}
malloc_spin_unlock(&mLock);
return slot;
@@ -4494,17 +4503,17 @@ MALLOC_OUT:
* reset to the default value for the main arena. */
gMainArena->mMaxDirty = opt_dirty_max;
/*
* Assign the initial arena to the initial thread.
*/
thread_arena.set(gMainArena);
- gChunkRTree = AddressRadixTree::Create((SIZEOF_PTR << 3) - CHUNK_2POW_DEFAULT);
+ gChunkRTree = AddressRadixTree<(SIZEOF_PTR << 3) - CHUNK_2POW_DEFAULT>::Create();
if (!gChunkRTree) {
return true;
}
malloc_initialized = true;
#if !defined(XP_WIN) && !defined(XP_DARWIN)
/* Prevent potential deadlock on malloc locks after fork. */