]> git.sur5r.net Git - cc65/blobdiff - src/ca65/span.c
Merge remote-tracking branch 'upstream/master' into a5200
[cc65] / src / ca65 / span.c
index 47db633b0b878e7a0fffaa4bb03a81c147e67403..5b42d9eb509f06cbf5a4595bc25aaa2e3b086226 100644 (file)
 
 
 /* common */
+#include "hashfunc.h"
+#include "hashtab.h"
 #include "xmalloc.h"
 
 /* ca65 */
+#include "global.h"
 #include "objfile.h"
 #include "segment.h"
 #include "span.h"
+#include "spool.h"
+
+
+
+/*****************************************************************************/
+/*                                 Forwards                                  */
+/*****************************************************************************/
+
+
+
+static unsigned HT_GenHash (const void* Key);
+/* Generate the hash over a key. */
+
+static const void* HT_GetKey (const void* Entry);
+/* Given a pointer to the user entry data, return a pointer to the key */
+
+static int HT_Compare (const void* Key1, const void* Key2);
+/* Compare two keys. The function must return a value less than zero if
+ * Key1 is smaller than Key2, zero if both are equal, and a value greater
+ * than zero if Key1 is greater then Key2.
+ */
 
 
 
 
 
 
+/* Hash table functions */
+static const HashFunctions HashFunc = {
+    HT_GenHash,
+    HT_GetKey,
+    HT_Compare
+};
+
+/* Span hash table */
+static HashTable SpanTab = STATIC_HASHTABLE_INITIALIZER (1051, &HashFunc);
+
+
+
+/*****************************************************************************/
+/*                           Hash table functions                            */
+/*****************************************************************************/
+
+
+
+static unsigned HT_GenHash (const void* Key)
+/* Generate the hash over a key. */
+{
+    /* Key is a Span pointer */
+    const Span* S = Key;
+
+    /* Hash over a combination of segment number, start and end */
+    return HashInt ((S->Seg->Num << 28) ^ (S->Start << 14) ^ S->End);
+}
+
+
+
+static const void* HT_GetKey (const void* Entry)
+/* Given a pointer to the user entry data, return a pointer to the key */
+{
+    return Entry;
+}
+
+
+
+static int HT_Compare (const void* Key1, const void* Key2)
+/* Compare two keys. The function must return a value less than zero if
+ * Key1 is smaller than Key2, zero if both are equal, and a value greater
+ * than zero if Key1 is greater then Key2.
+ */
+{
+    /* Convert both parameters to Span pointers */
+    const Span* S1 = Key1;
+    const Span* S2 = Key2;
+
+    /* Compare segment number, then start and end */
+    int Res = (int)S2->Seg->Num - (int)S1->Seg->Num;
+    if (Res == 0) {
+        Res = (int)S2->Start - (int)S1->Start;
+        if (Res == 0) {
+            Res = (int)S2->End - (int)S1->End;
+        }
+    }
+
+    /* Done */
+    return Res;
+}
+
+
+
 /*****************************************************************************/
 /*                                   Code                                    */
 /*****************************************************************************/
@@ -64,9 +151,12 @@ static Span* NewSpan (Segment* Seg, unsigned long Start, unsigned long End)
     Span* S = xmalloc (sizeof (Span));
 
     /* Initialize the struct */
+    InitHashNode (&S->Node);
+    S->Id       = ~0U;
     S->Seg      = Seg;
     S->Start    = Start;
     S->End      = End;
+    S->Type     = EMPTY_STRING_ID;
 
     /* Return the new struct */
     return S;
@@ -82,7 +172,81 @@ static void FreeSpan (Span* S)
 
 
 
-void OpenSpans (Collection* Spans)
+static Span* MergeSpan (Span* S)
+/* Check if we have a span with the same data as S already. If so, free S and
+ * return the already existing one. If not, remember S and return it.
+ */
+{
+    /* Check if we have such a span already. If so use the existing
+     * one and free the one from the collection. If not, add the one to
+     * the hash table and return it.
+     */
+    Span* E = HT_Find (&SpanTab, S);
+    if (E) {
+        /* If S has a type and E not, move the type */
+        if (S->Type != EMPTY_STRING_ID) {
+            CHECK (E->Type == EMPTY_STRING_ID);
+            E->Type = S->Type;
+        }
+
+        /* Free S and return E */
+        FreeSpan (S);
+        return E;
+    } else {
+        /* Assign the id, insert S, then return it */
+        S->Id = HT_GetCount (&SpanTab);
+        HT_Insert (&SpanTab, S);
+        return S;
+    }
+}
+
+
+
+void SetSpanType (Span* S, const StrBuf* Type)
+/* Set the generic type of the span to Type */
+{                                 
+    /* Ignore the call if we won't generate debug infos */
+    if (DbgSyms) {
+        S->Type = GetStrBufId (Type);
+    }
+}
+
+
+
+Span* OpenSpan (void)
+/* Open a span for the active segment and return it. */
+{
+    return NewSpan (ActiveSeg, ActiveSeg->PC, ActiveSeg->PC);
+}
+
+
+
+Span* CloseSpan (Span* S)
+/* Close the given span. Be sure to replace the passed span by the one
+ * returned, since the span will get deleted if it is empty or may be
+ * replaced if a duplicate exists.
+ */
+{
+    /* Set the end offset */
+    if (S->Start == S->Seg->PC) {
+        /* Span is empty */
+        FreeSpan (S);
+        return 0;
+    } else {
+        /* Span is not empty */
+        S->End = S->Seg->PC;
+
+        /* Check if we have such a span already. If so use the existing
+         * one and free the one from the collection. If not, add the one to
+         * the hash table and return it.
+         */
+        return MergeSpan (S);
+    }
+}
+
+
+
+void OpenSpanList (Collection* Spans)
 /* Open a list of spans for all existing segments to the given collection of
  * spans. The currently active segment will be inserted first with all others
  * following.
@@ -90,6 +254,9 @@ void OpenSpans (Collection* Spans)
 {
     unsigned I;
 
+    /* Grow the Spans collection as necessary */
+    CollGrow (Spans, CollCount (&SegmentList));
+
     /* Add the currently active segment */
     CollAppend (Spans, NewSpan (ActiveSeg, ActiveSeg->PC, ActiveSeg->PC));
 
