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