1 /*****************************************************************************/
5 /* Source file line info structure */
9 /* (C) 2001-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* 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 /*****************************************************************************/
52 /*****************************************************************************/
54 /*****************************************************************************/
58 static unsigned HT_GenHash (const void* Key);
59 /* Generate the hash over a key. */
61 static const void* HT_GetKey (const void* Entry);
62 /* Given a pointer to the user entry data, return a pointer to the key */
64 static int HT_Compare (const void* Key1, const void* Key2);
65 /* Compare two keys. The function must return a value less than zero if
66 * Key1 is smaller than Key2, zero if both are equal, and a value greater
67 * than zero if Key1 is greater then Key2.
72 /*****************************************************************************/
74 /*****************************************************************************/
78 /* Structure that holds the key for a line info */
79 typedef struct LineInfoKey LineInfoKey;
81 FilePos Pos; /* File position */
82 unsigned Type; /* Type/count of line info */
85 /* Structure that holds line info */
87 HashNode Node; /* Hash table node */
88 unsigned Id; /* Index */
89 LineInfoKey Key; /* Key for this line info */
90 unsigned RefCount; /* Reference counter */
91 Collection Spans; /* Segment spans for this line info */
92 Collection OpenSpans; /* List of currently open spans */
97 /* Collection containing all line infos */
98 static Collection LineInfoList = STATIC_COLLECTION_INITIALIZER;
100 /* Collection with currently active line infos */
101 static Collection CurLineInfo = STATIC_COLLECTION_INITIALIZER;
103 /* Hash table functions */
104 static const HashFunctions HashFunc = {
110 /* Line info hash table */
111 static HashTable LineInfoTab = STATIC_HASHTABLE_INITIALIZER (1051, &HashFunc);
113 /* The current assembler input line */
114 static LineInfo* AsmLineInfo = 0;
118 /*****************************************************************************/
119 /* Hash table functions */
120 /*****************************************************************************/
124 static unsigned HT_GenHash (const void* Key)
125 /* Generate the hash over a key. */
127 /* Key is a LineInfoKey pointer */
128 const LineInfoKey* K = Key;
130 /* Hash over a combination of type, file and line */
131 return HashInt ((K->Type << 18) ^ (K->Pos.Name << 14) ^ K->Pos.Line);
136 static const void* HT_GetKey (const void* Entry)
137 /* Given a pointer to the user entry data, return a pointer to the key */
139 return &((const LineInfo*)Entry)->Key;
144 static int HT_Compare (const void* Key1, const void* Key2)
145 /* Compare two keys. The function must return a value less than zero if
146 * Key1 is smaller than Key2, zero if both are equal, and a value greater
147 * than zero if Key1 is greater then Key2.
150 /* Convert both parameters to FileInfoKey pointers */
151 const LineInfoKey* K1 = Key1;
152 const LineInfoKey* K2 = Key2;
154 /* Compare line number, then file and type */
155 int Res = (int)K2->Pos.Line - (int)K1->Pos.Line;
157 Res = (int)K2->Pos.Name - (int)K1->Pos.Name;
159 Res = (int)K2->Type - (int)K1->Type;
169 /*****************************************************************************/
170 /* struct LineInfo */
171 /*****************************************************************************/
175 static LineInfo* NewLineInfo (const LineInfoKey* Key)
176 /* Create and return a new line info. Usage will be zero. */
178 /* Allocate memory */
179 LineInfo* LI = xmalloc (sizeof (LineInfo));
181 /* Initialize the fields */
182 InitHashNode (&LI->Node);
186 InitCollection (&LI->Spans);
187 InitCollection (&LI->OpenSpans);
189 /* Add it to the hash table, so we will find it if necessary */
190 HT_InsertEntry (&LineInfoTab, LI);
192 /* Return the new struct */
198 static void FreeLineInfo (LineInfo* LI)
199 /* Free a LineInfo structure */
201 /* Free the Spans collection. It is supposed to be empty */
202 CHECK (CollCount (&LI->Spans) == 0);
203 DoneCollection (&LI->Spans);
204 DoneCollection (&LI->OpenSpans);
206 /* Free the structure itself */
212 static int CheckLineInfo (void* Entry, void* Data attribute ((unused)))
213 /* Called from HT_Walk. Remembers used line infos and assigns them an id */
215 /* Entry is actually a line info */
216 LineInfo* LI = Entry;
218 /* The entry is used if there are spans or the ref counter is non zero */
219 if (LI->RefCount > 0 || CollCount (&LI->Spans) > 0) {
220 LI->Id = CollCount (&LineInfoList);
221 CollAppend (&LineInfoList, LI);
222 return 0; /* Keep the entry */
225 return 1; /* Remove entry from table */
231 /*****************************************************************************/
233 /*****************************************************************************/
237 void InitLineInfo (void)
238 /* Initialize the line infos */
240 static const FilePos DefaultPos = STATIC_FILEPOS_INITIALIZER;
242 /* Increase the initial count of the line info collection */
243 CollGrow (&LineInfoList, 200);
245 /* Create a LineInfo for the default source. This is necessary to allow
246 * error message to be generated without any input file open.
248 AsmLineInfo = StartLine (&DefaultPos, LI_TYPE_ASM, 0);
253 void DoneLineInfo (void)
254 /* Close down line infos */
256 /* Close all current line infos */
257 unsigned Count = CollCount (&CurLineInfo);
259 EndLine (CollAt (&CurLineInfo, --Count));
262 /* Walk over the entries in the hash table and sort them into used and
263 * unused ones. Add the used ones to the line info list and assign them
266 HT_Walk (&LineInfoTab, CheckLineInfo, 0);
271 void EndLine (LineInfo* LI)
272 /* End a line that is tracked by the given LineInfo structure */
276 /* Close the spans for the line */
277 CloseSpans (&LI->OpenSpans);
279 /* Move the spans to the list of all spans for this line, then clear the
280 * list of open spans.
282 for (I = 0; I < CollCount (&LI->OpenSpans); ++I) {
283 CollAppend (&LI->Spans, CollAtUnchecked (&LI->OpenSpans, I));
285 CollDeleteAll (&LI->OpenSpans);
287 /* Line info is no longer active - remove it from the list of current
290 CollDeleteItem (&CurLineInfo, LI);
295 LineInfo* StartLine (const FilePos* Pos, unsigned Type, unsigned Count)
296 /* Start line info for a new line */
301 /* Prepare the key struct */
303 Key.Type = LI_MAKE_TYPE (Type, Count);
305 /* Try to find a line info with this position and type in the hash table.
306 * If so, reuse it. Otherwise create a new one.
308 LI = HT_FindEntry (&LineInfoTab, &Key);
310 /* Allocate a new LineInfo */
311 LI = NewLineInfo (&Key);
314 /* Open the spans for this line info */
315 OpenSpans (&LI->OpenSpans);
317 /* Add the line info to the list of current line infos */
318 CollAppend (&CurLineInfo, LI);
320 /* Return the new info */
326 void NewAsmLine (void)
327 /* Start a new assembler input line. Use this function when generating new
328 * line of LI_TYPE_ASM. It will check if line and/or file have actually
329 * changed, end the old and start the new line as necessary.
332 /* Check if we can reuse the old line */
334 if (AsmLineInfo->Key.Pos.Line == CurTok.Pos.Line &&
335 AsmLineInfo->Key.Pos.Name == CurTok.Pos.Name) {
336 /* We do already have line info for this line */
340 /* Line has changed -> end the old line */
341 EndLine (AsmLineInfo);
344 /* Start a new line using the current line info */
345 AsmLineInfo = StartLine (&CurTok.Pos, LI_TYPE_ASM, 0);
350 LineInfo* GetAsmLineInfo (void)
351 /* Return the line info for the current assembler file. The function will
352 * bump the reference counter before returning the line info.
355 ++AsmLineInfo->RefCount;
361 void ReleaseLineInfo (LineInfo* LI)
362 /* Decrease the reference count for a line info */
364 /* Decrease the reference counter */
365 CHECK (LI->RefCount > 0);
371 void GetFullLineInfo (Collection* LineInfos)
372 /* Return full line infos, that is line infos for currently active Slots. The
373 * infos will be added to the given collection, existing entries will be left
374 * intact. The reference count of all added entries will be increased.
379 /* If the collection is currently empty, grow it as necessary */
380 if (CollCount (LineInfos) == 0) {
381 CollGrow (LineInfos, CollCount (&CurLineInfo));
384 /* Copy all valid line infos to the collection */
385 for (I = 0; I < CollCount (&CurLineInfo); ++I) {
387 /* Get the line info from the slot */
388 LineInfo* LI = CollAt (&CurLineInfo, I);
390 /* Bump the reference counter */
393 /* Return it to the caller */
394 CollAppend (LineInfos, LI);
400 void ReleaseFullLineInfo (Collection* LineInfos)
401 /* Decrease the reference count for a collection full of LineInfos, then clear
407 /* Walk over all entries */
408 for (I = 0; I < CollCount (LineInfos); ++I) {
409 /* Release the the line info */
410 ReleaseLineInfo (CollAt (LineInfos, I));
413 /* Delete all entries */
414 CollDeleteAll (LineInfos);
419 const FilePos* GetSourcePos (const LineInfo* LI)
420 /* Return the source file position from the given line info */
427 unsigned GetLineInfoType (const LineInfo* LI)
428 /* Return the type of a line info */
430 return LI_GET_TYPE (LI->Key.Type);
435 void WriteLineInfo (const Collection* LineInfos)
436 /* Write a list of line infos to the object file. */
440 /* Write the count */
441 ObjWriteVar (CollCount (LineInfos));
443 /* Write the line info indices */
444 for (I = 0; I < CollCount (LineInfos); ++I) {
446 /* Get a pointer to the line info */
447 const LineInfo* LI = CollConstAt (LineInfos, I);
450 CHECK (LI->Id != ~0U);
452 /* Write the index to the file */
453 ObjWriteVar (LI->Id);
459 void WriteLineInfos (void)
460 /* Write a list of all line infos to the object file. */
464 Collection EmptySpans = STATIC_COLLECTION_INITIALIZER;
466 /* Tell the object file module that we're about to write line infos */
467 ObjStartLineInfos ();
469 /* Write the line info count to the list */
470 ObjWriteVar (CollCount (&LineInfoList));
472 /* Walk over the list and write all line infos */
473 for (I = 0; I < CollCount (&LineInfoList); ++I) {
475 /* Get a pointer to this line info */
476 LineInfo* LI = CollAt (&LineInfoList, I);
478 /* Write the source file position */
479 ObjWritePos (&LI->Key.Pos);
481 /* Write the type and count of the line info */
482 ObjWriteVar (LI->Key.Type);
484 /* Spans are only added to the debug file if debug information is
485 * requested. Otherwise we write an empty list.
488 WriteSpans (&LI->Spans);
490 /* Write out an empty list */
491 WriteSpans (&EmptySpans);
495 /* End of line infos */
498 /* For the sake of completeness, but not really necessary */
499 DoneCollection (&EmptySpans);