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