1 /*****************************************************************************
2 *
3 * Copyright (c) 2008-2010, CoreCodec, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of CoreCodec, Inc. nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY CoreCodec, Inc. ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL CoreCodec, Inc. BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 ****************************************************************************/
29
30 #include "parser.h"
31
32 // Don't use dataheap in win32 debug mode. It's easier to track down memory corruptions.
33 #if defined(NDEBUG) || !defined(TARGET_WIN32)
34 #define DATAHEAP_LIMIT 72
35 #else
36 #define DATAHEAP_LIMIT 1
37 #endif
38
39 #ifdef MIPS64
40 typedef uint64_t dataunit;
41 #else
42 typedef uintptr_t dataunit;
43 #endif
44
45 #define BUFFER_SIZE 1024 //in dataunit
46
47 #define DATAALIGN(n) (((n)+sizeof(dataunit)-1)/sizeof(dataunit))
48
DataSize(dataunit * i)49 static INLINE size_t DataSize(dataunit* i) { return (size_t)*i & 65535; }
DataNext(dataunit * i)50 static INLINE size_t DataNext(dataunit* i) { return (size_t)*i >> 16; }
51
52 struct dataheap_free
53 {
54 dataheap_free* Next;
55 };
56
57 typedef struct dataheap_block
58 {
59 dataunit* Data;
60 uint16_t Count;
61 uint16_t MaxSize;
62
63 } dataheap_block;
64
65 #if 0
66 static void DataHeap_Check(dataheap* p)
67 {
68 dataheap_block* i;
69 size_t MaxSize=0;
70
71 for (i=ARRAYBEGIN(p->Buffer,dataheap_block);i!=ARRAYEND(p->Buffer,dataheap_block);++i)
72 {
73 dataunit* a = i->Data;
74 dataunit* b = i->Data+BUFFER_SIZE-1;
75 size_t Count=0;
76
77 assert(i->MaxSize>=MaxSize);
78 assert(!DataSize(a));
79 assert(*b==0);
80
81 while (a!=b)
82 {
83 if (i->MaxSize)
84 {
85 assert(DataSize(a)<=i->MaxSize);
86 if (DataSize(a)==i->MaxSize)
87 ++Count;
88 }
89 assert(DataSize(a)<=DataNext(a));
90 assert(a+DataNext(a)<=b);
91 a += DataNext(a);
92 }
93
94 MaxSize = i->MaxSize;
95 assert(!i->MaxSize || i->Count==Count);
96 }
97 }
98 #else
99 #define DataHeap_Check(p) {}
100 #endif
101
DataHeap_Write(dataheap * UNUSED_PARAM (p),void * Ptr,const void * Src,size_t Pos,size_t Size)102 static void DataHeap_Write(dataheap* UNUSED_PARAM(p),void* Ptr,const void* Src,size_t Pos,size_t Size)
103 {
104 memcpy((uint8_t*)Ptr+Pos,Src,Size);
105 }
106
DataHeap_Alloc(dataheap * p,size_t Size,int UNUSED_PARAM (Flags))107 static void* DataHeap_Alloc(dataheap* p, size_t Size, int UNUSED_PARAM(Flags))
108 {
109 dataheap_block Block;
110 dataheap_block* i;
111 dataunit* curr;
112 dataunit* prev;
113 size_t n,Count,MaxSize;
114
115 if (!Size)
116 return NULL;
117
118 Size = DATAALIGN(Size);
119
120 if (Size>=DATAHEAP_LIMIT)
121 return MemHeap_Alloc(p->Heap,Size*sizeof(dataunit),0);
122
123 LockEnter(p->Lock);
124
125 if (Size==DATAALIGN(3*sizeof(void*)))
126 {
127 dataheap_free* i;
128 if (!p->Free3)
129 {
130 Block.Count = 0;
131 Block.MaxSize = 0;
132 Block.Data = MemHeap_Alloc(p->Heap,BUFFER_SIZE*sizeof(dataunit),0);
133 if (!Block.Data)
134 goto failed;
135
136 if (!ArrayInsert(&p->Buffer,0,&Block,sizeof(Block),256))
137 goto failed_array;
138
139 Block.Data[0] = (BUFFER_SIZE-1)<<16; // head delimiter
140 Block.Data[BUFFER_SIZE-1] = 0; // tail delimiter
141
142 for (n=1;n<BUFFER_SIZE-3;n+=3)
143 {
144 i=(dataheap_free*)(Block.Data+n);
145 i->Next = p->Free3;
146 p->Free3 = i;
147 }
148 }
149
150 i=p->Free3;
151 p->Free3 = i->Next;
152 LockLeave(p->Lock);
153 return i;
154 }
155
156 DataHeap_Check(p);
157
158 if (!ARRAYEMPTY(p->Buffer))
159 {
160 for (;;)
161 {
162 i=ARRAYEND(p->Buffer,dataheap_block)-1;
163 if (i->MaxSize<Size)
164 break;
165
166 MaxSize=i->Count?i->MaxSize:0;
167 Count=0;
168
169 curr = i->Data;
170 do
171 {
172 prev = curr;
173 curr += DataNext(curr);
174
175 if ((n = DataSize(curr)) >= Size)
176 {
177 if (n==i->MaxSize)
178 {
179 assert(i->Count>0);
180 i->Count = (uint16_t)(i->Count-1);
181 }
182
183 if (n == Size)
184 *prev += DataNext(curr) << 16;
185 else
186 {
187 *prev += Size << 16;
188 curr[Size] = (n-Size) | ((DataNext(curr)-Size)<<16);
189 }
190
191 LockLeave(p->Lock);
192 return curr;
193 }
194
195 if (MaxSize<=n)
196 {
197 if (MaxSize==n)
198 ++Count;
199 else
200 {
201 MaxSize=n;
202 Count=1;
203 }
204 }
205 }
206 while (n);
207
208 assert(i->Count==0);
209
210 i->Count = (uint16_t)Count;
211 i->MaxSize = (uint16_t)MaxSize;
212 while (i!=ARRAYBEGIN(p->Buffer,dataheap_block) && i[-1].MaxSize > i->MaxSize)
213 {
214 SWAPVAL(dataheap_block,i[-1],i[0]);
215 --i;
216 }
217 }
218 }
219
220 Block.Data = MemHeap_Alloc(p->Heap,BUFFER_SIZE*sizeof(dataunit),0);
221 if (!Block.Data)
222 goto failed;
223
224 if (!ArrayAppend(&p->Buffer,&Block,sizeof(Block),256))
225 goto failed_array;
226
227 MaxSize = BUFFER_SIZE-2-Size;
228
229 i = ARRAYEND(p->Buffer,dataheap_block)-1;
230 i->Count = 1;
231 i->MaxSize = (uint16_t)MaxSize;
232
233 curr = i->Data;
234 curr[0] = (1+Size)<<16; // head delimiter
235 curr[1+Size] = MaxSize + (MaxSize<<16);
236 curr[BUFFER_SIZE-1] = 0; // tail delimiter
237
238 while (i!=ARRAYBEGIN(p->Buffer,dataheap_block) && i[-1].MaxSize > i->MaxSize)
239 {
240 SWAPVAL(dataheap_block,i[-1],i[0]);
241 --i;
242 }
243
244 LockLeave(p->Lock);
245 return curr+1;
246
247 failed_array:
248 MemHeap_Free(p->Heap,Block.Data,BUFFER_SIZE*sizeof(dataunit));
249 failed:
250 LockLeave(p->Lock);
251 return NULL;
252 }
253
DataHeap_Free(dataheap * p,void * Ptr,size_t Size)254 static void DataHeap_Free(dataheap* p, void* Ptr, size_t Size)
255 {
256 if (Ptr && Size)
257 {
258 dataunit *curr = (dataunit*)Ptr;
259 dataunit *next;
260 dataunit *prev;
261 dataheap_block* i;
262
263 Size = DATAALIGN(Size);
264
265 if (Size>=DATAHEAP_LIMIT)
266 {
267 MemHeap_Free(p->Heap,Ptr,Size*sizeof(dataunit));
268 return;
269 }
270
271 LockEnter(p->Lock);
272
273 if (Size==3)
274 {
275 ((dataheap_free*)Ptr)->Next = p->Free3;
276 p->Free3 = (dataheap_free*)Ptr;
277 LockLeave(p->Lock);
278 return;
279 }
280
281 for (i=ARRAYEND(p->Buffer,dataheap_block);i!=ARRAYBEGIN(p->Buffer,dataheap_block);)
282 {
283 --i;
284 if (i->Data < curr && i->Data+BUFFER_SIZE > curr)
285 {
286 DataHeap_Check(p);
287
288 next = i->Data;
289 do
290 {
291 prev = next;
292 next += DataNext(next);
293 }
294 while (next<curr);
295
296 *curr = Size + ((next - curr)<<16);
297 *prev = DataSize(prev) + ((curr - prev)<<16);
298
299 // merge with next (avoid delimiter)
300 if (DataSize(next) && DataSize(curr)==DataNext(curr))
301 *curr += *next;
302
303 // merge with prev (avoid delimiter)
304 if (DataSize(prev) && DataSize(prev)==DataNext(prev))
305 {
306 *prev += *curr;
307 curr = prev;
308 }
309
310 Size = DataSize(curr);
311 if (Size > i->MaxSize)
312 {
313 i->MaxSize = (uint16_t)Size;
314 i->Count = 1;
315
316 while (++i!=ARRAYEND(p->Buffer,dataheap_block) && i[-1].MaxSize > i->MaxSize)
317 {
318 SWAPVAL(dataheap_block,i[-1],i[0]);
319 }
320 }
321 else
322 if (Size == i->MaxSize)
323 i->Count = (uint16_t)(i->Count+1);
324
325 DataHeap_Check(p);
326 break;
327 }
328 }
329
330 LockLeave(p->Lock);
331 }
332 }
333
DataHeap_ReAlloc(dataheap * p,void * Old,size_t OldSize,size_t NewSize)334 static void* DataHeap_ReAlloc(dataheap* p, void* Old, size_t OldSize, size_t NewSize)
335 {
336 size_t n;
337 void* New;
338
339 OldSize = DATAALIGN(OldSize)*sizeof(dataunit);
340 NewSize = DATAALIGN(NewSize)*sizeof(dataunit);
341
342 if (OldSize == NewSize)
343 return Old;
344
345 if (DATAHEAP_LIMIT*sizeof(dataunit)<=OldSize && DATAHEAP_LIMIT*sizeof(dataunit)<=NewSize)
346 return MemHeap_ReAlloc(p->Heap,Old,OldSize,NewSize);
347
348 New = DataHeap_Alloc(p,NewSize,0);
349
350 if (!New && NewSize)
351 return NULL; // failed
352
353 if (Old && New)
354 {
355 n = min(OldSize,NewSize);
356 memcpy(New,Old,n);
357 }
358
359 DataHeap_Free(p,Old,OldSize);
360 return New;
361 }
362
DataHeap_Init(dataheap * p,const cc_memheap * Heap)363 void DataHeap_Init(dataheap* p,const cc_memheap* Heap)
364 {
365 assert(BUFFER_SIZE-2>=DATAHEAP_LIMIT);
366 p->Base.Alloc = (memheap_alloc)DataHeap_Alloc;
367 p->Base.ReAlloc = (memheap_realloc)DataHeap_ReAlloc;
368 p->Base.Free = (memheap_free)DataHeap_Free;
369 p->Base.Write = (memheap_write)DataHeap_Write;
370 p->Base.Null.Heap = &p->Base;
371 p->Base.Null.Size = DATA_FLAG_MEMHEAP;
372 p->Heap = Heap;
373 ArrayInitEx(&p->Buffer,Heap);
374 ArrayAlloc(&p->Buffer,512,1);
375 p->Lock = LockCreate();
376 p->Free3 = NULL;
377 }
378
DataHeap_Done(dataheap * p)379 void DataHeap_Done(dataheap* p)
380 {
381 dataheap_block* i;
382 for (i=ARRAYBEGIN(p->Buffer,dataheap_block);i!=ARRAYEND(p->Buffer,dataheap_block);++i)
383 MemHeap_Free(p->Heap,i->Data,BUFFER_SIZE*sizeof(dataunit));
384 ArrayClear(&p->Buffer);
385 p->Free3 = NULL;
386 LockDelete(p->Lock);
387 p->Lock = NULL;
388 }
389
390