| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #pragma once
- namespace Js
- {
- template<typename T>
- uint32 SparseArraySegment<T>::GetAlignedSize(uint32 size)
- {
- return (uint32)(HeapInfo::GetAlignedSize(UInt32Math::MulAdd<sizeof(T), sizeof(SparseArraySegmentBase)>(size)) - sizeof(SparseArraySegmentBase)) / sizeof(T);
- }
- template<typename T>
- template<bool isLeaf>
- SparseArraySegment<T> * SparseArraySegment<T>::Allocate(Recycler* recycler, uint32 left, uint32 length, uint32 size, uint32 fillStart /*= 0*/)
- {
- AssertOrFailFast(length <= size);
- Assert(size <= JavascriptArray::MaxArrayLength - left);
- uint32 bufferSize = UInt32Math::Mul<sizeof(T)>(size);
- SparseArraySegment<T> *seg =
- isLeaf ?
- RecyclerNewPlusLeafZ(recycler, bufferSize, SparseArraySegment<T>, left, length, size) :
- RecyclerNewPlusZ(recycler, bufferSize, SparseArraySegment<T>, left, length, size);
- seg->FillSegmentBuffer(fillStart, size);
- return seg;
- }
- template<>
- inline SparseArraySegment<int> *SparseArraySegment<int>::AllocateLiteralHeadSegment(
- Recycler *const recycler,
- const uint32 length)
- {
- if (DoNativeArrayLeafSegment())
- {
- return SparseArraySegment<int>::AllocateLiteralHeadSegmentImpl<true>(recycler, length);
- }
- return SparseArraySegment<int>::AllocateLiteralHeadSegmentImpl<false>(recycler, length);
- }
- template<>
- inline SparseArraySegment<double> *SparseArraySegment<double>::AllocateLiteralHeadSegment(
- Recycler *const recycler,
- const uint32 length)
- {
- if (DoNativeArrayLeafSegment())
- {
- return SparseArraySegment<double>::AllocateLiteralHeadSegmentImpl<true>(recycler, length);
- }
- return SparseArraySegment<double>::AllocateLiteralHeadSegmentImpl<false>(recycler, length);
- }
- template<typename T>
- SparseArraySegment<T> *SparseArraySegment<T>::AllocateLiteralHeadSegment(
- Recycler *const recycler,
- const uint32 length)
- {
- return SparseArraySegment<T>::AllocateLiteralHeadSegmentImpl<false>(recycler, length);
- }
- template<typename T>
- template<bool isLeaf>
- SparseArraySegment<T> *SparseArraySegment<T>::AllocateLiteralHeadSegmentImpl(
- Recycler *const recycler,
- const uint32 length)
- {
- Assert(length != 0);
- const uint32 size = GetAlignedSize(length);
- return SparseArraySegment<T>::Allocate<isLeaf>(recycler, 0, length, size, length);
- }
- template<>
- inline SparseArraySegment<int> * SparseArraySegment<int>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, SparseArraySegmentBase *nextSeg)
- {
- if (DoNativeArrayLeafSegment() && nextSeg == nullptr)
- {
- return AllocateSegmentImpl<true>(recycler, left, length, nextSeg);
- }
- return AllocateSegmentImpl<false>(recycler, left, length, nextSeg);
- }
- template<>
- inline SparseArraySegment<double> * SparseArraySegment<double>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, SparseArraySegmentBase *nextSeg)
- {
- if (DoNativeArrayLeafSegment() && nextSeg == nullptr)
- {
- return AllocateSegmentImpl<true>(recycler, left, length, nextSeg);
- }
- return AllocateSegmentImpl<false>(recycler, left, length, nextSeg);
- }
- template<typename T>
- SparseArraySegment<T> * SparseArraySegment<T>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, SparseArraySegmentBase *nextSeg)
- {
- return AllocateSegmentImpl<false>(recycler, left, length, nextSeg);
- }
- template<typename T>
- template<bool isLeaf>
- SparseArraySegment<T> * SparseArraySegment<T>::AllocateSegmentImpl(Recycler* recycler, uint32 left, uint32 length, SparseArraySegmentBase *nextSeg)
- {
- Assert(!isLeaf || nextSeg == nullptr);
- uint32 size;
- if ((length <= CHUNK_SIZE) && (left < BigLeft))
- {
- size = GetAlignedSize(CHUNK_SIZE);
- }
- else
- {
- size = GetAlignedSize(length);
- }
- //But don't overshoot next segment
- EnsureSizeInBound(left, length, size, nextSeg);
- return SparseArraySegment<T>::Allocate<isLeaf>(recycler, left, length, size);
- }
- template<>
- inline SparseArraySegment<int> * SparseArraySegment<int>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, uint32 size, SparseArraySegmentBase *nextSeg)
- {
- if (DoNativeArrayLeafSegment() && nextSeg == nullptr)
- {
- return AllocateSegmentImpl<true>(recycler, left, length, size, nextSeg);
- }
- return AllocateSegmentImpl<false>(recycler, left, length, size, nextSeg);
- }
- template<>
- inline SparseArraySegment<double> * SparseArraySegment<double>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, uint32 size, SparseArraySegmentBase *nextSeg)
- {
- if (DoNativeArrayLeafSegment() && nextSeg == nullptr)
- {
- return AllocateSegmentImpl<true>(recycler, left, length, size, nextSeg);
- }
- return AllocateSegmentImpl<false>(recycler, left, length, size, nextSeg);
- }
- template<typename T>
- inline SparseArraySegment<T> * SparseArraySegment<T>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, uint32 size, SparseArraySegmentBase *nextSeg)
- {
- return AllocateSegmentImpl<false>(recycler, left, length, size, nextSeg);
- }
- template<typename T>
- template<bool isLeaf>
- SparseArraySegment<T> * SparseArraySegment<T>::AllocateSegmentImpl(Recycler* recycler, uint32 left, uint32 length, uint32 size, SparseArraySegmentBase *nextSeg)
- {
- Assert(!isLeaf || nextSeg == nullptr);
- AssertMsg(size > 0, "size too small");
- if ((size <= CHUNK_SIZE) && (size < BigLeft))
- {
- size = GetAlignedSize(CHUNK_SIZE);
- }
- else
- {
- size = GetAlignedSize(size);
- }
- //But don't overshoot next segment
- EnsureSizeInBound(left, length, size, nextSeg);
- return SparseArraySegment<T>::Allocate<isLeaf>(recycler, left, length, size);
- }
- template<>
- inline SparseArraySegment<int>* SparseArraySegment<int>::AllocateSegment(Recycler* recycler, SparseArraySegmentBase* prev, uint32 index)
- {
- if (DoNativeArrayLeafSegment() && prev->next == nullptr)
- {
- return AllocateSegmentImpl<true>(recycler, prev, index);
- }
- return AllocateSegmentImpl<false>(recycler, prev, index);
- }
- template<>
- inline SparseArraySegment<double>* SparseArraySegment<double>::AllocateSegment(Recycler* recycler, SparseArraySegmentBase* prev, uint32 index)
- {
- if (DoNativeArrayLeafSegment() && prev->next == nullptr)
- {
- return AllocateSegmentImpl<true>(recycler, prev, index);
- }
- return AllocateSegmentImpl<false>(recycler, prev, index);
- }
- template<typename T>
- SparseArraySegment<T>* SparseArraySegment<T>::AllocateSegment(Recycler* recycler, SparseArraySegmentBase* prev, uint32 index)
- {
- return AllocateSegmentImpl<false>(recycler, prev, index);
- }
- // Allocate a segment in between (prev, next) to contain an index
- template<typename T>
- template<bool isLeaf>
- SparseArraySegment<T>* SparseArraySegment<T>::AllocateSegmentImpl(Recycler* recycler, SparseArraySegmentBase* prev, uint32 index)
- {
- Assert(prev);
- Assert(index > prev->left && index - prev->left >= prev->size);
- SparseArraySegmentBase* next = prev->next;
- Assert(!next || index < next->left);
- Assert(!next || !isLeaf);
- uint32 left = index;
- uint32 size = (left < BigLeft ? GetAlignedSize(CHUNK_SIZE) : GetAlignedSize(1));
- // Try to move the segment leftwards if it overshoots next segment
- if (next && size > next->left - left)
- {
- size = min(size, next->left - (prev->left + prev->size));
- left = next->left - size;
- }
- Assert(index >= left && index - left < size);
- uint32 length = index - left + 1;
- EnsureSizeInBound(left, length, size, next);
- return SparseArraySegment<T>::Allocate<isLeaf>(recycler, left, length, size);
- }
- template<>
- inline Var SparseArraySegment<int32>::GetMissingItemVar()
- {
- return JavascriptArray::IntMissingItemVar;
- }
- template<>
- inline Var SparseArraySegment<double>::GetMissingItemVar()
- {
- return (Var)FloatMissingItemPattern;
- }
- template<typename T>
- void SparseArraySegment<T>::FillSegmentBuffer(uint32 start, uint32 size)
- {
- // Fill the segment buffer using gp-register-sized stores. Avoid using the FPU for the sake
- // of perf (especially x86).
- Var fill = (Var)SparseArraySegment<T>::GetMissingItemVar();
- if (sizeof(Var) > sizeof(T))
- {
- // Pointer size is greater than the element (int32 buffer on x64).
- // Fill as much as we can and do one int32-sized store at the end if necessary.
- uint32 i, step = sizeof(Var) / sizeof(T);
- if (start & 1)
- {
- Assert(sizeof(T) == sizeof(int32));
- ((int32*)(this->elements))[start] = JavascriptNativeIntArray::MissingItem;
- }
- for (i = (start + step-1)/step; i < (size/step); i++)
- {
- ((Var*)(this->elements))[i] = fill; // swb: no write barrier, set to non-GC pointer
- }
- if ((i *= step) < size)
- {
- Assert(sizeof(T) == sizeof(int32));
- ((int32*)(this->elements))[i] = JavascriptNativeIntArray::MissingItem;
- }
- }
- else
- {
- // Pointer size <= element size. Fill with pointer-sized stores.
- Assert(sizeof(T) % sizeof(Var) == 0);
- uint step = sizeof(T) / sizeof(Var);
- for (uint i = start; i < size * step; i++)
- {
- ((Var*)(this->elements))[i] = fill; // swb: no write barrier, set to non-GC pointer
- }
- }
- }
- template<typename T>
- void SparseArraySegment<T>::SetElement(Recycler *recycler, uint32 index, T value)
- {
- AssertMsg(index >= left && index - left < size, "Index out of range");
- uint32 offset = index - left;
- elements[offset] = value;
- if ((offset + 1) > length)
- {
- length = offset + 1;
- }
- AssertOrFailFast(length <= size);
- Assert(left + length > left);
- }
- template<typename T>
- SparseArraySegment<T> *SparseArraySegment<T>::SetElementGrow(Recycler *recycler, SparseArraySegmentBase* prev, uint32 index, T value)
- {
- AssertMsg((index + 1) == left || index == (left + size), "Index out of range");
- uint32 offset = index - left;
- SparseArraySegment<T> *current = this;
- if (index + 1 == left)
- {
- Assert(prev && prev->next == current);
- Assert(left > prev->left && left - prev->left > prev->size);
- Assert(left - prev->left - prev->size > 1); // Otherwise we would be growing/merging prev
- // Grow front up to (prev->left + prev->size + 1), so that setting (prev->left + prev->size)
- // later would trigger segment merging.
- current = GrowFrontByMax(recycler, left - prev->left - prev->size - 1);
- current->SetElement(recycler, index, value);
- }
- else if (offset == size)
- {
- if (next == nullptr)
- {
- current = GrowByMin(recycler, offset + 1 - size);
- }
- else
- {
- current = GrowByMinMax(recycler, offset + 1 - size, next->left - left - size);
- }
- current->elements[offset] = value;
- current->length = offset + 1;
- current->CheckLengthvsSize();
- }
- else
- {
- AssertMsg(false, "Invalid call to SetElementGrow");
- }
- return current;
- }
- template<typename T>
- T SparseArraySegment<T>::GetElement(uint32 index)
- {
- AssertMsg(index >= left && index <= left + length - 1, "Index is out of the segment range");
- return elements[index - left];
- }
- // This is a very inefficient function, we have to move element
- template<typename T>
- void SparseArraySegment<T>::RemoveElement(Recycler *recycler, uint32 index)
- {
- AssertMsg(index >= left && index < left + length, "Index is out of the segment range");
- if (index + 1 < left + length)
- {
- MoveArray(elements + index - left, elements + index + 1 - left, length - (index - left) - 1);
- }
- Assert(length);
- length--;
- elements[length] = SparseArraySegment<T>::GetMissingItem();
- }
- template<typename T>
- SparseArraySegment<T>* SparseArraySegment<T>::CopySegment(Recycler *recycler, SparseArraySegment<T>* dst, uint32 dstIndex, SparseArraySegment<T>* src, uint32 srcIndex, uint32 inputLen)
- {
- AssertMsg(src != nullptr && dst != nullptr, "Null input!");
- uint32 newLen = dstIndex - dst->left + inputLen;
- if (newLen > dst->size)
- {
- dst = dst->GrowBy(recycler, newLen - dst->size);
- }
- dst->length = newLen;
- dst->CheckLengthvsSize();
- AssertMsg(srcIndex >= src->left,"src->left > srcIndex resulting in negative indexing of src->elements");
- CopyArray(dst->elements + dstIndex - dst->left, inputLen, src->elements + srcIndex - src->left, inputLen);
- return dst;
- }
- template<typename T>
- uint32 SparseArraySegment<T>::GetGrowByFactor()
- {
- if (size < CHUNK_SIZE/2)
- {
- return (GetAlignedSize(size * 4) - size);
- }
- else if (size < 1024)
- {
- return (GetAlignedSize(size * 2) - size);
- }
- return (GetAlignedSize(UInt32Math::Mul(size, 5) / 3) - size);
- }
- template<typename T>
- SparseArraySegment<T>* SparseArraySegment<T>::GrowByMin(Recycler *recycler, uint32 minValue)
- {
- Assert(size <= JavascriptArray::MaxArrayLength - left);
- uint32 maxGrow = JavascriptArray::MaxArrayLength - (left + size);
- return GrowByMinMax(recycler, minValue, maxGrow);
- }
- template<typename T>
- SparseArraySegment<T>* SparseArraySegment<T>::GrowByMinMax(Recycler *recycler, uint32 minValue, uint32 maxValue)
- {
- Assert(size <= JavascriptArray::MaxArrayLength - left);
- Assert(maxValue <= JavascriptArray::MaxArrayLength - (left + size));
- AssertMsg(minValue <= maxValue, "Invalid values to GrowByMinMax");
- return GrowBy(recycler, max(minValue,min(maxValue, GetGrowByFactor())));
- }
- template<>
- inline SparseArraySegment<int>* SparseArraySegment<int>::GrowBy(Recycler *recycler, uint32 n)
- {
- if (!DoNativeArrayLeafSegment() || this->next != nullptr)
- {
- return GrowByImpl<false>(recycler, n);
- }
- return GrowByImpl<true>(recycler, n);
- }
- template<>
- inline SparseArraySegment<double>* SparseArraySegment<double>::GrowBy(Recycler *recycler, uint32 n)
- {
- if (!DoNativeArrayLeafSegment() || this->next != nullptr)
- {
- return GrowByImpl<false>(recycler, n);
- }
- return GrowByImpl<true>(recycler, n);
- }
- template<typename T>
- SparseArraySegment<T>* SparseArraySegment<T>::GrowBy(Recycler *recycler, uint32 n)
- {
- return GrowByImpl<false>(recycler, n);
- }
- template<typename T>
- template<bool isLeaf>
- SparseArraySegment<T>* SparseArraySegment<T>::GrowByImpl(Recycler *recycler, uint32 n)
- {
- AssertOrFailFast(length <= size);
- Assert(n != 0);
- uint32 newSize = size + n;
- if (newSize <= size)
- {
- Throw::OutOfMemory();
- }
- SparseArraySegment<T> *newSeg = Allocate<isLeaf>(recycler, left, length, newSize);
- newSeg->next = this->next;
- // (sizeof(T) * newSize) will throw OOM in Allocate if it overflows.
- CopyArray(newSeg->elements, newSize, this->elements, length);
- return newSeg;
- }
- //
- // Grows segment in the front. Note that the result new segment's left is changed.
- //
- template<>
- inline SparseArraySegment<int>* SparseArraySegment<int>::GrowFrontByMax(Recycler *recycler, uint32 n)
- {
- if (DoNativeArrayLeafSegment() && this->next == nullptr)
- {
- return GrowFrontByMaxImpl<true>(recycler, n);
- }
- return GrowFrontByMaxImpl<false>(recycler, n);
- }
- template<>
- inline SparseArraySegment<double>* SparseArraySegment<double>::GrowFrontByMax(Recycler *recycler, uint32 n)
- {
- if (DoNativeArrayLeafSegment() && this->next == nullptr)
- {
- return GrowFrontByMaxImpl<true>(recycler, n);
- }
- return GrowFrontByMaxImpl<false>(recycler, n);
- }
- template<typename T>
- SparseArraySegment<T>* SparseArraySegment<T>::GrowFrontByMax(Recycler *recycler, uint32 n)
- {
- return GrowFrontByMaxImpl<false>(recycler, n);
- }
- template<typename T>
- template<bool isLeaf>
- SparseArraySegment<T>* SparseArraySegment<T>::GrowFrontByMaxImpl(Recycler *recycler, uint32 n)
- {
- AssertOrFailFast(length <= size);
- Assert(n > 0);
- Assert(n <= left);
- Assert(size + n > size);
- n = min(n, GetGrowByFactor());
- if (size + n <= size)
- {
- Throw::OutOfMemory();
- }
- SparseArraySegment<T> *newSeg = Allocate<isLeaf>(recycler, left - n, length + n, size + n);
- newSeg->next = this->next;
- CopyArray(newSeg->elements + n, length, this->elements, length);
- return newSeg;
- }
- template<typename T>
- void SparseArraySegment<T>::ClearElements(__out_ecount(len) Field(T)* elements, uint32 len)
- {
- T fill = SparseArraySegment<T>::GetMissingItem();
- for (uint i = 0; i < len; i++)
- {
- elements[i] = fill;
- }
- }
- template<typename T>
- void SparseArraySegment<T>::Truncate(uint32 index)
- {
- AssertMsg(index >= left && (index - left) < size, "Index out of range");
- ClearElements(elements + (index - left), size - (index - left));
- if (index - left < length)
- {
- length = index - left;
- }
- AssertOrFailFast(length <= size);
- }
- template<typename T>
- void SparseArraySegment<T>::ReverseSegment(Recycler *recycler)
- {
- if (length <= 1)
- {
- return;
- }
- T temp;
- uint32 lower = 0;
- uint32 upper = length - 1;
- while (lower < upper)
- {
- temp = elements[lower];
- elements[lower] = elements[upper];
- elements[upper] = temp;
- ++lower;
- --upper;
- }
- }
- }
|