RecyclerPointers.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  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. #include "WriteBarrierMacros.h"
  7. namespace Memory
  8. {
  9. class Recycler;
  10. class RecyclerNonLeafAllocator;
  11. // Dummy tag class to mark no write barrier value
  12. struct _no_write_barrier_tag {};
  13. // Dummy tag classes to mark yes/no write barrier policy
  14. //
  15. struct _write_barrier_policy {};
  16. struct _no_write_barrier_policy {};
  17. // ----------------------------------------------------------------------------
  18. // Field write barrier
  19. //
  20. // Determines if a field needs to be wrapped in WriteBarrierPtr
  21. // ----------------------------------------------------------------------------
  22. // Type write barrier policy
  23. //
  24. // By default following potentially contains GC pointers and use write barrier policy:
  25. // pointer, WriteBarrierPtr, _write_barrier_policy
  26. //
  27. template <class T>
  28. struct TypeWriteBarrierPolicy { typedef _no_write_barrier_policy Policy; };
  29. template <class T>
  30. struct TypeWriteBarrierPolicy<T*> { typedef _write_barrier_policy Policy; };
  31. template <class T>
  32. struct TypeWriteBarrierPolicy<T* const> { typedef _write_barrier_policy Policy; };
  33. template <class T>
  34. struct TypeWriteBarrierPolicy<WriteBarrierPtr<T>> { typedef _write_barrier_policy Policy; };
  35. template <>
  36. struct TypeWriteBarrierPolicy<_write_barrier_policy> { typedef _write_barrier_policy Policy; };
  37. // AllocatorType write barrier policy
  38. //
  39. // Recycler allocator type => _write_barrier_policy
  40. // Note that Recycler allocator type consists of multiple allocators:
  41. // Recycler, RecyclerNonLeafAllocator, RecyclerLeafAllocator
  42. //
  43. template <class AllocatorType>
  44. struct _AllocatorTypeWriteBarrierPolicy { typedef _no_write_barrier_policy Policy; };
  45. template <>
  46. struct _AllocatorTypeWriteBarrierPolicy<Recycler> { typedef _write_barrier_policy Policy; };
  47. template <class Policy1, class Policy2>
  48. struct _AndWriteBarrierPolicy { typedef _no_write_barrier_policy Policy; };
  49. template <>
  50. struct _AndWriteBarrierPolicy<_write_barrier_policy, _write_barrier_policy>
  51. {
  52. typedef _write_barrier_policy Policy;
  53. };
  54. // Combine Allocator + Data => write barrier policy
  55. // Specialize RecyclerNonLeafAllocator
  56. //
  57. template <class Allocator, class T>
  58. struct AllocatorWriteBarrierPolicy
  59. {
  60. typedef typename AllocatorInfo<Allocator, void>::AllocatorType AllocatorType;
  61. typedef typename _AndWriteBarrierPolicy<
  62. typename _AllocatorTypeWriteBarrierPolicy<AllocatorType>::Policy,
  63. typename TypeWriteBarrierPolicy<T>::Policy>::Policy Policy;
  64. };
  65. template <class T>
  66. struct AllocatorWriteBarrierPolicy<RecyclerNonLeafAllocator, T> { typedef _write_barrier_policy Policy; };
  67. template <>
  68. struct AllocatorWriteBarrierPolicy<RecyclerNonLeafAllocator, int> { typedef _no_write_barrier_policy Policy; };
  69. // Choose write barrier Field type: T unchanged, or WriteBarrierPtr based on Policy.
  70. //
  71. template <class T, class Policy>
  72. struct _WriteBarrierFieldType { typedef T Type; };
  73. template <class T>
  74. struct _WriteBarrierFieldType<T*, _write_barrier_policy> { typedef WriteBarrierPtr<T> Type; };
  75. template <class T>
  76. struct _WriteBarrierFieldType<T* const, _write_barrier_policy> { typedef const WriteBarrierPtr<T> Type; };
  77. template <class T,
  78. class Allocator = Recycler,
  79. class Policy = typename AllocatorWriteBarrierPolicy<Allocator, T>::Policy>
  80. struct WriteBarrierFieldTypeTraits { typedef typename _WriteBarrierFieldType<T, Policy>::Type Type; };
  81. // ----------------------------------------------------------------------------
  82. // Array write barrier
  83. //
  84. // Determines if an array operation needs to trigger write barrier
  85. // ----------------------------------------------------------------------------
  86. // ArrayWriteBarrier behavior
  87. //
  88. typedef void FN_VerifyIsNotBarrierAddress(void*, size_t);
  89. extern "C" FN_VerifyIsNotBarrierAddress* g_verifyIsNotBarrierAddress;
  90. template <class Policy>
  91. struct _ArrayWriteBarrier
  92. {
  93. template <class T>
  94. static void WriteBarrier(T * address, size_t count)
  95. {
  96. #if defined(RECYCLER_WRITE_BARRIER)
  97. #if ENABLE_DEBUG_CONFIG_OPTIONS
  98. if (Js::Configuration::Global.flags.StrictWriteBarrierCheck)
  99. {
  100. if (g_verifyIsNotBarrierAddress)
  101. {
  102. g_verifyIsNotBarrierAddress(address, count);
  103. }
  104. }
  105. #endif
  106. #endif
  107. }
  108. template <class T>
  109. static void WriteBarrierSetVerifyBits(T * address, size_t count) { }
  110. };
  111. #ifdef RECYCLER_WRITE_BARRIER
  112. template <>
  113. struct _ArrayWriteBarrier<_write_barrier_policy>
  114. {
  115. template <class T>
  116. static void WriteBarrier(T * address, size_t count)
  117. {
  118. RecyclerWriteBarrierManager::WriteBarrier(address, sizeof(T) * count);
  119. }
  120. template <class T>
  121. static void WriteBarrierSetVerifyBits(T * address, size_t count)
  122. {
  123. #if DBG && GLOBAL_ENABLE_WRITE_BARRIER
  124. Recycler::WBSetBitRange((char*)address, (uint)(sizeof(T) * count / sizeof(void*)));
  125. #endif
  126. }
  127. };
  128. #endif
  129. // Determines array write barrier policy based on array item type.
  130. //
  131. // Note: If individual array item needs write barrier, we choose to use
  132. // WriteBarrierPtr with the item type. Thus we only specialize on
  133. // WriteBarrierPtr (and _write_barrier_policy if user wants to force write
  134. // barrier).
  135. //
  136. template <class T>
  137. struct _ArrayItemWriteBarrierPolicy
  138. { typedef _no_write_barrier_policy Policy; };
  139. template <class T>
  140. struct _ArrayItemWriteBarrierPolicy<WriteBarrierPtr<T>>
  141. { typedef _write_barrier_policy Policy; };
  142. template <>
  143. struct _ArrayItemWriteBarrierPolicy<_write_barrier_policy>
  144. { typedef _write_barrier_policy Policy; };
  145. template <class T, int N> // in case calling with type WriteBarrierPtr<void> [N]
  146. struct _ArrayItemWriteBarrierPolicy<WriteBarrierPtr<T>[N]>
  147. { typedef _write_barrier_policy Policy; };
  148. // Trigger write barrier on changing array content if element type determines
  149. // write barrier is needed. Ignore otherwise.
  150. //
  151. template <class T, class PolicyType = T, class Allocator = Recycler>
  152. void ArrayWriteBarrier(T * address, size_t count)
  153. {
  154. typedef typename _ArrayItemWriteBarrierPolicy<PolicyType>::Policy ItemPolicy;
  155. typedef typename AllocatorWriteBarrierPolicy<Allocator, ItemPolicy>::Policy Policy;
  156. return _ArrayWriteBarrier<Policy>::WriteBarrier(address, count);
  157. }
  158. template <class T, class PolicyType = T, class Allocator = Recycler>
  159. void ArrayWriteBarrierVerifyBits(T * address, size_t count)
  160. {
  161. typedef typename _ArrayItemWriteBarrierPolicy<PolicyType>::Policy ItemPolicy;
  162. typedef typename AllocatorWriteBarrierPolicy<Allocator, ItemPolicy>::Policy Policy;
  163. return _ArrayWriteBarrier<Policy>::WriteBarrierSetVerifyBits(address, count);
  164. }
  165. // Copy array content. Triggers write barrier on the dst array content if if
  166. // Allocator and element type determines write barrier is needed.
  167. //
  168. template <class T, class PolicyType = T, class Allocator = Recycler>
  169. void CopyArray(T* dst, size_t dstCount, const T* src, size_t srcCount)
  170. {
  171. ArrayWriteBarrierVerifyBits<T, PolicyType, Allocator>(dst, dstCount);
  172. js_memcpy_s(reinterpret_cast<void*>(dst), sizeof(T) * dstCount,
  173. reinterpret_cast<const void*>(src), sizeof(T) * srcCount);
  174. ArrayWriteBarrier<T, PolicyType, Allocator>(dst, dstCount);
  175. }
  176. template <class T, class PolicyType = T, class Allocator = Recycler>
  177. void CopyArray(WriteBarrierPtr<T>& dst, size_t dstCount,
  178. const WriteBarrierPtr<T>& src, size_t srcCount)
  179. {
  180. return CopyArray<T, PolicyType, Allocator>(
  181. static_cast<T*>(dst), dstCount, static_cast<const T*>(src), srcCount);
  182. }
  183. template <class T, class PolicyType = T, class Allocator = Recycler>
  184. void CopyArray(T* dst, size_t dstCount,
  185. const WriteBarrierPtr<T>& src, size_t srcCount)
  186. {
  187. return CopyArray<T, PolicyType, Allocator>(
  188. dst, dstCount, static_cast<const T*>(src), srcCount);
  189. }
  190. template <class T, class PolicyType = T, class Allocator = Recycler>
  191. void CopyArray(WriteBarrierPtr<T>& dst, size_t dstCount,
  192. const T* src, size_t srcCount)
  193. {
  194. return CopyArray<T, PolicyType, Allocator>(
  195. static_cast<T*>(dst), dstCount, src, srcCount);
  196. }
  197. // Copy pointer array to WriteBarrierPtr array
  198. //
  199. template <class T, class PolicyType = WriteBarrierPtr<T>, class Allocator = Recycler>
  200. void CopyArray(WriteBarrierPtr<T>* dst, size_t dstCount,
  201. T* const * src, size_t srcCount)
  202. {
  203. CompileAssert(sizeof(WriteBarrierPtr<T>) == sizeof(T*));
  204. return CopyArray<T*, PolicyType, Allocator>(
  205. reinterpret_cast<T**>(dst), dstCount, src, srcCount);
  206. }
  207. // Move Array content (memmove)
  208. //
  209. template <class T, class PolicyType = T, class Allocator = Recycler>
  210. void MoveArray(T* dst, const T* src, size_t count)
  211. {
  212. ArrayWriteBarrierVerifyBits<T, PolicyType, Allocator>(dst, count);
  213. memmove(reinterpret_cast<void*>(dst),
  214. reinterpret_cast<const void*>(src),
  215. sizeof(T) * count);
  216. ArrayWriteBarrier<T, PolicyType, Allocator>(dst, count);
  217. }
  218. template <class T>
  219. void ClearArray(T* dst, size_t count)
  220. {
  221. // assigning NULL don't need write barrier, just cast it and null it out
  222. memset(reinterpret_cast<void*>(dst), 0, sizeof(T) * count);
  223. }
  224. template <class T>
  225. void ClearArray(WriteBarrierPtr<T>& dst, size_t count)
  226. {
  227. ClearArray(static_cast<T*>(dst), count);
  228. }
  229. template <class T, size_t N>
  230. void ClearArray(T (&dst)[N])
  231. {
  232. ClearArray(dst, N);
  233. }
  234. template <typename T>
  235. class NoWriteBarrierField
  236. {
  237. public:
  238. NoWriteBarrierField() : value() {}
  239. explicit NoWriteBarrierField(T const& value) : value(value) {}
  240. // Getters
  241. operator T const&() const { return value; }
  242. operator T&() { return value; }
  243. T const* operator&() const { return &value; }
  244. T* operator&() { return &value; }
  245. // Setters
  246. NoWriteBarrierField& operator=(T const& value)
  247. {
  248. #if ENABLE_DEBUG_CONFIG_OPTIONS
  249. RecyclerWriteBarrierManager::VerifyIsNotBarrierAddress(this);
  250. #endif
  251. this->value = value;
  252. return *this;
  253. }
  254. private:
  255. T value;
  256. };
  257. template <typename T>
  258. class NoWriteBarrierPtr
  259. {
  260. public:
  261. NoWriteBarrierPtr() : value(nullptr) {}
  262. NoWriteBarrierPtr(T * value) : value(value) {}
  263. // Getters
  264. T * operator->() const { return this->value; }
  265. operator T* const & () const { return this->value; }
  266. T* const * operator&() const { return &value; }
  267. T** operator&() { return &value; }
  268. // Setters
  269. NoWriteBarrierPtr& operator=(T * value)
  270. {
  271. #if ENABLE_DEBUG_CONFIG_OPTIONS
  272. RecyclerWriteBarrierManager::VerifyIsNotBarrierAddress(this);
  273. #endif
  274. this->value = value;
  275. return *this;
  276. }
  277. private:
  278. T * value;
  279. };
  280. template <typename T>
  281. class WriteBarrierObjectConstructorTrigger
  282. {
  283. public:
  284. WriteBarrierObjectConstructorTrigger(T* object, Recycler* recycler):
  285. object((char*) object),
  286. recycler(recycler)
  287. {
  288. }
  289. ~WriteBarrierObjectConstructorTrigger()
  290. {
  291. // WriteBarrier-TODO: trigger write barrier if the GC is in concurrent mark state
  292. }
  293. operator T*()
  294. {
  295. return object;
  296. }
  297. private:
  298. T* object;
  299. Recycler* recycler;
  300. };
  301. template <typename T>
  302. class WriteBarrierPtr
  303. {
  304. public:
  305. WriteBarrierPtr() : ptr(nullptr) {}
  306. WriteBarrierPtr(const std::nullptr_t&) : ptr(nullptr) {}
  307. WriteBarrierPtr(T * ptr)
  308. {
  309. // WriteBarrier
  310. WriteBarrierSet(ptr);
  311. }
  312. WriteBarrierPtr(T * ptr, const _no_write_barrier_tag&)
  313. {
  314. NoWriteBarrierSet(ptr);
  315. }
  316. WriteBarrierPtr(WriteBarrierPtr<T>& other)
  317. {
  318. WriteBarrierSet(other.ptr);
  319. }
  320. WriteBarrierPtr(WriteBarrierPtr<T>&& other)
  321. {
  322. WriteBarrierSet(other.ptr);
  323. }
  324. // Getters
  325. T * operator->() const { return ptr; }
  326. operator T* const & () const { return ptr; }
  327. // Taking immutable address is ok
  328. //
  329. T* const * AddressOf() const
  330. {
  331. return &ptr;
  332. }
  333. // Taking mutable address is not allowed
  334. // Setters
  335. WriteBarrierPtr& operator=(T * ptr)
  336. {
  337. WriteBarrierSet(ptr);
  338. return *this;
  339. }
  340. WriteBarrierPtr& operator=(const std::nullptr_t& ptr)
  341. {
  342. NoWriteBarrierSet(ptr);
  343. return *this;
  344. }
  345. void NoWriteBarrierSet(T * ptr)
  346. {
  347. this->ptr = ptr;
  348. }
  349. void WriteBarrierSet(T * ptr)
  350. {
  351. #if DBG && GLOBAL_ENABLE_WRITE_BARRIER
  352. // set the verification bits before updating the reference so it's ready to verify while background marking hit the reference
  353. Recycler::WBSetBit((char*)this);
  354. #endif
  355. NoWriteBarrierSet(ptr);
  356. #ifdef RECYCLER_WRITE_BARRIER
  357. // set the barrier bit after updating the reference to prevent a race issue that background thread is resetting all the dirty pages
  358. RecyclerWriteBarrierManager::WriteBarrier(this);
  359. #endif
  360. }
  361. WriteBarrierPtr& operator=(WriteBarrierPtr const& other)
  362. {
  363. WriteBarrierSet(other.ptr);
  364. return *this;
  365. }
  366. WriteBarrierPtr& operator++() // prefix ++
  367. {
  368. #if DBG && GLOBAL_ENABLE_WRITE_BARRIER
  369. Recycler::WBSetBit((char*)this);
  370. #endif
  371. ++ptr;
  372. #ifdef RECYCLER_WRITE_BARRIER
  373. RecyclerWriteBarrierManager::WriteBarrier(this);
  374. #endif
  375. return *this;
  376. }
  377. WriteBarrierPtr operator++(int) // postfix ++
  378. {
  379. WriteBarrierPtr result(*this);
  380. ++(*this);
  381. return result;
  382. }
  383. WriteBarrierPtr& operator--() // prefix --
  384. {
  385. #if DBG && GLOBAL_ENABLE_WRITE_BARRIER
  386. Recycler::WBSetBit((char*)this);
  387. #endif
  388. --ptr;
  389. #ifdef RECYCLER_WRITE_BARRIER
  390. RecyclerWriteBarrierManager::WriteBarrier(this);
  391. #endif
  392. return *this;
  393. }
  394. WriteBarrierPtr operator--(int) // postfix --
  395. {
  396. WriteBarrierPtr result(*this);
  397. --(*this);
  398. return result;
  399. }
  400. private:
  401. T * ptr;
  402. };
  403. template <class T>
  404. struct _AddressOfType
  405. {
  406. typedef T ValueType;
  407. inline static const ValueType* AddressOf(const T& val) { return &val; }
  408. };
  409. template <class T>
  410. struct _AddressOfType< WriteBarrierPtr<T> >
  411. {
  412. typedef T* ValueType;
  413. inline static const ValueType* AddressOf(const WriteBarrierPtr<T>& val)
  414. {
  415. return val.AddressOf();
  416. }
  417. };
  418. template <class T>
  419. inline const typename _AddressOfType<T>::ValueType* AddressOf(const T& val)
  420. {
  421. return _AddressOfType<T>::AddressOf(val);
  422. }
  423. template <class T>
  424. inline T* const& PointerValue(T* const& ptr) { return ptr; }
  425. template <class T>
  426. inline T* const& PointerValue(const WriteBarrierPtr<T>& ptr) { return ptr; }
  427. // Unsafe NoWriteBarrierSet. Use only when necessary and you are sure skipping
  428. // write barrier is ok.
  429. //
  430. template <class T>
  431. inline void NoWriteBarrierSet(T*& dst, T* ptr) { dst = ptr; }
  432. template <class T>
  433. inline void NoWriteBarrierSet(WriteBarrierPtr<T>& dst, T* ptr)
  434. {
  435. dst.NoWriteBarrierSet(ptr);
  436. }
  437. template <class T>
  438. inline void NoWriteBarrierSet(WriteBarrierPtr<T>& dst, const WriteBarrierPtr<T>& ptr)
  439. {
  440. dst.NoWriteBarrierSet(ptr);
  441. }
  442. } // namespace Memory
  443. template<class T> inline
  444. const T& min(const T& a, const NoWriteBarrierField<T>& b) { return a < b ? a : b; }
  445. template<class T> inline
  446. const T& min(const NoWriteBarrierField<T>& a, const T& b) { return a < b ? a : b; }
  447. template<class T> inline
  448. const T& min(const NoWriteBarrierField<T>& a, const NoWriteBarrierField<T>& b) { return a < b ? a : b; }
  449. template<class T> inline
  450. const T& max(const NoWriteBarrierField<T>& a, const T& b) { return a > b ? a : b; }
  451. // TODO: Add this method back once we figure out why OACR is tripping on it
  452. template<class T> inline
  453. const T& max(const T& a, const NoWriteBarrierField<T>& b) { return a > b ? a : b; }
  454. template<class T> inline
  455. const T& max(const NoWriteBarrierField<T>& a, const NoWriteBarrierField<T>& b) { return a > b ? a : b; }
  456. // QuickSort Array content
  457. //
  458. template <class Policy>
  459. struct _QuickSortImpl
  460. {
  461. template<class T, class Comparer>
  462. static void Sort(T* arr, size_t count, const Comparer& comparer, void* context, size_t elementSize = sizeof(T))
  463. {
  464. #ifndef _WIN32
  465. JsUtil::QuickSort<Policy, char, Comparer>::Sort((char*)arr, count, elementSize, comparer, context);
  466. #else
  467. // by default use system qsort_s
  468. ::qsort_s(arr, count, elementSize, comparer, context);
  469. #endif
  470. }
  471. };
  472. #ifdef RECYCLER_WRITE_BARRIER
  473. template <>
  474. struct _QuickSortImpl<_write_barrier_policy>
  475. {
  476. template<class T, class Comparer>
  477. static void Sort(T* arr, size_t count, const Comparer& comparer, void* context,
  478. size_t _ = 1 /* QuickSortSwap does not memcpy when SWB policy is in place*/)
  479. {
  480. // Use custom implementation if policy needs write barrier
  481. JsUtil::QuickSort<_write_barrier_policy, T, Comparer>::Sort(arr, count, 1, comparer, context);
  482. }
  483. };
  484. #endif
  485. template<class T, class PolicyType = T, class Allocator = Recycler, class Comparer>
  486. void qsort_s(T* arr, size_t count, const Comparer& comparer, void* context)
  487. {
  488. typedef typename _ArrayItemWriteBarrierPolicy<PolicyType>::Policy ItemPolicy;
  489. typedef typename AllocatorWriteBarrierPolicy<Allocator, ItemPolicy>::Policy Policy;
  490. _QuickSortImpl<Policy>::Sort(arr, count, comparer, context);
  491. }
  492. #ifndef _WIN32
  493. // on xplat we use our custom qsort_s
  494. template<class T, class PolicyType = T, class Allocator = Recycler, class Comparer>
  495. void qsort_s(T* arr, size_t count, size_t size, const Comparer& comparer, void* context)
  496. {
  497. typedef typename _ArrayItemWriteBarrierPolicy<PolicyType>::Policy ItemPolicy;
  498. typedef typename AllocatorWriteBarrierPolicy<Allocator, ItemPolicy>::Policy Policy;
  499. _QuickSortImpl<Policy>::Sort(arr, count, comparer, context, size);
  500. }
  501. #endif
  502. template<class T, class Comparer>
  503. void qsort_s(WriteBarrierPtr<T>* _Base, size_t _NumOfElements, size_t _SizeOfElements,
  504. const Comparer& comparer, void* _Context)
  505. {
  506. CompileAssert(false); // Disallow this. Use an overload above.
  507. }
  508. // Disallow memcpy, memmove of WriteBarrierPtr
  509. template <typename T>
  510. void * __cdecl memmove(_Out_writes_bytes_all_opt_(_Size) WriteBarrierPtr<T> * _Dst, _In_reads_bytes_opt_(_Size) const void * _Src, _In_ size_t _Size)
  511. {
  512. CompileAssert(false);
  513. }
  514. template <typename T>
  515. void* __cdecl memcpy(WriteBarrierPtr<T> *dst, const void *src, size_t count)
  516. {
  517. CompileAssert(false);
  518. }
  519. template <typename T>
  520. errno_t __cdecl memcpy_s(WriteBarrierPtr<T> *dst, size_t dstSize, const void *src, size_t srcSize)
  521. {
  522. static_assert(false, "Use CopyArray instead");
  523. }
  524. template <typename T>
  525. void __stdcall js_memcpy_s(__bcount(sizeInBytes) WriteBarrierPtr<T> *dst, size_t sizeInBytes, __bcount(count) const void *src, size_t count)
  526. {
  527. static_assert(false, "Use CopyArray instead");
  528. }
  529. template <typename T>
  530. void * __cdecl memset(_Out_writes_bytes_all_(_Size) WriteBarrierPtr<T> * _Dst, _In_ int _Val, _In_ size_t _Size)
  531. {
  532. CompileAssert(false);
  533. }
  534. // This class abstract a pointer value with its last 2 bits set to avoid conservative GC tracking.
  535. template <class T>
  536. class TaggedPointer
  537. {
  538. public:
  539. operator T*() const { return GetPointerValue(); }
  540. bool operator!= (T* p) const { return GetPointerValue() != p; }
  541. bool operator== (T* p) const { return GetPointerValue() == p; }
  542. T* operator-> () const { return GetPointerValue(); }
  543. TaggedPointer<T>& operator= (T* inPtr)
  544. {
  545. SetPointerValue(inPtr);
  546. return (*this);
  547. }
  548. TaggedPointer(T* inPtr) : ptr(inPtr)
  549. {
  550. SetPointerValue(inPtr);
  551. }
  552. TaggedPointer() : ptr(NULL) {};
  553. private:
  554. T * GetPointerValue() const { return reinterpret_cast<T*>(reinterpret_cast<ULONG_PTR>(ptr) & ~3); }
  555. T * SetPointerValue(T* inPtr)
  556. {
  557. AssertMsg((reinterpret_cast<ULONG_PTR>(inPtr) & 3) == 0, "Invalid pointer value, 2 least significant bits must be zero");
  558. ptr = reinterpret_cast<T*>((reinterpret_cast<ULONG_PTR>(inPtr) | 3));
  559. return ptr;
  560. }
  561. FieldNoBarrier(T*) ptr;
  562. };