as_memory.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2020 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. andreas@angelcode.com
  22. */
  23. //
  24. // as_memory.cpp
  25. //
  26. // Overload the default memory management functions so that we
  27. // can let the application decide how to do it.
  28. //
  29. #include <stdlib.h>
  30. #if !defined(__APPLE__) && !defined(__SNC__) && !defined(__ghs__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
  31. #include <malloc.h>
  32. #endif
  33. #include "as_config.h"
  34. #include "as_memory.h"
  35. #include "as_scriptnode.h"
  36. #include "as_bytecode.h"
  37. BEGIN_AS_NAMESPACE
  38. #ifdef WIP_16BYTE_ALIGN
  39. // TODO: Add support for 16byte aligned application types (e.g. __m128). The following is a list of things that needs to be implemented:
  40. //
  41. // ok - The script context must make sure to always allocate the local stack memory buffer on 16byte aligned boundaries (asCContext::ReserveStackSpace)
  42. // ok - The engine must make sure to always allocate the memory for the script objects on 16byte aligned boundaries (asCScriptEngine::CallAlloc)
  43. // ok - The application needs to inform a new flag when registering types that require 16byte alignment, e.g. asOBJ_APP_ALIGN16 (asCScriptEngine::RegisterObjectType)
  44. // ok - The script object type must make sure to align member properties of these types correctly (asCObjectType::AddPropertyToClass)
  45. // ok - Script global properties must allocate memory on 16byte boundaries if holding these types (asCGlobalProperty::AllocateMemory)
  46. // TODO - The script compiler must make sure to allocate the local variables on 16byte boundaries (asCCompiler::AllocateVariable)
  47. // TODO - The script compiler must add pad bytes on the stack for all function calls to guarantee that the stack position is 16byte aligned on entry in the called function (asCCompiler)
  48. // TODO - The bytecode serializer must be capable of adjusting these pad bytes to guarantee platform independent saved bytecode. Remember that the registered type may not be 16byte aligned on all platforms (asCWriter & asCReader)
  49. // TODO - The bytecode serializer must also be prepared to adjust the position of the local variables according to the need fro 16byte alignment (asCWriter & asCReader)
  50. // TODO - The code for the native calling conventions must be adjusted for all platforms that should support 16byte aligned types (as_callfunc...)
  51. // ok - When the context needs to grow the local stack memory it must copy the function arguments so that the stack entry position is 16byte aligned (asCContext::CallScriptFunction)
  52. // TODO - When the context is prepared for a new call, it must set the initial stack position so the stack entry position is 16byte aligned (asCContext::Prepare)
  53. //
  54. // http://www.gamedev.net/topic/650555-alignment-requirements/
  55. // TODO: Allow user to register its own aligned memory routines
  56. // Wrappers for aligned allocations
  57. void *debugAlignedMalloc(size_t size, size_t align, const char *file, int line)
  58. {
  59. void *mem = ((asALLOCFUNCDEBUG_t)userAlloc)(size + (align-1) + sizeof(void*), file, line);
  60. char *amem = ((char*)mem) + sizeof(void*);
  61. if( (uintptr_t)amem & (align - 1) )
  62. amem += align - ((uintptr_t)amem & (align - 1));
  63. ((void**)amem)[-1] = mem;
  64. return amem;
  65. }
  66. void *alignedMalloc(size_t size, size_t align)
  67. {
  68. void *mem = userAlloc(size + (align-1) + sizeof(void*));
  69. char *amem = ((char*)mem) + sizeof(void*);
  70. if( (uintptr_t)amem & (align - 1) )
  71. amem += align - ((uintptr_t)amem & (align - 1));
  72. ((void**)amem)[-1] = mem;
  73. return amem;
  74. }
  75. void alignedFree(void *mem)
  76. {
  77. userFree( ((void**)mem)[-1] );
  78. }
  79. bool isAligned(const void* const pointer, asUINT alignment)
  80. {
  81. return (uintptr_t(pointer) % alignment) == 0;
  82. }
  83. #endif
  84. // By default we'll use the standard memory management functions
  85. // Make sure these globals are initialized first. Otherwise the
  86. // library may crash in case the application initializes the engine
  87. // as a global variable.
  88. #ifdef _MSC_VER
  89. // MSVC let's us choose between a couple of different initialization orders.
  90. #pragma warning(disable: 4073)
  91. #pragma init_seg(lib)
  92. asALLOCFUNC_t userAlloc = malloc;
  93. asFREEFUNC_t userFree = free;
  94. #ifdef WIP_16BYTE_ALIGN
  95. #ifdef AS_DEBUG
  96. asALLOCALIGNEDFUNC_t userAllocAligned = (asALLOCALIGNEDFUNC_t)debugAlignedMalloc;
  97. #else
  98. asALLOCALIGNEDFUNC_t userAllocAligned = alignedMalloc;
  99. #endif
  100. asFREEALIGNEDFUNC_t userFreeAligned = alignedFree;
  101. #endif
  102. #else
  103. // Other compilers will just have to rely on luck.
  104. asALLOCFUNC_t userAlloc = malloc;
  105. asFREEFUNC_t userFree = free;
  106. #ifdef WIP_16BYTE_ALIGN
  107. asALLOCALIGNEDFUNC_t userAllocAligned = alignedMalloc;
  108. asFREEALIGNEDFUNC_t userFreeAligned = alignedFree;
  109. #endif
  110. #endif
  111. extern "C"
  112. {
  113. // interface
  114. int asSetGlobalMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc)
  115. {
  116. // Clean-up thread local memory before changing the allocation routines to avoid
  117. // potential problem with trying to free memory using a different allocation
  118. // routine than used when allocating it.
  119. asThreadCleanup();
  120. userAlloc = allocFunc;
  121. userFree = freeFunc;
  122. return 0;
  123. }
  124. // interface
  125. int asResetGlobalMemoryFunctions()
  126. {
  127. // Clean-up thread local memory before changing the allocation routines to avoid
  128. // potential problem with trying to free memory using a different allocation
  129. // routine than used when allocating it.
  130. asThreadCleanup();
  131. userAlloc = malloc;
  132. userFree = free;
  133. return 0;
  134. }
  135. // interface
  136. void *asAllocMem(size_t size)
  137. {
  138. return asNEWARRAY(asBYTE, size);
  139. }
  140. // interface
  141. void asFreeMem(void *mem)
  142. {
  143. asDELETEARRAY(mem);
  144. }
  145. } // extern "C"
  146. asCMemoryMgr::asCMemoryMgr()
  147. {
  148. }
  149. asCMemoryMgr::~asCMemoryMgr()
  150. {
  151. FreeUnusedMemory();
  152. }
  153. void asCMemoryMgr::FreeUnusedMemory()
  154. {
  155. // It's necessary to protect the scriptNodePool from multiple
  156. // simultaneous accesses, as the parser is used by several methods
  157. // that can be executed simultaneously.
  158. ENTERCRITICALSECTION(cs);
  159. int n;
  160. for( n = 0; n < (signed)scriptNodePool.GetLength(); n++ )
  161. userFree(scriptNodePool[n]);
  162. scriptNodePool.Allocate(0, false);
  163. LEAVECRITICALSECTION(cs);
  164. // The engine already protects against multiple threads
  165. // compiling scripts simultaneously so this pool doesn't have
  166. // to be protected again.
  167. for( n = 0; n < (signed)byteInstructionPool.GetLength(); n++ )
  168. userFree(byteInstructionPool[n]);
  169. byteInstructionPool.Allocate(0, false);
  170. }
  171. void *asCMemoryMgr::AllocScriptNode()
  172. {
  173. ENTERCRITICALSECTION(cs);
  174. if( scriptNodePool.GetLength() )
  175. {
  176. void *tRet = scriptNodePool.PopLast();
  177. LEAVECRITICALSECTION(cs);
  178. return tRet;
  179. }
  180. LEAVECRITICALSECTION(cs);
  181. #if defined(AS_DEBUG)
  182. return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCScriptNode), __FILE__, __LINE__);
  183. #else
  184. return userAlloc(sizeof(asCScriptNode));
  185. #endif
  186. }
  187. void asCMemoryMgr::FreeScriptNode(void *ptr)
  188. {
  189. ENTERCRITICALSECTION(cs);
  190. // Pre allocate memory for the array to avoid slow growth
  191. if( scriptNodePool.GetLength() == 0 )
  192. scriptNodePool.Allocate(100, 0);
  193. scriptNodePool.PushLast(ptr);
  194. #ifdef AS_DEBUG
  195. // clear the memory to facilitate identification of use after free
  196. memset(ptr, 0xCDCDCDCD, sizeof(asCScriptNode));
  197. #endif
  198. LEAVECRITICALSECTION(cs);
  199. }
  200. #ifndef AS_NO_COMPILER
  201. void *asCMemoryMgr::AllocByteInstruction()
  202. {
  203. // This doesn't need a critical section because, only one compilation is allowed at a time
  204. if( byteInstructionPool.GetLength() )
  205. return byteInstructionPool.PopLast();
  206. #if defined(AS_DEBUG)
  207. return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCByteInstruction), __FILE__, __LINE__);
  208. #else
  209. return userAlloc(sizeof(asCByteInstruction));
  210. #endif
  211. }
  212. void asCMemoryMgr::FreeByteInstruction(void *ptr)
  213. {
  214. // Pre allocate memory for the array to avoid slow growth
  215. if( byteInstructionPool.GetLength() == 0 )
  216. byteInstructionPool.Allocate(100, 0);
  217. byteInstructionPool.PushLast(ptr);
  218. #ifdef AS_DEBUG
  219. // clear the memory to facilitate identification of use after free
  220. memset(ptr, 0xCDCDCDCD, sizeof(asCByteInstruction));
  221. #endif
  222. }
  223. #endif // AS_NO_COMPILER
  224. END_AS_NAMESPACE