SparseArraySegment.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeLibraryPch.h"
  6. namespace Js
  7. {
  8. const uint32 SparseArraySegmentBase::MaxLength = static_cast<uint32>(INT32_MAX);
  9. SparseArraySegmentBase::SparseArraySegmentBase(uint32 left, uint32 length, uint32 size) : left(left), length(length), size(size), next(nullptr)
  10. {
  11. }
  12. // "Reduce" size if it exceeds next.left boundary, after operations that shift the following segments.
  13. void SparseArraySegmentBase::EnsureSizeInBound()
  14. {
  15. EnsureSizeInBound(left, length, size, next);
  16. }
  17. // Reduce size if it exceeds next.left boundary or MaxArrayLength
  18. void SparseArraySegmentBase::EnsureSizeInBound(uint32 left, uint32 length, uint32& size, SparseArraySegmentBase* next)
  19. {
  20. uint32 nextLeft = next ? next->left : JavascriptArray::MaxArrayLength;
  21. Assert(nextLeft > left);
  22. if(size != 0)
  23. {
  24. // Avoid writing to 'size' for an empty segment. The empty segment is a constant structure and writing to it (even
  25. // if it's not being changed) may cause an AV.
  26. size = min(size, nextLeft - left);
  27. }
  28. AssertOrFailFast(length <= size);
  29. }
  30. // Test if an element value is null/undefined.
  31. inline static bool IsMissingOrUndefined(Var value, RecyclableObject *undefined, uint32& countUndefined)
  32. {
  33. if (SparseArraySegment<Var>::IsMissingItem(&value))
  34. {
  35. return true;
  36. }
  37. if (JavascriptOperators::IsUndefinedObject(value, undefined))
  38. {
  39. ++countUndefined;
  40. return true;
  41. }
  42. return false;
  43. }
  44. bool SparseArraySegmentBase::IsLeafSegment(SparseArraySegmentBase *seg, Recycler *recycler)
  45. {
  46. if (!DoNativeArrayLeafSegment())
  47. {
  48. return false;
  49. }
  50. RecyclerHeapObjectInfo heapObject;
  51. if (recycler->FindHeapObject(
  52. seg,
  53. (Memory::FindHeapObjectFlags)(FindHeapObjectFlags_VerifyFreeBitForAttribute | FindHeapObjectFlags_AllowInterior),
  54. heapObject))
  55. {
  56. return heapObject.IsLeaf();
  57. }
  58. return false;
  59. }
  60. // Remove null/undefined from this segment. May reorder elements and compact this segment in preparing for sort.
  61. uint32 SparseArraySegmentBase::RemoveUndefined(ScriptContext* scriptContext)
  62. {
  63. SparseArraySegment<Var> *_this = (SparseArraySegment<Var>*)this;
  64. // Shortcut length==0, otherwise the code below will AV when left==length==0. (WOOB 1114975)
  65. if (length == 0)
  66. {
  67. return 0;
  68. }
  69. //remove undefine values
  70. RecyclableObject *undefined = scriptContext->GetLibrary()->GetUndefined();
  71. uint32 i = 0;
  72. uint32 j = length - 1;
  73. uint32 countUndefined = 0;
  74. while (i <= j)
  75. {
  76. //get the first null/undefined slot from left
  77. while (i < j && !IsMissingOrUndefined(_this->elements[i], undefined, countUndefined))
  78. {
  79. i++;
  80. }
  81. bool iIsMissingOrUndefined = (i < j); // Flag to avoid test again if later j comes down to == i
  82. //get the first slot which is not null/undefined from the right
  83. while (i < j && IsMissingOrUndefined(_this->elements[j], undefined, countUndefined))
  84. {
  85. j--;
  86. }
  87. if (i < j)
  88. {
  89. //move
  90. _this->elements[i] = _this->elements[j];
  91. i++;
  92. j--;
  93. }
  94. else
  95. {
  96. Assert(i == j);
  97. if (iIsMissingOrUndefined || IsMissingOrUndefined(_this->elements[j], undefined, countUndefined))
  98. {
  99. j--; // ok if j becomes -1. We'll truncate to length (j + 1).
  100. }
  101. break; // done
  102. }
  103. }
  104. if (j != length - 1) // Truncate if j has changed
  105. {
  106. uint32 newLen = j + 1;
  107. Assert(newLen < length);
  108. Assert(countUndefined <= length - newLen);
  109. _this->Truncate(left + newLen); // Truncate to new length (also clears moved elements)
  110. }
  111. AssertOrFailFast(length <= size);
  112. return countUndefined;
  113. }
  114. }