Remove _mesa_strcpy in favor of plain strcpy.
[mesa.git] / src / mesa / shader / slang / slang_mem.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.3
4 *
5 * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file slang_mem.c
27 *
28 * Memory manager for GLSL compiler. The general idea is to do all
29 * allocations out of a large pool then just free the pool when done
30 * compiling to avoid intricate malloc/free tracking and memory leaks.
31 *
32 * \author Brian Paul
33 */
34
35 #include "main/context.h"
36 #include "main/macros.h"
37 #include "slang_mem.h"
38
39
40 #define GRANULARITY 8
41 #define ROUND_UP(B) ( ((B) + (GRANULARITY - 1)) & ~(GRANULARITY - 1) )
42
43
44 /** If 1, use conventional malloc/free. Helpful for debugging */
45 #define USE_MALLOC_FREE 0
46
47
48 struct slang_mempool_
49 {
50 GLuint Size, Used, Count, Largest;
51 char *Data;
52 struct slang_mempool_ *Next;
53 };
54
55
56 slang_mempool *
57 _slang_new_mempool(GLuint initialSize)
58 {
59 slang_mempool *pool = (slang_mempool *) _mesa_calloc(sizeof(slang_mempool));
60 if (pool) {
61 pool->Data = (char *) _mesa_calloc(initialSize);
62 /*printf("ALLOC MEMPOOL %d at %p\n", initialSize, pool->Data);*/
63 if (!pool->Data) {
64 _mesa_free(pool);
65 return NULL;
66 }
67 pool->Size = initialSize;
68 pool->Used = 0;
69 }
70 return pool;
71 }
72
73
74 void
75 _slang_delete_mempool(slang_mempool *pool)
76 {
77 GLuint total = 0;
78 while (pool) {
79 slang_mempool *next = pool->Next;
80 /*
81 printf("DELETE MEMPOOL %u / %u count=%u largest=%u\n",
82 pool->Used, pool->Size, pool->Count, pool->Largest);
83 */
84 total += pool->Used;
85 _mesa_free(pool->Data);
86 _mesa_free(pool);
87 pool = next;
88 }
89 /*printf("TOTAL ALLOCATED: %u\n", total);*/
90 }
91
92
93 #ifdef DEBUG
94 static void
95 check_zero(const char *addr, GLuint n)
96 {
97 GLuint i;
98 for (i = 0; i < n; i++) {
99 assert(addr[i]==0);
100 }
101 }
102 #endif
103
104
105 #ifdef DEBUG
106 static GLboolean
107 is_valid_address(const slang_mempool *pool, void *addr)
108 {
109 while (pool) {
110 if ((char *) addr >= pool->Data &&
111 (char *) addr < pool->Data + pool->Used)
112 return GL_TRUE;
113
114 pool = pool->Next;
115 }
116 return GL_FALSE;
117 }
118 #endif
119
120
121 /**
122 * Alloc 'bytes' from shader mempool.
123 */
124 void *
125 _slang_alloc(GLuint bytes)
126 {
127 #if USE_MALLOC_FREE
128 return _mesa_calloc(bytes);
129 #else
130 slang_mempool *pool;
131 GET_CURRENT_CONTEXT(ctx);
132 pool = (slang_mempool *) ctx->Shader.MemPool;
133
134 if (bytes == 0)
135 bytes = 1;
136
137 while (pool) {
138 if (pool->Used + bytes <= pool->Size) {
139 /* found room */
140 void *addr = (void *) (pool->Data + pool->Used);
141 #ifdef DEBUG
142 check_zero((char*) addr, bytes);
143 #endif
144 pool->Used += ROUND_UP(bytes);
145 pool->Largest = MAX2(pool->Largest, bytes);
146 pool->Count++;
147 /*printf("alloc %u Used %u\n", bytes, pool->Used);*/
148 return addr;
149 }
150 else if (pool->Next) {
151 /* try next block */
152 pool = pool->Next;
153 }
154 else {
155 /* alloc new pool */
156 const GLuint sz = MAX2(bytes, pool->Size);
157 pool->Next = _slang_new_mempool(sz);
158 if (!pool->Next) {
159 /* we're _really_ out of memory */
160 return NULL;
161 }
162 else {
163 pool = pool->Next;
164 pool->Largest = bytes;
165 pool->Count++;
166 pool->Used = ROUND_UP(bytes);
167 #ifdef DEBUG
168 check_zero((char*) pool->Data, bytes);
169 #endif
170 return (void *) pool->Data;
171 }
172 }
173 }
174 return NULL;
175 #endif
176 }
177
178
179 void *
180 _slang_realloc(void *oldBuffer, GLuint oldSize, GLuint newSize)
181 {
182 #if USE_MALLOC_FREE
183 return _mesa_realloc(oldBuffer, oldSize, newSize);
184 #else
185 GET_CURRENT_CONTEXT(ctx);
186 slang_mempool *pool = (slang_mempool *) ctx->Shader.MemPool;
187 (void) pool;
188
189 if (newSize < oldSize) {
190 return oldBuffer;
191 }
192 else {
193 const GLuint copySize = (oldSize < newSize) ? oldSize : newSize;
194 void *newBuffer = _slang_alloc(newSize);
195
196 if (oldBuffer)
197 ASSERT(is_valid_address(pool, oldBuffer));
198
199 if (newBuffer && oldBuffer && copySize > 0)
200 _mesa_memcpy(newBuffer, oldBuffer, copySize);
201
202 return newBuffer;
203 }
204 #endif
205 }
206
207
208 /**
209 * Clone string, storing in current mempool.
210 */
211 char *
212 _slang_strdup(const char *s)
213 {
214 if (s) {
215 size_t l = _mesa_strlen(s);
216 char *s2 = (char *) _slang_alloc(l + 1);
217 if (s2)
218 strcpy(s2, s);
219 return s2;
220 }
221 else {
222 return NULL;
223 }
224 }
225
226
227 /**
228 * Don't actually free memory, but mark it (for debugging).
229 */
230 void
231 _slang_free(void *addr)
232 {
233 #if USE_MALLOC_FREE
234 _mesa_free(addr);
235 #else
236 if (addr) {
237 GET_CURRENT_CONTEXT(ctx);
238 slang_mempool *pool = (slang_mempool *) ctx->Shader.MemPool;
239 (void) pool;
240 ASSERT(is_valid_address(pool, addr));
241 }
242 #endif
243 }