Bug 968520 - Explicitly specify the allocator for nsTArray_base functions. r=froydnj

This commit is contained in:
Birunthan Mohanathas 2015-05-18 13:50:34 -07:00
parent 325bfafcd0
commit ed7aa96d0a
2 changed files with 86 additions and 69 deletions

View File

@ -109,13 +109,14 @@ bool IsTwiceTheRequiredBytesRepresentableAsUint32(size_t aCapacity,
size_t aElemSize);
template<class Alloc, class Copy>
typename Alloc::ResultTypeProxy
template<typename ActualAlloc>
typename ActualAlloc::ResultTypeProxy
nsTArray_base<Alloc, Copy>::EnsureCapacity(size_type aCapacity,
size_type aElemSize)
{
// This should be the most common case so test this first
if (aCapacity <= mHdr->mCapacity) {
return Alloc::SuccessResult();
return ActualAlloc::SuccessResult();
}
// If the requested memory allocation exceeds size_type(-1)/2, then
@ -124,24 +125,24 @@ nsTArray_base<Alloc, Copy>::EnsureCapacity(size_type aCapacity,
// Header::mCapacity member. Just bail out in cases like that. We don't want
// to be allocating 2 GB+ arrays anyway.
if (!IsTwiceTheRequiredBytesRepresentableAsUint32(aCapacity, aElemSize)) {
Alloc::SizeTooBig((size_t)aCapacity * aElemSize);
return Alloc::FailureResult();
ActualAlloc::SizeTooBig((size_t)aCapacity * aElemSize);
return ActualAlloc::FailureResult();
}
size_t reqSize = sizeof(Header) + aCapacity * aElemSize;
if (mHdr == EmptyHdr()) {
// Malloc() new data
Header* header = static_cast<Header*>(Alloc::Malloc(reqSize));
Header* header = static_cast<Header*>(ActualAlloc::Malloc(reqSize));
if (!header) {
return Alloc::FailureResult();
return ActualAlloc::FailureResult();
}
header->mLength = 0;
header->mCapacity = aCapacity;
header->mIsAutoArray = 0;
mHdr = header;
return Alloc::SuccessResult();
return ActualAlloc::SuccessResult();
}
// We increase our capacity so that the allocated buffer grows exponentially,
@ -167,21 +168,21 @@ nsTArray_base<Alloc, Copy>::EnsureCapacity(size_type aCapacity,
Header* header;
if (UsesAutoArrayBuffer() || !Copy::allowRealloc) {
// Malloc() and copy
header = static_cast<Header*>(Alloc::Malloc(bytesToAlloc));
header = static_cast<Header*>(ActualAlloc::Malloc(bytesToAlloc));
if (!header) {
return Alloc::FailureResult();
return ActualAlloc::FailureResult();
}
Copy::CopyHeaderAndElements(header, mHdr, Length(), aElemSize);
if (!UsesAutoArrayBuffer()) {
Alloc::Free(mHdr);
ActualAlloc::Free(mHdr);
}
} else {
// Realloc() existing data
header = static_cast<Header*>(Alloc::Realloc(mHdr, bytesToAlloc));
header = static_cast<Header*>(ActualAlloc::Realloc(mHdr, bytesToAlloc));
if (!header) {
return Alloc::FailureResult();
return ActualAlloc::FailureResult();
}
}
@ -192,10 +193,11 @@ nsTArray_base<Alloc, Copy>::EnsureCapacity(size_type aCapacity,
mHdr = header;
return Alloc::SuccessResult();
return ActualAlloc::SuccessResult();
}
template<class Alloc, class Copy>
template<typename ActualAlloc>
void
nsTArray_base<Alloc, Copy>::ShrinkCapacity(size_type aElemSize,
size_t aElemAlign)
@ -217,20 +219,20 @@ nsTArray_base<Alloc, Copy>::ShrinkCapacity(size_type aElemSize,
header->mLength = length;
Copy::CopyElements(header + 1, mHdr + 1, length, aElemSize);
Alloc::Free(mHdr);
ActualAlloc::Free(mHdr);
mHdr = header;
return;
}
if (length == 0) {
MOZ_ASSERT(!IsAutoArray(), "autoarray should have fit 0 elements");
Alloc::Free(mHdr);
ActualAlloc::Free(mHdr);
mHdr = EmptyHdr();
return;
}
size_type size = sizeof(Header) + length * aElemSize;
void* ptr = Alloc::Realloc(mHdr, size);
void* ptr = ActualAlloc::Realloc(mHdr, size);
if (!ptr) {
return;
}
@ -239,6 +241,7 @@ nsTArray_base<Alloc, Copy>::ShrinkCapacity(size_type aElemSize,
}
template<class Alloc, class Copy>
template<typename ActualAlloc>
void
nsTArray_base<Alloc, Copy>::ShiftData(index_type aStart,
size_type aOldLen, size_type aNewLen,
@ -254,7 +257,7 @@ nsTArray_base<Alloc, Copy>::ShiftData(index_type aStart,
// Compute the resulting length of the array
mHdr->mLength += aNewLen - aOldLen;
if (mHdr->mLength == 0) {
ShrinkCapacity(aElemSize, aElemAlign);
ShrinkCapacity<ActualAlloc>(aElemSize, aElemAlign);
} else {
// Maybe nothing needs to be shifted
if (num == 0) {
@ -270,6 +273,7 @@ nsTArray_base<Alloc, Copy>::ShiftData(index_type aStart,
}
template<class Alloc, class Copy>
template<typename ActualAlloc>
bool
nsTArray_base<Alloc, Copy>::InsertSlotsAt(index_type aIndex, size_type aCount,
size_type aElemSize,
@ -278,7 +282,7 @@ nsTArray_base<Alloc, Copy>::InsertSlotsAt(index_type aIndex, size_type aCount,
MOZ_ASSERT(aIndex <= Length(), "Bogus insertion index");
size_type newLen = Length() + aCount;
EnsureCapacity(newLen, aElemSize);
EnsureCapacity<ActualAlloc>(newLen, aElemSize);
// Check for out of memory conditions
if (Capacity() < newLen) {
@ -287,7 +291,7 @@ nsTArray_base<Alloc, Copy>::InsertSlotsAt(index_type aIndex, size_type aCount,
// Move the existing elements as needed. Note that this will
// change our mLength, so no need to call IncrementLength.
ShiftData(aIndex, 0, aCount, aElemSize, aElemAlign);
ShiftData<ActualAlloc>(aIndex, 0, aCount, aElemSize, aElemAlign);
return true;
}
@ -325,8 +329,8 @@ nsTArray_base<Alloc, Copy>::IsAutoArrayRestorer::~IsAutoArrayRestorer()
}
template<class Alloc, class Copy>
template<class Allocator>
typename Alloc::ResultTypeProxy
template<typename ActualAlloc, class Allocator>
typename ActualAlloc::ResultTypeProxy
nsTArray_base<Alloc, Copy>::SwapArrayElements(nsTArray_base<Allocator,
Copy>& aOther,
size_type aElemSize,
@ -348,16 +352,16 @@ nsTArray_base<Alloc, Copy>::SwapArrayElements(nsTArray_base<Allocator,
if ((!UsesAutoArrayBuffer() || Capacity() < aOther.Length()) &&
(!aOther.UsesAutoArrayBuffer() || aOther.Capacity() < Length())) {
if (!EnsureNotUsingAutoArrayBuffer(aElemSize) ||
!aOther.EnsureNotUsingAutoArrayBuffer(aElemSize)) {
return Alloc::FailureResult();
if (!EnsureNotUsingAutoArrayBuffer<ActualAlloc>(aElemSize) ||
!aOther.template EnsureNotUsingAutoArrayBuffer<ActualAlloc>(aElemSize)) {
return ActualAlloc::FailureResult();
}
Header* temp = mHdr;
mHdr = aOther.mHdr;
aOther.mHdr = temp;
return Alloc::SuccessResult();
return ActualAlloc::SuccessResult();
}
// Swap the two arrays by copying, since at least one is using an auto
@ -371,9 +375,9 @@ nsTArray_base<Alloc, Copy>::SwapArrayElements(nsTArray_base<Allocator,
// write Y straight into X's auto buffer, write X's malloc'ed buffer on top
// of Y, and then switch X to using its auto buffer.)
if (!Alloc::Successful(EnsureCapacity(aOther.Length(), aElemSize)) ||
!Allocator::Successful(aOther.EnsureCapacity(Length(), aElemSize))) {
return Alloc::FailureResult();
if (!ActualAlloc::Successful(EnsureCapacity<ActualAlloc>(aOther.Length(), aElemSize)) ||
!Allocator::Successful(aOther.template EnsureCapacity<Allocator>(Length(), aElemSize))) {
return ActualAlloc::FailureResult();
}
// The EnsureCapacity calls above shouldn't have caused *both* arrays to
@ -398,9 +402,10 @@ nsTArray_base<Alloc, Copy>::SwapArrayElements(nsTArray_base<Allocator,
// job for AutoTArray! (One of the two arrays we're swapping is using an
// auto buffer, so we're likely not allocating a lot of space here. But one
// could, in theory, allocate a huge AutoTArray on the heap.)
nsAutoArrayBase<nsTArray_Impl<uint8_t, Alloc>, 64> temp;
if (!Alloc::Successful(temp.EnsureCapacity(smallerLength, aElemSize))) {
return Alloc::FailureResult();
nsAutoArrayBase<nsTArray_Impl<uint8_t, ActualAlloc>, 64> temp;
if (!ActualAlloc::Successful(temp.template EnsureCapacity<ActualAlloc>(smallerLength,
aElemSize))) {
return ActualAlloc::FailureResult();
}
Copy::CopyElements(temp.Elements(), smallerElements, smallerLength, aElemSize);
@ -422,10 +427,11 @@ nsTArray_base<Alloc, Copy>::SwapArrayElements(nsTArray_base<Allocator,
aOther.mHdr->mLength = tempLength;
}
return Alloc::SuccessResult();
return ActualAlloc::SuccessResult();
}
template<class Alloc, class Copy>
template<typename ActualAlloc>
bool
nsTArray_base<Alloc, Copy>::EnsureNotUsingAutoArrayBuffer(size_type aElemSize)
{
@ -442,7 +448,7 @@ nsTArray_base<Alloc, Copy>::EnsureNotUsingAutoArrayBuffer(size_type aElemSize)
size_type size = sizeof(Header) + Length() * aElemSize;
Header* header = static_cast<Header*>(Alloc::Malloc(size));
Header* header = static_cast<Header*>(ActualAlloc::Malloc(size));
if (!header) {
return false;
}

View File

@ -380,12 +380,14 @@ protected:
// @param aCapacity The requested number of array elements.
// @param aElemSize The size of an array element.
// @return False if insufficient memory is available; true otherwise.
typename Alloc::ResultTypeProxy EnsureCapacity(size_type aCapacity,
size_type aElemSize);
template<typename ActualAlloc>
typename ActualAlloc::ResultTypeProxy EnsureCapacity(size_type aCapacity,
size_type aElemSize);
// Resize the storage to the minimum required amount.
// @param aElemSize The size of an array element.
// @param aElemAlign The alignment in bytes of an array element.
template<typename ActualAlloc>
void ShrinkCapacity(size_type aElemSize, size_t aElemAlign);
// This method may be called to resize a "gap" in the array by shifting
@ -396,6 +398,7 @@ protected:
// @param aNewLen The desired length of the gap.
// @param aElemSize The size of an array element.
// @param aElemAlign The alignment in bytes of an array element.
template<typename ActualAlloc>
void ShiftData(index_type aStart, size_type aOldLen, size_type aNewLen,
size_type aElemSize, size_t aElemAlign);
@ -421,12 +424,12 @@ protected:
// @param aCount the number of slots to insert
// @param aElementSize the size of an array element.
// @param aElemAlign the alignment in bytes of an array element.
template<typename ActualAlloc>
bool InsertSlotsAt(index_type aIndex, size_type aCount,
size_type aElementSize, size_t aElemAlign);
protected:
template<class Allocator>
typename Alloc::ResultTypeProxy
template<typename ActualAlloc, class Allocator>
typename ActualAlloc::ResultTypeProxy
SwapArrayElements(nsTArray_base<Allocator, Copy>& aOther,
size_type aElemSize,
size_t aElemAlign);
@ -446,6 +449,7 @@ protected:
// Helper function for SwapArrayElements. Ensures that if the array
// is an nsAutoTArray that it doesn't use the built-in buffer.
template<typename ActualAlloc>
bool EnsureNotUsingAutoArrayBuffer(size_type aElemSize);
// Returns true if this nsTArray is an nsAutoTArray with a built-in buffer.
@ -1219,13 +1223,13 @@ public:
const Item* aArray, size_type aArrayLen)
{
// Adjust memory allocation up-front to catch errors.
if (!Alloc::Successful(this->EnsureCapacity(Length() + aArrayLen - aCount,
sizeof(elem_type)))) {
if (!Alloc::Successful(this->template EnsureCapacity<Alloc>(
Length() + aArrayLen - aCount, sizeof(elem_type)))) {
return nullptr;
}
DestructRange(aStart, aCount);
this->ShiftData(aStart, aCount, aArrayLen,
sizeof(elem_type), MOZ_ALIGNOF(elem_type));
this->template ShiftData<Alloc>(aStart, aCount, aArrayLen,
sizeof(elem_type), MOZ_ALIGNOF(elem_type));
AssignRange(aStart, aArrayLen, aArray);
return Elements() + aStart;
}
@ -1274,11 +1278,12 @@ public:
// @return A pointer to the newly inserted element, or null on OOM.
elem_type* InsertElementAt(index_type aIndex)
{
if (!Alloc::Successful(this->EnsureCapacity(Length() + 1,
sizeof(elem_type)))) {
if (!Alloc::Successful(this->template EnsureCapacity<Alloc>(
Length() + 1, sizeof(elem_type)))) {
return nullptr;
}
this->ShiftData(aIndex, 0, 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
this->template ShiftData<Alloc>(aIndex, 0, 1, sizeof(elem_type),
MOZ_ALIGNOF(elem_type));
elem_type* elem = Elements() + aIndex;
elem_traits::Construct(elem);
return elem;
@ -1288,11 +1293,12 @@ public:
template<class Item>
elem_type* InsertElementAt(index_type aIndex, Item&& aItem)
{
if (!Alloc::Successful(this->EnsureCapacity(Length() + 1,
sizeof(elem_type)))) {
if (!Alloc::Successful(this->template EnsureCapacity<Alloc>(
Length() + 1, sizeof(elem_type)))) {
return nullptr;
}
this->ShiftData(aIndex, 0, 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
this->template ShiftData<Alloc>(aIndex, 0, 1, sizeof(elem_type),
MOZ_ALIGNOF(elem_type));
elem_type* elem = Elements() + aIndex;
elem_traits::Construct(elem, mozilla::Forward<Item>(aItem));
return elem;
@ -1358,8 +1364,8 @@ public:
template<class Item>
elem_type* AppendElements(const Item* aArray, size_type aArrayLen)
{
if (!Alloc::Successful(this->EnsureCapacity(Length() + aArrayLen,
sizeof(elem_type)))) {
if (!Alloc::Successful(this->template EnsureCapacity<Alloc>(
Length() + aArrayLen, sizeof(elem_type)))) {
return nullptr;
}
index_type len = Length();
@ -1379,8 +1385,8 @@ public:
template<class Item>
elem_type* AppendElement(Item&& aItem)
{
if (!Alloc::Successful(this->EnsureCapacity(Length() + 1,
sizeof(elem_type)))) {
if (!Alloc::Successful(this->template EnsureCapacity<Alloc>(
Length() + 1, sizeof(elem_type)))) {
return nullptr;
}
elem_type* elem = Elements() + Length();
@ -1394,8 +1400,8 @@ public:
// @return A pointer to the newly appended elements, or null on OOM.
elem_type* AppendElements(size_type aCount)
{
if (!Alloc::Successful(this->EnsureCapacity(Length() + aCount,
sizeof(elem_type)))) {
if (!Alloc::Successful(this->template EnsureCapacity<Alloc>(
Length() + aCount, sizeof(elem_type)))) {
return nullptr;
}
elem_type* elems = Elements() + Length();
@ -1421,14 +1427,15 @@ public:
MOZ_ASSERT(&aArray != this, "argument must be different aArray");
index_type len = Length();
index_type otherLen = aArray.Length();
if (!Alloc::Successful(this->EnsureCapacity(len + otherLen,
sizeof(elem_type)))) {
if (!Alloc::Successful(this->template EnsureCapacity<Alloc>(
len + otherLen, sizeof(elem_type)))) {
return nullptr;
}
copy_type::CopyElements(Elements() + len, aArray.Elements(), otherLen,
sizeof(elem_type));
this->IncrementLength(otherLen);
aArray.ShiftData(0, otherLen, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
aArray.template ShiftData<Alloc>(0, otherLen, 0, sizeof(elem_type),
MOZ_ALIGNOF(elem_type));
return Elements() + len;
}
template<class Item, class Allocator>
@ -1447,8 +1454,8 @@ public:
// Check that the previous assert didn't overflow
MOZ_ASSERT(aStart <= aStart + aCount, "Start index plus length overflows");
DestructRange(aStart, aCount);
this->ShiftData(aStart, aCount, 0,
sizeof(elem_type), MOZ_ALIGNOF(elem_type));
this->template ShiftData<Alloc>(aStart, aCount, 0,
sizeof(elem_type), MOZ_ALIGNOF(elem_type));
}
// A variation on the RemoveElementsAt method defined above.
@ -1511,8 +1518,8 @@ public:
template<class Allocator>
typename Alloc::ResultType SwapElements(nsTArray_Impl<E, Allocator>& aOther)
{
return Alloc::Result(this->SwapArrayElements(aOther, sizeof(elem_type),
MOZ_ALIGNOF(elem_type)));
return Alloc::Result(this->template SwapArrayElements<Alloc>(
aOther, sizeof(elem_type), MOZ_ALIGNOF(elem_type)));
}
//
@ -1527,7 +1534,8 @@ public:
// @return True if the operation succeeded; false if we ran out of memory
typename Alloc::ResultType SetCapacity(size_type aCapacity)
{
return Alloc::Result(this->EnsureCapacity(aCapacity, sizeof(elem_type)));
return Alloc::Result(this->template EnsureCapacity<Alloc>(
aCapacity, sizeof(elem_type)));
}
// This method modifies the length of the array. If the new length is
@ -1587,8 +1595,9 @@ public:
// @param aCount the number of elements to insert
elem_type* InsertElementsAt(index_type aIndex, size_type aCount)
{
if (!base_type::InsertSlotsAt(aIndex, aCount, sizeof(elem_type),
MOZ_ALIGNOF(elem_type))) {
if (!base_type::template InsertSlotsAt<Alloc>(aIndex, aCount,
sizeof(elem_type),
MOZ_ALIGNOF(elem_type))) {
return nullptr;
}
@ -1613,8 +1622,9 @@ public:
elem_type* InsertElementsAt(index_type aIndex, size_type aCount,
const Item& aItem)
{
if (!base_type::InsertSlotsAt(aIndex, aCount, sizeof(elem_type),
MOZ_ALIGNOF(elem_type))) {
if (!base_type::template InsertSlotsAt<Alloc>(aIndex, aCount,
sizeof(elem_type),
MOZ_ALIGNOF(elem_type))) {
return nullptr;
}
@ -1631,7 +1641,8 @@ public:
// This method may be called to minimize the memory used by this array.
void Compact()
{
ShrinkCapacity(sizeof(elem_type), MOZ_ALIGNOF(elem_type));
this->template ShrinkCapacity<Alloc>(sizeof(elem_type),
MOZ_ALIGNOF(elem_type));
}
//
@ -1694,8 +1705,8 @@ public:
template<class Item, class Comparator>
elem_type* PushHeap(const Item& aItem, const Comparator& aComp)
{
if (!base_type::InsertSlotsAt(Length(), 1, sizeof(elem_type),
MOZ_ALIGNOF(elem_type))) {
if (!base_type::template InsertSlotsAt<Alloc>(Length(), 1, sizeof(elem_type),
MOZ_ALIGNOF(elem_type))) {
return nullptr;
}
// Sift up the new node