@@ -11814,24 +11814,42 @@ using namespace Js;
11814
11814
#endif
11815
11815
11816
11816
template <typename T>
11817
- void JavascriptArray::InitBoxedInlineSegments(SparseArraySegment<T> * dst, SparseArraySegment<T> * src , bool deepCopy)
11817
+ void JavascriptArray::InitBoxedInlineSegments(T * instance , bool deepCopy)
11818
11818
{
11819
11819
// Don't copy the segment map, we will build it again
11820
11820
SetFlags(GetFlags() & ~DynamicObjectFlags::HasSegmentMap);
11821
11821
11822
- SetHeadAndLastUsedSegment(dst);
11822
+ SparseArraySegment<typename T::TElement>* src = SparseArraySegment<typename T::TElement>::From(instance->head);
11823
+ SparseArraySegment<typename T::TElement>* dst;
11824
+
11825
+ if (IsInlineSegment(src, instance))
11826
+ {
11827
+ Assert(src->size <= SparseArraySegmentBase::INLINE_CHUNK_SIZE);
11828
+
11829
+ // Copy head segment data between inlined head segments
11830
+ dst = DetermineInlineHeadSegmentPointer<T, 0, true>(static_cast<T*>(this));
11831
+ dst->left = src->left;
11832
+ dst->length = src->length;
11833
+ dst->size = src->size;
11834
+ }
11835
+ else
11836
+ {
11837
+ // Otherwise, ensure that the new head segment is allocated now in the recycler so that the data can be copied.
11838
+ // Note: src->next is provided to control whether a leaf segment is allocated just as it is with instance. If
11839
+ // src->next is non-null, the appropriate update to dst->next will continue below.
11840
+ dst = SparseArraySegment<typename T::TElement>::AllocateSegment(GetRecycler(), src->left, src->length, src->size, src->next);
11841
+ }
11823
11842
11824
- // Copy head segment data
11825
- dst->left = src->left;
11826
- dst->length = src->length;
11827
- dst->size = src->size;
11843
+ SetHeadAndLastUsedSegment(dst);
11828
11844
dst->CheckLengthvsSize();
11829
11845
11846
+ Assert(IsInlineSegment(src, instance) == IsInlineSegment(dst, static_cast<T*>(this)));
11847
+
11830
11848
CopyArray(dst->elements, dst->size, src->elements, src->size);
11831
11849
11832
11850
if (!deepCopy)
11833
11851
{
11834
- // Without a deep copy, point to the existing next segment
11852
+ // Without a deep copy, point to the existing next segment from the original instance
11835
11853
dst->next = src->next;
11836
11854
}
11837
11855
else
@@ -11845,10 +11863,10 @@ using namespace Js;
11845
11863
{
11846
11864
// Allocate a new segment in the destination and copy from src
11847
11865
// note: PointerValue is to strip SWB wrapping before static_cast
11848
- src = static_cast<SparseArraySegment<T >*>(PointerValue(src->next));
11866
+ src = static_cast<SparseArraySegment<typename T::TElement >*>(PointerValue(src->next));
11849
11867
11850
11868
dst->next = dst->AllocateSegment(GetRecycler(), src->left, src->length, src->size, src->next);
11851
- dst = static_cast<SparseArraySegment<T >*>(PointerValue(dst->next));
11869
+ dst = static_cast<SparseArraySegment<typename T::TElement >*>(PointerValue(dst->next));
11852
11870
11853
11871
CopyArray(dst->elements, dst->size, src->elements, src->size);
11854
11872
}
@@ -11861,14 +11879,20 @@ using namespace Js;
11861
11879
} while (dst != nullptr);
11862
11880
failFastError.Completed();
11863
11881
}
11882
+
11883
+ // Assert either
11884
+ // - there is only the head segment
11885
+ // - the new head segment points to a new next segment
11886
+ // - the new head segment points to the existing next segment because this is not a deepCopy
11887
+ Assert(this->head->next == nullptr || this->head->next != src->next || !deepCopy);
11864
11888
}
11865
11889
11866
11890
JavascriptArray::JavascriptArray(JavascriptArray * instance, bool boxHead, bool deepCopy)
11867
11891
: ArrayObject(instance, deepCopy)
11868
11892
{
11869
11893
if (boxHead)
11870
11894
{
11871
- InitBoxedInlineSegments(DetermineInlineHeadSegmentPointer<JavascriptArray, 0, true>(this), SparseArraySegment<Var>::From( instance->head), false );
11895
+ InitBoxedInlineSegments(instance, deepCopy );
11872
11896
}
11873
11897
else
11874
11898
{
@@ -11880,13 +11904,19 @@ using namespace Js;
11880
11904
}
11881
11905
11882
11906
// Allocate a new Array with its own segments and copy the data in instance
11883
- // into the new Array
11907
+ // into the new Array. If the instance being deepCopy'd has an inline head
11908
+ // segment, then make sure the new instance also has allocation for an inline
11909
+ // head segment.
11884
11910
template <typename T>
11885
11911
T * JavascriptArray::DeepCopyInstance(T * instance)
11886
11912
{
11887
- return RecyclerNewPlusZ(instance->GetRecycler(),
11888
- instance->GetTypeHandler()->GetInlineSlotsSize() + sizeof(Js::SparseArraySegmentBase) + instance->head->size * sizeof(typename T::TElement),
11889
- T, instance, true /*boxHead*/, true /*deepCopy*/);
11913
+ size_t allocSize = instance->GetTypeHandler()->GetInlineSlotsSize();
11914
+ if (IsInlineSegment(instance->head, instance))
11915
+ {
11916
+ allocSize += sizeof(Js::SparseArraySegmentBase) + instance->head->size * sizeof(typename T::TElement);
11917
+ }
11918
+
11919
+ return RecyclerNewPlusZ(instance->GetRecycler(), allocSize, T, instance, true /*boxHead*/, true /*deepCopy*/);
11890
11920
}
11891
11921
11892
11922
ArrayObject* JavascriptArray::DeepCopyInstance(ArrayObject* arrayObject)
@@ -12051,7 +12081,7 @@ using namespace Js;
12051
12081
{
12052
12082
if (boxHead)
12053
12083
{
12054
- InitBoxedInlineSegments(DetermineInlineHeadSegmentPointer<JavascriptNativeIntArray, 0, true>(this), SparseArraySegment<int>::From( instance->head) , deepCopy);
12084
+ InitBoxedInlineSegments(instance, deepCopy);
12055
12085
}
12056
12086
else
12057
12087
{
@@ -12097,7 +12127,7 @@ using namespace Js;
12097
12127
{
12098
12128
if (boxHead)
12099
12129
{
12100
- InitBoxedInlineSegments(DetermineInlineHeadSegmentPointer<JavascriptNativeFloatArray, 0, true>(this), SparseArraySegment<double>::From( instance->head) , deepCopy);
12130
+ InitBoxedInlineSegments(instance, deepCopy);
12101
12131
}
12102
12132
else
12103
12133
{
0 commit comments