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