]> git.sur5r.net Git - cc65/blob - src/cc65/litpool.c
Rewrote literal handling. Literals are now saved together with other function
[cc65] / src / cc65 / litpool.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 litpool.c                                 */
4 /*                                                                           */
5 /*              Literal string handling for the cc65 C compiler              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2009, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <string.h>
38
39 /* common */
40 #include "attrib.h"
41 #include "check.h"
42 #include "coll.h"
43 #include "tgttrans.h"
44 #include "xmalloc.h"
45
46 /* cc65 */
47 #include "asmlabel.h"
48 #include "codegen.h"
49 #include "error.h"
50 #include "global.h"
51 #include "litpool.h"
52
53
54
55 /*****************************************************************************/
56 /*                                   Data                                    */
57 /*****************************************************************************/
58
59
60
61 /* Definition of a literal */
62 struct Literal {
63     unsigned    Label;                  /* Asm label for this literal */
64     int         RefCount;               /* Reference count */
65     StrBuf      Data;                   /* Literal data */
66 };
67
68 /* Definition of the literal pool */
69 struct LiteralPool {
70     struct SymEntry*    Func;               /* Function that owns the pool */
71     Collection          WritableLiterals;   /* Writable literals in the pool */
72     Collection          ReadOnlyLiterals;   /* Readonly literals in the pool */
73 };
74
75 /* The global and current literal pool */
76 static LiteralPool*     GlobalPool = 0;
77 static LiteralPool*     LP         = 0;
78
79 /* Stack that contains the nested literal pools. Since TOS is in LiteralPool
80  * and functions aren't nested in C, the maximum depth is 1. I'm using a
81  * collection anyway, so the code is prepared for nested functions or
82  * whatever.
83  */
84 static Collection       LPStack  = STATIC_COLLECTION_INITIALIZER;
85
86
87
88 /*****************************************************************************/
89 /*                              struct Literal                               */
90 /*****************************************************************************/
91
92
93
94 static Literal* NewLiteral (const void* Buf, unsigned Len)
95 /* Create a new literal and return it */
96 {
97     /* Allocate memory */
98     Literal* L = xmalloc (sizeof (*L));
99
100     /* Initialize the fields */
101     L->Label    = GetLocalLabel ();
102     L->RefCount = 0;
103     SB_Init (&L->Data);
104     SB_AppendBuf (&L->Data, Buf, Len);
105
106     /* Return the new literal */
107     return L;
108 }
109
110
111
112 static void FreeLiteral (Literal* L)
113 /* Free a literal */
114 {
115     /* Free the literal data */
116     SB_Done (&L->Data);
117
118     /* Free the structure itself */
119     xfree (L);
120 }
121
122
123
124 Literal* UseLiteral (Literal* L)
125 /* Increase the reference counter for the literal and return it */
126 {
127     ++L->RefCount;
128     return L;
129 }
130
131
132
133 void ReleaseLiteral (Literal* L)
134 /* Decrement the reference counter for the literal */
135 {
136     CHECK (--L->RefCount >= 0);
137 }
138
139
140
141 void TranslateLiteral (Literal* L)
142 /* Translate a literal into the target charset. */
143 {
144     TgtTranslateBuf (SB_GetBuf (&L->Data), SB_GetLen (&L->Data));
145 }
146
147
148
149 unsigned GetLiteralLabel (const Literal* L)
150 /* Return the asm label for a literal */
151 {
152     return L->Label;
153 }
154
155
156
157 const char* GetLiteralStr (const Literal* L)
158 /* Return the data for a literal as pointer to char */
159 {
160     return SB_GetConstBuf (&L->Data);
161 }
162
163
164
165 const StrBuf* GetLiteralStrBuf (const Literal* L)
166 /* Return the data for a literal as pointer to the string buffer */
167 {
168     return &L->Data;
169 }
170
171
172
173 unsigned GetLiteralSize (const Literal* L)
174 /* Get the size of a literal string */
175 {
176     return SB_GetLen (&L->Data);
177 }
178
179
180
181 /*****************************************************************************/
182 /*                                   Code                                    */
183 /*****************************************************************************/
184
185
186
187 static LiteralPool* NewLiteralPool (struct SymEntry* Func)
188 /* Create a new literal pool and return it */
189 {
190     /* Allocate memory */
191     LiteralPool* LP = xmalloc (sizeof (*LP));
192
193     /* Initialize the fields */
194     LP->Func  = Func;
195     InitCollection (&LP->WritableLiterals);
196     InitCollection (&LP->ReadOnlyLiterals);
197
198     /* Return the new pool */
199     return LP;
200 }
201
202
203
204 static void FreeLiteralPool (LiteralPool* LP)
205 /* Free a LiteralPool structure */
206 {
207     /* Free the collections contained within the struct */
208     DoneCollection (&LP->WritableLiterals);
209     DoneCollection (&LP->ReadOnlyLiterals);
210
211     /* Free the struct itself */
212     xfree (LP);
213 }
214
215
216
217 static int Compare (void* Data attribute ((unused)),
218                     const void* Left, const void* Right)
219 /* Compare function used when sorting the literal pool */
220 {
221     /* Larger strings are considered "smaller" */
222     return (int) GetLiteralSize (Right) - (int) GetLiteralSize (Left);
223 }
224
225
226
227 void InitLiteralPool (void)
228 /* Initialize the literal pool */
229 {
230     /* Create the global literal pool */
231     GlobalPool = LP = NewLiteralPool (0);
232 }
233
234
235
236 void PushLiteralPool (struct SymEntry* Func)
237 /* Push the current literal pool onto the stack and create a new one */
238 {
239     /* We must have a literal pool to push! */
240     PRECONDITION (LP != 0);
241
242     /* Push the old pool */
243     CollAppend (&LPStack, LP);
244
245     /* Create a new one */
246     LP = NewLiteralPool (Func);
247 }
248
249
250
251 LiteralPool* PopLiteralPool (void)
252 /* Pop the last literal pool from TOS and activate it. Return the old
253  * literal pool.
254  */
255 {
256     /* Remember the current literal pool */
257     LiteralPool* Old = LP;
258
259     /* Pop one from stack */
260     LP = CollPop (&LPStack);
261
262     /* Return the old one */
263     return Old;
264 }
265
266
267
268 static void MoveLiterals (Collection* Source, Collection* Target)
269 /* Move referenced literals from Source to Target, delete unreferenced ones */
270 {
271     unsigned I;
272
273     /* Move referenced literals, remove unreferenced ones */
274     for (I = 0; I < CollCount (Source); ++I) {
275
276         /* Get the literal */
277         Literal* L = CollAt (Source, I);
278
279         /* If it is referenced, add it to the Target pool, otherwise free it */
280         if (L->RefCount) {
281             CollAppend (Target, L);
282         } else {
283             FreeLiteral (L);
284         }
285     }
286 }
287
288
289
290 void MoveLiteralPool (LiteralPool* LocalPool)
291 /* Move all referenced literals in LocalPool to the global literal pool. This
292  * function will free LocalPool after moving the used string literals.
293  */
294 {
295     /* Move the literals */
296     MoveLiterals (&LocalPool->WritableLiterals, &GlobalPool->WritableLiterals);
297     MoveLiterals (&LocalPool->ReadOnlyLiterals, &GlobalPool->ReadOnlyLiterals);
298
299     /* Free the local literal pool */
300     FreeLiteralPool (LocalPool);
301 }
302
303
304
305 static void DumpWritableLiterals (Collection* Literals)
306 /* Dump the given writable literals */
307 {
308     unsigned I;
309
310     /* If nothing there, exit... */
311     if (CollCount (Literals) == 0) {
312         return;
313     }
314
315     /* Switch to the correct segment */
316     g_usedata ();
317
318     /* Emit all literals that have a reference */
319     for (I = 0; I < CollCount (Literals); ++I) {
320
321         /* Get the next literal */
322         Literal* L = CollAt (Literals, I);
323
324         /* Ignore it, if it doesn't have references */
325         if (L->RefCount == 0) {
326             continue;
327         }
328
329         /* Translate the literal into the target charset */
330         TranslateLiteral (L);
331
332         /* Define the label for the literal */
333         g_defdatalabel (L->Label);
334
335         /* Output the literal data */
336         g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data));
337
338     }
339 }
340
341
342
343 static void DumpReadOnlyLiterals (Collection* Literals)
344 /* Dump the given readonly literals merging (even partial) duplicates */
345 {
346     unsigned I;
347
348     /* If nothing there, exit... */
349     if (CollCount (Literals) == 0) {
350         return;
351     }
352
353     /* Switch to the correct segment */
354     g_userodata ();
355
356     /* Sort the literal pool by literal size. Larger strings go first */
357     CollSort (Literals, Compare, 0);
358
359     /* Emit all literals that have a reference */
360     for (I = 0; I < CollCount (Literals); ++I) {
361
362         unsigned J;
363         Literal* C;
364
365         /* Get the next literal */
366         Literal* L = CollAt (Literals, I);
367
368         /* Ignore it, if it doesn't have references */
369         if (L->RefCount == 0) {
370             continue;
371         }
372
373         /* Translate the literal into the target charset */
374         TranslateLiteral (L);
375
376         /* Check if this literal is part of another one. Since the literals
377          * are sorted by size (larger ones first), it can only be part of a
378          * literal with a smaller index.
379          * Beware: Only check literals that have actually been referenced.
380          */
381         C = 0;
382         for (J = 0; J < I; ++J) {
383
384             const void* D;
385
386             /* Get a pointer to the compare literal */
387             Literal* L2 = CollAt (Literals, J);
388
389             /* Ignore literals that have no reference */
390             if (L2->RefCount == 0) {
391                 continue;
392             }
393
394             /* Get a pointer to the data */
395             D = SB_GetConstBuf (&L2->Data) + SB_GetLen (&L2->Data) - SB_GetLen (&L->Data);
396
397             /* Compare the data */
398             if (memcmp (D, SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data)) == 0) {
399                 /* Remember the literal and terminate the loop */
400                 C = L2;
401                 break;
402             }
403         }
404
405         /* Check if we found a match */
406         if (C != 0) {
407
408             /* This literal is part of a longer literal, merge them */
409             g_aliasdatalabel (L->Label, C->Label, GetLiteralSize (C) - GetLiteralSize (L));
410
411
412         } else {
413
414             /* Define the label for the literal */
415             g_defdatalabel (L->Label);
416
417             /* Output the literal data */
418             g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data));
419
420         }
421     }
422 }
423
424
425
426 void DumpLiteralPool (void)
427 /* Dump the global literal pool */
428 {
429     /* Dump both sorts of literals */
430     DumpWritableLiterals (&GlobalPool->WritableLiterals);
431     DumpReadOnlyLiterals (&GlobalPool->ReadOnlyLiterals);
432 }
433
434
435
436 Literal* AddLiteral (const char* S)
437 /* Add a literal string to the literal pool. Return the literal. */
438 {
439     return AddLiteralBuf (S, strlen (S) + 1);
440 }
441
442
443
444 Literal* AddLiteralBuf (const void* Buf, unsigned Len)
445 /* Add a buffer containing a literal string to the literal pool. Return the
446  * literal.
447  */
448 {
449     /* Create a new literal */
450     Literal* L = NewLiteral (Buf, Len);
451
452     /* Add the literal to the correct pool */
453     if (IS_Get (&WritableStrings)) {
454         CollAppend (&LP->WritableLiterals, L);
455     } else {
456         CollAppend (&LP->ReadOnlyLiterals, L);
457     }
458
459     /* Return the new literal */
460     return L;
461 }
462
463
464
465 Literal* AddLiteralStr (const StrBuf* S)
466 /* Add a literal string to the literal pool. Return the literal. */
467 {
468     return AddLiteralBuf (SB_GetConstBuf (S), SB_GetLen (S));
469 }
470
471
472