Allocator.h 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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. // Disable the warning about no matching operator delete found, we don't need those for the Arena and Recycler
  7. #pragma warning(disable:4291)
  8. // Page heap mode is supported currently only in the Recycler
  9. // Defining here so that other allocators can take advantage of this
  10. // in the future
  11. enum PageHeapMode : byte
  12. {
  13. PageHeapModeOff = 0, // No Page heap
  14. PageHeapModeBlockStart = 1, // Allocate the object at the beginning of the page
  15. PageHeapModeBlockEnd = 2 // Allocate the object at the end of the page
  16. };
  17. #if PROFILE_DICTIONARY
  18. #include "DictionaryStats.h"
  19. #endif
  20. #if DBG || defined(RECYCLER_FREE_MEM_FILL)
  21. #define DbgMemFill 0XFE
  22. #endif
  23. #ifdef RECYCLER_PAGE_HEAP
  24. #define PageHeapMemFill 0XF0
  25. #endif
  26. namespace Memory
  27. {
  28. template<typename> class WriteBarrierPtr;
  29. template<typename> class NoWriteBarrierPtr;
  30. #ifdef TRACK_ALLOC
  31. struct TrackAllocData
  32. {
  33. void Clear() { typeinfo = nullptr; plusSize = 0; count = 0; }
  34. bool IsEmpty() { return typeinfo == nullptr && plusSize == 0 && count == 0; }
  35. type_info const * GetTypeInfo() const { return typeinfo; }
  36. size_t GetPlusSize() const { return plusSize; }
  37. size_t GetCount() const { return count; }
  38. static TrackAllocData CreateTrackAllocData(type_info const& typeinfo, size_t size, size_t count, char const * const filename, DWORD line)
  39. {
  40. TrackAllocData data;
  41. data.typeinfo = &typeinfo;
  42. data.plusSize = size;
  43. data.count = count;
  44. data.filename = filename;
  45. data.line = line;
  46. return data;
  47. };
  48. type_info const * typeinfo;
  49. size_t plusSize;
  50. size_t count;
  51. char const * filename;
  52. DWORD line;
  53. };
  54. #define TRACK_ALLOC_INFO(alloc, T, AllocatorType, size, count) static_cast<AllocatorType *>((alloc)->TrackAllocInfo(TrackAllocData::CreateTrackAllocData(typeid(T), size, count, __FILE__, __LINE__)))
  55. #else
  56. #define TRACK_ALLOC_INFO(alloc, T, AllocatorType, size, count) static_cast<AllocatorType *>(alloc)
  57. #endif
  58. #ifdef HEAP_ENUMERATION_VALIDATION
  59. namespace Js {
  60. class DynamicObject;
  61. };
  62. extern void PostAllocationCallbackForHeapEnumValidation(const type_info&, Js::DynamicObject*);
  63. template <typename T>
  64. inline T* PostAllocationCallback(const type_info& objType, T *obj)
  65. {
  66. if (__is_base_of(Js::DynamicObject, T))
  67. {
  68. PostAllocationCallbackForHeapEnumValidation(objType, (Js::DynamicObject*)obj);
  69. }
  70. return obj;
  71. }
  72. #define VALIDATE_OBJECT(T, obj) (PostAllocationCallback(typeid(T), obj))
  73. #else
  74. #define VALIDATE_OBJECT(T, obj) obj
  75. #endif
  76. // Any allocator
  77. #define AllocatorNewBaseFuncPtr(AllocatorType, alloc, AllocFuncPtr, T, ...) VALIDATE_OBJECT(T, new (TRACK_ALLOC_INFO(static_cast<AllocatorType *>(alloc), T, AllocatorType, 0, (size_t)-1), AllocFuncPtr) T(__VA_ARGS__))
  78. #define AllocatorNewPlusBaseFuncPtr(AllocatorType, alloc, AllocFuncPtr, size, T, ...) VALIDATE_OBJECT(T, new (TRACK_ALLOC_INFO(static_cast<AllocatorType *>(alloc), T, AllocatorType, size, (size_t)-1), AllocFuncPtr, size) T(__VA_ARGS__))
  79. #define AllocatorNewArrayBaseFuncPtr(AllocatorType, alloc, AllocFuncPtr, T, count) AllocateArray<AllocatorType, T, false>(TRACK_ALLOC_INFO(alloc, T, AllocatorType, 0, count), AllocFuncPtr, count)
  80. #define AllocatorNewStructBaseFuncPtr(AllocatorType, alloc, AllocFuncPtr, T) new (TRACK_ALLOC_INFO(static_cast<AllocatorType *>(alloc), T, AllocatorType, 0, (size_t)-1),AllocFuncPtr) T
  81. #define AllocatorNewStructPlusBaseFuncPtr(AllocatorType, alloc, AllocFuncPtr, size, T) new (TRACK_ALLOC_INFO(static_cast<AllocatorType *>(alloc), T, AllocatorType, size, (size_t)-1), AllocFuncPtr, size) T
  82. #define AllocatorNewBase(AllocatorType, alloc, AllocFunc, T, ...) AllocatorNewBaseFuncPtr(AllocatorType, alloc, &AllocatorType::AllocFunc, T, __VA_ARGS__)
  83. #define AllocatorNewPlusBase(AllocatorType, alloc, AllocFunc, size, T, ...) AllocatorNewPlusBaseFuncPtr(AllocatorType, alloc, &AllocatorType::AllocFunc, size, T, __VA_ARGS__)
  84. #define AllocatorNewArrayBase(AllocatorType, alloc, AllocFunc, T, count) AllocatorNewArrayBaseFuncPtr(AllocatorType, alloc, &AllocatorType::AllocFunc, T, count)
  85. #define AllocatorNewStructBase(AllocatorType, alloc, AllocFunc, T) AllocatorNewStructBaseFuncPtr(AllocatorType, alloc, &AllocatorType::AllocFunc, T)
  86. #define AllocatorNewStructPlusBase(AllocatorType, alloc, AllocFunc, size, T) AllocatorNewStructPlusBaseFuncPtr(AllocatorType, alloc, &AllocatorType::AllocFunc, size, T)
  87. #define AllocatorNew(AllocatorType, alloc, T, ...) AllocatorNewBase(AllocatorType, alloc, Alloc, T, __VA_ARGS__)
  88. #define AllocatorNewLeaf(AllocatorType, alloc, T, ...) AllocatorNewBase(AllocatorType, alloc, AllocLeaf, T, __VA_ARGS__)
  89. #define AllocatorNewZ(AllocatorType, alloc, T, ...) AllocatorNewBase(AllocatorType, alloc, AllocZero, T, __VA_ARGS__)
  90. #define AllocatorNewLeafZ(AllocatorType, alloc, T, ...) AllocatorNewBase(AllocatorType, alloc, AllocLeafZero, T, __VA_ARGS__)
  91. #define AllocatorNewPlus(AllocatorType, alloc, size, T, ...) AllocatorNewPlusBase(AllocatorType, alloc, Alloc, size, T, __VA_ARGS__)
  92. #define AllocatorNewPlusLeaf(AllocatorType, alloc, size, T, ...) AllocatorNewPlusBase(AllocatorType, alloc, AllocLeaf, size, T, __VA_ARGS__)
  93. #define AllocatorNewPlusLeafZ(AllocatorType, alloc, size, T, ...) AllocatorNewPlusBase(AllocatorType, alloc, AllocLeafZero, size, T, __VA_ARGS__)
  94. #define AllocatorNewPlusZ(AllocatorType, alloc, size, T, ...) AllocatorNewPlusBase(AllocatorType, alloc, AllocZero, size, T, __VA_ARGS__)
  95. #define AllocatorNewStruct(AllocatorType, alloc, T) AllocatorNewStructBase(AllocatorType, alloc, Alloc, T)
  96. #define AllocatorNewStructZ(AllocatorType, alloc, T) AllocatorNewStructBase(AllocatorType, alloc, AllocZero, T)
  97. #define AllocatorNewStructLeaf(AllocatorType, alloc, T) AllocatorNewStructBase(AllocatorType, alloc, AllocLeaf, T)
  98. #define AllocatorNewStructLeafZ(AllocatorType, alloc, T) AllocatorNewStructBase(AllocatorType, alloc, AllocLeafZero, T)
  99. #define AllocatorNewStructPlus(AllocatorType, alloc, size, T) AllocatorNewStructPlusBase(AllocatorType, alloc, Alloc, size, T)
  100. #define AllocatorNewStructPlusZ(AllocatorType, alloc, size, T) AllocatorNewStructPlusBase(AllocatorType, alloc, AllocZero, size, T)
  101. #define AllocatorNewStructPlusLeaf(AllocatorType, alloc, size, T) AllocatorNewStructPlusBase(AllocatorType, alloc, AllocLeaf, size, T)
  102. #define AllocatorNewStructPlusLeafZ(AllocatorType, alloc, size, T) AllocatorNewStructPlusBase(AllocatorType, alloc, AllocLeafZero, size, T);
  103. #define AllocatorNewArray(AllocatorType, alloc, T, count) AllocatorNewArrayBase(AllocatorType, alloc, Alloc, T, count)
  104. #define AllocatorNewArrayLeaf(AllocatorType, alloc, T, count) AllocatorNewArrayBase(AllocatorType, alloc, AllocLeaf, T, count)
  105. #define AllocatorNewArrayZ(AllocatorType, alloc, T, count) AllocatorNewArrayBase(AllocatorType, alloc, AllocZero, T, count)
  106. #define AllocatorNewArrayLeafZ(AllocatorType, alloc, T, count) AllocatorNewArrayBase(AllocatorType, alloc, AllocLeafZero, T, count)
  107. #define AllocatorNewNoThrowBase(AllocatorType, alloc, AllocFunc, T, ...) new (TRACK_ALLOC_INFO(static_cast<AllocatorType *>(alloc), T, AllocatorType, 0, (size_t)-1), true, &AllocatorType::NoThrow ## AllocFunc) T(__VA_ARGS__)
  108. #define AllocatorNewNoThrowPlusBase(AllocatorType, alloc, AllocFunc, size, T, ...) new (TRACK_ALLOC_INFO(static_cast<AllocatorType *>(alloc), T, AllocatorType, size, (size_t)-1), true, &AllocatorType::NoThrow ## AllocFunc, size) T(__VA_ARGS__)
  109. #define AllocatorNewNoThrowArrayBase(AllocatorType, alloc, AllocFunc, T, count) AllocateArray<AllocatorType, T, true>(TRACK_ALLOC_INFO(alloc, T, AllocatorType, 0, count), &AllocatorType::NoThrow ## AllocFunc, count)
  110. #define AllocatorNewNoThrowStructBase(AllocatorType, alloc, AllocFunc, T) new (TRACK_ALLOC_INFO(static_cast<AllocatorType *>(alloc), T, AllocatorType, 0, (size_t)-1), true, &AllocatorType::NoThrow ## AllocFunc) T
  111. #define AllocatorNewNoThrowStructPlusBase(AllocatorType, alloc, AllocFunc, size, T) new (TRACK_ALLOC_INFO(static_cast<AllocatorType *>(alloc), T, AllocatorType, size, (size_t)-1), true, &AllocatorType::NoThrow ## AllocFunc, size) T
  112. #define AllocatorNewNoThrowPlusPrefixBase(AllocatorType, alloc, AllocFunc, size, T, ...) new (TRACK_ALLOC_INFO(static_cast<AllocatorType *>(alloc), T, AllocatorType, size, (size_t)-1), true, &AllocatorType::NoThrow ## AllocFunc, size, true) T(__VA_ARGS__)
  113. #define AllocatorNewNoThrow(AllocatorType, alloc, T, ...) AllocatorNewNoThrowBase(AllocatorType, alloc, Alloc, T, __VA_ARGS__)
  114. #define AllocatorNewNoThrowLeaf(AllocatorType, alloc, T, ...) AllocatorNewNoThrowBase(AllocatorType, alloc, AllocLeaf, T, __VA_ARGS__)
  115. #define AllocatorNewNoThrowZ(AllocatorType, alloc, T, ...) AllocatorNewNoThrowBase(AllocatorType, alloc, AllocZero, T, __VA_ARGS__)
  116. #define AllocatorNewNoThrowLeafZ(AllocatorType, alloc, T, ...) AllocatorNewNoThrowBase(AllocatorType, alloc, AllocLeafZero, T, __VA_ARGS__)
  117. #define AllocatorNewNoThrowPlus(AllocatorType, alloc, size, T, ...) AllocatorNewNoThrowPlusBase(AllocatorType, alloc, Alloc, size, T, __VA_ARGS__)
  118. #define AllocatorNewNoThrowPlusZ(AllocatorType, alloc, size, T, ...) AllocatorNewNoThrowPlusBase(AllocatorType, alloc, AllocZero, size, T, __VA_ARGS__)
  119. #define AllocatorNewNoThrowPlusPrefixZ(AllocatorType, alloc, size, T, ...) AllocatorNewNoThrowPlusPrefixBase(AllocatorType, alloc, AllocZero, size, T, __VA_ARGS__)
  120. #define AllocatorNewNoThrowStruct(AllocatorType, alloc, T) AllocatorNewNoThrowStructBase(AllocatorType, alloc, Alloc, T)
  121. #define AllocatorNewNoThrowStructZ(AllocatorType, alloc, T) AllocatorNewNoThrowStructBase(AllocatorType, alloc, AllocZero, T)
  122. #define AllocatorNewNoThrowStructPlus(AllocatorType, alloc, size, T) AllocatorNewNoThrowStructPlusBase(AllocatorType, alloc, Alloc, size, T)
  123. #define AllocatorNewNoThrowStructPlusZ(AllocatorType, alloc, size, T) AllocatorNewNoThrowStructPlusBase(AllocatorType, alloc, AllocZero, size, T)
  124. #define AllocatorNewNoThrowStructPlusLeaf(AllocatorType, alloc, size, T) AllocatorNewNoThrowStructPlusBase(AllocatorType, alloc, AllocLeaf, size, T)
  125. #define AllocatorNewNoThrowStructPlusLeafZ(AllocatorType, alloc, size, T) AllocatorNewNoThrowStructPlusBase(AllocatorType, alloc, AllocLeafZero, size, T);
  126. #define AllocatorNewNoThrowArray(AllocatorType, alloc, T, count) AllocatorNewNoThrowArrayBase(AllocatorType, alloc, Alloc, T, count)
  127. #define AllocatorNewNoThrowArrayLeaf(AllocatorType, alloc, T, count) AllocatorNewNoThrowArrayBase(AllocatorType, alloc, AllocLeaf, T, count)
  128. #define AllocatorNewNoThrowArrayZ(AllocatorType, alloc, T, count) AllocatorNewNoThrowArrayBase(AllocatorType, alloc, AllocZero, T, count)
  129. #define AllocatorNewNoThrowNoRecoveryArrayBase(AllocatorType, alloc, AllocFunc, T, count) AllocateArray<AllocatorType, T, true>(TRACK_ALLOC_INFO(alloc, T, AllocatorType, 0, count), &AllocatorType::NoThrowNoRecovery ## AllocFunc, count)
  130. #define AllocatorNewNoThrowNoRecoveryPlusBase(AllocatorType, alloc, AllocFunc, size, T, ...) new (TRACK_ALLOC_INFO(static_cast<AllocatorType *>(alloc), T, AllocatorType, size, (size_t)-1), true, &AllocatorType::NoThrowNoRecovery ## AllocFunc, size) T(__VA_ARGS__)
  131. #define AllocatorNewNoThrowNoRecoveryArrayZ(AllocatorType, alloc, T, count) AllocatorNewNoThrowNoRecoveryArrayBase(AllocatorType, alloc, AllocZero, T, count)
  132. #define AllocatorNewNoThrowNoRecoveryPlus(AllocatorType, alloc, size, T, ...) AllocatorNewNoThrowNoRecoveryPlusBase(AllocatorType, alloc, Alloc, size, T, __VA_ARGS__)
  133. // A few versions below supplies optional flags through ..., used by HeapDelete.
  134. #define AllocatorDelete(AllocatorType, alloc, obj, ...) \
  135. DeleteObject<AllocatorType, ##__VA_ARGS__>(alloc, obj)
  136. #define AllocatorDeleteInline(AllocatorType, alloc, obj) \
  137. DeleteObjectInline<AllocatorType>(alloc, obj)
  138. #define AllocatorDeleteLeaf(TAllocator, alloc, obj) \
  139. DeleteObject<ForceLeafAllocator<TAllocator>::AllocatorType>(alloc, obj)
  140. #define AllocatorDeletePlus(AllocatorType, alloc, size, obj, ...) \
  141. DeleteObject<AllocatorType, ##__VA_ARGS__>(alloc, obj, size);
  142. #define AllocatorDeletePlusLeaf(TAllocator, alloc, size, obj) \
  143. DeleteObject<ForceLeafAllocator<TAllocator>::AllocatorType>(alloc, obj, size);
  144. #define AllocatorDeletePlusPrefix(AllocatorType, alloc, size, obj, ...) \
  145. DeleteObject<AllocatorType, ##__VA_ARGS__>(alloc, obj, size, true);
  146. #define AllocatorDeletePlusPrefixLeaf(TAllocator, alloc, size, obj) \
  147. DeleteObject<ForceLeafAllocator<TAllocator>::AllocatorType>(alloc, obj, size, true);
  148. #define AllocatorDeleteArray(AllocatorType, alloc, count, obj) \
  149. DeleteArray<AllocatorType>(alloc, count, obj)
  150. #define AllocatorDeleteArrayLeaf(TAllocator, alloc, count, obj) \
  151. DeleteArray<ForceLeafAllocator<TAllocator>::AllocatorType>(alloc, count, obj)
  152. // Free routine where we don't care about following C++ semantics (e.g. calling the destructor)
  153. #define AllocatorFree(alloc, freeFunc, obj, size) \
  154. (alloc->*freeFunc)(obj, size)
  155. // default type allocator implementation
  156. template <typename TAllocator, typename T>
  157. class TypeAllocatorFunc
  158. {
  159. public:
  160. typedef char * (TAllocator::*AllocFuncType)(size_t);
  161. typedef void(TAllocator::*FreeFuncType)(void*, size_t);
  162. static AllocFuncType GetAllocFunc()
  163. {
  164. return &TAllocator::Alloc;
  165. }
  166. static AllocFuncType GetAllocZeroFunc()
  167. {
  168. return &TAllocator::AllocZero;
  169. }
  170. static FreeFuncType GetFreeFunc()
  171. {
  172. return &TAllocator::Free;
  173. }
  174. };
  175. // List specific allocator info
  176. template <typename TAllocator, bool isLeaf>
  177. class ListTypeAllocatorFunc
  178. {
  179. public:
  180. typedef TAllocator EffectiveAllocatorType; // used by write barrier type traits
  181. typedef char * (TAllocator::*AllocFuncType)(size_t);
  182. typedef void(TAllocator::*FreeFuncType)(void*, size_t);
  183. static AllocFuncType GetAllocFunc()
  184. {
  185. return isLeaf ? &TAllocator::AllocLeaf: &TAllocator::Alloc;
  186. }
  187. static FreeFuncType GetFreeFunc()
  188. {
  189. return &TAllocator::Free;
  190. }
  191. };
  192. // Default allocation policy
  193. template <typename TAllocator, typename TAllocType>
  194. struct AllocatorInfo
  195. {
  196. typedef TAllocator AllocatorType;
  197. typedef TAllocator TemplateAllocatorType;
  198. typedef TypeAllocatorFunc<TAllocator, TAllocType> AllocatorFunc; // allocate/free an array of given type
  199. typedef TypeAllocatorFunc<TAllocator, TAllocType> InstAllocatorFunc;// allocate/free an object instance itself of given type
  200. };
  201. // Allocator doesn't change for by default for forcing non leaf
  202. template <typename TAllocator>
  203. struct ForceNonLeafAllocator
  204. {
  205. static const bool FakeZeroLengthArray = true;
  206. typedef TAllocator AllocatorType;
  207. };
  208. // Allocator doesn't change for by default for forcing leaf
  209. template <typename TAllocator>
  210. struct ForceLeafAllocator
  211. {
  212. typedef TAllocator AllocatorType;
  213. static const bool FakeZeroLengthArray = true;
  214. };
  215. // Optional AllocatorDelete flags
  216. enum class AllocatorDeleteFlags
  217. {
  218. None,
  219. UnknownSize, // used to bypass size check
  220. };
  221. template <typename T, AllocatorDeleteFlags deleteFlags>
  222. struct _AllocatorDelete
  223. {
  224. static size_t Size() { return sizeof(T); }
  225. static size_t Size(size_t plusSize) { return sizeof(T) + plusSize; }
  226. };
  227. template <typename T>
  228. struct _AllocatorDelete<T, AllocatorDeleteFlags::UnknownSize>
  229. {
  230. static size_t Size() { return (size_t)-1; }
  231. static size_t Size(size_t plusSize) { return (size_t)-1; }
  232. };
  233. template <typename TAllocator,
  234. AllocatorDeleteFlags deleteFlags = AllocatorDeleteFlags::None,
  235. typename T>
  236. void DeleteObject(typename AllocatorInfo<TAllocator, T>::AllocatorType * allocator, T * obj)
  237. {
  238. obj->~T();
  239. auto freeFunc = AllocatorInfo<TAllocator, T>::InstAllocatorFunc::GetFreeFunc(); // Use InstAllocatorFunc
  240. (allocator->*freeFunc)(
  241. (void*)obj, _AllocatorDelete<T, deleteFlags>::Size());
  242. }
  243. template <typename TAllocator,
  244. AllocatorDeleteFlags deleteFlags = AllocatorDeleteFlags::None,
  245. typename T>
  246. void DeleteObject(typename AllocatorInfo<TAllocator, T>::AllocatorType * allocator, WriteBarrierPtr<T> obj)
  247. {
  248. DeleteObject<TAllocator, deleteFlags>(allocator, PointerValue(obj));
  249. }
  250. template <typename TAllocator, typename T>
  251. void DeleteObjectInline(TAllocator * allocator, T * obj)
  252. {
  253. obj->~T();
  254. allocator->FreeInline(obj, sizeof(T));
  255. }
  256. template <typename TAllocator,
  257. AllocatorDeleteFlags deleteFlags = AllocatorDeleteFlags::None,
  258. typename T>
  259. void DeleteObject(typename AllocatorInfo<TAllocator, T>::AllocatorType * allocator, T * obj, size_t plusSize)
  260. {
  261. obj->~T();
  262. // DeleteObject can only be called when an object is allocated successfully.
  263. // So the add should never overflow
  264. Assert(sizeof(T) + plusSize >= sizeof(T));
  265. auto freeFunc = AllocatorInfo<TAllocator, T>::InstAllocatorFunc::GetFreeFunc(); // Use InstAllocatorFunc
  266. (allocator->*freeFunc)(
  267. (void*)obj, _AllocatorDelete<T, deleteFlags>::Size(plusSize));
  268. }
  269. template <typename TAllocator,
  270. AllocatorDeleteFlags deleteFlags = AllocatorDeleteFlags::None,
  271. typename T>
  272. void DeleteObject(typename AllocatorInfo<TAllocator, T>::AllocatorType * allocator, T * obj, size_t plusSize, bool prefix)
  273. {
  274. Assert(prefix);
  275. obj->~T();
  276. // DeleteObject can only be called when an object is allocated successfully.
  277. // So the add should never overflow
  278. Assert(sizeof(T) + plusSize >= sizeof(T));
  279. // NOTE: This may cause the object not be double aligned
  280. Assert(plusSize == Math::Align<size_t>(plusSize, sizeof(size_t)));
  281. auto freeFunc = AllocatorInfo<TAllocator, T>::InstAllocatorFunc::GetFreeFunc(); // Use InstAllocatorFunc
  282. (allocator->*freeFunc)(((char *)obj) - plusSize,
  283. _AllocatorDelete<T, deleteFlags>::Size(plusSize));
  284. }
  285. #define ZERO_LENGTH_ARRAY (void *)sizeof(void *)
  286. template <typename TAllocator, typename T, bool nothrow>
  287. _When_(nothrow, _Ret_writes_to_maybenull_(count, 0)) _When_(!nothrow, _Ret_writes_to_(count, 0))
  288. inline T * AllocateArray(TAllocator * allocator, char * (TAllocator::*AllocFunc)(size_t), DECLSPEC_GUARD_OVERFLOW size_t count)
  289. {
  290. if (count == 0 && TAllocator::FakeZeroLengthArray)
  291. {
  292. #ifdef TRACK_ALLOC
  293. allocator->ClearTrackAllocInfo();
  294. #endif
  295. // C++ standard requires allocator to return non-null if it isn't out of memory
  296. // Just return some small number so we will still AV if someone try to use the memory
  297. return (T *)ZERO_LENGTH_ARRAY;
  298. }
  299. if (nothrow)
  300. {
  301. return new (allocator, nothrow, AllocFunc) T[count];
  302. }
  303. return new (allocator, AllocFunc) T[count];
  304. }
  305. // Skip item destructor loop on some trivial types. The loop is likely to be
  306. // optimized away in release build. Skipping it improves debug build.
  307. //
  308. struct _true_value { static const bool value = true; };
  309. struct _false_value { static const bool value = false; };
  310. template <typename T> struct _has_trivial_destructor : _false_value {};
  311. template <typename T> struct _has_trivial_destructor<T*> : _true_value {};
  312. template <> struct _has_trivial_destructor<char> : _true_value {};
  313. template <> struct _has_trivial_destructor<const char> : _true_value {};
  314. template <> struct _has_trivial_destructor<unsigned char> : _true_value {};
  315. template <> struct _has_trivial_destructor<char16> : _true_value {};
  316. template <> struct _has_trivial_destructor<const char16> : _true_value {};
  317. template <> struct _has_trivial_destructor<int> : _true_value {};
  318. template <bool trivial_destructor>
  319. struct _DestructArray
  320. {
  321. template <typename T>
  322. static void Destruct(size_t count, T* obj)
  323. {
  324. for (size_t i = 0; i < count; i++)
  325. {
  326. obj[i].~T();
  327. }
  328. }
  329. };
  330. template <>
  331. struct _DestructArray</*trivial_destructor*/true>
  332. {
  333. template <typename T>
  334. static void Destruct(size_t count, T* obj) {}
  335. };
  336. template <typename T>
  337. void DestructArray(size_t count, T* obj)
  338. {
  339. _DestructArray<_has_trivial_destructor<T>::value>::Destruct(count, obj);
  340. }
  341. template <typename TAllocator, typename T>
  342. void DeleteArray(typename AllocatorInfo<TAllocator, T>::AllocatorType * allocator, size_t count, T * obj)
  343. {
  344. if (count == 0 && AllocatorInfo<TAllocator, T>::AllocatorType::FakeZeroLengthArray)
  345. {
  346. return;
  347. }
  348. if (count != 0)
  349. {
  350. DestructArray(count, obj);
  351. // DeleteArray can only be called when an array is allocated successfully.
  352. // So the add should never overflow
  353. Assert(count * sizeof(T) / count == sizeof(T));
  354. }
  355. auto freeFunc = AllocatorInfo<TAllocator, T>::AllocatorFunc::GetFreeFunc();
  356. (allocator->*freeFunc)((void *)obj, sizeof(T) * count);
  357. }
  358. #define AllocatorFieldMove(dest, src, field) \
  359. Assert(dest->field == 0); \
  360. dest->field = src->field; \
  361. src->field = 0;
  362. class Allocator
  363. {
  364. public:
  365. Allocator(void (*outOfMemoryFunc)(), void (*recoverMemoryFunc)() = JsUtil::ExternalApi::RecoverUnusedMemory) : outOfMemoryFunc(outOfMemoryFunc), recoverMemoryFunc(recoverMemoryFunc) {}
  366. void Move(Allocator *srcAllocator)
  367. {
  368. Assert(srcAllocator != nullptr);
  369. AllocatorFieldMove(this, srcAllocator, outOfMemoryFunc);
  370. }
  371. void (*outOfMemoryFunc)();
  372. void (*recoverMemoryFunc)();
  373. };
  374. template <typename T>
  375. void AssertValue(void * mem, T value, uint byteCount)
  376. {
  377. #if DBG
  378. Assert(byteCount % sizeof(T) == 0);
  379. for (uint i = 0; i < byteCount; i += sizeof(T))
  380. {
  381. Assert(*(T *)(((char *)mem) + i) == value);
  382. }
  383. #endif
  384. }
  385. }
  386. #ifndef _WIN32
  387. #define NO_EXPORT(x) \
  388. __attribute__((visibility("hidden"))) \
  389. x
  390. #else
  391. #define NO_EXPORT(x) x
  392. #endif
  393. // For the debugger extension, we don't need the placement news
  394. #ifndef __PLACEMENT_NEW_INLINE
  395. #define __PLACEMENT_NEW_INLINE
  396. _Ret_notnull_
  397. NO_EXPORT(inline void *) __cdecl
  398. operator new(
  399. DECLSPEC_GUARD_OVERFLOW size_t byteSize,
  400. _In_ void * previousAllocation) throw()
  401. {
  402. return previousAllocation;
  403. }
  404. NO_EXPORT(inline void) __cdecl
  405. operator delete(
  406. void * allocationToFree, // Allocation to free
  407. void * previousAllocation // Previously allocated memory
  408. ) throw()
  409. {
  410. }
  411. #endif
  412. //----------------------------------------
  413. // throwing operator new overrides
  414. //----------------------------------------
  415. template <typename TAllocator>
  416. _Ret_notnull_
  417. NO_EXPORT(void *) __cdecl
  418. operator new(DECLSPEC_GUARD_OVERFLOW size_t byteSize, TAllocator * alloc, char * (TAllocator::*AllocFunc)(size_t))
  419. {
  420. AssertCanHandleOutOfMemory();
  421. Assert(byteSize != 0);
  422. void * buffer = (alloc->*AllocFunc)(byteSize);
  423. Assume(buffer != nullptr);
  424. return buffer;
  425. }
  426. template <typename TAllocator>
  427. _Ret_notnull_
  428. NO_EXPORT(inline void *) __cdecl
  429. operator new[](DECLSPEC_GUARD_OVERFLOW size_t byteSize, TAllocator * alloc, char * (TAllocator::*AllocFunc)(size_t))
  430. {
  431. AssertCanHandleOutOfMemory();
  432. Assert(byteSize != 0 || !TAllocator::FakeZeroLengthArray);
  433. void * buffer = (alloc->*AllocFunc)(byteSize);
  434. Assume(buffer != nullptr);
  435. return buffer;
  436. }
  437. template <typename TAllocator>
  438. _Ret_notnull_
  439. NO_EXPORT(inline void *) __cdecl
  440. operator new(DECLSPEC_GUARD_OVERFLOW size_t byteSize, TAllocator * alloc, char * (TAllocator::*AllocFunc)(size_t), DECLSPEC_GUARD_OVERFLOW size_t plusSize)
  441. {
  442. AssertCanHandleOutOfMemory();
  443. Assert(byteSize != 0);
  444. //Assert(plusSize != 0);
  445. // byteSize is usually a compile-time constant, so put it on the RHS of the add for
  446. // slightly better (smaller and faster) code.
  447. void * buffer = (alloc->*AllocFunc)(AllocSizeMath::Add(plusSize, byteSize));
  448. Assume(buffer != nullptr);
  449. return buffer;
  450. }
  451. //----------------------------------------
  452. // nothrow operator new overrides
  453. //----------------------------------------
  454. template <typename TAllocator>
  455. _Ret_maybenull_
  456. NO_EXPORT(inline void *) __cdecl
  457. operator new(DECLSPEC_GUARD_OVERFLOW size_t byteSize, TAllocator * alloc, bool nothrow, char * (TAllocator::*AllocFunc)(size_t))
  458. {
  459. Assert(nothrow);
  460. Assert(byteSize != 0);
  461. void * buffer = (alloc->*AllocFunc)(byteSize);
  462. return buffer;
  463. }
  464. template <typename TAllocator>
  465. _Ret_maybenull_
  466. NO_EXPORT(inline void *) __cdecl
  467. operator new[](DECLSPEC_GUARD_OVERFLOW size_t byteSize, TAllocator * alloc, bool nothrow, char * (TAllocator::*AllocFunc)(size_t))
  468. {
  469. Assert(nothrow);
  470. Assert(byteSize != 0 || !TAllocator::FakeZeroLengthArray);
  471. void * buffer = (alloc->*AllocFunc)(byteSize);
  472. return buffer;
  473. }
  474. template <typename TAllocator>
  475. _Ret_maybenull_
  476. NO_EXPORT(inline void *) __cdecl
  477. operator new(DECLSPEC_GUARD_OVERFLOW size_t byteSize, TAllocator * alloc, bool nothrow, char * (TAllocator::*AllocFunc)(size_t), DECLSPEC_GUARD_OVERFLOW size_t plusSize)
  478. {
  479. Assert(nothrow);
  480. Assert(byteSize != 0);
  481. //Assert(plusSize != 0);
  482. // byteSize is usually a compile-time constant, so put it on the RHS of the add for
  483. // slightly better (smaller and faster) code.
  484. void * buffer = (alloc->*AllocFunc)(AllocSizeMath::Add(plusSize, byteSize));
  485. return buffer;
  486. }
  487. template <typename TAllocator>
  488. _Ret_maybenull_
  489. NO_EXPORT(inline void *) __cdecl
  490. operator new(DECLSPEC_GUARD_OVERFLOW size_t byteSize, TAllocator * alloc, bool nothrow, char * (TAllocator::*AllocFunc)(size_t), DECLSPEC_GUARD_OVERFLOW size_t plusSize, bool prefix)
  491. {
  492. Assert(nothrow);
  493. Assert(prefix);
  494. Assert(byteSize != 0);
  495. Assert(plusSize != 0);
  496. // NOTE: This may cause the object not be double aligned
  497. Assert(plusSize == Math::Align<size_t>(plusSize, sizeof(size_t)));
  498. // byteSize is usually a compile-time constant, so put it on the RHS of the add for
  499. // slightly better (smaller and faster) code.
  500. char * buffer = (alloc->*AllocFunc)(AllocSizeMath::Add(plusSize, byteSize));
  501. // This seems to generate the most compact code
  502. return buffer + ((uintptr_t)buffer > 0 ? plusSize : (size_t)buffer);
  503. }