PRBool nsSupportsArray::GrowArrayBy(PRInt32 aGrowBy) { // We have to grow the array. Grow by kGrowArrayBy slots if we're smaller // than kLinearThreshold bytes, or a power of two if we're larger. // This is much more efficient with most memory allocators, especially // if it's very large, or of the allocator is binned. if (aGrowBy < kGrowArrayBy) aGrowBy = kGrowArrayBy; PRUint32 newCount = mArraySize + aGrowBy; // Minimum increase PRUint32 newSize = sizeof(mArray[0]) * newCount; if (newSize >= (PRUint32) kLinearThreshold) { // newCount includes enough space for at least kGrowArrayBy new slots. // Select the next power-of-two size in bytes above that if newSize is // not a power of two. if (newSize & (newSize - 1)) newSize = PR_BIT(PR_CeilingLog2(newSize)); newCount = newSize / sizeof(mArray[0]); } // XXX This would be far more efficient in many allocators if we used // XXX PR_Realloc(), etc nsISupports** oldArray = mArray; mArray = new nsISupports*[newCount]; if (!mArray) { // ran out of memory mArray = oldArray; return PR_FALSE; } mArraySize = newCount; #if DEBUG_SUPPORTSARRAY if (oldArray == mArray) // can't happen without use of realloc ADD_TO_STATS(GrowInPlace,mCount); ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0])); if (mArraySize > mMaxSize) { ADD_TO_STATS(NumberOfSize,mArraySize*sizeof(mArray[0])); if (oldArray != &(mAutoArray[0])) SUB_FROM_STATS(NumberOfSize,mCount*sizeof(mArray[0])); mMaxSize = mArraySize; } #endif if (oldArray) { // need to move old data if (0 < mCount) { ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*)); } if (oldArray != &(mAutoArray[0])) { delete[] oldArray; } } return PR_TRUE; }
// This does all allocation/reallocation of the array. // It also will compact down to N - good for things that might grow a lot // at times, but usually are smaller, like JS deferred GC releases. PRBool nsVoidArray::SizeTo(PRInt32 aSize) { PRUint32 oldsize = GetArraySize(); PRBool isOwner = IsArrayOwner(); PRBool hasAuto = HasAutoBuffer(); if (aSize == (PRInt32) oldsize) return PR_TRUE; // no change if (aSize <= 0) { // free the array if allocated if (mImpl) { if (isOwner) { free(reinterpret_cast<char *>(mImpl)); if (hasAuto) { static_cast<nsAutoVoidArray*>(this)->ResetToAutoBuffer(); } else { mImpl = nsnull; } } else { mImpl->mCount = 0; // nsAutoVoidArray } } return PR_TRUE; } if (mImpl && isOwner) { // We currently own an array impl. Resize it appropriately. if (aSize < mImpl->mCount) { // XXX Note: we could also just resize to mCount return PR_TRUE; // can't make it that small, ignore request } char* bytes = (char *) realloc(mImpl,SIZEOF_IMPL(aSize)); Impl* newImpl = reinterpret_cast<Impl*>(bytes); if (!newImpl) return PR_FALSE; #if DEBUG_VOIDARRAY if (mImpl == newImpl) ADD_TO_STATS(GrowInPlace,oldsize); ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize)); if (aSize > mMaxSize) { ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize)); if (oldsize) SUB_FROM_STATS(NumberOfSize,oldsize); mMaxSize = aSize; if (mIsAuto) { ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize)); SUB_FROM_STATS(MaxAuto,oldsize); } } #endif SetArray(newImpl, aSize, newImpl->mCount, PR_TRUE, hasAuto); return PR_TRUE; } if ((PRUint32) aSize < oldsize) { // No point in allocating if it won't free the current Impl anyway. return PR_TRUE; } // just allocate an array // allocate the exact size requested char* bytes = (char *) malloc(SIZEOF_IMPL(aSize)); Impl* newImpl = reinterpret_cast<Impl*>(bytes); if (!newImpl) return PR_FALSE; #if DEBUG_VOIDARRAY ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize)); if (aSize > mMaxSize) { ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize)); if (oldsize && !mImpl) SUB_FROM_STATS(NumberOfSize,oldsize); mMaxSize = aSize; } #endif if (mImpl) { #if DEBUG_VOIDARRAY ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize)); SUB_FROM_STATS(MaxAuto,0); SUB_FROM_STATS(NumberOfSize,0); mIsAuto = PR_TRUE; #endif // We must be growing an nsAutoVoidArray - copy since we didn't // realloc. memcpy(newImpl->mArray, mImpl->mArray, mImpl->mCount * sizeof(mImpl->mArray[0])); } SetArray(newImpl, aSize, mImpl ? mImpl->mCount : 0, PR_TRUE, hasAuto); // no memset; handled later in ReplaceElementAt if needed return PR_TRUE; }
// This does all allocation/reallocation of the array. // It also will compact down to N - good for things that might grow a lot // at times, but usually are smaller, like JS deferred GC releases. bool nsVoidArray::SizeTo(int32_t aSize) { uint32_t oldsize = GetArraySize(); if (aSize == (int32_t) oldsize) return true; // no change if (aSize <= 0) { // free the array if allocated if (mImpl) { free(reinterpret_cast<char *>(mImpl)); mImpl = nullptr; } return true; } if (mImpl) { // We currently own an array impl. Resize it appropriately. if (aSize < mImpl->mCount) { // XXX Note: we could also just resize to mCount return true; // can't make it that small, ignore request } char* bytes = (char *) realloc(mImpl,SIZEOF_IMPL(aSize)); Impl* newImpl = reinterpret_cast<Impl*>(bytes); if (!newImpl) return false; #if DEBUG_VOIDARRAY if (mImpl == newImpl) ADD_TO_STATS(GrowInPlace,oldsize); ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize)); if (aSize > mMaxSize) { ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize)); if (oldsize) SUB_FROM_STATS(NumberOfSize,oldsize); mMaxSize = aSize; if (mIsAuto) { ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize)); SUB_FROM_STATS(MaxAuto,oldsize); } } #endif SetArray(newImpl, aSize, newImpl->mCount); return true; } if ((uint32_t) aSize < oldsize) { // No point in allocating if it won't free the current Impl anyway. return true; } // just allocate an array // allocate the exact size requested char* bytes = (char *) malloc(SIZEOF_IMPL(aSize)); Impl* newImpl = reinterpret_cast<Impl*>(bytes); if (!newImpl) return false; #if DEBUG_VOIDARRAY ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize)); if (aSize > mMaxSize) { ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize)); if (oldsize && !mImpl) SUB_FROM_STATS(NumberOfSize,oldsize); mMaxSize = aSize; } #endif if (mImpl) { #if DEBUG_VOIDARRAY ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize)); SUB_FROM_STATS(MaxAuto,0); SUB_FROM_STATS(NumberOfSize,0); mIsAuto = true; #endif // We must be growing an nsAutoVoidArray - copy since we didn't // realloc. memcpy(newImpl->mArray, mImpl->mArray, mImpl->mCount * sizeof(mImpl->mArray[0])); } SetArray(newImpl, aSize, mImpl ? mImpl->mCount : 0); // no memset; handled later in ReplaceElementAt if needed return true; }