SparseArraySegment.inl 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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. #pragma once
  6. namespace Js
  7. {
  8. template<typename T>
  9. uint32 SparseArraySegment<T>::GetAlignedSize(uint32 size)
  10. {
  11. return (uint32)(HeapInfo::GetAlignedSize(UInt32Math::MulAdd<sizeof(T), sizeof(SparseArraySegmentBase)>(size)) - sizeof(SparseArraySegmentBase)) / sizeof(T);
  12. }
  13. template<typename T>
  14. template<bool isLeaf>
  15. SparseArraySegment<T> * SparseArraySegment<T>::Allocate(Recycler* recycler, uint32 left, uint32 length, uint32 size, uint32 fillStart /*= 0*/)
  16. {
  17. AssertOrFailFast(length <= size);
  18. Assert(size <= JavascriptArray::MaxArrayLength - left);
  19. uint32 bufferSize = UInt32Math::Mul<sizeof(T)>(size);
  20. SparseArraySegment<T> *seg =
  21. isLeaf ?
  22. RecyclerNewPlusLeafZ(recycler, bufferSize, SparseArraySegment<T>, left, length, size) :
  23. RecyclerNewPlusZ(recycler, bufferSize, SparseArraySegment<T>, left, length, size);
  24. seg->FillSegmentBuffer(fillStart, size);
  25. return seg;
  26. }
  27. template<>
  28. inline SparseArraySegment<int> *SparseArraySegment<int>::AllocateLiteralHeadSegment(
  29. Recycler *const recycler,
  30. const uint32 length)
  31. {
  32. if (DoNativeArrayLeafSegment())
  33. {
  34. return SparseArraySegment<int>::AllocateLiteralHeadSegmentImpl<true>(recycler, length);
  35. }
  36. return SparseArraySegment<int>::AllocateLiteralHeadSegmentImpl<false>(recycler, length);
  37. }
  38. template<>
  39. inline SparseArraySegment<double> *SparseArraySegment<double>::AllocateLiteralHeadSegment(
  40. Recycler *const recycler,
  41. const uint32 length)
  42. {
  43. if (DoNativeArrayLeafSegment())
  44. {
  45. return SparseArraySegment<double>::AllocateLiteralHeadSegmentImpl<true>(recycler, length);
  46. }
  47. return SparseArraySegment<double>::AllocateLiteralHeadSegmentImpl<false>(recycler, length);
  48. }
  49. template<typename T>
  50. SparseArraySegment<T> *SparseArraySegment<T>::AllocateLiteralHeadSegment(
  51. Recycler *const recycler,
  52. const uint32 length)
  53. {
  54. return SparseArraySegment<T>::AllocateLiteralHeadSegmentImpl<false>(recycler, length);
  55. }
  56. template<typename T>
  57. template<bool isLeaf>
  58. SparseArraySegment<T> *SparseArraySegment<T>::AllocateLiteralHeadSegmentImpl(
  59. Recycler *const recycler,
  60. const uint32 length)
  61. {
  62. Assert(length != 0);
  63. const uint32 size = GetAlignedSize(length);
  64. return SparseArraySegment<T>::Allocate<isLeaf>(recycler, 0, length, size, length);
  65. }
  66. template<>
  67. inline SparseArraySegment<int> * SparseArraySegment<int>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, SparseArraySegmentBase *nextSeg)
  68. {
  69. if (DoNativeArrayLeafSegment() && nextSeg == nullptr)
  70. {
  71. return AllocateSegmentImpl<true>(recycler, left, length, nextSeg);
  72. }
  73. return AllocateSegmentImpl<false>(recycler, left, length, nextSeg);
  74. }
  75. template<>
  76. inline SparseArraySegment<double> * SparseArraySegment<double>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, SparseArraySegmentBase *nextSeg)
  77. {
  78. if (DoNativeArrayLeafSegment() && nextSeg == nullptr)
  79. {
  80. return AllocateSegmentImpl<true>(recycler, left, length, nextSeg);
  81. }
  82. return AllocateSegmentImpl<false>(recycler, left, length, nextSeg);
  83. }
  84. template<typename T>
  85. SparseArraySegment<T> * SparseArraySegment<T>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, SparseArraySegmentBase *nextSeg)
  86. {
  87. return AllocateSegmentImpl<false>(recycler, left, length, nextSeg);
  88. }
  89. template<typename T>
  90. template<bool isLeaf>
  91. SparseArraySegment<T> * SparseArraySegment<T>::AllocateSegmentImpl(Recycler* recycler, uint32 left, uint32 length, SparseArraySegmentBase *nextSeg)
  92. {
  93. Assert(!isLeaf || nextSeg == nullptr);
  94. uint32 size;
  95. if ((length <= CHUNK_SIZE) && (left < BigLeft))
  96. {
  97. size = GetAlignedSize(CHUNK_SIZE);
  98. }
  99. else
  100. {
  101. size = GetAlignedSize(length);
  102. }
  103. //But don't overshoot next segment
  104. EnsureSizeInBound(left, length, size, nextSeg);
  105. return SparseArraySegment<T>::Allocate<isLeaf>(recycler, left, length, size);
  106. }
  107. template<>
  108. inline SparseArraySegment<int> * SparseArraySegment<int>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, uint32 size, SparseArraySegmentBase *nextSeg)
  109. {
  110. if (DoNativeArrayLeafSegment() && nextSeg == nullptr)
  111. {
  112. return AllocateSegmentImpl<true>(recycler, left, length, size, nextSeg);
  113. }
  114. return AllocateSegmentImpl<false>(recycler, left, length, size, nextSeg);
  115. }
  116. template<>
  117. inline SparseArraySegment<double> * SparseArraySegment<double>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, uint32 size, SparseArraySegmentBase *nextSeg)
  118. {
  119. if (DoNativeArrayLeafSegment() && nextSeg == nullptr)
  120. {
  121. return AllocateSegmentImpl<true>(recycler, left, length, size, nextSeg);
  122. }
  123. return AllocateSegmentImpl<false>(recycler, left, length, size, nextSeg);
  124. }
  125. template<typename T>
  126. inline SparseArraySegment<T> * SparseArraySegment<T>::AllocateSegment(Recycler* recycler, uint32 left, uint32 length, uint32 size, SparseArraySegmentBase *nextSeg)
  127. {
  128. return AllocateSegmentImpl<false>(recycler, left, length, size, nextSeg);
  129. }
  130. template<typename T>
  131. template<bool isLeaf>
  132. SparseArraySegment<T> * SparseArraySegment<T>::AllocateSegmentImpl(Recycler* recycler, uint32 left, uint32 length, uint32 size, SparseArraySegmentBase *nextSeg)
  133. {
  134. Assert(!isLeaf || nextSeg == nullptr);
  135. AssertMsg(size > 0, "size too small");
  136. if ((size <= CHUNK_SIZE) && (size < BigLeft))
  137. {
  138. size = GetAlignedSize(CHUNK_SIZE);
  139. }
  140. else
  141. {
  142. size = GetAlignedSize(size);
  143. }
  144. //But don't overshoot next segment
  145. EnsureSizeInBound(left, length, size, nextSeg);
  146. return SparseArraySegment<T>::Allocate<isLeaf>(recycler, left, length, size);
  147. }
  148. template<>
  149. inline SparseArraySegment<int>* SparseArraySegment<int>::AllocateSegment(Recycler* recycler, SparseArraySegmentBase* prev, uint32 index)
  150. {
  151. if (DoNativeArrayLeafSegment() && prev->next == nullptr)
  152. {
  153. return AllocateSegmentImpl<true>(recycler, prev, index);
  154. }
  155. return AllocateSegmentImpl<false>(recycler, prev, index);
  156. }
  157. template<>
  158. inline SparseArraySegment<double>* SparseArraySegment<double>::AllocateSegment(Recycler* recycler, SparseArraySegmentBase* prev, uint32 index)
  159. {
  160. if (DoNativeArrayLeafSegment() && prev->next == nullptr)
  161. {
  162. return AllocateSegmentImpl<true>(recycler, prev, index);
  163. }
  164. return AllocateSegmentImpl<false>(recycler, prev, index);
  165. }
  166. template<typename T>
  167. SparseArraySegment<T>* SparseArraySegment<T>::AllocateSegment(Recycler* recycler, SparseArraySegmentBase* prev, uint32 index)
  168. {
  169. return AllocateSegmentImpl<false>(recycler, prev, index);
  170. }
  171. // Allocate a segment in between (prev, next) to contain an index
  172. template<typename T>
  173. template<bool isLeaf>
  174. SparseArraySegment<T>* SparseArraySegment<T>::AllocateSegmentImpl(Recycler* recycler, SparseArraySegmentBase* prev, uint32 index)
  175. {
  176. Assert(prev);
  177. Assert(index > prev->left && index - prev->left >= prev->size);
  178. SparseArraySegmentBase* next = prev->next;
  179. Assert(!next || index < next->left);
  180. Assert(!next || !isLeaf);
  181. uint32 left = index;
  182. uint32 size = (left < BigLeft ? GetAlignedSize(CHUNK_SIZE) : GetAlignedSize(1));
  183. // Try to move the segment leftwards if it overshoots next segment
  184. if (next && size > next->left - left)
  185. {
  186. size = min(size, next->left - (prev->left + prev->size));
  187. left = next->left - size;
  188. }
  189. Assert(index >= left && index - left < size);
  190. uint32 length = index - left + 1;
  191. EnsureSizeInBound(left, length, size, next);
  192. return SparseArraySegment<T>::Allocate<isLeaf>(recycler, left, length, size);
  193. }
  194. template<>
  195. inline Var SparseArraySegment<int32>::GetMissingItemVar()
  196. {
  197. return JavascriptArray::IntMissingItemVar;
  198. }
  199. template<>
  200. inline Var SparseArraySegment<double>::GetMissingItemVar()
  201. {
  202. return (Var)FloatMissingItemPattern;
  203. }
  204. template<typename T>
  205. void SparseArraySegment<T>::FillSegmentBuffer(uint32 start, uint32 size)
  206. {
  207. // Fill the segment buffer using gp-register-sized stores. Avoid using the FPU for the sake
  208. // of perf (especially x86).
  209. Var fill = (Var)SparseArraySegment<T>::GetMissingItemVar();
  210. if (sizeof(Var) > sizeof(T))
  211. {
  212. // Pointer size is greater than the element (int32 buffer on x64).
  213. // Fill as much as we can and do one int32-sized store at the end if necessary.
  214. uint32 i, step = sizeof(Var) / sizeof(T);
  215. if (start & 1)
  216. {
  217. Assert(sizeof(T) == sizeof(int32));
  218. ((int32*)(this->elements))[start] = JavascriptNativeIntArray::MissingItem;
  219. }
  220. for (i = (start + step-1)/step; i < (size/step); i++)
  221. {
  222. ((Var*)(this->elements))[i] = fill; // swb: no write barrier, set to non-GC pointer
  223. }
  224. if ((i *= step) < size)
  225. {
  226. Assert(sizeof(T) == sizeof(int32));
  227. ((int32*)(this->elements))[i] = JavascriptNativeIntArray::MissingItem;
  228. }
  229. }
  230. else
  231. {
  232. // Pointer size <= element size. Fill with pointer-sized stores.
  233. Assert(sizeof(T) % sizeof(Var) == 0);
  234. uint step = sizeof(T) / sizeof(Var);
  235. // We're filling [length...size-1] based on the element size. If this is going to be a float segment on 32-bit,
  236. // only fill past the point where the float elements will reside. Size * step has to be a 32-bit number.
  237. start *= step;
  238. size *= step;
  239. for (uint i = start; i < size; i++)
  240. {
  241. ((Var*)(this->elements))[i] = fill; // swb: no write barrier, set to non-GC pointer
  242. }
  243. }
  244. }
  245. template<typename T>
  246. void SparseArraySegment<T>::SetElement(Recycler *recycler, uint32 index, T value)
  247. {
  248. AssertMsg(index >= left && index - left < size, "Index out of range");
  249. uint32 offset = index - left;
  250. elements[offset] = value;
  251. if ((offset + 1) > length)
  252. {
  253. length = offset + 1;
  254. }
  255. AssertOrFailFast(length <= size);
  256. Assert(left + length > left);
  257. }
  258. template<typename T>
  259. SparseArraySegment<T> *SparseArraySegment<T>::SetElementGrow(Recycler *recycler, SparseArraySegmentBase* prev, uint32 index, T value)
  260. {
  261. AssertMsg((index + 1) == left || index == (left + size), "Index out of range");
  262. uint32 offset = index - left;
  263. SparseArraySegment<T> *current = this;
  264. if (index + 1 == left)
  265. {
  266. Assert(prev && prev->next == current);
  267. Assert(left > prev->left && left - prev->left > prev->size);
  268. Assert(left - prev->left - prev->size > 1); // Otherwise we would be growing/merging prev
  269. // Grow front up to (prev->left + prev->size + 1), so that setting (prev->left + prev->size)
  270. // later would trigger segment merging.
  271. current = GrowFrontByMax(recycler, left - prev->left - prev->size - 1);
  272. current->SetElement(recycler, index, value);
  273. }
  274. else if (offset == size)
  275. {
  276. if (next == nullptr)
  277. {
  278. current = GrowByMin(recycler, offset + 1 - size);
  279. }
  280. else
  281. {
  282. current = GrowByMinMax(recycler, offset + 1 - size, next->left - left - size);
  283. }
  284. current->elements[offset] = value;
  285. current->length = offset + 1;
  286. current->CheckLengthvsSize();
  287. }
  288. else
  289. {
  290. AssertMsg(false, "Invalid call to SetElementGrow");
  291. }
  292. return current;
  293. }
  294. template<typename T>
  295. T SparseArraySegment<T>::GetElement(uint32 index)
  296. {
  297. AssertMsg(index >= left && index <= left + length - 1, "Index is out of the segment range");
  298. return elements[index - left];
  299. }
  300. // This is a very inefficient function, we have to move element
  301. template<typename T>
  302. void SparseArraySegment<T>::RemoveElement(Recycler *recycler, uint32 index)
  303. {
  304. AssertMsg(index >= left && index < left + length, "Index is out of the segment range");
  305. if (index + 1 < left + length)
  306. {
  307. MoveArray(elements + index - left, elements + index + 1 - left, length - (index - left) - 1);
  308. }
  309. Assert(length);
  310. length--;
  311. elements[length] = SparseArraySegment<T>::GetMissingItem();
  312. }
  313. template<typename T>
  314. SparseArraySegment<T>* SparseArraySegment<T>::CopySegment(Recycler *recycler, SparseArraySegment<T>* dst, uint32 dstIndex, SparseArraySegment<T>* src, uint32 srcIndex, uint32 inputLen)
  315. {
  316. AssertMsg(src != nullptr && dst != nullptr, "Null input!");
  317. uint32 newLen = dstIndex - dst->left + inputLen;
  318. if (newLen > dst->size)
  319. {
  320. dst = dst->GrowBy(recycler, newLen - dst->size);
  321. }
  322. dst->length = newLen;
  323. dst->CheckLengthvsSize();
  324. AssertMsg(srcIndex >= src->left,"src->left > srcIndex resulting in negative indexing of src->elements");
  325. CopyArray(dst->elements + dstIndex - dst->left, inputLen, src->elements + srcIndex - src->left, inputLen);
  326. return dst;
  327. }
  328. template<typename T>
  329. uint32 SparseArraySegment<T>::GetGrowByFactor()
  330. {
  331. if (size < CHUNK_SIZE/2)
  332. {
  333. return (GetAlignedSize(size * 4) - size);
  334. }
  335. else if (size < 1024)
  336. {
  337. return (GetAlignedSize(size * 2) - size);
  338. }
  339. return (GetAlignedSize(UInt32Math::Mul(size, 5) / 3) - size);
  340. }
  341. template<typename T>
  342. SparseArraySegment<T>* SparseArraySegment<T>::GrowByMin(Recycler *recycler, uint32 minValue)
  343. {
  344. Assert(size <= JavascriptArray::MaxArrayLength - left);
  345. uint32 maxGrow = JavascriptArray::MaxArrayLength - (left + size);
  346. return GrowByMinMax(recycler, minValue, maxGrow);
  347. }
  348. template<typename T>
  349. SparseArraySegment<T>* SparseArraySegment<T>::GrowByMinMax(Recycler *recycler, uint32 minValue, uint32 maxValue)
  350. {
  351. Assert(size <= JavascriptArray::MaxArrayLength - left);
  352. Assert(maxValue <= JavascriptArray::MaxArrayLength - (left + size));
  353. AssertMsg(minValue <= maxValue, "Invalid values to GrowByMinMax");
  354. return GrowBy(recycler, max(minValue,min(maxValue, GetGrowByFactor())));
  355. }
  356. template<>
  357. inline SparseArraySegment<int>* SparseArraySegment<int>::GrowBy(Recycler *recycler, uint32 n)
  358. {
  359. if (!DoNativeArrayLeafSegment() || this->next != nullptr)
  360. {
  361. return GrowByImpl<false>(recycler, n);
  362. }
  363. return GrowByImpl<true>(recycler, n);
  364. }
  365. template<>
  366. inline SparseArraySegment<double>* SparseArraySegment<double>::GrowBy(Recycler *recycler, uint32 n)
  367. {
  368. if (!DoNativeArrayLeafSegment() || this->next != nullptr)
  369. {
  370. return GrowByImpl<false>(recycler, n);
  371. }
  372. return GrowByImpl<true>(recycler, n);
  373. }
  374. template<typename T>
  375. SparseArraySegment<T>* SparseArraySegment<T>::GrowBy(Recycler *recycler, uint32 n)
  376. {
  377. return GrowByImpl<false>(recycler, n);
  378. }
  379. template<typename T>
  380. template<bool isLeaf>
  381. SparseArraySegment<T>* SparseArraySegment<T>::GrowByImpl(Recycler *recycler, uint32 n)
  382. {
  383. AssertOrFailFast(length <= size);
  384. Assert(n != 0);
  385. uint32 newSize = size + n;
  386. if (newSize <= size)
  387. {
  388. Throw::OutOfMemory();
  389. }
  390. SparseArraySegment<T> *newSeg = Allocate<isLeaf>(recycler, left, length, newSize);
  391. newSeg->next = this->next;
  392. // (sizeof(T) * newSize) will throw OOM in Allocate if it overflows.
  393. CopyArray(newSeg->elements, newSize, this->elements, length);
  394. return newSeg;
  395. }
  396. //
  397. // Grows segment in the front. Note that the result new segment's left is changed.
  398. //
  399. template<>
  400. inline SparseArraySegment<int>* SparseArraySegment<int>::GrowFrontByMax(Recycler *recycler, uint32 n)
  401. {
  402. if (DoNativeArrayLeafSegment() && this->next == nullptr)
  403. {
  404. return GrowFrontByMaxImpl<true>(recycler, n);
  405. }
  406. return GrowFrontByMaxImpl<false>(recycler, n);
  407. }
  408. template<>
  409. inline SparseArraySegment<double>* SparseArraySegment<double>::GrowFrontByMax(Recycler *recycler, uint32 n)
  410. {
  411. if (DoNativeArrayLeafSegment() && this->next == nullptr)
  412. {
  413. return GrowFrontByMaxImpl<true>(recycler, n);
  414. }
  415. return GrowFrontByMaxImpl<false>(recycler, n);
  416. }
  417. template<typename T>
  418. SparseArraySegment<T>* SparseArraySegment<T>::GrowFrontByMax(Recycler *recycler, uint32 n)
  419. {
  420. return GrowFrontByMaxImpl<false>(recycler, n);
  421. }
  422. template<typename T>
  423. template<bool isLeaf>
  424. SparseArraySegment<T>* SparseArraySegment<T>::GrowFrontByMaxImpl(Recycler *recycler, uint32 n)
  425. {
  426. AssertOrFailFast(length <= size);
  427. Assert(n > 0);
  428. Assert(n <= left);
  429. Assert(size + n > size);
  430. n = min(n, GetGrowByFactor());
  431. if (size + n <= size)
  432. {
  433. Throw::OutOfMemory();
  434. }
  435. SparseArraySegment<T> *newSeg = Allocate<isLeaf>(recycler, left - n, length + n, size + n);
  436. newSeg->next = this->next;
  437. CopyArray(newSeg->elements + n, length, this->elements, length);
  438. return newSeg;
  439. }
  440. template<typename T>
  441. void SparseArraySegment<T>::ClearElements(__out_ecount(len) Field(T)* elements, uint32 len)
  442. {
  443. T fill = SparseArraySegment<T>::GetMissingItem();
  444. for (uint i = 0; i < len; i++)
  445. {
  446. elements[i] = fill;
  447. }
  448. }
  449. template<typename T>
  450. void SparseArraySegment<T>::Truncate(uint32 index)
  451. {
  452. AssertMsg(index >= left && (index - left) < size, "Index out of range");
  453. ClearElements(elements + (index - left), size - (index - left));
  454. if (index - left < length)
  455. {
  456. length = index - left;
  457. }
  458. AssertOrFailFast(length <= size);
  459. }
  460. template<typename T>
  461. void SparseArraySegment<T>::ReverseSegment(Recycler *recycler)
  462. {
  463. if (length <= 1)
  464. {
  465. return;
  466. }
  467. T temp;
  468. uint32 lower = 0;
  469. uint32 upper = length - 1;
  470. while (lower < upper)
  471. {
  472. temp = elements[lower];
  473. elements[lower] = elements[upper];
  474. elements[upper] = temp;
  475. ++lower;
  476. --upper;
  477. }
  478. }
  479. }