2
0

AuxPtrs.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. // Use fixed size structure to save pointers
  9. // AuxPtrsFix(16 bytes or 32 bytes) layout:
  10. // max count metadata(init'd type) pointers array
  11. // --------------------------------------------------------------------------------------------------
  12. // AuxPtr16 on x64 1 byte 1 bytes 8 bytes to hold up to 1 pointer
  13. // AuxPtr32 on x64 1 byte 3 bytes 24 bytes to hold up to 3 pointers
  14. // AuxPtr16 on x86 1 byte 3 bytes 12 bytes to hold up to 3 pointers
  15. // AuxPtr32 on x86 1 byte 6 bytes 24 bytes to hold up to 6 pointers
  16. template<typename FieldsEnum, uint8 size, uint8 _MaxCount = (size - 1) / (1 + sizeof(void*))>
  17. struct AuxPtrsFix
  18. {
  19. static const uint8 MaxCount;
  20. FieldWithBarrier(uint8) count; // always saving maxCount
  21. typename FieldWithBarrier(FieldsEnum) type[_MaxCount]; // save instantiated pointer enum
  22. FieldWithBarrier(void*) ptr[_MaxCount]; // save instantiated pointer address
  23. AuxPtrsFix();
  24. AuxPtrsFix(AuxPtrsFix<FieldsEnum, 16>* ptr16); // called when promoting from AuxPtrs16 to AuxPtrs32
  25. void* Get(FieldsEnum e);
  26. bool Set(FieldsEnum e, void* p);
  27. };
  28. template<typename FieldsEnum, uint8 size, uint8 _MaxCount>
  29. const uint8 AuxPtrsFix<FieldsEnum, size, _MaxCount>::MaxCount = _MaxCount;
  30. // Use flexible size structure to save pointers. when pointer count exceeds AuxPtrsFix<FieldsEnum, 32>::MaxCount,
  31. // it will promote to this structure to save the pointers
  32. // Layout:
  33. // count array of positions array of instantiated pointers
  34. // ----------------------------------------------------------------
  35. // 1 byte FieldsEnum::Max bytes dynamic array depending on how many pointers has been instantiated
  36. template<class T, typename FieldsEnum>
  37. struct AuxPtrs
  38. {
  39. typedef AuxPtrsFix<FieldsEnum, 16> AuxPtrs16;
  40. typedef AuxPtrsFix<FieldsEnum, 32> AuxPtrs32;
  41. typedef AuxPtrs<T, FieldsEnum> AuxPtrsT;
  42. FieldWithBarrier(uint8) count; // save instantiated pointers count
  43. FieldWithBarrier(uint8) capacity; // save number of pointers can be hold in current instance of AuxPtrs
  44. FieldWithBarrier(uint8) offsets[static_cast<int>(FieldsEnum::Max)]; // save position of each instantiated pointers, if not instantiate, it's invalid
  45. FieldWithBarrier(void*) ptrs[1]; // instantiated pointer addresses
  46. AuxPtrs(uint8 capacity, AuxPtrs32* ptr32); // called when promoting from AuxPtrs32 to AuxPtrs
  47. AuxPtrs(uint8 capacity, AuxPtrs* ptr); // called when expanding (i.e. promoting from AuxPtrs to bigger AuxPtrs)
  48. void* Get(FieldsEnum e);
  49. bool Set(FieldsEnum e, void* p);
  50. static void AllocAuxPtrFix(T* host, uint8 size);
  51. static void AllocAuxPtr(T* host, uint8 count);
  52. static void* GetAuxPtr(const T* host, FieldsEnum e);
  53. static void SetAuxPtr(T* host, FieldsEnum e, void* ptr);
  54. };
  55. template<typename FieldsEnum, uint8 size, uint8 _MaxCount>
  56. AuxPtrsFix<FieldsEnum, size, _MaxCount>::AuxPtrsFix()
  57. {
  58. static_assert(_MaxCount == AuxPtrsFix<FieldsEnum, 16>::MaxCount, "Should only be called on AuxPtrsFix<FieldsEnum, 16>");
  59. this->count = AuxPtrsFix<FieldsEnum, 16>::MaxCount;
  60. for (uint8 i = 0; i < count; i++)
  61. {
  62. this->type[i] = FieldsEnum::Invalid;
  63. }
  64. }
  65. template<typename FieldsEnum, uint8 size, uint8 _MaxCount>
  66. AuxPtrsFix<FieldsEnum, size, _MaxCount>::AuxPtrsFix(AuxPtrsFix<FieldsEnum, 16>* ptr16)
  67. {
  68. static_assert(_MaxCount == AuxPtrsFix<FieldsEnum, 32>::MaxCount, "Should only be called on AuxPtrsFix<FieldsEnum, 32>");
  69. this->count = AuxPtrsFix<FieldsEnum, 32>::MaxCount;
  70. for (uint8 i = 0; i < AuxPtrsFix<FieldsEnum, 16>::MaxCount; i++)
  71. {
  72. this->type[i] = ptr16->type[i];
  73. this->ptr[i] = ptr16->ptr[i];
  74. }
  75. for (uint8 i = AuxPtrsFix<FieldsEnum, 16>::MaxCount; i < count; i++)
  76. {
  77. this->type[i] = FieldsEnum::Invalid;
  78. }
  79. }
  80. template<typename FieldsEnum, uint8 size, uint8 _MaxCount>
  81. inline void* AuxPtrsFix<FieldsEnum, size, _MaxCount>::Get(FieldsEnum e)
  82. {
  83. Assert(count == _MaxCount);
  84. for (uint8 i = 0; i < _MaxCount; i++) // using _MaxCount instead of count so compiler can optimize in case _MaxCount is 1.
  85. {
  86. if ((FieldsEnum) type[i] == e)
  87. {
  88. return ptr[i];
  89. }
  90. }
  91. return nullptr;
  92. }
  93. template<typename FieldsEnum, uint8 size, uint8 _MaxCount>
  94. inline bool AuxPtrsFix<FieldsEnum, size, _MaxCount>::Set(FieldsEnum e, void* p)
  95. {
  96. Assert(count == _MaxCount);
  97. for (uint8 i = 0; i < _MaxCount; i++)
  98. {
  99. if ((FieldsEnum) type[i] == e || (FieldsEnum) type[i] == FieldsEnum::Invalid)
  100. {
  101. ptr[i] = p;
  102. type[i] = e;
  103. return true;
  104. }
  105. }
  106. return false;
  107. }
  108. template<class T, typename FieldsEnum>
  109. AuxPtrs<T, FieldsEnum>::AuxPtrs(uint8 capacity, AuxPtrs32* ptr32)
  110. {
  111. Assert(ptr32->count >= AuxPtrs32::MaxCount);
  112. this->count = ptr32->count;
  113. this->capacity = capacity;
  114. memset(offsets, (uint8)FieldsEnum::Invalid, (uint8)FieldsEnum::Max);
  115. for (uint8 i = 0; i < ptr32->count; i++)
  116. {
  117. offsets[(uint8)(FieldsEnum)ptr32->type[i]] = i;
  118. ptrs[i] = ptr32->ptr[i];
  119. }
  120. }
  121. template<class T, typename FieldsEnum>
  122. AuxPtrs<T, FieldsEnum>::AuxPtrs(uint8 capacity, AuxPtrs* ptr)
  123. {
  124. ArrayWriteBarrierVerifyBits(&this->ptrs, ptr->count);
  125. memcpy(this, ptr, offsetof(AuxPtrs, ptrs) + ptr->count * sizeof(void*));
  126. ArrayWriteBarrier(&this->ptrs, ptr->count);
  127. this->capacity = capacity;
  128. }
  129. template<class T, typename FieldsEnum>
  130. inline void* AuxPtrs<T, FieldsEnum>::Get(FieldsEnum e)
  131. {
  132. uint8 u = (uint8)e;
  133. return offsets[u] == (uint8)FieldsEnum::Invalid ? nullptr : (void*)ptrs[offsets[u]];
  134. }
  135. template<class T, typename FieldsEnum>
  136. inline bool AuxPtrs<T, FieldsEnum>::Set(FieldsEnum e, void* p)
  137. {
  138. uint8 u = (uint8)e;
  139. if (offsets[u] != (uint8)FieldsEnum::Invalid)
  140. {
  141. ptrs[offsets[u]] = p;
  142. return true;
  143. }
  144. else
  145. {
  146. if (count == capacity)
  147. {
  148. // need to expand
  149. return false;
  150. }
  151. else
  152. {
  153. offsets[u] = count++;
  154. ptrs[(uint8)offsets[u]] = p;
  155. return true;
  156. }
  157. }
  158. }
  159. template<class T, typename FieldsEnum>
  160. void AuxPtrs<T, FieldsEnum>::AllocAuxPtrFix(T* host, uint8 size)
  161. {
  162. Recycler* recycler = host->GetRecycler();
  163. Assert(recycler != nullptr);
  164. if (size == 16)
  165. {
  166. host->auxPtrs = (AuxPtrs<T, FieldsEnum>*)RecyclerNewWithBarrierStructZ(recycler, AuxPtrs16);
  167. }
  168. else if (size == 32)
  169. {
  170. host->auxPtrs = (AuxPtrs<T, FieldsEnum>*)RecyclerNewWithBarrierPlusZ(recycler, 0, AuxPtrs32, (AuxPtrs16*)(void*)host->auxPtrs);
  171. }
  172. else
  173. {
  174. Assert(false);
  175. }
  176. }
  177. template<class T, typename FieldsEnum>
  178. void AuxPtrs<T, FieldsEnum>::AllocAuxPtr(T* host, uint8 count)
  179. {
  180. Recycler* recycler = host->GetRecycler();
  181. Assert(recycler != nullptr);
  182. Assert(count >= AuxPtrs32::MaxCount);
  183. auto requestSize = sizeof(AuxPtrs<T, FieldsEnum>) + (count - 1)*sizeof(void*);
  184. auto allocSize = ::Math::Align<uint8>((uint8)requestSize, 16);
  185. auto capacity = (uint8)((allocSize - offsetof(AuxPtrsT, ptrs)) / sizeof(void*));
  186. if (host->auxPtrs->count != AuxPtrs32::MaxCount) // expanding
  187. {
  188. host->auxPtrs = RecyclerNewWithBarrierPlusZ(recycler, allocSize - sizeof(AuxPtrsT), AuxPtrsT, capacity, host->auxPtrs);
  189. }
  190. else // promoting from AuxPtrs32
  191. {
  192. host->auxPtrs = RecyclerNewWithBarrierPlusZ(recycler, allocSize - sizeof(AuxPtrsT), AuxPtrsT, capacity, (AuxPtrs32*)(void*)host->auxPtrs);
  193. }
  194. }
  195. template<class T, typename FieldsEnum>
  196. inline void* AuxPtrs<T, FieldsEnum>::GetAuxPtr(const T* host, FieldsEnum e)
  197. {
  198. auto tmpAuxPtrs = PointerValue(host->auxPtrs);
  199. if (tmpAuxPtrs->count == AuxPtrs16::MaxCount)
  200. {
  201. return ((AuxPtrs16*)(void*)tmpAuxPtrs)->Get(e);
  202. }
  203. if (tmpAuxPtrs->count == AuxPtrs32::MaxCount)
  204. {
  205. return ((AuxPtrs32*)(void*)tmpAuxPtrs)->Get(e);
  206. }
  207. return tmpAuxPtrs->Get(e);
  208. }
  209. template<class T, typename FieldsEnum>
  210. void AuxPtrs<T, FieldsEnum>::SetAuxPtr(T* host, FieldsEnum e, void* ptr)
  211. {
  212. if (host->auxPtrs == nullptr)
  213. {
  214. AuxPtrs<FunctionProxy, FieldsEnum>::AllocAuxPtrFix(host, 16);
  215. bool ret = ((AuxPtrs16*)(void*)host->auxPtrs)->Set(e, ptr);
  216. Assert(ret);
  217. return;
  218. }
  219. if (host->auxPtrs->count == AuxPtrs16::MaxCount)
  220. {
  221. bool ret = ((AuxPtrs16*)(void*)host->auxPtrs)->Set(e, ptr);
  222. if (ret)
  223. {
  224. return;
  225. }
  226. else
  227. {
  228. AuxPtrs<FunctionProxy, FieldsEnum>::AllocAuxPtrFix(host, 32);
  229. }
  230. }
  231. if (host->auxPtrs->count == AuxPtrs32::MaxCount)
  232. {
  233. bool ret = ((AuxPtrs32*)(void*)host->auxPtrs)->Set(e, ptr);
  234. if (ret)
  235. {
  236. return;
  237. }
  238. else
  239. {
  240. AuxPtrs<FunctionProxy, FieldsEnum>::AllocAuxPtr(host, AuxPtrs32::MaxCount + 1);
  241. }
  242. }
  243. bool ret = host->auxPtrs->Set(e, ptr);
  244. if (!ret)
  245. {
  246. AuxPtrs<FunctionProxy, FieldsEnum>::AllocAuxPtr(host, host->auxPtrs->count + 1);
  247. ret = host->auxPtrs->Set(e, ptr);
  248. Assert(ret);
  249. }
  250. }
  251. }