hkThreadMemory.h
上传用户:yisoukefu
上传日期:2020-08-09
资源大小:39506k
文件大小:19k
源码类别:

其他游戏

开发平台:

Visual C++

  1. /* 
  2.  * 
  3.  * Confidential Information of Telekinesys Research Limited (t/a Havok). Not for disclosure or distribution without Havok's
  4.  * prior written consent. This software contains code, techniques and know-how which is confidential and proprietary to Havok.
  5.  * Level 2 and Level 3 source code contains trade secrets of Havok. Havok Software (C) Copyright 1999-2009 Telekinesys Research Limited t/a Havok. All Rights Reserved. Use of this software is subject to the terms of an end user license agreement.
  6.  * 
  7.  */
  8. #ifndef HKBASE_hkThreadMemory_H
  9. #define HKBASE_hkThreadMemory_H
  10. #include <Common/Base/Config/hkConfigThread.h>
  11. #include <Common/Base/Thread/Thread/hkThreadLocalData.h>
  12. #include <Common/Base/Memory/MemoryClasses/hkMemoryClassDefinitions.h>
  13. class hkMemory;
  14. // This allocator forwards to hkSystemMalloc
  15. #if !defined(HK_PLATFORM_PS3_SPU)
  16. extern void* (HK_CALL *hkSystemMalloc)(int size, int align);
  17. extern void (HK_CALL *hkSystemFree) (void* p);
  18. #define HK_DECLARE_SYSTEM_ALLOCATOR() 
  19. HK_FORCE_INLINE void* HK_CALL operator new(hk_size_t nbytes) { return hkSystemMalloc(int(hkUlong(nbytes)),16); }
  20. HK_FORCE_INLINE void  HK_CALL operator delete(void* p) { hkSystemFree(p); }
  21. HK_FORCE_INLINE void* HK_CALL operator new(hk_size_t, void* p) { return p; }
  22. HK_FORCE_INLINE void  HK_CALL operator delete(void*, void*) { }
  23. class MustEndWithSemiColon
  24. # define HK_VIRTUAL virtual
  25. #else // SPU
  26. # define HK_DECLARE_SYSTEM_ALLOCATOR()
  27. # define virtual
  28. #endif
  29. /// All memory allocations per thread are handled by this class.
  30. /// All memory allocations are shared between the threads, that means a block
  31. /// which is allocated by one hkThreadMemory can be freed by another.
  32. /// hkThreadMemory forwards requests to the hkMemory singleton.<br>
  33. ///
  34. /// Notes:
  35. ///    - It is highly optimized for handling memory for a single thread. It
  36. ///      is doing so by caching a limited number of blocks in a thread local
  37. ///      free list. There is a several free lists for different sizes of blocks.
  38. ///    - Each free list (for each size) can hold only a maximum number of items (m_maxNumElemsOnFreeList)
  39. ///    - If maxNumElemsOnFreeList==0 than the free list is not checked at all and the hkThreadMemory
  40. ///  calls the appropriate hkMemory::getInstance() functions
  41. ///    - If for a given size, there is no free block on the free list, some blocks are fetched by calling
  42. ///      hkMemory::getInstance().allocateBatch()
  43. ///    - If a block is freed, it is assumed that this block was allocated by this memory manager, its
  44. ///      corresponding free list is found (by rounding up the size of the block to the next suitable
  45. ///      block size) and the block added to the free list.
  46. ///  If the number of elements on this particular free list is exceeding m_maxNumElemsOnFreeList, some
  47. ///      blocks are forwarded to the hkMemory::getInstance().deallocateBatch()
  48. /// Notes
  49. /// - all allocations greater than 8 bytes should be 16 byte aligned.
  50. /// - Allocations of 8 bytes or less should be aligned to 8 bytes.
  51. ///     - Only if you use this class with the pool memory, you are allowed to set maxNumElemsOnFreeList != 0
  52. ///     - This class cannot be replaced like the hkMemory(), but can be disabled.
  53. class hkThreadMemory
  54. {
  55. public:
  56. HK_DECLARE_SYSTEM_ALLOCATOR();
  57. /// Creates a new instance of a thread memory. Initialise the reference count to 1.
  58. hkThreadMemory( hkMemory* mainMemoryManager );
  59. /// Allocates a fixed size piece of memory, aligned to 16 bytes.
  60. /// Allocations of 8 bytes or less are aligned to 8 bytes.
  61. /// Note that the size is not stored and must be supplied when deallocating.
  62. void* allocateChunk( int nbytes, HK_MEMORY_CLASS cl );
  63. /// Deallocates a piece of memory that has been allocated by allocateChunk
  64. void deallocateChunk(void*, int nbytes, HK_MEMORY_CLASS );
  65. /// Allocate nbytes bytes, aligned to 16 bytes.
  66. /// Allocations of 8 bytes or less are aligned to 8 bytes.
  67. /// Memory classes are defined in 'hkbase/memory/hkMemoryClass.h'.
  68. void* allocate( int nbytes, HK_MEMORY_CLASS cl );
  69. /// Deallocates a piece of memory.
  70. void deallocate(void*);
  71. /// A very fast inline version allocateChunk() which requires that the size is known at compile time and is less than 8k
  72. HK_FORCE_INLINE void* allocateChunkConstSize( int nbytes, HK_MEMORY_CLASS cl );
  73. /// A very fast inline version of deallocateChunk() which requires that the size is known at compile time and is less than 8k, and not null.
  74. HK_FORCE_INLINE void deallocateChunkConstSize(void* p, int nbytes, HK_MEMORY_CLASS cl );
  75. /// Allocates a piece of memory from a LIFO pool, aligned to 16 bytes.
  76. HK_FORCE_INLINE void* allocateStack(int nbytes);
  77. /// Reduces the size of the top allocated stack
  78. HK_FORCE_INLINE void shrinkAllocatedStack(void* ptr, int newSize);
  79. /// Deallocates a piece of memory that has been allocated by allocateStack
  80. HK_FORCE_INLINE void deallocateStack(void* p);
  81. /// Allocates nbytes bytes, aligned to 'alignment' which is a power of 2.
  82. /// Note that the default allocate is already 16 byte aligned.
  83. /// Memory classes are defined in 'hkbase/memoryclasses/hkMemoryClasses.h'.
  84. virtual void* alignedAllocate(int alignment, int nbytes, HK_MEMORY_CLASS cl);
  85. /// Deallocates a piece of memory. This must have been allocated by a call to alignedAllocate.
  86. virtual void  alignedDeallocate(void* ptr);
  87. /// Make initial stack allocations come from buf. buf should be 16 byte aligned.
  88. /// Havok requires temporary memory (called a "stack area") to perform many of its operations.
  89. /// This memory must be explicitly set after hkBaseSystem has been initialised.
  90. /// You can call this method any time the stack is empty, e.g. outside of hkpWorld::stepDeltaTime callbacks.
  91. virtual void setStackArea(void* buf, int nbytes);
  92. /// Get the thread local instance of this memory manager
  93. static inline hkThreadMemory* HK_CALL getInstancePtr(); // may be null
  94. static inline hkThreadMemory& HK_CALL getInstance(); // will assert if null
  95. #if !defined(HK_PLATFORM_PS3_SPU)
  96. /// Replace the thread local instance of this memory manager
  97. static void HK_CALL replaceInstance(hkThreadMemory* m);
  98. /// Adds a reference
  99. void addReference();
  100. /// removes a reference
  101. void removeReference();
  102. #endif
  103. /// Gives all local memory back to the main memory manager
  104. virtual void releaseCachedMemory();
  105. /// Calls releaseCachedMemory
  106. HK_FORCE_INLINE virtual ~hkThreadMemory(){ releaseCachedMemory(); }
  107. protected:
  108. /// Override this function to hook into the frame based allocation.
  109. /// This function is called from allocateStack when there is not enough
  110. /// room in the current stack to satisfy the request. It should adjust
  111. /// m_stack as necessary and return a pointer to a new block of nbytes.<p>
  112. /// You can disable the frame based allocation completely (for instance if
  113. /// you are running several threads) by overriding this method
  114. /// (and onStackUnderflow)to simply return a new block of memory without
  115. /// updating m_stack. This ensures that allocateStack will always forward
  116. /// to onStackOverflow.
  117. virtual void* onStackOverflow(int nbytes);
  118. /// Override this function to hook into the frame based allocation.
  119. /// Called when the current stack becomes empty. See also onStackOverflow.
  120. virtual void onStackUnderflow(void* p);
  121. public:
  122. enum
  123. {
  124. // We are aligning on a 64 byte boundary,
  125. // as all the data layout of all major functions is optimized for
  126. // the 64 bytes cache line width of playstation
  127. PAGE_ALIGN  = 64,
  128. // All small rows must align with this shift
  129. MEMORY_SMALL_BLOCK_RSHIFT_BITS = 4,
  130. /// Added before the shift
  131. MEMORY_SMALL_BLOCK_ADD = 0xf,
  132. // The number of small chunk sizes
  133. MEMORY_MAX_SMALL_ROW  = 13,
  134. // The number of small and large chunk sizes
  135. MEMORY_MAX_ALL_ROW = (MEMORY_MAX_SMALL_ROW+4),
  136. // The largest small block we allocate from this pool - this is specially sized to match sizeof(hkpRigidBody)
  137. MEMORY_MAX_SIZE_SMALL_BLOCK  = 512 + 32,
  138. // The largest large block we allocate from this pool
  139. MEMORY_MAX_SIZE_LARGE_BLOCK = 8192,
  140. // The low bits we ignore when indexing into the large arrays
  141. MEMORY_LARGE_BLOCK_RSHIFT_BITS = 10,
  142. // How much we allocate when the small pool becomes full
  143. MEMORY_SYSTEM_PAGE_SIZE = 8192,
  144. // Debugging
  145. MEMORY_MAGIC_NUMBER = 0x3425234
  146. };
  147. struct Stack
  148. {
  149. Stack()
  150. : m_current(HK_NULL),
  151. m_prev(HK_NULL),
  152. m_base((char*)-1),
  153. m_end(HK_NULL)
  154. // base is used several ways:
  155. // usually points to base of current block.
  156. {
  157. }
  158. HK_ALIGN16(char* m_current);
  159. Stack* m_prev;
  160. char* m_base;
  161. char* m_end;
  162. int getFreeBytes() { return int(m_end - m_current)-16; }
  163. };
  164. HK_FORCE_INLINE Stack& HK_CALL getStack();
  165. /// Get the row of a given size. The size has to be less than the largest small block size
  166. HK_FORCE_INLINE int getRow(int nbytes) const;
  167. /// Get the row of a given size. The size has to be less than the largest small block size
  168. /// This is faster if the size is known at compile time
  169. static HK_FORCE_INLINE int HK_CALL constSizeToRow( int size );
  170. /// returns the memory block size of the elements per row
  171. HK_FORCE_INLINE int rowToSize( int row ) const;
  172. protected:
  173. // thread memory talks to main memory in batches of this size
  174. enum { BATCH_SIZE=4 };
  175. // Called when an allocation from an empty row is requested.
  176. void* onRowEmpty(int row, HK_MEMORY_CLASS cl);
  177. // Called when an deallocation from a full row is requested. p is a ptr that will be added to that row
  178. void onRowFull(int row, void* p, HK_MEMORY_CLASS cl);
  179. // Clear all of the pointers on that row. 
  180. void clearRow(int rowIndex, HK_MEMORY_CLASS cl);
  181. //
  182. // Internal public section
  183. //
  184. public:
  185. // pointer to the main memory
  186. hkMemory* m_memory;
  187. // reference count
  188. int m_referenceCount;
  189. // a stack based allocation system
  190. Stack m_stack;
  191. int m_stackSize;
  192. // the maximum number of elements on each free list before the parent hkMemory is called
  193. int m_maxNumElemsOnFreeList;
  194. struct FreeList
  195. {
  196. enum { MAX_FREELIST=0x0fffffff };
  197. FreeList() : m_head(HK_NULL), m_numElem(0) {}
  198. void put( void* p )
  199. {
  200. m_numElem += 1;
  201. FreeElem* fl = static_cast<FreeElem*>(p);
  202. fl->m_next = m_head;
  203. m_head = fl;
  204. }
  205. void* get()
  206. {
  207. if(void* p = m_head)
  208. {
  209. m_numElem -= 1;
  210. m_head = m_head->m_next;
  211. return p;
  212. }
  213. return HK_NULL;
  214. }
  215. struct FreeElem { FreeElem* m_next; };
  216. FreeElem* m_head;
  217. int m_numElem;
  218. };
  219. // free list for blocks of each size
  220. FreeList m_free_list[MEMORY_MAX_ALL_ROW];
  221. // a lookup table of size of each block size
  222. int m_row_to_size_lut[MEMORY_MAX_ALL_ROW];
  223. // a lookup table of sizes to small block size
  224. char m_small_size_to_row_lut[(MEMORY_MAX_SIZE_SMALL_BLOCK >> MEMORY_SMALL_BLOCK_RSHIFT_BITS)+1];
  225. // a lookup table of sizes to large block size
  226. int m_large_size_to_row_lut[ (MEMORY_MAX_SIZE_LARGE_BLOCK >> MEMORY_LARGE_BLOCK_RSHIFT_BITS) ];
  227. };
  228. #if defined(HK_PLATFORM_PS3_SPU)
  229. # undef virtual
  230. #endif
  231. hkThreadMemory* HK_CALL hkThreadMemory::getInstancePtr()
  232. {
  233. // move this back to a static member when compiler bug fixed
  234. // TLS slot to store this threads mem instance.
  235. extern HK_THREAD_LOCAL( hkThreadMemory* ) hkThreadMemory__s_threadMemoryInstance;
  236. return HK_THREAD_LOCAL_GET(hkThreadMemory__s_threadMemoryInstance);
  237. }
  238. hkThreadMemory& HK_CALL hkThreadMemory::getInstance()
  239. {
  240. hkThreadMemory* instance = getInstancePtr();
  241. //HK_ASSERT( 0xf032de34, instance != HK_NULL && "No hkThreadMemory. Did you call hkBaseSystem::initThread() for your new thread?" );
  242. return *instance;
  243. }
  244. template <typename TYPE> HK_FORCE_INLINE TYPE* HK_CALL hkAllocateStack(int n, const char* what = 0);
  245. template <typename TYPE>    HK_FORCE_INLINE void HK_CALL hkShrinkAllocatedStack(TYPE* ptr, int newSize ); // shrink the last piece allocated by hkAllocateStack
  246. template <typename TYPE> HK_FORCE_INLINE void HK_CALL hkDeallocateStack(TYPE* ptr);
  247. #if defined(HK_COMPILER_MWERKS)
  248. # define HK_OPERATOR_DELETE
  249. # define HK_OPERATOR_NONVIRTUAL_DELETE
  250. #else
  251. # define HK_OPERATOR_DELETE 
  252. HK_FORCE_INLINE void  HK_CALL operator delete(void*, void*) { }
  253. HK_FORCE_INLINE void  HK_CALL operator delete[](void*, void*) { HK_BREAKPOINT(0); }
  254. # define HK_OPERATOR_NONVIRTUAL_DELETE 
  255. HK_FORCE_INLINE void  HK_CALL operator delete(void*, void*) { } 
  256. HK_FORCE_INLINE void  HK_CALL operator delete[](void*, void*) { }
  257. #endif
  258. # define HK_MUST_END_WITH_SEMICOLON class MustEndWithSemiColon
  259. #if defined( HK_PLATFORM_PS3_SPU)
  260. #define HK_DECLARE_CLASS_ALLOCATOR_UNCHECKED(TYPE) 
  261. HK_FORCE_INLINE void* HK_CALL operator new(hk_size_t nbytes) { static int q; return &q; }
  262. HK_FORCE_INLINE void  HK_CALL operator delete(void* p) { } 
  263. HK_FORCE_INLINE void* HK_CALL operator new[](hk_size_t nbytes) { static int q; return &q; }
  264. HK_FORCE_INLINE void  HK_CALL operator delete[](void* p) {  }
  265. HK_FORCE_INLINE void* HK_CALL operator new(hk_size_t, void* p) { return p; }
  266. HK_FORCE_INLINE void* HK_CALL operator new[](hk_size_t, void* p){ return p; }
  267. HK_OPERATOR_DELETE 
  268. HK_MUST_END_WITH_SEMICOLON
  269. #else
  270. #define HK_DECLARE_CLASS_ALLOCATOR_UNCHECKED(TYPE) 
  271. HK_FORCE_INLINE void* HK_CALL operator new(hk_size_t nbytes) { HK_ASSERT_OBJECT_SIZE_OK(nbytes); hkReferencedObject* b = static_cast<hkReferencedObject*>(hkThreadMemory::getInstance().allocateChunk(static_cast<int>(nbytes),TYPE)); b->m_memSizeAndFlags = static_cast<hkUint16>(nbytes); return b; }
  272. HK_FORCE_INLINE void  HK_CALL operator delete(void* p) { hkReferencedObject* b = static_cast<hkReferencedObject*>(p); hkThreadMemory::getInstance().deallocateChunk(p, b->m_memSizeAndFlags,TYPE); }
  273. HK_FORCE_INLINE void* HK_CALL operator new[](hk_size_t nbytes) { hkReferencedObject* b = static_cast<hkReferencedObject*>(hkThreadMemory::getInstance().allocateChunk(static_cast<int>(nbytes),TYPE)); b->m_memSizeAndFlags = static_cast<hkUint16>(nbytes); return b; }
  274. HK_FORCE_INLINE void  HK_CALL operator delete[](void* p) { hkReferencedObject* b = static_cast<hkReferencedObject*>(p); hkThreadMemory::getInstance().deallocateChunk(p, b->m_memSizeAndFlags,TYPE); }
  275. HK_FORCE_INLINE void* HK_CALL operator new(hk_size_t, void* p) { return p; }
  276. HK_FORCE_INLINE void* HK_CALL operator new[](hk_size_t, void* p){ HK_BREAKPOINT(0); return p; }
  277. HK_OPERATOR_DELETE 
  278. HK_MUST_END_WITH_SEMICOLON
  279. #endif
  280. #define HK_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR_BY_SIZE_UNCHECKED(TYPE,CLASS_SIZE) 
  281. HK_FORCE_INLINE void* HK_CALL operator new(hk_size_t nbytes) { HK_ASSERT(0x6c787b7f, nbytes == CLASS_SIZE ); return hkThreadMemory::getInstance().allocateChunkConstSize(static_cast<int>(nbytes),TYPE); }
  282. HK_FORCE_INLINE void  HK_CALL operator delete(void* p) { if (p) hkThreadMemory::getInstance().deallocateChunkConstSize(p, CLASS_SIZE, TYPE); }
  283. HK_FORCE_INLINE void* HK_CALL operator new[](hk_size_t nbytes) { return hkThreadMemory::getInstance().allocate(static_cast<int>(nbytes),TYPE); }
  284. HK_FORCE_INLINE void  HK_CALL operator delete[](void* p) { hkThreadMemory::getInstance().deallocate(p); } 
  285. HK_FORCE_INLINE void* HK_CALL operator new(hk_size_t n, void* p){ HK_ASSERT(0x77bb90a1, n == CLASS_SIZE); return p; } 
  286. HK_FORCE_INLINE void* HK_CALL operator new[](hk_size_t, void* p){ return p; } 
  287. HK_OPERATOR_NONVIRTUAL_DELETE 
  288. HK_MUST_END_WITH_SEMICOLON
  289. //
  290. // In debug, use some compile time trickery to ensure correct allocator is used.
  291. // Use -Wshadow to catch nonvirtual allocators in virtual classes.
  292. //
  293. #if defined(HK_DEBUG)
  294. #   define HK_DECLARE_CLASS_ALLOCATOR(TYPE) 
  295.         HK_FORCE_INLINE const hkReferencedObject* iMustBeDerivedFromReferencedObject() const { return static_cast<const hkReferencedObject*>(this); } 
  296.         HK_DECLARE_CLASS_ALLOCATOR_UNCHECKED(TYPE)
  297. #   define HK_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR(TYPE,THIS_CLASS) 
  298.         HK_FORCE_INLINE void iShouldNotHaveVtable() const { int m_memSizeAndFlags = 0; m_memSizeAndFlags--; /* if you get this error, you derive from hkReferencedObject! */ } 
  299.         HK_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR_BY_SIZE_UNCHECKED(TYPE, sizeof(THIS_CLASS))
  300. #else
  301. #   define HK_DECLARE_CLASS_ALLOCATOR(TYPE) 
  302. HK_DECLARE_CLASS_ALLOCATOR_UNCHECKED(TYPE)
  303. #   define HK_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR(TYPE,THIS_CLASS) 
  304.         HK_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR_BY_SIZE_UNCHECKED(TYPE, sizeof(THIS_CLASS))
  305. #endif
  306. /// Convenience inline function to allocate memory of the correct type
  307. template <typename TYPE>
  308. HK_FORCE_INLINE TYPE* HK_CALL hkAllocate(int numberOfObjects, HK_MEMORY_CLASS cl)
  309. {
  310. return static_cast<TYPE*>(hkThreadMemory::getInstance().allocate(numberOfObjects*hkSizeOf(TYPE), cl));
  311. }
  312. /// Convenience inline function to deallocate memory of the correct type
  313. template <typename TYPE>
  314. HK_FORCE_INLINE void HK_CALL hkDeallocate(TYPE* ptr)
  315. {
  316. hkThreadMemory::getInstance().deallocate(static_cast<void *>(ptr));
  317. }
  318. /// Convenience inline function to allocate aligned memory of the correct type
  319. template <typename TYPE>
  320. HK_FORCE_INLINE TYPE* HK_CALL hkAlignedAllocate(int alignment,int numberOfObjects, HK_MEMORY_CLASS cl)
  321. {
  322. return static_cast<TYPE*>(hkThreadMemory::getInstance().alignedAllocate(alignment,numberOfObjects*hkSizeOf(TYPE), cl));
  323. }
  324. /// Convenience inline function to deallocate memory of the correct type
  325. template <typename TYPE>
  326. HK_FORCE_INLINE void HK_CALL hkAlignedDeallocate(TYPE* ptr)
  327. {
  328. hkThreadMemory::getInstance().alignedDeallocate(static_cast<void *>(ptr));
  329. }
  330. /// Convenience function to allocate memory of the correct type
  331. template <typename TYPE>
  332. HK_FORCE_INLINE TYPE* HK_CALL hkAllocateChunk(int numberOfObjects, HK_MEMORY_CLASS cl)
  333. {
  334. return static_cast<TYPE*>(hkThreadMemory::getInstance().allocateChunk(numberOfObjects*hkSizeOf(TYPE), cl));
  335. }
  336. /// Convenience function to deallocate memory of the correct type
  337. template <typename TYPE>
  338. HK_FORCE_INLINE void HK_CALL hkDeallocateChunk(TYPE* ptr, int numberOfObjects, HK_MEMORY_CLASS cl)
  339. {
  340. hkThreadMemory::getInstance().deallocateChunk(static_cast<void*>(ptr), numberOfObjects*hkSizeOf(TYPE), cl);
  341. }
  342. #if defined(HK_DEBUG) && !defined(HK_PLATFORM_PS3_SPU)
  343. extern void HK_CALL HK_ASSERT_OBJECT_SIZE_OK_FUNC(hk_size_t nbytes);
  344. # define HK_ASSERT_OBJECT_SIZE_OK(A) HK_ASSERT_OBJECT_SIZE_OK_FUNC(A)
  345. #else
  346. # define HK_ASSERT_OBJECT_SIZE_OK(A)
  347. #endif
  348. #endif // HKBASE_hkThreadMemory_H
  349. /*
  350. * Havok SDK - NO SOURCE PC DOWNLOAD, BUILD(#20090216)
  351. * Confidential Information of Havok.  (C) Copyright 1999-2009
  352. * Telekinesys Research Limited t/a Havok. All Rights Reserved. The Havok
  353. * Logo, and the Havok buzzsaw logo are trademarks of Havok.  Title, ownership
  354. * rights, and intellectual property rights in the Havok software remain in
  355. * Havok and/or its suppliers.
  356. * Use of this software for evaluation purposes is subject to and indicates
  357. * acceptance of the End User licence Agreement for this product. A copy of
  358. * the license is included with this software and is also available at www.havok.com/tryhavok.
  359. */