From 9708d4f1a23b48e60cf26aae9ff7ee2494a55101 Mon Sep 17 00:00:00 2001 From: Neil Rashbrook Date: Wed, 19 Dec 2012 21:33:54 +0000 Subject: [PATCH] Bug 493711 Part 1: switch nsCOMArray from nsVoidArray to nsTArray r=sicking --- xpcom/glue/nsCOMArray.cpp | 197 +++++++++++++++++++++++++------------- xpcom/glue/nsCOMArray.h | 113 +++++++++------------- 2 files changed, 176 insertions(+), 134 deletions(-) diff --git a/xpcom/glue/nsCOMArray.cpp b/xpcom/glue/nsCOMArray.cpp index 47be5eb31df..e760250d480 100644 --- a/xpcom/glue/nsCOMArray.cpp +++ b/xpcom/glue/nsCOMArray.cpp @@ -6,23 +6,47 @@ #include "nsCOMArray.h" #include "nsCOMPtr.h" -static bool ReleaseObjects(void* aElement, void*); +// This specialization is private to nsCOMArray. +// It exists solely to automatically zero-out newly created array elements. +template<> +class nsTArrayElementTraits +{ + typedef nsISupports* E; +public: + // Zero out the value + static inline void Construct(E *e) { + new (static_cast(e)) E(); + } + // Invoke the copy-constructor in place. + template + static inline void Construct(E *e, const A &arg) { + new (static_cast(e)) E(arg); + } + // Invoke the destructor in place. + static inline void Destruct(E *e) { + e->~E(); + } +}; + +static void ReleaseObjects(nsTArray &aArray); // implementations of non-trivial methods in nsCOMArray_base -// copy constructor - we can't just memcpy here, because -// we have to make sure we own our own array buffer, and that each -// object gets another AddRef() nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther) { // make sure we do only one allocation - mArray.SizeTo(aOther.Count()); + mArray.SetCapacity(aOther.Count()); AppendObjects(aOther); } nsCOMArray_base::~nsCOMArray_base() { - Clear(); + Clear(); +} + +int32_t +nsCOMArray_base::IndexOf(nsISupports* aObject) const { + return mArray.IndexOf(aObject); } int32_t @@ -30,12 +54,11 @@ nsCOMArray_base::IndexOfObject(nsISupports* aObject) const { nsCOMPtr supports = do_QueryInterface(aObject); NS_ENSURE_TRUE(supports, -1); - int32_t i, count; + uint32_t i, count; int32_t retval = -1; - count = mArray.Count(); + count = mArray.Length(); for (i = 0; i < count; ++i) { - nsCOMPtr arrayItem = - do_QueryInterface(reinterpret_cast(mArray.ElementAt(i))); + nsCOMPtr arrayItem = do_QueryInterface(mArray[i]); if (arrayItem == supports) { retval = i; break; @@ -44,41 +67,80 @@ nsCOMArray_base::IndexOfObject(nsISupports* aObject) const { return retval; } +bool +nsCOMArray_base::EnumerateForwards(nsBaseArrayEnumFunc aFunc, void* aData) const +{ + for (uint32_t index = 0; index < mArray.Length(); index++) + if (!(*aFunc)(mArray[index], aData)) + return false; + + return true; +} + +bool +nsCOMArray_base::EnumerateBackwards(nsBaseArrayEnumFunc aFunc, void* aData) const +{ + for (uint32_t index = mArray.Length(); index--; ) + if (!(*aFunc)(mArray[index], aData)) + return false; + + return true; +} + +int +nsCOMArray_base::nsCOMArrayComparator(const void* aElement1, const void* aElement2, void* aData) +{ + nsCOMArrayComparatorContext* ctx = static_cast(aData); + return (*ctx->mComparatorFunc)(*static_cast(aElement1), + *static_cast(aElement2), + ctx->mData); +} + +void nsCOMArray_base::Sort(nsBaseArrayComparatorFunc aFunc, void* aData) +{ + if (mArray.Length() > 1) { + nsCOMArrayComparatorContext ctx = {aFunc, aData}; + NS_QuickSort(mArray.Elements(), mArray.Length(), sizeof(nsISupports*), + nsCOMArrayComparator, &ctx); + } +} + bool nsCOMArray_base::InsertObjectAt(nsISupports* aObject, int32_t aIndex) { - bool result = mArray.InsertElementAt(aObject, aIndex); - if (result) - NS_IF_ADDREF(aObject); - return result; + if ((uint32_t)aIndex > mArray.Length()) + return false; + + if (!mArray.InsertElementAt(aIndex, aObject)) + return false; + + NS_IF_ADDREF(aObject); + return true; } bool nsCOMArray_base::InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex) { - bool result = mArray.InsertElementsAt(aObjects.mArray, aIndex); - if (result) { - // need to addref all these - int32_t count = aObjects.Count(); - for (int32_t i = 0; i < count; ++i) { - NS_IF_ADDREF(aObjects.ObjectAt(i)); - } - } - return result; + if ((uint32_t)aIndex > mArray.Length()) + return false; + + if (!mArray.InsertElementsAt(aIndex, aObjects.mArray)) + return false; + + // need to addref all these + int32_t count = aObjects.Count(); + for (int32_t i = 0; i < count; ++i) + NS_IF_ADDREF(aObjects.ObjectAt(i)); + + return true; } bool nsCOMArray_base::ReplaceObjectAt(nsISupports* aObject, int32_t aIndex) { - // its ok if oldObject is null here - nsISupports *oldObject = - reinterpret_cast(mArray.SafeElementAt(aIndex)); - - bool result = mArray.ReplaceElementAt(aObject, aIndex); - - // ReplaceElementAt could fail, such as if the array grows - // so only release the existing object if the replacement succeeded + bool result = mArray.EnsureLengthAtLeast(aIndex + 1); if (result) { + nsISupports *oldObject = mArray[aIndex]; // Make sure to addref first, in case aObject == oldObject - NS_IF_ADDREF(aObject); + NS_IF_ADDREF(mArray[aIndex] = aObject); NS_IF_RELEASE(oldObject); } return result; @@ -96,12 +158,12 @@ nsCOMArray_base::RemoveObject(nsISupports *aObject) bool nsCOMArray_base::RemoveObjectAt(int32_t aIndex) { - if (uint32_t(aIndex) < uint32_t(Count())) { - nsISupports* element = ObjectAt(aIndex); + if (uint32_t(aIndex) < mArray.Length()) { + nsISupports* element = mArray[aIndex]; - bool result = mArray.RemoveElementAt(aIndex); + mArray.RemoveElementAt(aIndex); NS_IF_RELEASE(element); - return result; + return true; } return false; @@ -110,38 +172,31 @@ nsCOMArray_base::RemoveObjectAt(int32_t aIndex) bool nsCOMArray_base::RemoveObjectsAt(int32_t aIndex, int32_t aCount) { - if (uint32_t(aIndex) + uint32_t(aCount) <= uint32_t(Count())) { - nsVoidArray elementsToDestroy(aCount); - for (int32_t i = 0; i < aCount; ++i) { - elementsToDestroy.InsertElementAt(mArray.FastElementAt(aIndex + i), i); - } - bool result = mArray.RemoveElementsAt(aIndex, aCount); - for (int32_t i = 0; i < aCount; ++i) { - nsISupports* element = static_cast (elementsToDestroy.FastElementAt(i)); - NS_IF_RELEASE(element); - } - return result; + if (uint32_t(aIndex) + uint32_t(aCount) <= mArray.Length()) { + nsTArray elementsToDestroy(aCount); + elementsToDestroy.AppendElements(mArray.Elements() + aIndex, aCount); + mArray.RemoveElementsAt(aIndex, aCount); + ReleaseObjects(elementsToDestroy); + return true; } return false; } // useful for destructors -bool -ReleaseObjects(void* aElement, void*) +void +ReleaseObjects(nsTArray &aArray) { - nsISupports* element = static_cast(aElement); - NS_IF_RELEASE(element); - return true; + for (uint32_t i = 0; i < aArray.Length(); i++) + NS_IF_RELEASE(aArray[i]); } void nsCOMArray_base::Clear() { - nsAutoVoidArray objects; - objects = mArray; - mArray.Clear(); - objects.EnumerateForwards(ReleaseObjects, nullptr); + nsTArray objects; + objects.SwapElements(mArray); + ReleaseObjects(objects); } bool @@ -149,18 +204,24 @@ nsCOMArray_base::SetCount(int32_t aNewCount) { NS_ASSERTION(aNewCount >= 0,"SetCount(negative index)"); if (aNewCount < 0) - return false; + return false; - int32_t count = Count(), i; - nsAutoVoidArray objects; - if (count > aNewCount) { - objects.SetCount(count - aNewCount); - for (i = aNewCount; i < count; ++i) { - objects.ReplaceElementAt(ObjectAt(i), i - aNewCount); - } - } - bool result = mArray.SetCount(aNewCount); - objects.EnumerateForwards(ReleaseObjects, nullptr); - return result; + int32_t count = mArray.Length(); + if (count > aNewCount) + RemoveObjectsAt(aNewCount, mArray.Length() - aNewCount); + return mArray.SetLength(aNewCount); } +size_t +nsCOMArray_base::SizeOfExcludingThis( + nsBaseArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, + nsMallocSizeOfFun aMallocSizeOf, void* aData) const +{ + size_t n = mArray.SizeOfExcludingThis(aMallocSizeOf); + + if (aSizeOfElementIncludingThis) + for (uint32_t index = 0; index < mArray.Length(); index++) + n += aSizeOfElementIncludingThis(mArray[index], aMallocSizeOf, aData); + + return n; +} diff --git a/xpcom/glue/nsCOMArray.h b/xpcom/glue/nsCOMArray.h index ed9f7e9644b..07ed7d62dd9 100644 --- a/xpcom/glue/nsCOMArray.h +++ b/xpcom/glue/nsCOMArray.h @@ -10,6 +10,7 @@ #include "nsCycleCollectionNoteChild.h" #include "nsVoidArray.h" +#include "nsTArray.h" #include "nsISupports.h" // See below for the definition of nsCOMArray @@ -25,28 +26,28 @@ protected: nsCOMArray_base(const nsCOMArray_base& other); ~nsCOMArray_base(); - int32_t IndexOf(nsISupports* aObject) const { - return mArray.IndexOf(aObject); - } - + int32_t IndexOf(nsISupports* aObject) const; int32_t IndexOfObject(nsISupports* aObject) const; - bool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) { - return mArray.EnumerateForwards(aFunc, aData); - } + typedef bool (* nsBaseArrayEnumFunc) + (void* aElement, void *aData); - bool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData) { - return mArray.EnumerateBackwards(aFunc, aData); - } + // enumerate through the array with a callback. + bool EnumerateForwards(nsBaseArrayEnumFunc aFunc, void* aData) const; - void Sort(nsVoidArrayComparatorFunc aFunc, void* aData) { - mArray.Sort(aFunc, aData); - } - - // any method which is not a direct forward to mArray should - // avoid inline bodies, so that the compiler doesn't inline them - // all over the place - void Clear(); + bool EnumerateBackwards(nsBaseArrayEnumFunc aFunc, void* aData) const; + + typedef int (* nsBaseArrayComparatorFunc) + (nsISupports* aElement1, nsISupports* aElement2, void* aData); + + struct nsCOMArrayComparatorContext { + nsBaseArrayComparatorFunc mComparatorFunc; + void* mData; + }; + + static int nsCOMArrayComparator(const void* aElement1, const void* aElement2, void* aData); + void Sort(nsBaseArrayComparatorFunc aFunc, void* aData); + bool InsertObjectAt(nsISupports* aObject, int32_t aIndex); bool InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex); bool ReplaceObjectAt(nsISupports* aObject, int32_t aIndex); @@ -57,58 +58,63 @@ protected: return InsertObjectsAt(aObjects, Count()); } bool RemoveObject(nsISupports *aObject); - bool RemoveObjectAt(int32_t aIndex); - bool RemoveObjectsAt(int32_t aIndex, int32_t aCount); public: - // override nsVoidArray stuff so that they can be accessed by - // consumers of nsCOMArray + // elements in the array (including null elements!) int32_t Count() const { - return mArray.Count(); + return mArray.Length(); } + // If the array grows, the newly created entries will all be null; // if the array shrinks, the excess entries will all be released. bool SetCount(int32_t aNewCount); + // remove all elements in the array, and call NS_RELEASE on each one + void Clear(); + nsISupports* ObjectAt(int32_t aIndex) const { - return static_cast(mArray.FastElementAt(aIndex)); + return mArray[aIndex]; } nsISupports* SafeObjectAt(int32_t aIndex) const { - return static_cast(mArray.SafeElementAt(aIndex)); + return mArray.SafeElementAt(aIndex, nullptr); } nsISupports* operator[](int32_t aIndex) const { return ObjectAt(aIndex); } + // remove an element at a specific position, shrinking the array + // as necessary + bool RemoveObjectAt(int32_t aIndex); + + // remove a range of elements at a specific position, shrinking the array + // as necessary + bool RemoveObjectsAt(int32_t aIndex, int32_t aCount); + // Ensures there is enough space to store a total of aCapacity objects. // This method never deletes any objects. bool SetCapacity(uint32_t aCapacity) { - return aCapacity > 0 ? mArray.SizeTo(static_cast(aCapacity)) - : true; + return mArray.SetCapacity(aCapacity); } + typedef size_t (* nsBaseArraySizeOfElementIncludingThisFunc) + (nsISupports* aElement, nsMallocSizeOfFun aMallocSizeOf, void *aData); + // Measures the size of the array's element storage, and if // |aSizeOfElement| is non-NULL, measures the size of things pointed to by // elements. size_t SizeOfExcludingThis( - nsVoidArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, - nsMallocSizeOfFun aMallocSizeOf, void* aData = NULL) const { - return mArray.SizeOfExcludingThis(aSizeOfElementIncludingThis, - aMallocSizeOf, aData); - } - + nsBaseArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, + nsMallocSizeOfFun aMallocSizeOf, void* aData = NULL) const; + private: // the actual storage - nsVoidArray mArray; + nsTArray mArray; // don't implement these, defaults will muck with refcounts! nsCOMArray_base& operator=(const nsCOMArray_base& other) MOZ_DELETE; - - // needs to call Clear() which is protected - friend void ImplCycleCollectionUnlink(nsCOMArray_base& aField); }; inline void @@ -211,19 +217,6 @@ class nsCOMArray : public nsCOMArray_base return nsCOMArray_base::ReplaceObjectAt(static_cast(aObject), aIndex); } - // override nsVoidArray stuff so that they can be accessed by - // other methods - - // elements in the array (including null elements!) - int32_t Count() const { - return nsCOMArray_base::Count(); - } - - // remove all elements in the array, and call NS_RELEASE on each one - void Clear() { - nsCOMArray_base::Clear(); - } - // Enumerator callback function. Return false to stop // Here's a more readable form: // bool enumerate(T* aElement, void* aData) @@ -232,12 +225,12 @@ class nsCOMArray : public nsCOMArray_base // enumerate through the array with a callback. bool EnumerateForwards(nsCOMArrayEnumFunc aFunc, void* aData) { - return nsCOMArray_base::EnumerateForwards(nsVoidArrayEnumFunc(aFunc), + return nsCOMArray_base::EnumerateForwards(nsBaseArrayEnumFunc(aFunc), aData); } bool EnumerateBackwards(nsCOMArrayEnumFunc aFunc, void* aData) { - return nsCOMArray_base::EnumerateBackwards(nsVoidArrayEnumFunc(aFunc), + return nsCOMArray_base::EnumerateBackwards(nsBaseArrayEnumFunc(aFunc), aData); } @@ -245,7 +238,7 @@ class nsCOMArray : public nsCOMArray_base (T* aElement1, T* aElement2, void* aData); void Sort(nsCOMArrayComparatorFunc aFunc, void* aData) { - nsCOMArray_base::Sort(nsVoidArrayComparatorFunc(aFunc), aData); + nsCOMArray_base::Sort(nsBaseArrayComparatorFunc(aFunc), aData); } // append an object, growing the array as necessary @@ -265,18 +258,6 @@ class nsCOMArray : public nsCOMArray_base return nsCOMArray_base::RemoveObject(static_cast(aObject)); } - // remove an element at a specific position, shrinking the array - // as necessary - bool RemoveObjectAt(int32_t aIndex) { - return nsCOMArray_base::RemoveObjectAt(aIndex); - } - - // remove a range of elements at a specific position, shrinking the array - // as necessary - bool RemoveObjectsAt(int32_t aIndex, int32_t aCount) { - return nsCOMArray_base::RemoveObjectsAt(aIndex, aCount); - } - // Each element in an nsCOMArray is actually a T*, so this function is // "IncludingThis" rather than "ExcludingThis" because it needs to measure // the memory taken by the T itself as well as anything it points to. @@ -287,7 +268,7 @@ class nsCOMArray : public nsCOMArray_base nsCOMArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, nsMallocSizeOfFun aMallocSizeOf, void *aData = NULL) const { return nsCOMArray_base::SizeOfExcludingThis( - nsVoidArraySizeOfElementIncludingThisFunc(aSizeOfElementIncludingThis), + nsBaseArraySizeOfElementIncludingThisFunc(aSizeOfElementIncludingThis), aMallocSizeOf, aData); }