blob: 06cc9d58536d0cd760728caf31cc0f30cedad828 [file]
//-------------------------------------------------------------------------------------------------------
// 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
{
class SparseArraySegmentBase
{
public:
static const uint32 MaxLength;
Field(uint32) left; // TODO: (leish)(swb) this can easily be recycler false positive on x86, or on x64 if combine with length field
// find a way to either tag this or find a better solution
Field(uint32) length; //we use length instead of right so that we can denote a segment is empty
Field(uint32) size;
Field(SparseArraySegmentBase*) next;
static const uint32 CHUNK_SIZE = 16;
static const uint32 HEAD_CHUNK_SIZE = 16;
static const uint32 INLINE_CHUNK_SIZE = 64; // Max number of elements in a segment that is initialized inline within the array.
static const uint32 SMALL_CHUNK_SIZE = 4;
static const uint32 BigLeft = 1 << 20;
SparseArraySegmentBase(uint32 left, uint32 length, uint32 size);
bool HasIndex(uint32 index) { return (left <= index) && index < (left + length); };
uint32 RemoveUndefined(ScriptContext* scriptContext); //returns count of undefined removed
void EnsureSizeInBound();
void CheckLengthvsSize() { AssertOrFailFast(this->length <= this->size); }
static uint32 GetOffsetOfLeft() { return offsetof(SparseArraySegmentBase, left); }
static uint32 GetOffsetOfLength() { return offsetof(SparseArraySegmentBase, length); }
static uint32 GetOffsetOfSize() { return offsetof(SparseArraySegmentBase, size); }
static uint32 GetOffsetOfNext() { return offsetof(SparseArraySegmentBase, next); }
static bool DoNativeArrayLeafSegment() { return !PHASE_OFF1(Js::NativeArrayLeafSegmentPhase); }
static bool IsLeafSegment(SparseArraySegmentBase *seg, Recycler *recycler);
protected:
static void EnsureSizeInBound(uint32 left, uint32 length, uint32& size, SparseArraySegmentBase* next);
};
template<typename T>
class SparseArraySegment : public SparseArraySegmentBase
{
public:
SparseArraySegment(uint32 left, uint32 length, uint32 size) :
SparseArraySegmentBase(left, length, size) {}
Field(T) elements[]; // actual elements will follow this determined by size
void FillSegmentBuffer(uint start, uint size);
T GetElement(uint32 index);
void SetElement(Recycler *recycler, uint32 index, T value); // sets elements within the segment
void RemoveElement(Recycler *recycler, uint32 index); // NOTE: RemoveElement calls memmove, for perf reasons use SetElement(index, null)
SparseArraySegment<T> *GrowBy(Recycler *recycler, uint32 n);
SparseArraySegment<T>* GrowByMin(Recycler *recycler, uint32 minValue);
SparseArraySegment<T>* GrowByMinMax(Recycler *recycler, uint32 minValue, uint32 maxValue);
SparseArraySegment<T>* GrowFrontByMax(Recycler *recycler, uint32 n);
void ReverseSegment(Recycler *recycler);
void Truncate(uint32 index);
//following will change the current segment allocation
SparseArraySegment<T> *SetElementGrow(Recycler *recycler, SparseArraySegmentBase* prev, uint32 index, T value);
static SparseArraySegment<T> *AllocateLiteralHeadSegment(Recycler *const recycler, const uint32 length);
static SparseArraySegment<T> * AllocateSegment(Recycler* recycler, uint32 left, uint32 length, SparseArraySegmentBase *nextSeg);
static SparseArraySegment<T> * AllocateSegment(Recycler* recycler, uint32 left, uint32 length, uint32 size, SparseArraySegmentBase *nextSeg);
static SparseArraySegment<T> * AllocateSegment(Recycler* recycler, SparseArraySegmentBase* prev, uint32 index);
template<bool isLeaf>
static SparseArraySegment<T> * AllocateSegmentImpl(Recycler* recycler, uint32 left, uint32 length, SparseArraySegmentBase *nextSeg);
template<bool isLeaf>
static SparseArraySegment<T> * AllocateSegmentImpl(Recycler* recycler, uint32 left, uint32 length, uint32 size, SparseArraySegmentBase *nextSeg);
template<bool isLeaf>
static SparseArraySegment<T> * AllocateSegmentImpl(Recycler* recycler, SparseArraySegmentBase* prev, uint32 index);
template<bool isLeaf>
static SparseArraySegment<T> *AllocateLiteralHeadSegmentImpl(Recycler *const recycler, const uint32 length);
static void ClearElements(__out_ecount(len) Field(T)* elements, uint32 len);
static SparseArraySegment<T>* CopySegment(Recycler *recycler, SparseArraySegment<T>* dst, uint32 dstIndex, SparseArraySegment<T>* src, uint32 srcIndex, uint32 inputLen);
static T GetMissingItem();
static bool IsMissingItem(const T* value);
template <class S>
static bool IsMissingItem(const WriteBarrierPtr<S>* value)
{
return IsMissingItem(AddressOf(value[0]));
}
static uint32 GetAlignedSize(uint32 size);
static inline SparseArraySegment* From(SparseArraySegmentBase* seg)
{
return static_cast<SparseArraySegment*>(seg);
}
private:
template<bool isLeaf>
static SparseArraySegment<T>* Allocate(Recycler* recycler, uint32 left, uint32 length, uint32 size, uint32 fillStart = 0);
template<bool isLeaf>
SparseArraySegment<T> *GrowByImpl(Recycler *recycler, uint32 n);
template<bool isLeaf>
SparseArraySegment<T>* GrowFrontByMaxImpl(Recycler *recycler, uint32 n);
uint32 GetGrowByFactor();
};
template<typename T>
T SparseArraySegment<T>::GetMissingItem()
{
return (T)JavascriptArray::MissingItem;
}
template<>
inline int32 SparseArraySegment<int32>::GetMissingItem()
{
return 0x80000002;
}
template<>
inline double SparseArraySegment<double>::GetMissingItem()
{
uint64 u = 0x8000000280000002;
return *(double*)&u;
}
template<>
inline bool SparseArraySegment<double>::IsMissingItem(const double* value)
{
return *(uint64*)value == 0x8000000280000002ull;
}
template<typename T>
bool SparseArraySegment<T>::IsMissingItem(const T* value)
{
return *value == SparseArraySegment<T>::GetMissingItem();
}
} // namespace Js