@@ -106,7 +273,7 @@ void OpenSpans (Collection* Spans)
 
 
 
-void CloseSpans (Collection* Spans)
+void CloseSpanList (Collection* Spans)
 /* Close a list of spans. This will add new segments to the list, mark the end
  * of existing ones, and remove empty spans from the list.
  */
@@ -138,7 +305,9 @@ void CloseSpans (Collection* Spans)
         } else {
             /* Span is not empty */
             S->End = S->Seg->PC;
-            CollReplace (Spans, S, J++);
+
+            /* Merge duplicate spans, then insert it at the new position */
+            CollReplace (Spans, MergeSpan (S), J++);
         }
     }
 
@@ -148,30 +317,93 @@ void CloseSpans (Collection* Spans)
 
 
 
-void WriteSpans (const Collection* Spans)
+void WriteSpanList (const Collection* Spans)
 /* Write a list of spans to the output file */
 {
     unsigned I;
 
-    /* Write the number of spans */
-    ObjWriteVar (CollCount (Spans));
+    /* We only write spans if debug info is enabled */
+    if (DbgSyms == 0) {
+        /* Number of spans is zero */
+        ObjWriteVar (0);
+    } else {
+        /* Write the number of spans */
+        ObjWriteVar (CollCount (Spans));
+
+        /* Write the spans */
+        for (I = 0; I < CollCount (Spans); ++I) {
+            /* Write the id of the next span */
+            ObjWriteVar (((const Span*)CollConstAt (Spans, I))->Id);
+        }
+    }
+}
 
-    /* Write the spans */
-    for (I = 0; I < CollCount (Spans); ++I) {
 
-        /* Get next range */
-        const Span* S = CollConstAt (Spans, I);
 
-        /* Write data for th span We will write the size instead of the end
-         * offset to save some bytes, since most spans are expected to be
-         * rather small.
-         */
-        ObjWriteVar (S->Seg->Num);
-        ObjWriteVar (S->Start);
-        ObjWriteVar (S->End - S->Start);
-    }
+static int CollectSpans (void* Entry, void* Data)
+/* Collect all spans in a collection sorted by id */
+{
+    /* Cast the pointers to real objects */
+    Span* S       = Entry;
+    Collection* C = Data;
+
+    /* Place the entry into the collection */
+    CollReplaceExpand (C, S, S->Id);
+
+    /* Keep the span */
+    return 0;
 }
 
+                
+
+void WriteSpans (void)
+/* Write all spans to the object file */
+{
+    /* Tell the object file module that we're about to start the spans */
+    ObjStartSpans ();
+
+    /* We will write scopes only if debug symbols are requested */
+    if (DbgSyms) {
+
+        unsigned I;
 
+        /* We must first collect all items in a collection sorted by id */
+        Collection SpanList = STATIC_COLLECTION_INITIALIZER;
+        CollGrow (&SpanList, HT_GetCount (&SpanTab));
 
+        /* Walk over the hash table and fill the span list */
+        HT_Walk (&SpanTab, CollectSpans, &SpanList);
 
+        /* Write the span count to the file */
+        ObjWriteVar (CollCount (&SpanList));
+
+        /* Write all spans */
+        for (I = 0; I < CollCount (&SpanList); ++I) {
+
+            /* Get the span and check it */
+            const Span* S = CollAtUnchecked (&SpanList, I);
+            CHECK (S->End > S->Start);
+
+            /* Write data for the span We will write the size instead of the
+             * end offset to save some bytes, since most spans are expected
+             * to be rather small.
+             */
+            ObjWriteVar (S->Seg->Num);
+            ObjWriteVar (S->Start);
+            ObjWriteVar (S->End - S->Start);
+            ObjWriteVar (S->Type);
+        }
+
+        /* Free the collection with the spans */
+        DoneCollection (&SpanList);
+
+    } else {
+
+        /* No debug info requested */
+        ObjWriteVar (0);
+
+    }
+
+    /* Done writing the spans */
+    ObjEndSpans ();
+}