1 /*****************************************************************************/
5 /* Literal string handling for the cc65 C compiler */
9 /* (C) 1998-2009, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
55 /*****************************************************************************/
57 /*****************************************************************************/
61 /* Definition of a literal */
63 unsigned Label; /* Asm label for this literal */
64 int RefCount; /* Reference count */
65 int Output; /* True if output has been generated */
66 StrBuf Data; /* Literal data */
69 /* Definition of the literal pool */
71 struct SymEntry* Func; /* Function that owns the pool */
72 Collection WritableLiterals; /* Writable literals in the pool */
73 Collection ReadOnlyLiterals; /* Readonly literals in the pool */
76 /* The global and current literal pool */
77 static LiteralPool* GlobalPool = 0;
78 static LiteralPool* LP = 0;
80 /* Stack that contains the nested literal pools. Since TOS is in LiteralPool
81 * and functions aren't nested in C, the maximum depth is 1. I'm using a
82 * collection anyway, so the code is prepared for nested functions or
85 static Collection LPStack = STATIC_COLLECTION_INITIALIZER;
89 /*****************************************************************************/
91 /*****************************************************************************/
95 static Literal* NewLiteral (const void* Buf, unsigned Len)
96 /* Create a new literal and return it */
99 Literal* L = xmalloc (sizeof (*L));
101 /* Initialize the fields */
102 L->Label = GetLocalLabel ();
106 SB_AppendBuf (&L->Data, Buf, Len);
108 /* Return the new literal */
114 static void FreeLiteral (Literal* L)
117 /* Free the literal data */
120 /* Free the structure itself */
126 static void OutputLiteral (Literal* L)
127 /* Output one literal to the currently active data segment */
129 /* Translate the literal into the target charset */
130 TranslateLiteral (L);
132 /* Define the label for the literal */
133 g_defdatalabel (L->Label);
135 /* Output the literal data */
136 g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data));
138 /* Mark the literal as output */
144 Literal* UseLiteral (Literal* L)
145 /* Increase the reference counter for the literal and return it */
147 /* Increase the reference count */
150 /* If --local-strings was given, immediately output the literal */
151 if (IS_Get (&LocalStrings)) {
152 /* Switch to the proper data segment */
153 if (IS_Get (&WritableStrings)) {
158 /* Output the literal */
162 /* Return the literal */
168 void ReleaseLiteral (Literal* L)
169 /* Decrement the reference counter for the literal */
172 CHECK (L->RefCount >= 0 && (L->RefCount > 0 || !L->Output));
177 void TranslateLiteral (Literal* L)
178 /* Translate a literal into the target charset. */
180 TgtTranslateBuf (SB_GetBuf (&L->Data), SB_GetLen (&L->Data));
185 unsigned GetLiteralLabel (const Literal* L)
186 /* Return the asm label for a literal */
193 const char* GetLiteralStr (const Literal* L)
194 /* Return the data for a literal as pointer to char */
196 return SB_GetConstBuf (&L->Data);
201 const StrBuf* GetLiteralStrBuf (const Literal* L)
202 /* Return the data for a literal as pointer to the string buffer */
209 unsigned GetLiteralSize (const Literal* L)
210 /* Get the size of a literal string */
212 return SB_GetLen (&L->Data);
217 /*****************************************************************************/
219 /*****************************************************************************/
223 static LiteralPool* NewLiteralPool (struct SymEntry* Func)
224 /* Create a new literal pool and return it */
226 /* Allocate memory */
227 LiteralPool* LP = xmalloc (sizeof (*LP));
229 /* Initialize the fields */
231 InitCollection (&LP->WritableLiterals);
232 InitCollection (&LP->ReadOnlyLiterals);
234 /* Return the new pool */
240 static void FreeLiteralPool (LiteralPool* LP)
241 /* Free a LiteralPool structure */
243 /* Free the collections contained within the struct */
244 DoneCollection (&LP->WritableLiterals);
245 DoneCollection (&LP->ReadOnlyLiterals);
247 /* Free the struct itself */
253 static int Compare (void* Data attribute ((unused)),
254 const void* Left, const void* Right)
255 /* Compare function used when sorting the literal pool */
257 /* Larger strings are considered "smaller" */
258 return (int) GetLiteralSize (Right) - (int) GetLiteralSize (Left);
263 void InitLiteralPool (void)
264 /* Initialize the literal pool */
266 /* Create the global literal pool */
267 GlobalPool = LP = NewLiteralPool (0);
272 void PushLiteralPool (struct SymEntry* Func)
273 /* Push the current literal pool onto the stack and create a new one */
275 /* We must have a literal pool to push! */
276 PRECONDITION (LP != 0);
278 /* Push the old pool */
279 CollAppend (&LPStack, LP);
281 /* Create a new one */
282 LP = NewLiteralPool (Func);
287 LiteralPool* PopLiteralPool (void)
288 /* Pop the last literal pool from TOS and activate it. Return the old
292 /* Remember the current literal pool */
293 LiteralPool* Old = LP;
295 /* Pop one from stack */
296 LP = CollPop (&LPStack);
298 /* Return the old one */
304 static void MoveLiterals (Collection* Source, Collection* Target)
305 /* Move referenced literals from Source to Target, delete unreferenced ones */
309 /* Move referenced literals, remove unreferenced ones */
310 for (I = 0; I < CollCount (Source); ++I) {
312 /* Get the literal */
313 Literal* L = CollAt (Source, I);
315 /* If it is referenced and not output, add it to the Target pool,
318 if (L->RefCount && !L->Output) {
319 CollAppend (Target, L);
328 void MoveLiteralPool (LiteralPool* LocalPool)
329 /* Move all referenced literals in LocalPool to the global literal pool. This
330 * function will free LocalPool after moving the used string literals.
333 /* Move the literals */
334 MoveLiterals (&LocalPool->WritableLiterals, &GlobalPool->WritableLiterals);
335 MoveLiterals (&LocalPool->ReadOnlyLiterals, &GlobalPool->ReadOnlyLiterals);
337 /* Free the local literal pool */
338 FreeLiteralPool (LocalPool);
343 static void OutputWritableLiterals (Collection* Literals)
344 /* Output the given writable literals */
348 /* If nothing there, exit... */
349 if (CollCount (Literals) == 0) {
353 /* Switch to the correct segment */
356 /* Emit all literals that have a reference */
357 for (I = 0; I < CollCount (Literals); ++I) {
359 /* Get a pointer to the literal */
360 Literal* L = CollAtUnchecked (Literals, I);
362 /* Output this one, if it has references and wasn't already output */
363 if (L->RefCount > 0 && !L->Output) {
372 static void OutputReadOnlyLiterals (Collection* Literals)
373 /* Output the given readonly literals merging (even partial) duplicates */
377 /* If nothing there, exit... */
378 if (CollCount (Literals) == 0) {
382 /* Switch to the correct segment */
385 /* Sort the literal pool by literal size. Larger strings go first */
386 CollSort (Literals, Compare, 0);
388 /* Emit all literals that have a reference */
389 for (I = 0; I < CollCount (Literals); ++I) {
394 /* Get the next literal */
395 Literal* L = CollAt (Literals, I);
397 /* Ignore it, if it doesn't have references or was already output */
398 if (L->RefCount == 0 || L->Output) {
402 /* Translate the literal into the target charset */
403 TranslateLiteral (L);
405 /* Check if this literal is part of another one. Since the literals
406 * are sorted by size (larger ones first), it can only be part of a
407 * literal with a smaller index.
408 * Beware: Only check literals that have actually been referenced.
411 for (J = 0; J < I; ++J) {
415 /* Get a pointer to the compare literal */
416 Literal* L2 = CollAt (Literals, J);
418 /* Ignore literals that have no reference */
419 if (L2->RefCount == 0) {
423 /* Get a pointer to the data */
424 D = SB_GetConstBuf (&L2->Data) + SB_GetLen (&L2->Data) - SB_GetLen (&L->Data);
426 /* Compare the data */
427 if (memcmp (D, SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data)) == 0) {
428 /* Remember the literal and terminate the loop */
434 /* Check if we found a match */
437 /* This literal is part of a longer literal, merge them */
438 g_aliasdatalabel (L->Label, C->Label, GetLiteralSize (C) - GetLiteralSize (L));
442 /* Define the label for the literal */
443 g_defdatalabel (L->Label);
445 /* Output the literal data */
446 g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data));
450 /* Mark the literal */
457 void OutputLiteralPool (void)
458 /* Output the global literal pool */
460 /* Output both sorts of literals */
461 OutputWritableLiterals (&GlobalPool->WritableLiterals);
462 OutputReadOnlyLiterals (&GlobalPool->ReadOnlyLiterals);
467 Literal* AddLiteral (const char* S)
468 /* Add a literal string to the literal pool. Return the literal. */
470 return AddLiteralBuf (S, strlen (S) + 1);
475 Literal* AddLiteralBuf (const void* Buf, unsigned Len)
476 /* Add a buffer containing a literal string to the literal pool. Return the
480 /* Create a new literal */
481 Literal* L = NewLiteral (Buf, Len);
483 /* Add the literal to the correct pool */
484 if (IS_Get (&WritableStrings)) {
485 CollAppend (&LP->WritableLiterals, L);
487 CollAppend (&LP->ReadOnlyLiterals, L);
490 /* Return the new literal */
496 Literal* AddLiteralStr (const StrBuf* S)
497 /* Add a literal string to the literal pool. Return the literal. */
499 return AddLiteralBuf (SB_GetConstBuf (S), SB_GetLen (S));