PRBool nsVoidArray::GrowArrayBy(PRInt32 aGrowBy) { // We have to grow the array. Grow by kMinGrowArrayBy 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 < kMinGrowArrayBy) aGrowBy = kMinGrowArrayBy; PRUint32 newCapacity = GetArraySize() + aGrowBy; // Minimum increase PRUint32 newSize = SIZEOF_IMPL(newCapacity); if (newSize >= (PRUint32) kLinearThreshold) { // newCount includes enough space for at least kMinGrowArrayBy new // slots. Select the next power-of-two size in bytes above or // equal to that. // Also, limit the increase in size to about a VM page or two. if (GetArraySize() >= kMaxGrowArrayBy) { newCapacity = GetArraySize() + PR_MAX(kMaxGrowArrayBy,aGrowBy); newSize = SIZEOF_IMPL(newCapacity); } else { PR_CEILING_LOG2(newSize, newSize); newCapacity = CAPACITYOF_IMPL(PR_BIT(newSize)); } } // frees old mImpl IF this succeeds if (!SizeTo(newCapacity)) return PR_FALSE; return PR_TRUE; }
bool nsVoidArray::GrowArrayBy(int32_t aGrowBy) { // We have to grow the array. Grow by kMinGrowArrayBy 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 < kMinGrowArrayBy) aGrowBy = kMinGrowArrayBy; uint32_t newCapacity = GetArraySize() + aGrowBy; // Minimum increase uint32_t newSize = SIZEOF_IMPL(newCapacity); if (newSize >= (uint32_t) kLinearThreshold) { // newCount includes enough space for at least kMinGrowArrayBy new // slots. Select the next power-of-two size in bytes above or // equal to that. // Also, limit the increase in size to about a VM page or two. if (GetArraySize() >= kMaxGrowArrayBy) { newCapacity = GetArraySize() + XPCOM_MAX(kMaxGrowArrayBy,aGrowBy); newSize = SIZEOF_IMPL(newCapacity); } else { newSize = mozilla::CeilingLog2(newSize); newCapacity = CAPACITYOF_IMPL(1u << newSize); } } // frees old mImpl IF this succeeds if (!SizeTo(newCapacity)) return false; return 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; }