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 StrBuf Data; /* Literal data */
68 /* Definition of the literal pool */
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 */
75 /* The global and current literal pool */
76 static LiteralPool* GlobalPool = 0;
77 static LiteralPool* LP = 0;
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
84 static Collection LPStack = STATIC_COLLECTION_INITIALIZER;
88 /*****************************************************************************/
90 /*****************************************************************************/
94 static Literal* NewLiteral (const void* Buf, unsigned Len)
95 /* Create a new literal and return it */
98 Literal* L = xmalloc (sizeof (*L));
100 /* Initialize the fields */
101 L->Label = GetLocalLabel ();
104 SB_AppendBuf (&L->Data, Buf, Len);
106 /* Return the new literal */
112 static void FreeLiteral (Literal* L)
115 /* Free the literal data */
118 /* Free the structure itself */
124 Literal* UseLiteral (Literal* L)
125 /* Increase the reference counter for the literal and return it */
133 void ReleaseLiteral (Literal* L)
134 /* Decrement the reference counter for the literal */
136 CHECK (--L->RefCount >= 0);
141 void TranslateLiteral (Literal* L)
142 /* Translate a literal into the target charset. */
144 TgtTranslateBuf (SB_GetBuf (&L->Data), SB_GetLen (&L->Data));
149 unsigned GetLiteralLabel (const Literal* L)
150 /* Return the asm label for a literal */
157 const char* GetLiteralStr (const Literal* L)
158 /* Return the data for a literal as pointer to char */
160 return SB_GetConstBuf (&L->Data);
165 const StrBuf* GetLiteralStrBuf (const Literal* L)
166 /* Return the data for a literal as pointer to the string buffer */
173 unsigned GetLiteralSize (const Literal* L)
174 /* Get the size of a literal string */
176 return SB_GetLen (&L->Data);
181 /*****************************************************************************/
183 /*****************************************************************************/
187 static LiteralPool* NewLiteralPool (struct SymEntry* Func)
188 /* Create a new literal pool and return it */
190 /* Allocate memory */
191 LiteralPool* LP = xmalloc (sizeof (*LP));
193 /* Initialize the fields */
195 InitCollection (&LP->WritableLiterals);
196 InitCollection (&LP->ReadOnlyLiterals);
198 /* Return the new pool */
204 static void FreeLiteralPool (LiteralPool* LP)
205 /* Free a LiteralPool structure */
207 /* Free the collections contained within the struct */
208 DoneCollection (&LP->WritableLiterals);
209 DoneCollection (&LP->ReadOnlyLiterals);
211 /* Free the struct itself */
217 static int Compare (void* Data attribute ((unused)),
218 const void* Left, const void* Right)
219 /* Compare function used when sorting the literal pool */
221 /* Larger strings are considered "smaller" */
222 return (int) GetLiteralSize (Right) - (int) GetLiteralSize (Left);
227 void InitLiteralPool (void)
228 /* Initialize the literal pool */
230 /* Create the global literal pool */
231 GlobalPool = LP = NewLiteralPool (0);
236 void PushLiteralPool (struct SymEntry* Func)
237 /* Push the current literal pool onto the stack and create a new one */
239 /* We must have a literal pool to push! */
240 PRECONDITION (LP != 0);
242 /* Push the old pool */
243 CollAppend (&LPStack, LP);
245 /* Create a new one */
246 LP = NewLiteralPool (Func);
251 LiteralPool* PopLiteralPool (void)
252 /* Pop the last literal pool from TOS and activate it. Return the old
256 /* Remember the current literal pool */
257 LiteralPool* Old = LP;
259 /* Pop one from stack */
260 LP = CollPop (&LPStack);
262 /* Return the old one */
268 static void MoveLiterals (Collection* Source, Collection* Target)
269 /* Move referenced literals from Source to Target, delete unreferenced ones */
273 /* Move referenced literals, remove unreferenced ones */
274 for (I = 0; I < CollCount (Source); ++I) {
276 /* Get the literal */
277 Literal* L = CollAt (Source, I);
279 /* If it is referenced, add it to the Target pool, otherwise free it */
281 CollAppend (Target, L);
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.
295 /* Move the literals */
296 MoveLiterals (&LocalPool->WritableLiterals, &GlobalPool->WritableLiterals);
297 MoveLiterals (&LocalPool->ReadOnlyLiterals, &GlobalPool->ReadOnlyLiterals);
299 /* Free the local literal pool */
300 FreeLiteralPool (LocalPool);
305 static void DumpWritableLiterals (Collection* Literals)
306 /* Dump the given writable literals */
310 /* If nothing there, exit... */
311 if (CollCount (Literals) == 0) {
315 /* Switch to the correct segment */
318 /* Emit all literals that have a reference */
319 for (I = 0; I < CollCount (Literals); ++I) {
321 /* Get the next literal */
322 Literal* L = CollAt (Literals, I);
324 /* Ignore it, if it doesn't have references */
325 if (L->RefCount == 0) {
329 /* Translate the literal into the target charset */
330 TranslateLiteral (L);
332 /* Define the label for the literal */
333 g_defdatalabel (L->Label);
335 /* Output the literal data */
336 g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data));
343 static void DumpReadOnlyLiterals (Collection* Literals)
344 /* Dump the given readonly literals merging (even partial) duplicates */
348 /* If nothing there, exit... */
349 if (CollCount (Literals) == 0) {
353 /* Switch to the correct segment */
356 /* Sort the literal pool by literal size. Larger strings go first */
357 CollSort (Literals, Compare, 0);
359 /* Emit all literals that have a reference */
360 for (I = 0; I < CollCount (Literals); ++I) {
365 /* Get the next literal */
366 Literal* L = CollAt (Literals, I);
368 /* Ignore it, if it doesn't have references */
369 if (L->RefCount == 0) {
373 /* Translate the literal into the target charset */
374 TranslateLiteral (L);
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.
382 for (J = 0; J < I; ++J) {
386 /* Get a pointer to the compare literal */
387 Literal* L2 = CollAt (Literals, J);
389 /* Ignore literals that have no reference */
390 if (L2->RefCount == 0) {
394 /* Get a pointer to the data */
395 D = SB_GetConstBuf (&L2->Data) + SB_GetLen (&L2->Data) - SB_GetLen (&L->Data);
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 */
405 /* Check if we found a match */
408 /* This literal is part of a longer literal, merge them */
409 g_aliasdatalabel (L->Label, C->Label, GetLiteralSize (C) - GetLiteralSize (L));
414 /* Define the label for the literal */
415 g_defdatalabel (L->Label);
417 /* Output the literal data */
418 g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data));
426 void DumpLiteralPool (void)
427 /* Dump the global literal pool */
429 /* Dump both sorts of literals */
430 DumpWritableLiterals (&GlobalPool->WritableLiterals);
431 DumpReadOnlyLiterals (&GlobalPool->ReadOnlyLiterals);
436 Literal* AddLiteral (const char* S)
437 /* Add a literal string to the literal pool. Return the literal. */
439 return AddLiteralBuf (S, strlen (S) + 1);
444 Literal* AddLiteralBuf (const void* Buf, unsigned Len)
445 /* Add a buffer containing a literal string to the literal pool. Return the
449 /* Create a new literal */
450 Literal* L = NewLiteral (Buf, Len);
452 /* Add the literal to the correct pool */
453 if (IS_Get (&WritableStrings)) {
454 CollAppend (&LP->WritableLiterals, L);
456 CollAppend (&LP->ReadOnlyLiterals, L);
459 /* Return the new literal */
465 Literal* AddLiteralStr (const StrBuf* S)
466 /* Add a literal string to the literal pool. Return the literal. */
468 return AddLiteralBuf (SB_GetConstBuf (S), SB_GetLen (S));